Build REST CRUD APIs with Spring Boot and PostgreSQL

Hello everyone, In this article, we will learn how to develop a  REST-style web service with Spring Boot, Spring Data JPA, and PostgreSQL.The GitHub repository link is provided at the end of this tutorial. You could download the source code.



Technologies used: 

  • Spring Boot 2.6.3
  • Spring  Data JPA 2.6.3
  • Java 11
  • PostgresSQL connector 
  • PostgresSQL Server
  • Maven 3+ 

These are APIs that Spring backend App will export: 



Final Project Directory



Maven[pom.xml] 

A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details utilized by Maven to build the project.
<?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.6.3</version>
<relativePath/>
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-boot-postgresql-crud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-postgresql-crud</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</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.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>


application.properties

We need to override the H2 database properties being set by default in Spring Boot. The following properties are needed to configure PostgreSQL with Spring Boot. We can see these are pretty standard Java data source properties. Since in my example project, I’m using JPA too, we need to configure Hibernate for PostgreSQL too.

**create-drop option tells Hibernate to recreate the database on startup
spring.datasource.url= jdbc:postgresql://localhost:5432/postgres
spring.datasource.username= postgres
spring.datasource.password= password
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation= true
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.PostgreSQLDialect

spring.jpa.hibernate.ddl-auto=create-drop
server.port=8081



Creating the Entity User

The @Entity annotation specifies that the class is an entity and is mapped to a database table. 
The @Id annotation specifies the primary key of an entity and the @GeneratedValue provides for the specification of generation strategies for the values of primary keys. 
The @Column annotation is used to specify the mapped column for a persistent property or field. If no Column annotation is specified, the default value will be applied.
package com.knf.dev.demo.springbootpostgresqlcrud.entity;

import javax.persistence.Column;
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 {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email", nullable = false, length = 200)
private String email;

public User() {
super();
}

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

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

public User(String firstName, String lastName,
String email) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
}


Creating the User Repository

CrudRepository is a Spring Data interface for generic CRUD operations on a repository of a specific type. It provides several methods out of the box for interacting with a database.
package com.knf.dev.demo.springbootpostgresqlcrud.repository;

import org.springframework.data.repository.CrudRepository;
import com.knf.dev.demo.springbootpostgresqlcrud.entity.User;

public interface UserRepository
extends CrudRepository<User, Long> {

}


Exception Handler with Controller Advice in Spring

Spring supports exception handling by a global Exception Handler (@ExceptionHandler) with Controller Advice (@ControllerAdvice). This enables a mechanism that makes ResponseEntity work with the type safety and flexibility of @ExceptionHandler:
package com.knf.dev.demo.springbootpostgresqlcrud.exception;

import java.util.Date;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(InternalServerError.class)
public ResponseEntity<ErrorMessage>
internalServerError(Exception ex, WebRequest request) {
ErrorMessage errors =
new ErrorMessage(500, new Date(),
ex.getMessage(), "Internal Server Error");

return new ResponseEntity<>
(errors, HttpStatus.INTERNAL_SERVER_ERROR);
}

@ExceptionHandler(UserNotFound.class)
public ResponseEntity<ErrorMessage>
userNotFound(Exception ex, WebRequest request) {
ErrorMessage errors =
new ErrorMessage(404, new Date(),
ex.getMessage(), "User Not Found");

return new ResponseEntity<>
(errors, HttpStatus.NOT_FOUND);
}
}


Custom Exception - Internal Server Error

package com.knf.dev.demo.springbootpostgresqlcrud.exception;

public class InternalServerError extends RuntimeException {

private static final long serialVersionUID = 1L;

public InternalServerError(String msg) {
super(msg);
}
}


Custom Exception - UserNotFound

package com.knf.dev.demo.springbootpostgresqlcrud.exception;

public class UserNotFound extends RuntimeException {
private static final long serialVersionUID = 1L;

public UserNotFound(String msg) {
super(msg);
}
}


Error Message

package com.knf.dev.demo.springbootpostgresqlcrud.exception;

import java.util.Date;

public class ErrorMessage {

private Integer statusCode;
private Date timestamp;
private String message;
private String description;

public Integer getStatusCode() {
return statusCode;
}

public void setStatusCode(Integer statusCode) {
this.statusCode = statusCode;
}

public Date getTimestamp() {
return timestamp;
}

public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public ErrorMessage(Integer statusCode,
Date timestamp, String message,
String description) {
super();
this.statusCode = statusCode;
this.timestamp = timestamp;
this.message = message;
this.description = description;
}
}


User Rest Controller

The @RestController annotation was introduced in Spring 4.0 to simplify the engendering of RESTful web services. It's a convenience annotation that combines @Controller and @ResponseBody. @RequestMapping annotation maps HTTP requests to handler methods of MVC and REST controllers.
package com.knf.dev.demo.springbootpostgresqlcrud.controller;

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

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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.knf.dev.demo.
springbootpostgresqlcrud.entity.User;
import com.knf.dev.demo.
springbootpostgresqlcrud.exception.InternalServerError;
import com.knf.dev.demo.
springbootpostgresqlcrud.exception.UserNotFound;
import com.knf.dev.demo.
springbootpostgresqlcrud.repository.UserRepository;

@RestController
@RequestMapping("/api/v1/users")
public class UserController {

@Autowired
UserRepository userRepository;

// Create user
@PostMapping
public ResponseEntity<User>
createUser(@RequestBody User user) {
try {
User newuser = new User(user.getFirstName(),
user.getLastName(), user.getEmail());
userRepository.save(newuser);
return new ResponseEntity<>
(newuser, HttpStatus.CREATED);
} catch (Exception e) {
throw new InternalServerError(e.getMessage());
}
}

// Update user
@PutMapping("/{id}")
public ResponseEntity<User>
updateUser(@PathVariable("id") Long id,
@RequestBody User user) {

Optional<User> userdata = userRepository.findById(id);
if (userdata.isPresent()) {
User _user = userdata.get();
_user.setEmail(user.getEmail());
_user.setFirstName(user.getFirstName());
_user.setLastName(user.getLastName());
return new ResponseEntity<>
(userRepository.save(_user), HttpStatus.OK);
} else {
throw new UserNotFound("Invalid User Id");
}
}

// Get all Users
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {

try {
List<User> users = new ArrayList<User>();
userRepository.findAll().forEach(users::add);
return new ResponseEntity<>(users, HttpStatus.OK);
} catch (Exception e) {
throw new InternalServerError(e.getMessage());
}

}

// Get user by ID
@GetMapping("/{id}")
public ResponseEntity<User>
getUserByID(@PathVariable("id") Long id) {

Optional<User> userdata = userRepository.findById(id);
if (userdata.isPresent()) {
return new ResponseEntity<>
(userdata.get(), HttpStatus.OK);
} else {
throw new UserNotFound("Invalid User Id");
}

}

// Delete user
@DeleteMapping("/{id}")
public ResponseEntity<User>
deleteUser(@PathVariable("id") Long id) {

Optional<User> userdata = userRepository.findById(id);
if (userdata.isPresent()) {
userRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
throw new UserNotFound("Invalid User Id");
}
}
}


Spring Boot main driver

package com.knf.dev.demo.springbootpostgresqlcrud;

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

@SpringBootApplication
public class SpringBootPostgresqlCrudApplication {

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

}


Download the complete source code - click here                              

Local Setup and Run the application

Step1: Download or clone the source code from GitHub to the local machine - Click here

Step 2: mvn clean install

Step 3: Run the Spring Boot application - mvn spring-boot:run


Testing APIs using Postman

Create user:


Update user:


Get all users:


Get user by id:


Delete a user by id:

Comments

Popular posts from this blog

Learn Java 8 streams with an example - print odd/even numbers from Array and List

Java, Spring Boot Mini Project - Library Management System - Download

Java - Blowfish Encryption and decryption Example

Java - DES Encryption and Decryption example

Google Cloud Storage + Spring Boot - File Upload, Download, and Delete

ReactJS - Bootstrap - Buttons

Spring Boot 3 + Spring Security 6 + Thymeleaf - Registration and Login Example

File Upload, Download, And Delete - Azure Blob Storage + Spring Boot Example

Top 5 Java ORM tools - 2024

Java - How to Count the Number of Occurrences of Substring in a String