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-
- 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.
- getAllUsers() annotated with @GetMapping is used to get all the user records.
- 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.
- 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.
- 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.
- Select POST as request type.
- URL as http://localhost:8080/user/
- Select Body and provide user data
{ "firstName": "Kavin", "lastName": "Michael", "userType": "Silver", "startDate": "2018-08-20" }
- Specify content type as JSON.
- 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.
Getting specific user record
- Select GET as request type.
- URL as http://localhost:8080/user/5 (5 is userId)
- Click Send
Same way you can get all the users by Selecting GET as request type and URL as http://localhost:8080/user
Updating user record
- Select PUT as request type.
- URL as http://localhost:8080/user/updateuser
- 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" }
- Click Send
In the DB you can see that the user_type is modified for user id 6.
Deleting user record
- Select Delete as request type.
- URL as http://localhost:8080/user/6 to delete User with Id as 6.
- 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
You may also like-
Here you have accessed service from controller. But the flow should be controller-repository-service isn't it. Please explain.
ReplyDeleteNo, it's the other way round Controller-Service-Repository(DAO layer).. That way you keep your web layer (Controller) separate from DAO Layer. Service class is supposed to be a stand alone class in between having the business logic.
Delete