Spring Boot + PostgreSQL + JPA/Hibernate CRUD Restful API Tutorial

In this tutorial, we will learn how to build CRUD REST APIs using Spring Boot, JPA/Hibernate, and the PostgreSQL database. We will use the latest version of Spring Boot 3 in this tutorial.

YouTube Video

Before development, make sure that the PostgreSQL database is installed on your machine.

Check out these two links to download and install a PostgreSQL database on your machine.

Configuring Spring Boot to use the PostgreSQL database is a straightforward process. Additionally, since we are utilizing Hibernate, it provides built-in support for working with various database vendors, eliminating the need for altering the underlying code.

1. What we’ll build

We will build CRUD RESTFul APIs for a Simple Employee Management System using Spring Boot, JPA/Hibernate, and the PostgreSQL database. 
Following are five REST APIs (Controller handler methods) created for the Employee resource.

2. Tools and Technologies Used

  • Spring Boot 3
  • JDK - 17 or later
  • Spring Framework
  • Spring Data JPA (Hibernate)
  • Maven
  • IDE - Eclipse or Spring Tool Suite (STS)
  • PostgreSQL

3. Development Steps

Step 1: Create a Spring Boot Application
Step 2: Maven dependencies
Step 3: Configuring PostgreSQL Database
Step 4: Create JPA Entity - Employee.java
Step 5: Create a Spring Data Repository - EmployeeRepository.java
Step 6: Create a Custom Exception
Step 7: Create Spring Rest Controller - EmployeeController.java
Step 8: Running Spring Boot Application
Step 9: Testing CRUD REST APIs via Postman Client

Step 1: Create a Spring Boot Application

Spring Boot provides a web tool called Spring Initializer to bootstrap an application quickly. Just go to https://start.spring.io/ and generate a new spring boot project.

Use the below details in the Spring boot creation:

Project Name: springboot-backend

Project Type: Maven

Choose dependencies: Spring Web, Spring Data JPA, PostgreSQL, Dev Tools

Package name: net.javaguides.springboot

Step 2: Maven dependencies

Here is the complete pom.xml file for your reference:
<?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>3.0.4</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>net.javaguides</groupId>
	<artifactId>springboot-backend</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot-backend</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>17</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-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
	   
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</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>

Step 3: Configuring PostgreSQL Database

First, you need to create a database in the PostgreSQL server. You can use the following command to create a database in the PostgreSQL server:
CREATE DATABASE employees;
Now, let’s configure the Spring Boot application to use PostgreSQL as our data source. You can do that simply by adding PostgreSQL database URL, username, and password in the src/main/resources/application.properties file.

Open the src/main/resources/application.properties file and add the following content to it:
spring.datasource.url=jdbc:postgresql://localhost:5432/employees
spring.datasource.username=postgres
spring.datasource.password=root
spring.jpa.show-sql=true

## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

Make sure that you will change the above database configuration such as JDBC URL, username, and password as per your environment.
Hibernate will automatically create database tables so you only need to manually create the database and configure an application.properties file.

Step 4: Create JPA Entity - Employee.java

Let's create a new package called model inside net.javaguides.springboot package and then create the Employee class inside the model package with the following contents -
package net.javaguides.springboot.model;

import jakarta.persistence.*;

@Entity
@Table(name = "employees")
public class Employee {
	
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private long id;
	
	@Column(name = "first_name")
	private String firstName;

	@Column(name = "last_name")
	private String lastName;
	
	@Column(name = "email_address")
	private String emailId;
	
	public Employee() {
		
	}
	
	public Employee(String firstName, String lastName, String emailId) {
		super();
		this.firstName = firstName;
		this.lastName = lastName;
		this.emailId = emailId;
	}
	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 getEmailId() {
		return emailId;
	}
	public void setEmailId(String emailId) {
		this.emailId = emailId;
	}
}

Step 5: Create a Spring Data Repository - EmployeeRepository.java

Let's create a new package called repository inside net.javaguides.springboot package and then create the following interface inside the repository package -
package net.javaguides.springboot.repository;

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

import net.javaguides.springboot.model.Employee;

public interface EmployeeRepository extends JpaRepository<Employee, Long>{

}

Step 6: Create a Custom Exception

Let's create a new package called the exception inside net.javaguides.springboot base package. Within this package, create a ResourceNotFoundException class and add the following code to it:
package net.javaguides.springboot.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 = 1L;
	
	public ResourceNotFoundException(String message) {
		super(message);
	}
}

Step 7: Create Spring Rest Controller - EmployeeController.java

Let's create a controller package inside net.javaguides.springboot base package. Within this package, create an EmployeeController class and add the following code to it:
package net.javaguides.springboot.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
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 net.javaguides.springboot.exception.ResourceNotFoundException;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;

@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api/v1/")
public class EmployeeController {

	@Autowired
	private EmployeeRepository employeeRepository;
	
	// get all employees
	@GetMapping("/employees")
	public List<Employee> getAllEmployees(){
		return employeeRepository.findAll();
	}		
	
	// create employee rest api
	@PostMapping("/employees")
	public Employee createEmployee(@RequestBody Employee employee) {
		return employeeRepository.save(employee);
	}
	
	// get employee by id rest api
	@GetMapping("/employees/{id}")
	public ResponseEntity<Employee> getEmployeeById(@PathVariable Long id) {
		Employee employee = employeeRepository.findById(id)
				.orElseThrow(() -> new ResourceNotFoundException("Employee not exist with id :" + id));
		return ResponseEntity.ok(employee);
	}
	
	// update employee rest api
	
	@PutMapping("/employees/{id}")
	public ResponseEntity<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employeeDetails){
		Employee employee = employeeRepository.findById(id)
				.orElseThrow(() -> new ResourceNotFoundException("Employee not exist with id :" + id));
		
		employee.setFirstName(employeeDetails.getFirstName());
		employee.setLastName(employeeDetails.getLastName());
		employee.setEmailId(employeeDetails.getEmailId());
		
		Employee updatedEmployee = employeeRepository.save(employee);
		return ResponseEntity.ok(updatedEmployee);
	}
	
	// delete employee rest api
	@DeleteMapping("/employees/{id}")
	public ResponseEntity<Map<String, Boolean>> deleteEmployee(@PathVariable Long id){
		Employee employee = employeeRepository.findById(id)
				.orElseThrow(() -> new ResourceNotFoundException("Employee not exist with id :" + id));
		
		employeeRepository.delete(employee);
		Map<String, Boolean> response = new HashMap<>();
		response.put("deleted", Boolean.TRUE);
		return ResponseEntity.ok(response);
	}
}

Optional Step for Client Applications (React/Angular): Enable CORS on the Server

To enable CORS on the server, add a @CrossOrigin annotation to the EmployeeController:
@CrossOrigin(origins = "http://localhost:4200")
@RestController
@RequestMapping("/api/v1/")
public class EmployeeController {
// ..
}

Step 8: Running Spring Boot Application

This spring boot application has an entry point Java class called SpringbootBackendApplication 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 SpringbootBackendApplication {

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

}
Or you can start the spring boot application via the command line using mvn spring-boot:run command.

Once Spring boot application is up and running, then you can check the PostgreSQL database:

Step 9: Testing CRUD REST APIs via Postman Client

1. Create Employee REST API

HTTP Method: POST 
Note that request and response JSON in the above diagram, the response contains a database auto-generated id.

2. Get Employee by ID REST API

HTTP Method: GET 

3. Get all Employees REST API

HTTP Method: GET 

4. Update Employee REST API

HTTP Method: PUT 

5. Delete Employee REST API

HTTP Method: DELETE 

Conclusion

In conclusion, this tutorial has illustrated how to create a fully functional CRUD RESTful API for a simple Employee Management System using Spring Boot, PostgreSQL, and JPA/Hibernate. By utilizing Spring Boot and Spring Data JPA, we were able to develop a scalable and maintainable API with minimal boilerplate code. 

We started creating the Employee entity and then implementing the REST endpoints for CRUD operations. We also learned about JPA/Hibernate annotations such as @Entity, @Table, @Id, @Column, and @GeneratedValue, and how they map entities to database tables and columns. Finally, we tested our API using Postman and verified that it works as expected. This tutorial provides a solid foundation for building more complex applications with Spring Boot and PostgreSQL.

Comments

Post a Comment

Leave Comment