Monday 14 May 2018

A RESTful Web Service Using Spring Boot

A REST Service With Spring Boot


This example will help to get connected with Jira using their REST API and get all the Jira issues specific to Project. I am using basic authentication to connect with the JIRA rest services.

STEPS:- Go to Site http://start.spring.io/

Create a maven project by adding the required dependencies like DevTools e.t.c and also select a spring boot version. Few dependency will come as default. Then generate the maven project and import in your IDE.

STEP- 1 
pom.xml 

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.gaurav.jira.rest</groupId>
<artifactId>jira-services</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>

<name>jira-services</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.12.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--Spring HATEOAS provides some APIs to ease creating REST representations-->
                <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

STEP- 2
2) JiraService.java

package com.gaurav.jira.rest.service;

import com.gaurav.jira.rest.bean.JiraIssues;

/**
 * @author Kumar Gaurav
 *
 */
public interface JiraService {
public JiraIssues getAllIssueDetails(String projectId);
}

STEP- 3

3) JiraServiceImpl.java

package com.gaurav.jira.rest.service.impl;
/**
 * @author Kumar Gaurav
 *
 */
import java.util.HashMap;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.util.UriComponentsBuilder;

import com.gaurav.jira.rest.bean.JiraIssues;
import com.gaurav.jira.rest.constants.JiraRestServiceURLConstants;
import com.gaurav.jira.rest.consumer.JiraRestConsumer;
import com.gaurav.jira.rest.service.JiraService;

/**
 * The Class JiraServiceImpl.
 */
@Service
public class JiraServiceImpl implements JiraService {

/** The logger. */
Logger logger = Logger.getLogger(JiraServiceImpl.class.getName());

/** The Constant JIRA_ADDRESS. */
private final static String JIRA_SERVER_ADDRESS = "http://ip:port";


/** The rest helper. */
@Autowired
private JiraRestConsumer restHelper;

/**
* Sets the rest helper.
*
* @param restHelper
*            the new Jira rest helper
*/
public void setRestHelper(JiraRestConsumer restHelper) {
this.restHelper = restHelper;
}

/**
* @return the Jira all issues details specific to project.
*/
@Override
public JiraIssues getAllIssueDetails(String projectName) {
try {
logger.info("Getting details of all issues from Jira for the project :" + projectName);
UriComponentsBuilder builder = UriComponentsBuilder
.fromUriString(JIRA_SERVER_ADDRESS + JiraRestServiceURLConstants.ALL_ISSUES_BY_PROJECT);
Map<String, String> uriParams = new HashMap<String, String>();
uriParams.put("projectName", projectName);
builder.buildAndExpand(uriParams).toUri();
return restHelper.getJiraIssues(builder.buildAndExpand(uriParams).toUri());
} catch (Exception e) {
logger.error("error occurs" + e);
}
return null;
}
}

STEP- 4

4) JiraRestConsumer.java

package com.gaurav.jira.rest.consumer;
/**
 * @author Kumar Gaurav
 *
 */

import java.net.URI;
import java.util.Base64;

import org.apache.log4j.Logger;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.gaurav.jira.rest.bean.JiraIssues;

/**
 * The Class JiraRestConsumer :- This is a kind of helper class which will help to get the response from the rest call and map it with Java object.
 */

@Service
public class JiraRestConsumer {

/** The logger. */
Logger logger = Logger.getLogger(JiraRestConsumer.class.getName());

/**
* Jira rest call .
*
* @param uri
*            the uri
* @return the all jira issues specific to project
*/
public JiraIssues getJiraIssues(URI uri) {
try {

System.out.println("Jira URL is :->" + uri);
RestTemplate restTemplate = new RestTemplate();
try {

HttpHeaders headers = createHttpHeaders("username", "password");
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<JiraIssues> response = restTemplate.exchange(uri, HttpMethod.GET, entity,
JiraIssues.class);
System.out
.println("Result - status (" + response.getStatusCode() + ") has body: " + response.hasBody());
return response.getBody();
} catch (Exception eek) {
System.out.println("** Exception: " + eek.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}

return null;

}

/**
* This method will help to get the basic authentication.
* @param userName
* @param password
* @return
*/
private HttpHeaders createHttpHeaders(String userName, String password) {
String beforeEncode = userName + ":" + password;
String encodedAuth = Base64.getEncoder().encodeToString(beforeEncode.getBytes());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add("Authorization", "Basic " + encodedAuth);
return headers;
}
}

STEP- 5

5) JiraRestServiceURLConstants .java

package com.gaurav.jira.rest.constants;
/**
 * @author Kumar Gaurav
 *
 */
public class JiraRestServiceURLConstants {
/** This is the REST URL through which we will receive the specific project data */
public final static String ALL_ISSUES_BY_PROJECT="/rest/api/2/search?jql=project={projectName}&fields=none&maxResults=-1";
}

STEP- 6

6) JiraApplicationContants .java

package com.gaurav.jira.rest.constants;
/**
 * @author Kumar Gaurav
 *
 */
public class  JiraApplicationContants {
/** This is the URL through which we will hit to controller to get the specific project data */
public final static String JIRA_ALL_ISSUES="/jira/issues/{projectName}";

}

STEP- 7

7) JiraIssues.java

package com.gaurav.jira.rest.bean;

/**
 * @author Kumar Gaurav
 *
 */
public class JiraIssues {
private String total;

private Issues[] issues;

private String expand;

private String startAt;

private String maxResults;

public String getTotal() {
return total;
}

public void setTotal(String total) {
this.total = total;
}

public Issues[] getIssues() {
return issues;
}

public void setIssues(Issues[] issues) {
this.issues = issues;
}

public String getExpand() {
return expand;
}

public void setExpand(String expand) {
this.expand = expand;
}

public String getStartAt() {
return startAt;
}

public void setStartAt(String startAt) {
this.startAt = startAt;
}

public String getMaxResults() {
return maxResults;
}

public void setMaxResults(String maxResults) {
this.maxResults = maxResults;
}

@Override
public String toString() {
return "JiraIssues [total=" + total + ", expand=" + expand + ", startAt=" + startAt + ", maxResults="
+ maxResults + "]";
}

}

STEP- 8

8) Issues.java

package com.gaurav.jira.rest.bean;

/**
 * @author Kumar Gaurav
 *
 */
public class Issues {
private String id;

private String expand;

private String self;

private String key;

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getExpand() {
return expand;
}

public void setExpand(String expand) {
this.expand = expand;
}

public String getSelf() {
return self;
}

public void setSelf(String self) {
this.self = self;
}

public String getKey() {
return key;
}

public void setKey(String key) {
this.key = key;
}

@Override
public String toString() {
return "Issues [id=" + id + ", expand=" + expand + ", self=" + self + ", key=" + key + "]";
}

}

STEP- 9


9) JiraResponseResource.java

package com.gaurav.jira.rest.response;
/**
 * @author Kumar Gaurav
 *
 */
import org.springframework.hateoas.ResourceSupport;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.gaurav.jira.rest.bean.JiraIssues;
/** This ResourceSupport class is  provided by spring-hateos which will help to present REST response in customized way.*/

@JsonIgnoreProperties(ignoreUnknown = true)
public class JiraResponseResource<T>  extends ResourceSupport{
private JiraIssues jiraRespcontent;

public JiraIssues getJiraRespcontent() {
return jiraRespcontent;
}

public void setJiraRespcontent(JiraIssues jiraRespcontent) {
this.jiraRespcontent = jiraRespcontent;
}
}

STEP- 10

10) JiraServiceController.java

package com.gaurav.jira.rest.controller;
/**
 * @author Kumar Gaurav
 *
 */
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.gaurav.jira.rest.bean.JiraIssues;
import com.gaurav.jira.rest.constants.JiraApplicationContants;
import com.gaurav.jira.rest.response.JiraResponseResource;
import com.gaurav.jira.rest.service.JiraService;


/**
 * The Class JiraServiceController.
 */
@RestController
@RequestMapping("/rest")
public class JiraServiceController {

Logger logger = Logger.getLogger(JiraServiceController.class.getName());

@Autowired
private JiraService jiraService;

public void setJiraService(JiraService jiraService) {
this.jiraService = jiraService;
}

/**
* Gets the all issues for specific project.
* @param projectName
*            the project name
* @return JiraResponseResource
*/
@SuppressWarnings("rawtypes")
@CrossOrigin
@RequestMapping(value = JiraApplicationContants.JIRA_ALL_ISSUES, method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<JiraResponseResource> getAllIssuesByProject(@PathVariable("projectName") String projectName) {
JiraResponseResource response = new JiraResponseResource();
try {
logger.info("***********");
JiraIssues jiraIssues = jiraService.getAllIssueDetails(projectName);
response.setJiraRespcontent(jiraIssues);
} catch (Exception e) {
logger.error("Unable to Process the request:" + e);
return new ResponseEntity<JiraResponseResource>(HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<JiraResponseResource>(response, HttpStatus.OK);
}
}

STEP- 11

11) application.properties
#As we know that embedded tomcat default port in Spring Boot is 8080, so I am changing it to 9494.
server.port=9494

STEP- 12

12) JiraServicesApplication.java

package com.gaurav.jira.rest;
/**
 * @author Kumar Gaurav
 *
 */

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan("com.gaurav.jira")
public class JiraServicesApplication {

public static void main(String[] args) {
SpringApplication.run(JiraServicesApplication.class, args);
}
}

OUTPUT

We need to execute the class JiraServicesApplication as Spring Boot App. Then we can hit the controller using any REST client. I used postman to hit the below URL, so that our controller will execute the process to get the required data from the REST call.

Here {ProjectName} parameter I am passing as TEST.

The URL which we can hit through postman is http://localhost:9494/rest/jira/issues/TEST

Response Received by REST Service is

As I used private JiraIssues jiraRespcontent in ResourceSupport class, so we can see the below response is associated with that.

RESPONSE:-

{ "jiraRespcontent": { "total": "5", "issues": [ { "id": "11827", "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "self": "http://ip:port/rest/api/2/issue/11827", "key": "TEST-5" }, { "id": "11826", "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "self": "http://ip:port/rest/api/2/issue/11826", "key": "TEST-4" }, { "id": "11825", "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "self": "http://ip:port/rest/api/2/issue/11825", "key": "TEST-3" }, { "id": "11824", "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "self": "http://ip:port/rest/api/2/issue/11824", "key": "TEST-2" }, { "id": "11823", "expand": "operations,versionedRepresentations,editmeta,changelog,renderedFields", "self": "http://ip:port/rest/api/2/issue/11823", "key": "TEST-1" } ], "expand": "schema,names", "startAt": "0", "maxResults": "1000" } }

No comments:

Post a Comment