Monday, January 4, 2021

Spring Boot REST API CRUD Example With Spring Data JPA

In this tutorial we’ll create a Spring Boot REST API crud application using Spring Data JPA and MySQL database.


Maven dependencies

<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>org.netjs</groupId>
  <artifactId>SpringBootProject</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>SpringBootProject</name>
  <description>SpringBoot Demo Projects</description>
  <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.3.6.RELEASE</version>
 </parent>
 <dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
  </dependency>
  <!-- MySQL Driver -->
  <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>

In the configuration, Spring Boot version used is 2.3.6.RELEASE so Spring Boot gets the dependencies which are supported by this version.

Since we are using Spring Data JPA so spring-boot-starter-data-jpa dependency is added that will get Spring Data, Hibernate and other jars required for JPA.

This is a web application so we add spring-boot-starter-web dependency, that adds the necessary dependencies required for creating a Spring web application.

mysql-connector-java dependecy adds the MySQL driver required for the application to connect to DB.

Database table

In the application we are going to have a REST API to create, update and delete user records so we’ll have a USER table in the DB.

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(45) NOT NULL,
  `last_name` varchar(45) NOT NULL,
  `user_type` varchar(15) NOT NULL,
  `start_date` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

Entity Class

In the application we’ll have a JPA entity class with fields that map to the columns in the DB table USER.

  • @Entity annotation marks this model class as an Entity.
  • @Table annotation with the table name specifies the table to which this model class is mapped.
  • @Id annotation specifies the primary key of the entity.
  • @GeneratedValue annotation specifies the primary key generation strategy which is autoincrement in this case, so you don’t need to send ID data from the application, DB will take care of adding the ID.
  • @Column annotation specifies the corresponding table column for the annotated field.

While creating classes, create appropriate packages and create classes in those packages that makes the project more readable, makes component scanning easy from the root package. For example I have put model class in org.netjs.entities package, controller class in org.netjs.controller package and so on.

import java.time.LocalDate;
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="USER")
public class User {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "ID")
  private int userId;
  @Column(name="FIRST_NAME")
  private String firstName;
  @Column(name="LAST_NAME")
  private String lastName;
  @Column(name="USER_TYPE")
  private String userType;
  @Column(name="START_DATE")
  private LocalDate startDate;
    
  public int getUserId() {
    return userId;
  }
  public void setUserId(int userId) {
    this.userId = userId;
  }
  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 getUserType() {
    return userType;
  }
  public void setUserType(String userType) {
    this.userType = userType;
  }
  public LocalDate getStartDate() {
    return startDate;
  }
  public void setStartDate(LocalDate startDate) {
    this.startDate = startDate;
  }
  @Override
  public String toString() {
    return "UserId= " + getUserId() + " First Name= " + 
        getFirstName() + " Last Name= " + getLastName() + 
        " Type= "+ getUserType() + 
        " StartDate= " + getStartDate();
  }
}

Spring Boot JPA Repository

Since we are using Spring Data JPA so you just need to create an interface that extends JpaRepository interface.

JpaRepository interface in turn extends from CrudRepository (PagingAndSortingRepository as well) that contains method for CRUD operations. JpaRepository is a JPA specific extension of Repository thatadds JPA related functionalities like flushing, persistence context.

import org.netjs.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Integer>{

}

Here we have created interface UserRepository extending JpaRepository which takes the Entity class and the type of the Id as the type arguments. In our example Entity class is User and type of the Id is Integer so these are passed as type arguments.

This interface is the only thing you need to write as your data access code. You don’t need to explicitly implement this interface and implement all the CRUD methods. Spring framework automatically implements the operations.

Controller Class

We’ll create a Controller class UserController.java which is annotated using the @RestController annotation specifying it is a RESTful web service.

import java.util.List;
import java.util.NoSuchElementException;
import org.netjs.entities.User;
import org.netjs.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

@RestController
@RequestMapping("/user")
public class UserController {
  @Autowired
  UserService userService;
  // Insert user record
  @PostMapping
  @ResponseStatus(HttpStatus.CREATED)
  public User addEmployee(@RequestBody User user) {
    return userService.addUser(user);
  }
  // Fetch all user records
  @GetMapping
  public List<User> getAllUsers(){
    return userService.getAllUsers();
  }
  // Fetch single user
  @GetMapping("/{id}")
  public User getUserById(@PathVariable("id") int userId){
    return userService.getUserById(userId);
  }
  // Update user record
  @PutMapping("/updateuser")
  public ResponseEntity<String> updateUser(@RequestBody User user) {  
    try {
      userService.updateUser(user);
      return new ResponseEntity<String>(HttpStatus.OK);
    }catch(NoSuchElementException ex){
      // log the error message
      System.out.println(ex.getMessage());
      return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
    }
  }
  // Delete user record
  @DeleteMapping("/{id}")
  public ResponseEntity<String> deleteUser(@PathVariable int id){
    try {
      userService.deleteUserById(id);
      return new ResponseEntity<String>(HttpStatus.OK);
    }catch(RuntimeException ex){
      // log the error message
      System.out.println(ex.getMessage());
      return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
    }
  }
}

At the class level there is an annotation @RequestMapping("/user") which means any URL having /user at the end will come to this RestController. Controller class has a dependency on UserService which is injected automatically using the @Autowired annotation.

In the controller class there are following methods-

  1. addEmployee() annotated with @PostMapping is used to insert a user record. This method has User object as an argument which is annotated with @RequestBody annotation. User object which is passed as HttpRequest body is mapped to the model object by @RequestBody annotation which means this annotation provided automatic deserialization of the HttpRequest body onto a Java object.
  2. getAllUsers() annotated with @GetMapping is used to get all the user records.
  3. getUserById() annotated with @GetMapping("/{id}") is used to fetch specific user record. Id is specified as a path variable which means any URL having the form /user/1 will be intercepted by this method.
  4. updateUser() annotated with @PutMapping is used to update user record. Return value of the method is of type ResponseEntity and the appropriate HttpStatus code is returned from the method.
  5. deleteUser() annotated with @DeleteMapping is used to delete the User record whose Id is passed as a path variable.

Service Class

In the controller class there is a dependency on UserService and controller class just intercepts the request and calls the corresponding service class method. You don’t write any logic in Controller class.

UserService interface

import java.util.List;
import org.netjs.entities.User;

public interface UserService {
  User addUser(User user);
  User getUserById(int userId);
  void updateUser(User user);
  void deleteUserById(int userId);
  List<User> getAllUsers();
}

UserServiceImpl class

From the service layer we’ll call the DAO layer methods. With Spring Data we only need a repository so we’ll call methods of repository from the service class.

To use the repository, UserRepository instance is autowired in the Service class.

import java.util.List;
import org.netjs.dao.UserRepository;
import org.netjs.entities.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService{
  @Autowired
  private UserRepository repository;
  @Override
  public User addUser(User user) {
    return repository.save(user);
  }
  @Override
  public User getUserById(int userId) {
    return repository.findById(userId).get();
  }
  @Override
  public List<User> getAllUsers(){
    return repository.findAll();
  }
  
  @Override
  public void updateUser(User user) {
    // check if the user with the passed id exists or not
    User userDB = repository.findById(user.getUserId()).orElseThrow();
    // If user exists then updated
    repository.save(user);
  }
  
  @Override
  public void deleteUserById(int userId) {
    try {
      repository.deleteById(userId);  
    }catch(DataAccessException ex){
      throw new RuntimeException(ex.getMessage());
    }
  }
}

DB Configuration

By default Spring boot reads properties file from this location src/main/resources/application.properties. In the application.properties file provide the DB connection attributes like URL, driver class name, username, password and Hibernate related properties.

spring.datasource.url=jdbc:mysql://localhost:3306/netjs
spring.datasource.username=test
spring.datasource.password=test
#change the dialect as per MySQL version (optional)
#spring.jpa.properties.hibernate.sqldialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.properties.hibernate.show_sql=true

With these values in properties file and the jars in classpath for Hibernate and MySQL, Spring Boot can automatically configure Hibernate as JPA Vendor and set the DataSource using the DB connection attributes defined in application.properties file.

Spring Boot Application Class

Application class with the main method which is the entry point for Spring Boot application.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

@SpringBootApplicationis a convenience annotation that adds all of the following:

  • @Configuration- Marks this class as a source of bean definitions for the application context.
  • @EnableAutoConfiguration- Tells Spring Boot to automatically start creating beans based on classpath settings, other beans, and various property settings. For example, if spring-webmvc is on the classpath, this annotation 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 base package, letting it find the controllers.

Main method in the class is the application entry point. The main method delegates to Spring Boot’s SpringApplication class by calling run method. It is the task of SpringApplication to bootstrap our application, starting Spring, which, in turn, starts the auto-configured Tomcat web server.

Run it as a stand alone Java application by running the class with the main method (JPAApp.java) from Eclipse IDE itself. Right click JPAApp.java – Run As – Java Application. If your application has no problem then you should see in the console that the Tomcat is started and EntityManager is configured.

Tomcat initialized with port(s): 8080 (http)
2021-01-04 13:18:24.721  INFO 11348 --- [  restartedMain] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-01-04 13:18:24.723  INFO 11348 --- [  restartedMain] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.39]
2021-01-04 13:18:25.539  INFO 11348 --- [  restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-01-04 13:18:25.539  INFO 11348 --- [  restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 7797 ms

Tomcat started on port(s): 8080 (http) with context path ''
2021-01-04 13:18:30.459  INFO 11348 --- [  restartedMain] DeferredRepositoryInitializationListener : Triggering deferred initialization of Spring Data repositories…
2021-01-04 13:18:30.906  INFO 11348 --- [         task-1] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2021-01-04 13:18:31.633  INFO 11348 --- [         task-1] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL57Dialect
2021-01-04 13:18:33.929  INFO 11348 --- [         task-1] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2021-01-04 13:18:33.950  INFO 11348 --- [         task-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2021-01-04 13:18:34.554  INFO 11348 --- [  restartedMain] DeferredRepositoryInitializationListener : Spring Data repositories initialized!

Testing the application

For testing the application we’ll use the rest client Postman, ensure that you have Postman app installed.

Inserting User record.

  1. Select POST as request type.
  2. URL as http://localhost:8080/user/
  3. Select Body and provide user data
    {
      "firstName": "Kavin",
      "lastName": "Michael",
      "userType": "Silver",
      "startDate": "2018-08-20"
    }
    
  4. Specify content type as JSON.
  5. Click Send

In the response body you should see the status as “201 Created” and also the created user record. Note that the Id is also added in the returned record.

Spring Boot REST API example

Getting specific user record

  1. Select GET as request type.
  2. URL as http://localhost:8080/user/5 (5 is userId)
  3. Click Send
Spring Boot Spring Data JPA

Same way you can get all the users by Selecting GET as request type and URL as http://localhost:8080/user

Updating user record

  1. Select PUT as request type.
  2. URL as http://localhost:8080/user/updateuser
  3. Select Body and provide user data for the UserId that has to be updated.
    {
      "userId": 6,
      "firstName": "Kavin",
      "lastName": "Michael",
      "userType": "Gold",
      "startDate": "2018-08-20"
    }
    
  4. Click Send

In the DB you can see that the user_type is modified for user id 6.

Deleting user record

  1. Select Delete as request type.
  2. URL as http://localhost:8080/user/6 to delete User with Id as 6.
  3. Click Send

That's all for this topic Spring Boot REST API CRUD Example With Spring Data JPA. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring Boot Spring Initializr
  2. Spring Boot StandAlone (Console Based) Application Example
  3. Spring Boot spring-boot-starter-parent
  4. Spring MVC JSON as Response Example
  5. Spring NamedParameterJdbcTemplate Insert, Update And Delete Example

You may also like-

  1. Spring MVC Form Example With Bean Validation
  2. Transaction Management in Spring
  3. Spring JdbcTemplate Insert, Update And Delete Example
  4. Spring WebFlux Example Using Functional Programming - Spring Web Reactive
  5. How to Convert ArrayList to Array in Java
  6. Check if Given String or Number is a Palindrome Java Program
  7. Type Casting in Java With Conversion Examples
  8. Named Tuple in Python

No comments:

Post a Comment