Search Tutorials


Spring Boot + JPA + Hibernate + MySQL REST CRUD Example | JavaInUse

Spring Boot + JPA + Hibernate + MySQL REST CRUD Example

Overview

In a previous tutorial we had created a Spring Boot + JPA HelloWorld Example. In this tutorial we will create a Spring Boot + JPA Application to manage comments for our website. On a website users usually give comments in comments section. These comments need to be saved and later retrieved to be displayed. We will be making use of MySQL database to store these comments.

Spring Boot Comments

Lets Begin

The project structure is as follows-
Spring Boot + JPA Example
The pom.xml will be as follows-
<?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.example</groupId>
	<artifactId>easy-notes</artifactId>
	<version>1.0.0</version>
	<packaging>jar</packaging>

	<name>spring-boot-rest-jpa</name>
	<description>Rest API for a Comments Application</description>

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





Create the Main class with SpringBootApplication annotation.
package com.javainuse;

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

@SpringBootApplication
public class CommentsApplication {

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

In the configuration file define the database and hibernate properties-
spring.datasource.url = jdbc:mysql://localhost/bootdb?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username = root
spring.datasource.password = root

spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

spring.jpa.hibernate.ddl-auto = create
Define the model class Comment. It has the following fields -
  • id - Primary Key with Auto Increment.
  • postName - The Post for which the user will be adding the comment. This field cannot be null.
  • comment - The comment which the use wants to post. This field cannot be null.
  • createdAt - Time at which the comment was created.
  • updatedAt - Time at which the comment was updated.
Also in this class we will be using the following annotations-
  • @Entity - Mark the class as a persistent Java class
  • @Table - Table that this entity will be mapped to
  • @Id - Define the primary key
  • @GeneratedValue - Define the primary key generation strategy. We have declared the primary key to be an Auto Increment field.
  • @NotBlank - Field is not null or empty
  • @Column - Define the properties of the column that will be mapped to the annotated field
  • All your domain models must be annotated with @Entity annotation. It is used to mark the class as a persistent Java class.
  • @Temporal - used with java.util.Date and java.util.Calendar classes. It converts the date and time values from Java Object to compatible database type and vice versa.
  • @JsonIgnoreProperties - Jackson annotation for Serializing and Deserializing Java objects to and from JSON.
  • EntityListeners -
package com.javainuse.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 javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotBlank;

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

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@Entity
@Table(name = "comments")
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = { "createdAt", "updatedAt" }, allowGetters = true)
public class Comment {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private Long id;

	@NotBlank
	private String postName;
	@NotBlank
	private String comment;

	@Column(nullable = false, updatable = false)
	@Temporal(TemporalType.TIMESTAMP)
	@CreatedDate
	private Date createdAt;

	@Column(nullable = false)
	@Temporal(TemporalType.TIMESTAMP)
	@LastModifiedDate
	private Date updatedAt;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Date getCreatedAt() {
		return createdAt;
	}

	public void setCreatedAt(Date createdAt) {
		this.createdAt = createdAt;
	}

	public Date getUpdatedAt() {
		return updatedAt;
	}

	public void setUpdatedAt(Date updatedAt) {
		this.updatedAt = updatedAt;
	}

	public String getPostName() {
		return postName;
	}

	public void setPostName(String postName) {
		this.postName = postName;
	}

	public String getComment() {
		return comment;
	}

	public void setComment(String comment) {
		this.comment = comment;
	}

}

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

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

@SpringBootApplication
@EnableJpaAuditing
public class CommentsApplication {

	public static void main(String[] args) {
		SpringApplication.run(CommentsApplication.class, args);
	}
}
   
Next we will create the CommentRepository to access data from the Repository.
pring Data JPA has got us covered here. It comes with a JpaRepository interface which defines methods for all the CRUD operations on the entity, and a default implementation of JpaRepository called SimpleJpaRepository.
You will now be able to use JpaRepository's methods like save(), findOne(), findAll(), count(), delete() etc. You don't need to implement these methods. They are already implemented by Spring Data JPA's SimpleJpaRepository. This implementation is plugged in by Spring automatically at runtime. We use the following annotation - @Repository
package com.javainuse.repository;

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

import com.javainuse.model.Comment;

@Repository
public interface CommentRepository extends JpaRepository<Comment, Long> {

}
Create the custom exception as follows -
package com.javainuse.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {

	private static final long serialVersionUID = 5344320715962995240L;
	private String resourceName;
	private String fieldName;
	private Object fieldValue;

	public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
		super(String.format("%s not found with %s : '%s'", resourceName, fieldName, fieldValue));
		this.resourceName = resourceName;
		this.fieldName = fieldName;
		this.fieldValue = fieldValue;
	}

	public String getResourceName() {
		return resourceName;
	}

	public String getFieldName() {
		return fieldName;
	}

	public Object getFieldValue() {
		return fieldValue;
	}
}
Finally we will be creating the CommentController class-
   package com.javainuse.controller;

import java.util.List;

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.javainuse.exception.ResourceNotFoundException;
import com.javainuse.model.Comment;
import com.javainuse.repository.CommentRepository;

@RestController
@RequestMapping("/api")
public class CommentController {

	@Autowired
	CommentRepository commentRepository;

	@GetMapping("/comments")
	public List<Comment> getAllComments() {
		return commentRepository.findAll();
	}

	@PostMapping("/comments")
	public Comment createComment(@RequestBody Comment comment) {
		return commentRepository.save(comment);
	}

	@GetMapping("/comments/{id}")
	public Comment getCommentById(@PathVariable(value = "id") Long commentId) {
		return commentRepository.findById(commentId)
				.orElseThrow(() -> new ResourceNotFoundException("Comment", "id", commentId));
	}

	@PutMapping("/comments/{id}")
	public Comment updateComment(@PathVariable(value = "id") Long commentId, @RequestBody Comment commentDetails) {

		Comment comment = commentRepository.findById(commentId)
				.orElseThrow(() -> new ResourceNotFoundException("Comment", "id", commentId));

		comment.setPostName(commentDetails.getPostName());
		comment.setComment(commentDetails.getComment());

		Comment updatedComment = commentRepository.save(comment);
		return updatedComment;
	}

	@DeleteMapping("/comments/{id}")
	public ResponseEntity<?> deleteComment(@PathVariable(value = "id") Long commentId) {
		Comment comment = commentRepository.findById(commentId)
				.orElseThrow(() -> new ResourceNotFoundException("Comment", "id", commentId));

		commentRepository.delete(comment);

		return ResponseEntity.ok().build();
	}
}
   
We are done with all the changes. Start the Spring Boot Application.
  • Post a new comment -Make a POST call to localhost:8080/api/comments with following request
       {
        "postName":"spring-boot-rest-jpa",
        "comment":"Nice Post"
    }
    
    We can add multiple such comments.
    Spring Boot JPA Post
  • Update existing comment -Make a PUT call to localhost:8080/api/comments/{id} with following request
    {
        "postName":"spring-boot-rest-jpa",
        "comment":"Nice Post. Post more regularly"
    }
    

    Spring Boot JPA Update
  • Delete existing comment -Make a DELETE call to localhost:8080/api/comments/{id}
    Spring Boot JPA Delete
  • Get existing comment -Make a GET call to localhost:8080/api/comments/{id}
    Spring Boot JPA Get
  • Get all comments -Make a GET call to localhost:8080/api/comments
    Spring Boot JPA Get All

Download Source Code

Download it - Drools Spring Boot Integration example