Spring Boot Hibernate RESTful GET POST PUT and DELETE API Tutorial

In this tutorial, we will learn how to build a CRUD rest APIs using Spring boot, spring data JPA, Hibernate, and H2 database.
Learn Spring boot at https://www.javaguides.net/p/spring-boot-tutorial.html
Learn Hibernate at https://www.javaguides.net/p/hibernate-tutorial.html
We’ll first build the APIs to create, retrieve, update, and delete a Product, and then test them using postman.

Spring Boot has taken the Spring framework to the next level. It has drastically reduced the configuration and setup time required for spring projects.

You can set up a project with almost zero configuration and start building the things that actually matter to your application.

High-Level Architecture

The below diagram shows the high-level architecture of our spring boot project:

Tools and technologies used

  • Spring Boot - 2.1.0.RELEASE
  • JDK - 1.8 or later
  • Spring Framework - 5.1.2 RELEASE
  • Hibernate - 5.2.17. Final
  • JPA
  • Maven - 3.2+
  • IDE - Eclipse or Spring Tool Suite (STS)
  • H2 Embedded Database

1. Create a Spring Boot Application

There are many ways to create a Spring Boot application. You can refer below articles to create a Spring Boot application.

2. The pom.xml File

This is the Maven build file. The spring-boot-starter-web is a starter for building the web, including RESTful, applications using Spring MVC. 
The spring-boot-starter-data-jpa is a starter for using Spring Data JPA with Hibernate.
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <parent>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-parent</artifactId>
     <version>2.1.0.RELEASE</version>
     <relativePath/> <!-- lookup parent from repository -->
 </parent>
 <groupId>net.javaguides.springboot</groupId>
 <artifactId>springboot-crud-hibernate-example</artifactId>
 <version>0.0.1-SNAPSHOT</version>
 <name>springboot-crud-hibernate-example</name>
 <description>spring boot crud operations example with hibernate</description>

 <properties>
     <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>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <scope>runtime</scope>
  </dependency>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
  </dependency>
 </dependencies>

 <build>
     <plugins>
         <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
     </plugins>
 </build>
</project>

3. Configure H2 Database

By default, Spring Boot configures the application to connect to an H2 in-memory store with the username sa and an empty password.
In this example, we will use a default configuration of the H2 database (we don't use the above configuration, the above configuration is just to know more about H2 database configuration with Spring boot).

4. Create JPA Entity - Product.java

Let's create a JPA entity class which will map to relational database table "products":
package net.javaguides.springboot.model;

import java.math.BigDecimal;
import java.util.Date;

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

import org.hibernate.annotations.CreationTimestamp;

@Entity
@Table(name = "products")
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Column(name = "name")
    private String name;

    @Column(name = "description")
    private String description;

    @Column(name = "price")
    private BigDecimal price;

    @CreationTimestamp
    private Date createdAt;

    @CreationTimestamp
    private Date updatedAt;


    public long getId() {
        return id;
    }
    public void setId(long id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    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;
    }
}

5. Create a Spring Data Repository - ProductRepository.java

Let's create a Repository to access Product data from databaseL
package net.javaguides.springboot.repository;

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

import net.javaguides.springboot.model.Product;

public interface ProductRepository extends JpaRepository<Product, Long> {

}

6. Service Layer (uses repository)

The service layer is optional – still recommended to perform additional business logic if any. Generally, we will connect with the repository here for crud operations.

ProductService.java

package net.javaguides.springboot.service;

import java.util.List;

import net.javaguides.springboot.model.Product;

public interface ProductService {
    Product createProduct(Product product);

    Product updateProduct(Product product);

    List < Product > getAllProduct();

    Product getProductById(long productId);

    void deleteProduct(long id);
}

ProductServiceImpl.java

package net.javaguides.springboot.service;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import net.javaguides.springboot.exception.ResourceNotFoundException;
import net.javaguides.springboot.model.Product;
import net.javaguides.springboot.repository.ProductRepository;

@Service
@Transactional
public class ProductServiceImpl implements ProductService {


    @Autowired
    private ProductRepository productRepository;


    @Override
    public Product createProduct(Product product) {
        return productRepository.save(product);
    }

    @Override
    public Product updateProduct(Product product) {
        Optional < Product > productDb = this.productRepository.findById(product.getId());

        if (productDb.isPresent()) {
            Product productUpdate = productDb.get();
            productUpdate.setId(product.getId());
            productUpdate.setName(product.getName());
            productUpdate.setDescription(product.getDescription());
            productRepository.save(productUpdate);
            return productUpdate;
        } else {
            throw new ResourceNotFoundException("Record not found with id : " + product.getId());
        }
    }

    @Override
    public List < Product > getAllProduct() {
        return this.productRepository.findAll();
    }

    @Override
    public Product getProductById(long productId) {

        Optional < Product > productDb = this.productRepository.findById(productId);

        if (productDb.isPresent()) {
            return productDb.get();
        } else {
            throw new ResourceNotFoundException("Record not found with id : " + productId);
        }
    }

    @Override
    public void deleteProduct(long productId) {
        Optional < Product > productDb = this.productRepository.findById(productId);

        if (productDb.isPresent()) {
            this.productRepository.delete(productDb.get());
        } else {
            throw new ResourceNotFoundException("Record not found with id : " + productId);
        }

    }
}

7. Spring REST Controller - ProductController

Finally, expose all operations through MVC URLs or REST endpoints. Clients will connect with these endpoints to create/get/update/delete product records.
Notice the usage of annotations @RestController, @RequestMapping, @GetMapping, @PostMapping, and @DeleteMapping to map various URIs to controller methods.
package net.javaguides.springboot.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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.RestController;

import net.javaguides.springboot.model.Product;
import net.javaguides.springboot.service.ProductService;

@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/products")
    public ResponseEntity < List < Product >> getAllProduct() {
        return ResponseEntity.ok().body(productService.getAllProduct());
    }

    @GetMapping("/products/{id}")
    public ResponseEntity < Product > getProductById(@PathVariable long id) {
        return ResponseEntity.ok().body(productService.getProductById(id));
    }

    @PostMapping("/products")
    public ResponseEntity < Product > createProduct(@RequestBody Product product) {
        return ResponseEntity.ok().body(this.productService.createProduct(product));
    }

    @PutMapping("/products/{id}")
    public ResponseEntity < Product > updateProduct(@PathVariable long id, @RequestBody Product product) {
        product.setId(id);
        return ResponseEntity.ok().body(this.productService.updateProduct(product));
    }

    @DeleteMapping("/products/{id}")
    public HttpStatus deleteProduct(@PathVariable long id) {
        this.productService.deleteProduct(id);
        return HttpStatus.OK;
    }
}

ResourceNotFoundException.java

package net.javaguides.springboot.exception;

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

@ResponseStatus
public class ResourceNotFoundException extends RuntimeException {

    private static final long serialVersionUID = 1 L;

    public ResourceNotFoundException(String message) {
        super(message);
    }

    public ResourceNotFoundException(String message, Throwable throwable) {
        super(message, throwable);
    }
}

8. Running Spring boot application

This spring boot application has an entry point Java class called SpringbootCrudHibernateExampleApplication.java with the public static void main(String[] args) method, which you can run to start the application.
package net.javaguides.springboot;

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

@SpringBootApplication
public class SpringbootCrudHibernateExampleApplication {

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

9. Test Rest API using Postman Client

The below video tutorial covers testing rest APIs using postman client:

10. Download source code

The source code of this tutorial available on my GitHub Repository.

Comments