This tutorial will get you started with Spring Boot by helping you develop JAX-RS based REST services.
Abstract
Spring Boot framework makes it easy to create standalone, production-ready Spring applications. It requires very minimal configuration and gets you started with minimum fuss as it manages the versions of third party dependent libraries for you.
Spring Boot applications are easy to develop and deploy. It also helps you adopt Microservices like architecture by letting you build small standalone services that do not require any additional web/application servers. Web applications developed in Spring Boot contain embedded versions of servers that start and stop with your application. Spring Boot has support for Tomcat, Jetty and Undertow embedded servers, and can be extended to support others.
In simple terms, Spring Boot application is a simple Jar file that can easily be managed and migrated from one place to other. Spring Boot also comes with production-ready features such as metrics, health checks and externalised configuration.
In this tutorial, we will be creating a simple Tutorial service using Jersey framework in Spring Boot.
Pre-requisites
Here are the required softwares and skills required to build Tutorial service -
- Java 8 or later
- Eclipse IDE with Maven and STS (Spring Tool Suite) plugin
- Basic knowledge of REST and Spring Core
Developing JAX-RS Services using Spring Boot
Creating a Spring Boot project
We will be starting with creating a Spring Boot project called spring-boot-jaxrs-demo in Eclipse IDE using Spring Starter project wizard as follows -
Click next to go to dependency page and select Jersey (JAX-RS) option from Web section as shown below -
Click Finish to stop wizard and it will take some time to download dependencies. After it is over, you should see your project in Eclipse Project Explorer as below -
Although no changes are required in POM file, this is how it will look like (in case you want to copy dependencies manually) -
<?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.aksain.microservices.springboot.basics</groupId>
<artifactId>spring-boot-jaxrs-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-jaxrs-demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.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-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Develop local tutorial service
Let's now create a local service with methods to return all tutorials or tutorial with provided id. We will simply be keeping all tutorials in a list of Tutorial objects and serve the request from here. Here is how our Tutorial domain object looks like -
package com.aksain.microservices.springboot.basics.models;
/**
* @author Amit Kumar
*
*/
public class Tutorial {
private Long id;
private String name;
private String description;
private Long categoryId;
private Long publisherId;
public Tutorial() {
}
public Tutorial(Long id, String name, String description, Long categoryId, Long publisherId) {
this.id = id;
this.name = name;
this.description = description;
this.categoryId = categoryId;
this.publisherId = publisherId;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((categoryId == null) ? 0 : categoryId.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((publisherId == null) ? 0 : publisherId.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tutorial other = (Tutorial) obj;
if (categoryId == null) {
if (other.categoryId != null)
return false;
} else if (!categoryId.equals(other.categoryId))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (publisherId == null) {
if (other.publisherId != null)
return false;
} else if (!publisherId.equals(other.publisherId))
return false;
return true;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the description
*/
public String getDescription() {
return description;
}
/**
* @param description the description to set
*/
public void setDescription(String description) {
this.description = description;
}
/**
* @return the categoryId
*/
public Long getCategoryId() {
return categoryId;
}
/**
* @param categoryId the categoryId to set
*/
public void setCategoryId(Long categoryId) {
this.categoryId = categoryId;
}
/**
* @return the publisherId
*/
public Long getPublisherId() {
return publisherId;
}
/**
* @param publisherId the publisherId to set
*/
public void setPublisherId(Long publisherId) {
this.publisherId = publisherId;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Tutorial [id=" + id + ", name=" + name + ", description=" + description + ", categoryId=" + categoryId
+ ", publisherId=" + publisherId + "]";
}
}
And here is the complete code for our local TutorialService class -
package com.aksain.microservices.springboot.basics.services;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Service;
import com.aksain.microservices.springboot.basics.models.Tutorial;
/**
* @author Amit Kumar
*/
@Service
public class TutorialService {
private final List<Tutorial> tutorials = new ArrayList<>();
@PostConstruct
public void init() {
tutorials.add(new Tutorial(1l, "Tutorial1", "Tutorial 1 Description", 1l, 1l));
tutorials.add(new Tutorial(2l, "Tutorial2", "Tutorial 2 Description", 2l, 1l));
tutorials.add(new Tutorial(3l, "Tutorial3", "Tutorial 3 Description", 1l, 2l));
tutorials.add(new Tutorial(4l, "Tutorial4", "Tutorial 4 Description", 2l, 2l));
}
public Tutorial getById(Long tutorialId) {
return tutorials.stream().filter((tutorial) -> tutorial.getId() == tutorialId).findFirst().get();
}
public List<Tutorial> getAllTutorials() {
return tutorials;
}
}
Develop tutorial REST resource
We will now leveage our local TutorialService to expose a REST resource TutorialResource as shown below -
package com.aksain.microservices.springboot.basics.resources;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.aksain.microservices.springboot.basics.models.Tutorial;
import com.aksain.microservices.springboot.basics.services.TutorialService;
/**
* @author Amit Kumar
*/
@Path("/tutorials")
public class TutorialResource {
@Inject
private TutorialService tutorialService;
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getById() {
final List<Tutorial> tutorials = tutorialService.getAllTutorials();
return Response.ok(tutorials).build();
}
@Path("/{tutorialId}")
@GET
@Produces(MediaType.APPLICATION_JSON)
public Response getById(@PathParam("tutorialId") final Long tutorialId) {
final Tutorial tutorial = tutorialService.getById(tutorialId);
return Response.ok(tutorial).build();
}
}
Register REST resource
It's now time to register our TutorialResource REST resource with Jersey to expose it to client. In order to do this, we will extend Jersey ResourceConfig class and provide package containing REST resources. We can also register individual class but registering package is better from readability and maintainability purposes.
We will create JerseyConfig class extending ResourceConfig as below -
package com.aksain.microservices.springboot.basics.main;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
/**
* @author Amit Kumar
*/
@Component
public class JerseyConfig extends ResourceConfig{
public JerseyConfig() {
packages("com.aksain.microservices.springboot.basics.resources");
}
}
Enable package scanning
Since we are using Spring for injecting TutorialService into TutorialResource, we need to enable component scanning. This will allow Spring to search for all classes with Spring annotations and manage instances of those. As all of our packages start with com.aksain.microservices.springboot.basics, we will use this for scanning so that Spring can search all classes in our project.
In order to enable scanning, edit SpringBootJaxrsDemoApplication class by putting @ComponentScan("com.aksain.microservices.springboot.basics") annotation on it as shown below -
package com.aksain.microservices.springboot.basics.main;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan("com.aksain.microservices.springboot.basics")
public class SpringBootJaxrsDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootJaxrsDemoApplication.class, args);
}
}
Testing Tutorial Service
Finally let's start our application so that we can test our tutorial service. Since it is a Spring Boot application, you don't need to deploy it to any web/application server.
You can simply run SpringBootJaxrsDemoApplication class like any other Java program. This will start embedded Tomcat server at port 8080 (you can also change port using server.port property in application.properties file).
Once application has started successfully, open your favorite browser or REST client and make following call -
http://localhost:8080/tutorials
Here is how REST service response should look like -
[{"id":1,"name":"Tutorial1","description":"Tutorial 1 Description","categoryId":1,"publisherId":1},{"id":2,"name":"Tutorial2","description":"Tutorial 2 Description","categoryId":2,"publisherId":1},{"id":3,"name":"Tutorial3","description":"Tutorial 3 Description","categoryId":1,"publisherId":2},{"id":4,"name":"Tutorial4","description":"Tutorial 4 Description","categoryId":2,"publisherId":2}]
Simlarly, you can also try getting tutorials by an id as below -
http://localhost:8080/tutorials/3
Here is what response will look like, this time -
{"id":3,"name":"Tutorial3","description":"Tutorial 3 Description","categoryId":1,"publisherId":2}
Congratulations, you have successfully developed a simple JAX-RS based REST service using Spring Boot and Jersey.'
Thank you for reading through the tutorial. In case of any feedback/questions/concerns, you can communicate same to us through your comments and we shall get back to you as soon as possible.