Spring Boot REST and JPA – Save to a Database

In this blog post, I will share how to create a very simple RESTful Spring Boot Web Service that uses Spring Data JPA to save information to a database.

Our Web Service will accept HTTP Post requests with user details and then save these user details into MySQL Database using Spring Data JPA CrudRepository.

For code examples on how to use the H2 database, read “Adding H2 Database to Spring Boot Application“.

1) Create RESTful Spring Boot Web Service with Spring Boot

To begin, we will need to create a very simple RESTful Spring Boot Web Service which will be used to accept “User details” sent to it as an HTTP POST request.

Earlier I published a blog post that demonstrates how to do it. To create a RESTful Web Service with Spring Boot, please check the below link “Create a Simple Web Service with Spring Boot“.

2) Spring Boot Starter Data JPA Dependency

To use Spring Data JPA in our Web Service application, we will need to open the newly created project and update its pom.xml file by adding the below Spring Boot Starter Data JPA dependency.

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

3) User Details Request Model Class

When user details are sent to our web service endpoint, it will most likely be an XML or JSON payload. Let’s assume that the user details are sent to our web service endpoint as a JSON payload in an HTTP POST request:

{
  "firstName":"Sergey",
  "lastName":"Kargopolov",
  "email":"test@test.com",
  "password":"123"
}

When a web service receives the above JSON payload, the JSON will be converted into a Java object, and for that to happen, we will need to create a Java class with the class fields that will match the above JSON payload.

Below is an example of such a class:

package com.appsdeveloperblog.app.ws.ui.model.request;

public class UserDetailsRequestModel {
 
 private String firstName;
 private String lastName;
 private String email;
 private String password;
 
 
 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 getEmail() {
  return email;
 }
 public void setEmail(String email) {
  this.email = email;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }

}

4) Create RestController Class

For our application to be able to accept this HTTP Post request and to convert the received JSON Payload into a Java class, we will need to create a RestController class with a method that will handle HTTP Post Request.

package com.appsdeveloperblog.app.ws.ui.controllers;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.appsdeveloperblog.app.ws.service.UserService;
import com.appsdeveloperblog.app.ws.shared.dto.UserDto;
import com.appsdeveloperblog.app.ws.ui.model.request.UserDetailsRequestModel;
import com.appsdeveloperblog.app.ws.ui.model.response.UserRest;

@RestController
@RequestMapping("users")
public class UserController {

 @Autowired
 UserService userService;
 
 @PostMapping
 public UserRest createUser(@RequestBody UserDetailsRequestModel requestUserDetails)
 {
  UserRest returnValue = new UserRest();
  
  UserDto userDto = new UserDto();
  BeanUtils.copyProperties(requestUserDetails, userDto);
  
  UserDto createdUser = userService.createUser(userDto);
  BeanUtils.copyProperties(createdUser, returnValue);

  return returnValue;
 }
}

5) Web Service Endpoint Return Model Class

In the above code example of RestController you might have noticed that the return value of createUser() method is UserRest.

The UserRest object will contain information about the user we want to return back if the user details have been saved to a database successfully. This UserRest class will be converted into a JSON document and returned back as a body of HTTP Response.

Below is the UserRest class and its equivalent in JSON when it is converted by the framework.

package com.appsdeveloperblog.app.ws.ui.model.response;

public class UserRest {

    private String userId;
    private String firstName;
    private String lastName;
    private String email;
    private String href;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String publicId) {
        this.userId = publicId;
    }

    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 getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getHref() {
        return href;
    }

    public void setHref(String href) {
        this.href = href;
    }

}

and when it gets converted by the framework it will look this way:

{
    "userId": "VCcR6hK9M9s6ig3QSBtnbF5xLwZZ7P",
    "firstName": "Sergey",
    "lastName": "Kargopolov",
    "email": "test@test.com",
    "href": "/users/VCcR6hK9M9s6ig3QSBtnbF5xLwZZ7P"
}

6) The Service Class

Another class the user of which you might have noticed in the above RestController is the UserService class. Service classes are being used to Autowire the database access classes, factories, and providers and perform some lengthy or complex business operations. In our case the UserService class will:

  • Accept the UserDto class,
  • Autowire the CrudRepository to save data to a database,
  •  Create an Entity object and persist this data to a database.

UserService Interface

package com.appsdeveloperblog.app.ws.service;

import java.util.List;

import org.springframework.security.core.userdetails.UserDetailsService;
import com.appsdeveloperblog.app.ws.shared.dto.UserDto;

public interface UserService extends UserDetailsService {
    UserDto createUser(UserDto user);
}

UserSerivice interface implementation

package com.appsdeveloperblog.app.ws.service.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.appsdeveloperblog.app.ws.exceptions.UserServiceException;
import com.appsdeveloperblog.app.ws.io.entity.UserEntity;
import com.appsdeveloperblog.app.ws.io.repository.UserRepository;
import com.appsdeveloperblog.app.ws.service.UserService;
import com.appsdeveloperblog.app.ws.shared.dto.UserDto;
import com.appsdeveloperblog.app.ws.shared.utils.UserProfileUtils;
import com.appsdeveloperblog.app.ws.ui.model.response.ErrorMessages;

@Service
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;
    private final UserProfileUtils userProfileUtils;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    public UserServiceImpl(UserRepository userRepository, UserProfileUtils userProfileUtils,
            BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.userRepository = userRepository;
        this.userProfileUtils = userProfileUtils;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }
 

    @Override
    public UserDto createUser(UserDto userDto) {
        UserDto returnValue = new UserDto();
 

        // Check if user already exists
        UserDto existingUser = this.getUserByUserName(userDto.getEmail());
        if (existingUser != null) {
            throw new UserServiceException(ErrorMessages.RECORD_ALREADY_EXISTS.name());
        }

        // Generate secure public user id
        String userId = userProfileUtils.generateUserId(30);
        userDto.setUserId(userId);

        // Generate secure password
        userDto.setEncryptedPassword(bCryptPasswordEncoder.encode(userDto.getPassword()));
        userDto.setEmailVerificationStatus(false);
        userDto.setEmailVerificationToken(userProfileUtils.generateEmailverificationToken(30));

        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(userDto, userEntity);

        // Record data into a database
        userEntity = userRepository.save(userEntity);
        BeanUtils.copyProperties(userEntity, returnValue);

        return returnValue;
    }

    @Override
    public UserDto getUserByUserName(String userName) {
        UserDto returnValue = null;
        UserEntity userEntity = userRepository.findUserByEmail(userName);

        if (userEntity != null) {
            returnValue = new UserDto();
            BeanUtils.copyProperties(userEntity, returnValue);
        }

        return returnValue;
    }
 
}

7) UserDto class source code

package com.appsdeveloperblog.app.ws.shared.dto;

import java.io.Serializable;

public class UserDto implements Serializable {

    private static final long serialVersionUID = 4865903039190150223L;
    private long id;
    private String firstName;
    private String lastName;
    private String email;
    private String password;
    private String encryptedPassword;
    private String userId;

    /**
     * @return the id
     */
    public long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * @return the firstName
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * @param firstName the firstName to set
     */
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    /**
     * @return the lastName
     */
    public String getLastName() {
        return lastName;
    }

    /**
     * @param lastName the lastName to set
     */
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    /**
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email the email to set
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * @return the encryptedPassword
     */
    public String getEncryptedPassword() {
        return encryptedPassword;
    }

    /**
     * @param encryptedPassword the encryptedPassword to set
     */
    public void setEncryptedPassword(String encryptedPassword) {
        this.encryptedPassword = encryptedPassword;
    }

    /**
     * @return the userId
     */
    public String getUserId() {
        return userId;
    }

    /**
     * @param userId the userId to set
     */
    public void setUserId(String userId) {
        this.userId = userId;
    }
 

}

8) User Entity Class

We are going to use JPA to persist user details in MySQL database. Below is a source code of user entity class. Which when persisted will be:

  • Stored in a database table called Users. Database table will be created for us automatically because in the application.properties file we will specify so,
  • Users database table will be created for us automatically based on the information specified in this Entity class.
package com.appsdeveloperblog.app.ws.io.entity;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

/**
 *
 * @author sergeykargopolov
 */
@Entity(name = "Users")
public class UserEntity implements Serializable {

    private static final long serialVersionUID = 4865903039190150223L;
    @Id
    @GeneratedValue
    private long id;

    @Column(nullable = false)
    private String userId;

    @Column(length = 50, nullable = false)
    private String firstName;

    @Column(length = 50, nullable = false)
    private String lastName;

    @Column(length = 100, nullable = false)
    private String email;

    @Column(nullable = false)
    private String encryptedPassword;
 

    /**
     * @return the id
     */
    public long getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * @return the userId
     */
    public String getUserId() {
        return userId;
    }

    /**
     * @param userId the userId to set
     */
    public void setUserId(String userId) {
        this.userId = userId;
    }

    /**
     * @return the firstName
     */
    public String getFirstName() {
        return firstName;
    }

    /**
     * @param firstName the firstName to set
     */
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    /**
     * @return the lastName
     */
    public String getLastName() {
        return lastName;
    }

    /**
     * @param lastName the lastName to set
     */
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    /**
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email the email to set
     */
    public void setEmail(String email) {
        this.email = email;
    }


    /**
     * @return the encryptedPassword
     */
    public String getEncryptedPassword() {
        return encryptedPassword;
    }

    /**
     * @param encryptedPassword the encryptedPassword to set
     */
    public void setEncryptedPassword(String encryptedPassword) {
        this.encryptedPassword = encryptedPassword;
    }

}

9) Configure MySQL Database Support

Add JPA Dependency and MySQL driver to pom.xml file

For our Spring Boot application be able to save data in MySQL database using JPA we will need to add two more dependencies to our pom.xml file.

<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

<dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
</dependency>

Add MySQL Database Connection Details

For our Spring Boot to be able to connect to MySQL database we will need to update the application.properties file of our Spring Boot app with the following lines:

spring.datasource.url=jdbc:mysql://localhost:3306/photo_app
spring.datasource.username=sergey
spring.datasource.password=sergey
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

where the

  • photo_app – is the name of the database I am establishing the connection with. The database must exist. It can be an empty database with no tables. But it must exist before JPA can persist our Java objects in it,
  • username – is the username used to connect to a database,
  • password –  is the password used to connect to a database,
  • ddl-auto=update –  is set to update value so that the database table scheme can be updated when needed. Before UserEntity class can be persisted in Users database table, the database table must be created. We do not need to create the Users table manually, although we can. If we do not create the Users database table manually Hibernate will create it for us based on the information specified in the UserEntity class.
  • PhysicalNamingStrategyStandardImpl – is specified here because otherwise, the database table fields will contain underscore “_” in names which are made of two words. I do not want that.

And this all we need to do to make our Spring Boot app to store User Details it receives into a database and return back to a calling client some user details as a response.

I hope this tutorial was of some value to you.

If you are interested to learn more about RESTful Web Services Development and Spring Boot, please have a look at the video courses listed below. One of them might take your skills set to a whole new level. It is so much simpler and faster to learn RESTful Web Services development and programming in general by following step-by-step video lessons and courses.


Leave a Reply

Your email address will not be published. Required fields are marked *