Spring Boot 2 Jersey REST JPA Hibernate CRUD REST APIs Example - RameshMF/spring-boot-developers-guide GitHub Wiki
In this article, we will learn step by step how to develop CRUD REST APIs using integration of Jersey 2.26 with spring boot 2, JPA/Hibernate 5 and MySQL as a database.
Jersey RESTful Web Services framework is open source, production quality, a framework for developing RESTful Web Services in Java that provides support for JAX-RS APIs and serves as a JAX-RS (JSR 311 & JSR 339) Reference Implementation.
Spring boot provides support for integration of Jersey with spring boot application using spring-boot-starter-jersey starter dependency.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
Let's create a step by step Spring Boot Jersey CRUD RESTful APIs project.
- What we’ll build?
- Tools and Technologies Used
- Creating and Importing a Project
- Packaging Structure
- Configuring MySQL Database
- Create Jersey Resource - UserResource.java
- Creating a JerseyConfiguration Class
- Create a JPA Entity called User.java
- Create Spring Data JPA Repository - UserRepository.java
- Create ResourceNotFoundException.java Class
- Running the Application
- Testing via Postman Client
We are developing a CRUD REST APIs using integration of Jersey 2.26 with spring boot 2, JPA/Hibernate 5 and MySQL as a database.
- Spring Boot - 2.0.4.RELEASE
- JDK - 1.8 or later
- Spring Framework - 5.0.8 RELEASE
- Hibernate - 5.2.17.Final
- Maven - 3.2+
- Spring Data JPA - 2.0.10 RELEASE
- IDE - Eclipse or Spring Tool Suite (STS)
- MYSQL - 5.1.47
- Jersey - 2.26
There are many ways to create a Spring Boot application. The simplest way is to use Spring Initializr at http://start.spring.io/, which is an online Spring Boot application generator.
Look at the above diagram, we have specified following details:
- Generate: Maven Project
- Java Version: 1.8 (Default)
- Spring Boot:2.0.6
- Group: net.guides.springboot2
- Artifact: springboot-jersey-rest-crud-jpa
- Name: springboot-jersey-rest-crud-jpa
- Description: Rest API for a Simple User Management Application
- Package Name : com.companyname.springbootcrudrest
- Packaging: jar (This is the default value)
- Dependencies: Jersey, JPA, MySQL
Once, all the details are entered, click on Generate Project button will generate a spring boot project and downloads it. Next, Unzip the downloaded zip file and import it into your favorite IDE.
Following is the packing structure of our User Management Application -
diagram here
Let’s understand the details of some of the important files and packages -
- pom.xml
- resources
- SpringbootJerseyRestCrudJpaApplication.java
- SpringbootJerseyRestCrudJpaApplicationTests.java
<?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>net.guides.springboot2</groupId>
<artifactId>springboot-jersey-rest-crud-jpa</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-jersey-rest-crud-jpa</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.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-data-jpa</artifactId>
</dependency>
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
This spring boot application has an entry point Java class called SpringBootCrudRestApplication.java with the public static void main(String[] args) method, which you can run to start the application.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootCrudRestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootCrudRestApplication.class, args);
}
}
@SpringBootApplication is a convenience annotation that adds all of the following:
-
@Configuration tags the class as a source of bean definitions for the application context.
-
@EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
-
Normally you would add @EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet.
-
@ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers.
The main() method uses Spring Boot’s SpringApplication.run() method to launch an application. Did you notice that there wasn’t a single line of XML? No web.xml file either. This web application is 100% pure Java and you didn’t have to deal with configuring any plumbing or infrastructure.
Configure application.properties to connect to your MySQL database. Let's open application.properties file and add following database configuration to it.
spring.datasource.url = jdbc:mysql://localhost:3306/users_database?useSSL=false
spring.datasource.username = root
spring.datasource.password = root
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
Change the above configuration such as jdbc url, username and password as per your environment.
package net.guides.springboot2.springbootjerseyrestcrudjpa.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import net.guides.springboot2.springbootjerseyrestcrudjpa.exception.ResourceNotFoundException;
import net.guides.springboot2.springbootjerseyrestcrudjpa.model.User;
import net.guides.springboot2.springbootjerseyrestcrudjpa.repository.UserRepository;
@Component
@Path("/api/v1")
public class UserResource {
@Autowired
private UserRepository userRepository;
@GET
@Produces("application/json")
@Path("/users")
public List<User> getAllUsers() {
return userRepository.findAll();
}
@GET
@Produces("application/json")
@Path("/users/{id}")
public ResponseEntity<User> getUserById(@PathParam(value = "id") Long userId) throws ResourceNotFoundException {
User user = userRepository.findById(userId)
.orElseThrow(() -> new ResourceNotFoundException("User not found :: " + userId));
return ResponseEntity.ok().body(user);
}
@POST
@Produces("application/json")
@Consumes("application/json")
@Path("/users")
@PostMapping("/users")
public User createUser(User user) {
return userRepository.save(user);
}
@PUT
@Consumes("application/json")
@Path("/users/{id}}")
public ResponseEntity<User> updateUser(@PathParam(value = "id") Long userId,
@Valid @RequestBody User userDetails) throws ResourceNotFoundException {
User user = userRepository.findById(userId)
.orElseThrow(() -> new ResourceNotFoundException("User not found :: " + userId));
user.setEmailId(userDetails.getEmailId());
user.setLastName(userDetails.getLastName());
user.setFirstName(userDetails.getFirstName());
final User updatedUser = userRepository.save(user);
return ResponseEntity.ok(updatedUser);
}
@DELETE
@Path("/users/{id}")
public Map<String, Boolean> deleteUser(@PathParam(value = "id") Long userId) throws ResourceNotFoundException {
User user = userRepository.findById(userId)
.orElseThrow(() -> new ResourceNotFoundException("User not found :: " + userId));
userRepository.delete(user);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return response;
}
}
We have created a UserResource class and used JAX-RS annotations.
@Path is used to identify the URI path (relative) that a resource class or class method will serve requests for.
@PathParam is used to bind the value of a URI template parameter or a path segment containing the template parameter to a resource method parameter, resource class field, or resource class bean property. The value is URL decoded unless this is disabled using the @Encoded annotation.
@GET indicates that the annotated method handles HTTP GET requests.
@POST indicates that the annotated method handles HTTP POST requests.
@PUT indicates that the annotated method handles HTTP PUT requests.
@DELETE indicates that annotated method handles HTTP DELETE requests.
@Produces defines a media-type that the resource method can produce.
@Consumes defines a media-type that the resource method can accept.
You might have noticed that we have annotated UserResource with @Component, which is Spring's annotation, and registered it as a bean. We have done so to benefit Spring's DI for injecting the BookService service class.
While creating REST API's using Jersey the resource naming standard should be entity name suffix with "Resource" string. for example UserResource, EmployeeResource.
We created a JerseyConfiguration class that extends the ResourceConfig from package org.glassfish.jersey.server, which configures the web application. In the setUp(), we registered UserResource. @ApplicationPath identifies the application path that serves as the base URI for all the resources.
package net.guides.springboot2.springbootjerseyrestcrudjpa.config;
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.server.ResourceConfig;
import org.springframework.stereotype.Component;
import net.guides.springboot2.springbootjerseyrestcrudjpa.controller.UserResource;
@Component
@ApplicationPath("/boot-jersey")
public class JerseyConfiguration extends ResourceConfig {
public JerseyConfiguration() {
register(UserResource.class);
}
}
package net.guides.springboot2.springbootjerseyrestcrudjpa.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "table_users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name", nullable = false)
private String lastName;
@Column(name = "email_address", nullable = false)
private String emailId;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
}
package net.guides.springboot2.springbootjerseyrestcrudjpa.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.guides.springboot2.springbootjerseyrestcrudjpa.model.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long>{
}
package net.guides.springboot2.springbootjerseyrestcrudjpa.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends Exception{
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message){
super(message);
}
}
We have successfully developed all the CRUD Rest API for User model. now it's time to deploy our application in a servlet container(embedded tomcat). Two ways we can start the standalone Spring boot application.
- From the root directory of the application and type the following command to run it -
$ mvn spring-boot:run
- From your IDE, run the SpringbootJerseyRestCrudJpaApplication.main() method as a standalone Java class that will start the embedded Tomcat server on port 8080 and point the browser to http://localhost:8080/.
- Create User REST API
- HTTP Method: POST
- RequestURL: http://localhost:8080/api/v1/users
diagram here
- Get User by ID REST API
- HTTP Method: GET
- Request URL: http://localhost:8080/boot-jersey/api/v1/users/21
- Get all users REST API
- HTTP Method: GET
- Request URL: http://localhost:8080/api/v1/users
- Update User REST API
- HTTP Method: GET
- Request URL: http://localhost:8080/api/v1/users
- Delete User REST API
- HTTP Method: DELETE
- Request URL: http://localhost:8080/api/v1/users/25