Tuesday 15 May 2018

How to read multiple properties files in Spring Boot?


How to read multiple properties files in Spring Boot?


Answer:- As we know that application.properties is the default file for Spring Boot. This file will come by default once we will create a Sprint Boot project.
The default properties file will be loading automatically by the Sprint Boot initializer. But if we want to read some different property file which is placed at some different location then we can follow below steps.
If we can see the below directory structure then we will find that I have created one more property file other than the default one which is application.properties and I placed that in /config/db/ folder. Now, we need to load both the properties file using Spring Boot.


STEP 1                                      
database.properties
jdbc.url=jdbc:mysql://localhost:3306/experiments

STEP 2

application.properties
server.port=9494


STEP 3

MultiplePropServicesApplication.java


package com.gaurav.prop.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.ConfigurableEnvironment;

@SpringBootApplication
@ComponentScan("com.gaurav.prop")
public class MultiplePropServicesApplication {

private static Logger logger = LoggerFactory.getLogger(MultiplePropServicesApplication.class);

public static void main(String[] args) {

ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(MultiplePropServicesApplication.class)
                .properties("spring.config.name:application,database""spring.config.location:classpath:/, classpath:/config/db/")
                .build().run(args);

        ConfigurableEnvironment environment = applicationContext.getEnvironment();

        logger.info("jdbc.url:->"+environment.getProperty("jdbc.url"));
}
}

Output:-


2018-05-16 10:26:04.207  INFO 13240 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-05-16 10:26:04.207  INFO 13240 --- [  restartedMain] o.s.c.support.DefaultLifecycleProcessor  : Starting beans in phase 0
2018-05-16 10:26:04.208  INFO 13240 --- [  restartedMain] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 9494 (http)
2018-05-16 10:26:04.223  INFO 13240 --- [  restartedMain] c.g.prop.test.MultiplePropServicesApplication     : Started MultiplePropServicesApplication  in 0.792 seconds (JVM running for 506.018)
2018-05-16 10:26:04.223  INFO 13240 --- [  restartedMain] c.g.prop.test.MultiplePropServicesApplication     : jdbc.url:->jdbc:mysql://localhost:3306/experiments


Note:- We can see in the output that application successfully reads the property server.port as I mentioned this in the application.properties file and also it reads the property jbdc.url which I placed in database.properties file.


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" } }