Spring Boot 2 Hibernate 5 Mysql CRUD REST API Tutorial - RameshMF/spring-boot-developers-guide GitHub Wiki

In this tutorial, we will learn how to develop CRUD RESTFul API using Spring boot 2, Hibernate 5, JPA, Maven, and MySQL database.

Table of Contents

  1. What we’ll build
  2. Tools and Technologies Used
  3. Creating and Importing a Project
  4. Packaging Structure
  5. Configuring MySQL Database
  6. Create a JPA Entity called User.java
  7. Create Spring Data JPA Repository - UserRepository.java
  8. Exception(Error) Handling for RESTful Services
  9. Creating UserController(Contains REST APIs)
  10. Running the Application
  11. Unit Testing REST APIs
  12. Test Using Postman Client

1. What we’ll build

We are building a simple User Management Application which has below CRUD Rest APIs.

Following five REST APIs (Controller handler methods) are created for User resource.

Sr. No.
API Name
HTTP
Method
Path
Status
Code
Description
(1)
GET Users
GET
/api/v1/users
200
(OK)
All User resources are fetched.
(2)
POST User
POST
/api/v1/users
201
(Created)
A new User resource is created.
(3)
GET User
GET
/api/v1/users/{id}
200
(OK)
One User resource is fetched.
(4)
PUT User
PUT
/api/v1/users/{id}
200
(OK)
User resource is updated.
(5)
DELETE User
DELETE
/api/v1/users/{id}
204
(No Content)
User resource is deleted.

2. Tools and Technologies Used

  • 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

3. Creating and Importing a Project

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.4
  • Group: com.companyname
  • Artifact: springbootcrudrest
  • Name: springbootcrudrest
  • Description: Rest API for a Simple User Management Application
  • Package Name : com.companyname.springbootcrudrest
  • Packaging: jar (This is the default value)
  • Dependencies: Web, JPA, MySQL, DevTools

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.

4. Packaging Structure

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 -

  1. pom.xml
  2. resources
  3. SpringBootCrudRestApplication.java
  4. SpringBootCrudRestApplicationTests.java

The 4.1. pom.xml File

 <?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.companyname</groupId>
	<artifactId>springbootcrudrest</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>springbootcrudrest</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.4.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-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</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>

From above pom.xml, let's understand few important spring boot features.

Spring Boot Maven plugin

The Spring Boot Maven plugin provides many convenient features:

  • It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.

  • It searches for the public static void main() method to flag as a runnable class.

  • It provides a built-in dependency resolver that sets the version number to match Spring Boot dependencies. You can override any version you wish, but it will default to Boot’s chosen set of versions.

spring-boot-starter-parent

All Spring Boot projects typically use spring-boot-starter-parent as the parent in pom.xml.

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>

Parent Poms allow you to manage the following things for multiple child projects and modules:

  • Configuration - Java Version and Other Properties
  • Dependency Management - Version of dependencies
  • Default Plugin Configuration

Easy Dependency Management(Spring boot magic)

We added the spring-boot-starter-web dependency, it will by default pull all the commonly used libraries while developing Spring MVC applications, such as spring-webmvc, jackson-json, validation-api, and Tomcat.

We added the spring-boot-starter-data-jpa dependency. This pulls all the spring-data-jpa dependencies and adds Hibernate libraries because most applications use Hibernate as a JPA implementation.

Autoconfiguration(Spring boot magic)

Not only does the spring-boot-starter-web add all these libraries but it also configures the commonly registered beans like DispatcherServlet, ResourceHandlers, MessageSource, etc. with sensible defaults.

We haven’t defined any of the DataSource, EntityManagerFactory, or TransactionManager beans, but they are automatically created. How? If you have any in-memory database drivers like H2 or HSQL in the classpath, then Spring Boot will automatically create an in-memory data source and will register the EntityManagerFactory and TransactionManager beans automatically with sensible defaults. But you are using MySQL, so you need to explicitly provide MySQL connection details. You have configured those MySQL connection details in the application.properties file and Spring Boot creates a DataSource using those properties.

Embedded Servlet Container Support(Spring boot magic)

We added spring-boot-starter-web, which pulls spring-boot-starter-tomcat automatically. When we run the main() method, it starts tomcat as an embedded container so that we don’t have to deploy our application on any externally installed tomcat server. What if we want to use a Jetty server instead of Tomcat? You simply exclude spring-boot-starter-tomcat from spring-boot-starter-web and include spring-boot- starter-jetty. That’s it.

4.2. resources/

This directory, as the name suggests, is dedicated to all the static resources, templates and property files.

  • resources/static - contains static resources such as css, js and images.

  • resources/templates - contains server-side templates which are rendered by Spring.

  • resources/application.properties - This file is very important. It contains application-wide properties. Spring reads the properties defined in this file to configure your application. You can define a server’s default port, server’s context path, database URLs etc, in this file.

4.3. SpringBootCrudRestApplication.java

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.

4.4. SpringBootCrudRestApplicationTests

Define unit and integration tests here. Example:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootCrudRestApplicationTests {

	@Test
	public void contextLoads() {
	}

}

5. Configuring MySQL Database

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.

6. Create a JPA Entity called User.java

Let's create User model or domain class with following fields:

  • id - primary key
  • firstName - user first name
  • lastName - user last name
  • emailId - user email ID
  • createdAt - user object created date
  • createdBy - use object created by
  • updatedAt - user object updated by
  • updatedby - user object updated by
package com.companyname.springbootcrudrest.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
public class User {

	private long id;
	private String firstName;
	private String lastName;
	private String emailId;
	private Date createdAt;
	private String createdBy;
	private Date updatedAt;
	private String updatedby;
	
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	
	@Column(name = "first_name", nullable = false)
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	
	@Column(name = "last_name", nullable = false)
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	
	@Column(name = "email_address", nullable = false)
	public String getEmailId() {
		return emailId;
	}
	public void setEmailId(String emailId) {
		this.emailId = emailId;
	}
	
	@Column(name = "created_at", nullable = false)
	@CreatedDate
	public Date getCreatedAt() {
		return createdAt;
	}
	public void setCreatedAt(Date createdAt) {
		this.createdAt = createdAt;
	}
	
	@Column(name = "created_by", nullable = false)
	@CreatedBy
	public String getCreatedBy() {
		return createdBy;
	}
	public void setCreatedBy(String createdBy) {
		this.createdBy = createdBy;
	}
	
	@Column(name = "updated_at", nullable = false)
	@LastModifiedDate
	public Date getUpdatedAt() {
		return updatedAt;
	}
	public void setUpdatedAt(Date updatedAt) {
		this.updatedAt = updatedAt;
	}
	
	@Column(name = "updated_by", nullable = false)
	@LastModifiedBy
	public String getUpdatedby() {
		return updatedby;
	}
	public void setUpdatedby(String updatedby) {
		this.updatedby = updatedby;
	}
}

6.1 How to enable JPA Auditing

Let's understand important JPA Auditing annotations:

  1. @CreatedDate - Declares a field as the one representing the date the entity containing the field was created.

  2. @LastModifiedDate - Declares a field as the one representing the date the entity containing the field was recently modified.

  3. @CreatedBy- Declares a field as the one representing the principal that created the entity containing the field.

  4. @LastModifiedBy - Declares a field as the one representing the principal that recently modified the entity containing the field.

Now, what we want is that these fields should automatically get populated whenever we create or update an entity.

To achieve this, we need to do two things -

  1. Add Spring Data JPA’s AuditingEntityListener to the domain model.

We have already done this in our Note model with the annotation @EntityListeners(AuditingEntityListener.class).

@Entity
@Table(name = "users")
@EntityListeners(AuditingEntityListener.class)
public class User {
 // rest of the code here
}
  1. Enable JPA Auditing in the main application.

Open SpringBootCrudRestApplication.java and add @EnableJpaAuditing annotation.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@SpringBootApplication
@EnableJpaAuditing
public class SpringBootCrudRestApplication {

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

So far we have created User model and enabled JPa auditing on it. Next we need to create a repository to access user records to and from database.

7. Create Spring Data JPA Repository - UserRepository.java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.companyname.springbootcrudrest.model.User;

@Repository
public interface UserRepository extends JpaRepository<User, Long>{

}

Note that, we have annotated the interface with @Repository annotation. This tells Spring to bootstrap the repository during a component scan.

In the above code, UserRepository interface extends JpaRepository which provides below methodsto deal with database operations:

List<T> findAll();
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);
<S extends T> List<S> saveAll(Iterable<S> entities);
void flush();
<S extends T> S saveAndFlush(S entity);
void deleteInBatch(Iterable<T> entities);
void deleteAllInBatch();
T getOne(ID id);
@Override
<S extends T> List<S> findAll(Example<S> example);
<S extends T> List<S> findAll(Example<S> example, Sort sort);

8. Exception(Error) Handling for RESTful Services

Spring Boot provides good default implementation for exception handling for RESTful Services. Let’s quickly look at the default Exception Handling features provided by Spring Boot.

Resource Not Present

Heres what happens when you fire a request to not resource found: http://localhost:8080/some-dummy-url

{
  "timestamp": 1512713804164,
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/some-dummy-url"
}

Thats a cool error response. It contains all the details that are typically needed.

What happens when we throw an Exception?

Let’s see what Spring Boot does when an exception is thrown from a Resource. we can specify the Response Status for a specific exception along with the definition of the Exception with ‘@ResponseStatus’ annotation.

Lets create a ResourceNotFoundException.java class.

package com.companyname.springbootcrudrest.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);
    }
}

Customizing Error Response Structure

Default error response provided by Spring Boot contains all the details that are typically needed.

However, you might want to create a framework independent response structure for your organization. In that case, you can define a specific error response structure.

Let’s define a simple error response bean.

package com.companyname.springbootcrudrest.exception;

import java.util.Date;

public class ErrorDetails {
	private Date timestamp;
	private String message;
	private String details;

	public ErrorDetails(Date timestamp, String message, String details) {
		super();
		this.timestamp = timestamp;
		this.message = message;
		this.details = details;
	}

	public Date getTimestamp() {
		return timestamp;
	}

	public String getMessage() {
		return message;
	}

	public String getDetails() {
		return details;
	}
}

To use ErrorDetails to return the error response, let’s create a GlobalExceptionHandler class annotated with @ControllerAdvice annotation. This class handles exception specific and global exception in common place.

package com.companyname.springbootcrudrest.exception;

import java.util.Date;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class GlobalExceptionHandler {
	@ExceptionHandler(ResourceNotFoundException.class)
	public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
		ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
		return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
	}

	@ExceptionHandler(Exception.class)
	public ResponseEntity<?> globleExcpetionHandler(Exception ex, WebRequest request) {
		ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
		return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
	}
}

9. Creating UserController(Contains REST APIs)

Now, it's time to create CRUD Rest APIs for User model.

package com.companyname.springbootcrudrest.controller;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.companyname.springbootcrudrest.exception.ResourceNotFoundException;
import com.companyname.springbootcrudrest.model.User;
import com.companyname.springbootcrudrest.repository.UserRepository;

@RestController
@RequestMapping("/api/v1")
public class UserController {
	
	@Autowired
	private UserRepository userRepository;

	
	@GetMapping("/users")
	public List<User> getAllUsers() {
		return userRepository.findAll();
	}

	@GetMapping("/users/{id}")
	public ResponseEntity<User> getUserById(
			@PathVariable(value = "id") Long userId) throws ResourceNotFoundException {
		User user = userRepository.findById(userId)
        .orElseThrow(() -> new ResourceNotFoundException("User", "id", userId));
		return ResponseEntity.ok().body(user);
	}

	@PostMapping("/users")
	public User createUser(@Valid @RequestBody User user) {
		return userRepository.save(user);
	}

	@PutMapping("/users/{id}")
	public ResponseEntity<User> updateUser(
			@PathVariable(value = "id") Long userId,
			@Valid @RequestBody User userDetails) throws ResourceNotFoundException {
		User user = userRepository.findById(userId)
		        .orElseThrow(() -> new ResourceNotFoundException("User", "id", userId));
		
		user.setEmailId(userDetails.getEmailId());
		user.setLastName(userDetails.getLastName());
		user.setFirstName(userDetails.getFirstName());
		user.setUpdatedAt(new Date());
		final User updatedUser = userRepository.save(user);
		return ResponseEntity.ok(updatedUser);
	}

	@DeleteMapping("/user/{id}")
	public Map<String, Boolean> deleteUser(
			@PathVariable(value = "id") Long userId) throws Exception {
		User user = userRepository.findById(userId)
		        .orElseThrow(() -> new ResourceNotFoundException("User", "id", userId));

		userRepository.delete(user);
		Map<String, Boolean> response = new HashMap<>();
		response.put("deleted", Boolean.TRUE);
		return response;
	}
}

Let's understand all the annotations used in the UserController

  • @RequestMapping("/api/v1") - annotation declares that the url for all the apis in this controller will start with /api/v1
  • @RestController - annotation is a combination of Spring’s @Controller and @ResponseBody annotations.
  • @GetMapping("/users") - annotation is a short form of @RequestMapping(value="/users", method=RequestMethod.GET).
  • @GetMapping("/users/{id}") - annotation is a short form of @RequestMapping(value="/users/{id}", method=RequestMethod.GET).
  • @PostMapping("/users") - annotation is a short form of @RequestMapping(value="/users", method=RequestMethod.POST).
  • @PutMapping("/users/{id}") - annotation is a short form of @RequestMapping(value="/users/{id}", method=RequestMethod.PUT).
  • @DeleteMapping("/user/{id}") - annotation is a short form of @RequestMapping(value="/users/{id}", method=RequestMethod.DELETE).
  • @PathVariable - annotation is used to bind a path variable with a method parameter.

10. Running the Application

We have successfully developed all the CRUD Rest api for User model. now it's time to deploy our application in servlet container(embedded tomcat). Two ways we can start the standalone Spring boot application.

  1. From root directory of the application and type the following command to run it -
$ mvn spring-boot:run
  1. From your IDE, run the SpringBootCrudRestApplication.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/.

Once tomcat is up and running will produce below output:

2018-09-11 14:49:52.666  WARN 17232 --- [  restartedMain] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2018-09-11 14:49:52.702  INFO 17232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/v1/users],methods=[GET]}" onto public java.util.List<com.companyname.springbootcrudrest.model.User> com.companyname.springbootcrudrest.controller.UserController.getAllUsers()
2018-09-11 14:49:52.704  INFO 17232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/v1/users/{id}],methods=[GET]}" onto public org.springframework.http.ResponseEntity<com.companyname.springbootcrudrest.model.User> com.companyname.springbootcrudrest.controller.UserController.getUserById(java.lang.Long) throws com.companyname.springbootcrudrest.exception.ResourceNotFoundException
2018-09-11 14:49:52.705  INFO 17232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/v1/users],methods=[POST]}" onto public com.companyname.springbootcrudrest.model.User com.companyname.springbootcrudrest.controller.UserController.createUser(com.companyname.springbootcrudrest.model.User)
2018-09-11 14:49:52.705  INFO 17232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/v1/users/{id}],methods=[PUT]}" onto public org.springframework.http.ResponseEntity<com.companyname.springbootcrudrest.model.User> com.companyname.springbootcrudrest.controller.UserController.updateUser(java.lang.Long,com.companyname.springbootcrudrest.model.User) throws com.companyname.springbootcrudrest.exception.ResourceNotFoundException
2018-09-11 14:49:52.706  INFO 17232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/api/v1/user/{id}],methods=[DELETE]}" onto public java.util.Map<java.lang.String, java.lang.Boolean> com.companyname.springbootcrudrest.controller.UserController.deleteUser(java.lang.Long) throws java.lang.Exception
2018-09-11 14:49:52.708  INFO 17232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-09-11 14:49:52.709  INFO 17232 --- [  restartedMain] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-09-11 14:49:52.741  INFO 17232 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-11 14:49:52.741  INFO 17232 --- [  restartedMain] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-09-11 14:49:53.170  INFO 17232 --- [  restartedMain] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server is running on port 35729
2018-09-11 14:49:53.209  INFO 17232 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-09-11 14:49:53.211  INFO 17232 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'dataSource' has been autodetected for JMX exposure
2018-09-11 14:49:53.219  INFO 17232 --- [  restartedMain] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
2018-09-11 14:49:53.263  INFO 17232 --- [  restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-09-11 14:49:53.268  INFO 17232 --- [  restartedMain] c.c.s.SpringBootCrudRestApplication      : Started SpringBootCrudRestApplication in 5.304 seconds (JVM running for 6.442)

11.Unit Testing REST APIs

Let's write a Junit test cases for all Rest APIs of User entity.

package com.companyname.projectname.springbootcrudrest;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.HttpClientErrorException;

import com.companyname.springbootcrudrest.SpringBootCrudRestApplication;
import com.companyname.springbootcrudrest.model.User;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringBootCrudRestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringBootCrudRestApplicationTests {

	@Autowired
	private TestRestTemplate restTemplate;

	@LocalServerPort
	private int port;

	private String getRootUrl() {
		return "http://localhost:" + port;
	}

	@Test
	public void contextLoads() {

	}

	@Test
	public void testGetAllUsers() {
		HttpHeaders headers = new HttpHeaders();
		HttpEntity<String> entity = new HttpEntity<String>(null, headers);

		ResponseEntity<String> response = restTemplate.exchange(getRootUrl() + "/users",
				HttpMethod.GET, entity, String.class);
		
		assertNotNull(response.getBody());
	}

	@Test
	public void testGetUserById() {
		User user = restTemplate.getForObject(getRootUrl() + "/users/1", User.class);
		System.out.println(user.getFirstName());
		assertNotNull(user);
	}

	@Test
	public void testCreateUser() {
		User user = new User();
		user.setEmailId("[email protected]");
		user.setFirstName("admin");
		user.setLastName("admin");
		user.setCreatedBy("admin");
		user.setUpdatedby("admin");

		ResponseEntity<User> postResponse = restTemplate.postForEntity(getRootUrl() + "/users", user, User.class);
		assertNotNull(postResponse);
		assertNotNull(postResponse.getBody());
	}

	@Test
	public void testUpdatePost() {
		int id = 1;
		User user = restTemplate.getForObject(getRootUrl() + "/users/" + id, User.class);
		user.setFirstName("admin1");
		user.setLastName("admin2");

		restTemplate.put(getRootUrl() + "/users/" + id, user);

		User updatedUser = restTemplate.getForObject(getRootUrl() + "/users/" + id, User.class);
		assertNotNull(updatedUser);
	}

	@Test
	public void testDeletePost() {
		int id = 2;
		User user = restTemplate.getForObject(getRootUrl() + "/users/" + id, User.class);
		assertNotNull(user);

		restTemplate.delete(getRootUrl() + "/users/" + id);

		try {
			user = restTemplate.getForObject(getRootUrl() + "/users/" + id, User.class);
		} catch (final HttpClientErrorException e) {
			assertEquals(e.getStatusCode(), HttpStatus.NOT_FOUND);
		}
	}

}

@SpringBootTest(classes = SpringBootCrudRestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) : Launch the entire Spring Boot Application on a Random Port

Output

diagram here

12. Test Using Postman Client

1. Create User REST API

HTTP Method: POST Request URL : http://localhost:8080/api/v1/users Request JSON:

{
    "firstName": "Ramesh",
    "lastName": "fadatare",
    "emailId": "[email protected]",
    "createdBy": "Ramesh",
    "updatedby": "Ramesh"
}

diagram here

2. Get User by ID REST API

HTTP Method: GET Request URL : http://localhost:8080/api/v1/users/2

diagram here

3. Get all users REST API

HTTP Method: GET Request URL: http://localhost:8080/api/v1/users

diagram here

4. Update User REST API

HTTP Method: GET Request URL: http://localhost:8080/api/v1/users/5 Request JSON:

{
    "firstName": "Ram",
    "lastName": "Jadhav",
    "emailId": "[email protected]",
    "createdBy": "Ramesh",
    "updatedby": "Ramesh"
}

Response JSON:

{
    "id": 5,
    "firstName": "Ram",
    "lastName": "Jadhav",
    "emailId": "[email protected]",
    "createdAt": "2018-09-11T11:19:56.000+0000",
    "createdBy": "Ramesh",
    "updatedAt": "2018-09-11T11:26:31.259+0000",
    "updatedby": "Ramesh"
}

diagram here

  1. Delete User REST API HTTP Method: DELETE Request URL: http://localhost:8080/api/v1/users/2

diagram here

⚠️ **GitHub.com Fallback** ⚠️