CRUD Rest Service With Spring Boot and JPA

CRUD Rest Service With Spring Boot and JPA Example

Spring framework has become a platform for almost every development task. You can set up a project and start building very fast.

In this article, we are going to build a CRUD Rest Service With Spring Boot  and JPA to manage users.

We are going to use the same code throughout our series on spring boot and test the application using a Rest Client “Postman”. Please visit my previous post and do necessary steps here to create a project. I request you to keep patience as this article is gonna be quite long.

You will understand following

  1. How to Configure Spring Boot and JPA With Hibernate and Spring Data JPA.
  2. Basic Annotations of Spring Boot and JPA.
  3. How to Integrate Spring Boot, JPA, Hibernate to Create a REST API.

So, Let’s get Started !!

Understanding the Spring Boot and JPA Example 

What are we exactly going to build in this example

API End PointTypeDetails
/usersPOSTCreate an User Entity
users/{id}GETRetrieve a user entity
/users/{id}PUTUpdate a User Entity
/users/{id}DELETEDeleting a User entity

Project Structure

We are creating different packages for Beans, Controllers, Repository, and Services. Let’s go ahead and create following package structure as shown below. We are going to see each and every package and its functionalities one by one with code.

Rest Using Spring boot Jpa






SampleRestApplication.java:- 

It is the entry point of Spring Boot application.We are going to  annotate our class with @ComponentScan  and indicate the base package to scan for spring beans. It contains @SpringBootApplication annotation which is basically a combination of the following annotations.

  1. @Configuration
  2. @EnableAutoConfiguration
  3. @ComponentScan
package com.frugalis.SampleRest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@ComponentScan(basePackages="com.frugalis")
@EnableJpaRepositories(basePackages="com.frugalis.repository")
@EntityScan(basePackages="com.frugalis.entity")
public class SampleRestApplication {

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

We are using two more annotations:-

  1. @EntityScan:- This annotation Scans for all persistence based beans in your defined package.
  2. @EnableJpaRepositories:-  This annotation enables Spring Data JPA repositories support in your application.

User.java:-

We are going to create a simple bean to accept input and return as an output.

package com.frugalis.beans;

import java.io.Serializable;

public class User implements Serializable {

	Long id;
	String firstname;
	String lastname;
	String institute;
	
	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 getInstitute() {
		return institute;
	}
	public void setInstitute(String institute) {
		this.institute = institute;
	}
	
	
	
	
	
}


Configure Mysql Database:-

We are already adding the spring-data-jpadependency in our maven configuration. So spring-data-jpa is already in the classpath. It automatically tries to configure a DataSource by reading the database specific properties from the file.application.properties

Let’s add the database configuration in fileapplication.properties and spring automatically going to load at runtime. Create a database schema called springboot in MySQL .

spring.datasource.url=jdbc:mysql://localhost:3306/springboot
spring.datasource.username=root
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=create-drop
server.port=8088

Replace your database credentials in properties spring.datasource.username and spring.datasource.password . The property  spring.jpa.hibernate.ddl-auto can have two values create-drop and update  . create-drop will drop and recreate the existing database entity whereas update  will update the existing database entity if any changes are there.

Create Domain Classes or Entity:-

We now create our User entity which is going to persist in our database. Our entity is going to have following set of fields.

  1. id is  pk of the entity
  2. firstname
  3. lastname
  4. institute

User.java:-

package com.frugalis.entity;

import java.io.Serializable;

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

@Entity
@Table(name="USERS")
public class User implements Serializable {
	@Id
    @GeneratedValue(strategy = GenerationType.AUTO)
	Long id;
	String firstname;
	String lastname;
	String institute;
	
	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 getInstitute() {
		return institute;
	}
	public void setInstitute(String institute) {
		this.institute = institute;
	}
		
}

As we can see above , we are creating two User classes. User class as a simple plain POJO object and use it for sending as a response Object. Another One is User entity class because, we don’t want to expose our entity object directly as a response, hence we are creating another POJO  User object.


Access Users Data From Database:-

We are creating UserRepository to access data from database persisted by hibernate.Our repository class is going to extend JpaRepository.

Spring Data JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that’s actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.

UserRepository.java:-

package com.frugalis.repository;

import java.util.List;

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

import com.frugalis.entity.User;


public interface UserRepository extends JpaRepository<User, Long>{
	
	List<User> findByfirstname(String firstname);
	User findById(Long Id);
}

You will now be able to use JpaRepository’s methods like save() , delete(),findAll(),delete() etc. The repository above extendsJpaRepository , passes the JPA entity and its primary key.

Basic methods for finding a single record, all records, paginated records, create/update, and delete are automatically provided. It’s also very easy to overload any custom query to add pagination and sorting.

The methodfindByfirstname lets Spring Data JPA automatically generate a like query for the first name column. We can also write query in JQL and execute like below in case we need it.

 @Query(FIND_BY_INSTITUTE_QUERY)
    public List<Person> findByinstitute(@Param("institute") String institute);

Writing Our Business Service:-

We are almost done setting up our JPA , now we are going to use the repository and write our business logic.So we are going to do crud operations and declare our service methods in an interface and write separate implementations.

UserService.java:-

package com.frugalis.service;

import java.util.List;

import com.frugalis.beans.User;

public interface UserService {

	public User saveUser(User inUser);
	public List<User> getAllUsers();
	public User findbyId(Long id);
	
}

The above interface gives you an idea how our business logic is going to be implemented , let’s take a pause and write business service implementations one by one while creating Rest Implementations.

Writing Rest Implementations:-

Now we are actually going to do the rest implementations of the API.Let’s Open our HelloController and start implementing one by one. We are first going to write code in our RestController and call business service class UserService from the controller for a particular endpoint.Create a class named UserServiceImpl implements UserService to write our business logic and implement all the methods.

package com.frugalis.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
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.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.frugalis.beans.User;
import com.frugalis.service.UserService;
import com.mysql.cj.fabric.Response;

@RestController
public class HelloController {

	@Autowired
	UserService userService;
        
       //To DO all Rest Methods

}

Spring 4.0 introduced @RestController, a specialized version of the controller which is a convenience annotation that does nothing more than adding the @Controller and @ResponseBody annotations. By annotating the controller class with @RestController annotation, you no longer need to add @ResponseBody to all the request mapping methods. The @ResponseBody annotation is active by default.

Testing and Execution:-

Let’s see now how we are going to give final shape to our CRUD Rest Service With Spring Boot and JPA step by step.

1. Create a User:-  Method is Post and EndPoint is /users

Add following line of code in HelloController.java

@GetMapping("/users/{id}")
	public ResponseEntity<User> getNoteById(@PathVariable(value = "id") Long userId) {
	    User note = userService.findbyId(userId);
	    if(note == null) {
	        return ResponseEntity.notFound().build();
	    }
	    return ResponseEntity.ok().body(note);
	}

This method tells us that the above code will be executed once a Post request with url is localhost:8080/users requested. We are using @RequestBody which says that it expects user object in the body as JSON format.

Now that we have added our request mapping and  write business logic in UserServiceImpl.java.

	@Autowired
	UserRepository userRepository;

	@Override
	public User saveUser(User inUser) {

		com.frugalis.entity.User outUser2 = new com.frugalis.entity.User();

		BeanUtils.copyProperties(inUser, outUser2);

		outUser2 = userRepository.save(outUser2);

		BeanUtils.copyProperties(outUser2, inUser);
		return inUser;
	}

We are copying properties from User entity object to User Pojo using BeanUtils.copyProperties and returning a Pojo object from our service class.

Testing:-

2. Retrieve a User:-  Method is GET and EndPoint is /users/{id}

Add following line of code in HelloController.java

	@GetMapping("/users/{id}")
	public ResponseEntity<User> getUserById(@PathVariable(value = "id") Long userId) {
	    User user = userService.findbyId(userId);
	    if(user == null) {
	        return ResponseEntity.notFound().build();
	    }
	    return ResponseEntity.ok().body(user);
	}

This method tells us that the above code will be executed once a GET request with url is localhost:8080/users/1 requested. We are using RestEntity which says that returns a User Object .

Now that we have added our request mapping and  write business logic in UserServiceImpl.java.

	@Override
	public User findbyId(Long id) {
		// TODO Auto-generated method stub
	com.frugalis.entity.User dbUser=userRepository.findById(id);
	User outUser=null;
	if(dbUser!=null){
		outUser=new User();
		BeanUtils.copyProperties(dbUser, outUser);
	}
	
	
		return outUser;
	}

We are copying properties from dbUser entity object to User Pojo using BeanUtils.copyProperties and returning a Pojo object from our service class.Lets run our Project using mvn Spring-boot:run

Testing:-

GET Request Spring Boot

3. Update a User:-  Method is PUT and EndPoint is /users/{id}

Add following line of code in HelloController.java

@PutMapping("/users/{id}")
	public ResponseEntity<Object> updateUser(@PathVariable(value = "id") Long userId,@RequestBody User inUser) {
		inUser.setId(userId);
		User user = userService.updateUser(inUser);
	    if(user == null) {
	        return ResponseEntity.ok().body(new String("Not Found"));
	    }
	    return ResponseEntity.ok().body(user);
	}

This method tells us that the above code will be executed once a PUT request with url is localhost:8080/users/1 requested. We are using ResponseEntity which says that returns any Object .

Now that we have added our request mapping and  write business logic in UserServiceImpl.java.

	@Override
	public User updateUser(User inUser) {
		// TODO Auto-generated method stub
		com.frugalis.entity.User dbUser=userRepository.findById(inUser.getId());
		if(dbUser!=null){dbUser.setFirstname(inUser.getFirstname());
		dbUser.setInstitute(inUser.getInstitute());
		dbUser.setLastname(inUser.getLastname());
		userRepository.save(dbUser);
		BeanUtils.copyProperties(dbUser, inUser);
		return inUser;

		}else {
			return null;
		}
	}

Testing:-

Pur

3. Delete a User:- 

We are going to delete the user based on ID . Lte’s add following line of code in HelloController.java

@DeleteMapping("/users/{id}")
	public ResponseEntity<Object> deleteUser(@PathVariable(value = "id") Long userId) {
		
		int  user = userService.deleteUser(userId);
	    if(user<=0) {
	        return ResponseEntity.ok().body(new String("Not Found"));
	    }
	    return ResponseEntity.ok().body(new String("Deleted SuccessFully"));
	}

This method tells us that the above code will be executed once a DELETE request with url is localhost:8080/users/1 requested. We are using ResponseEntity which says that returns any Object.

Now that we have added our request mapping and  write business logic in UserServiceImpl.java.

@Override
	public int deleteUser(Long id) {
	
	try{
		com.frugalis.entity.User dbUser=userRepository.findById(id);
		if(dbUser==null){return -1;}
		else {
			userRepository.delete(id);
			return 1;
		}
		
	}catch(Exception e){
		
	}
	return 0;
		
	
	}

Testing:-

Download Code