Spring Boot + Spring Data JPA + Microsoft SQL Server - Build REST CRUD APIs

In this section, we will learn how to develop a REST-style web service with Spring BootSpring Data JPA, and Microsoft SQL Server. GitHub repository link is provided at the end of this tutorial. You can download the source code. 

*Before development, make sure that the Microsoft SQL server is installed on your machine - SQL Server Downloads | Microsoft

Technologies used:

  • Spring Boot 3.0.2
  • Spring Data JPA 3.0.2
  • Java 17
  • Maven 
  • Microsoft SQL Server Driver
  • Microsoft SQL Server

These are APIs that Spring Boot backend App will export:



1. Create database.

First, you need to create a database in the Microsoft SQL Server. 
CREATE DATABASE testdb;

2. Creating a simple spring boot web application:

First, open the Spring initializr https://start.spring.io/ 

Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact spring-boot-spring-data-jpa-sqlserver-crud. Here I selected the Maven project - language Java 17 - Spring Boot 3.0.2 and add Spring web dependencySpring Data JPA, and MS SQL Server Driver.

Then, click on the Generate button. When we click on the Generate button, it starts packing the project in a .zip(spring-boot-spring-data-jpa-sqlserver-crud) file and downloads the project. Then, Extract the Zip file. 
Then, import the project on your favourite IDE.

Final Project directory:


pom.xml

<?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.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>spring-boot-spring-data-jpa-sqlserver-crud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-spring-data-jpa-sqlserver-crud</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>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</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

spring.datasource.url= jdbc:sqlserver://localhost:1433;databaseName=testdb;
spring.datasource.username= knfuser
spring.datasource.password= root

spring.jpa.hibernate.ddl-auto= update
  • Specify Data Source Properties like url, username, and password.
  • spring.jpa.hibernate.ddl-auto is used for database initialization. We set the value to update value so that a table will be created in the database automatically corresponding to defined data model.

Create User Entity - User.java

package com.knf.dev.demo.entity;

import jakarta.persistence.*;

@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_id")
private String emailId;

public User() {
}

public User(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;
}
}
  • The @Entity annotation specifies that the class is an entity and is mapped to a database table. 
  • The @Table annotation allows you to specify the details of the table that will be used to persist the entity in the database.
  • 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.

Create User Repository - UserRepository.java

package com.knf.dev.demo.repository;

import com.knf.dev.demo.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {

}
JpaRepository is JPA specific extension of Repository. It contains the full API of CrudRepository and PagingAndSortingRepository. So, it contains API for basic CRUD operations and also API for pagination and sorting.

-Exception Handling

Create custom Exception -ResourceNotFoundException.java

package com.knf.dev.demo.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);
}
}

Create Custom Error Response

package com.knf.dev.demo.exception;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;

public class CustomErrorResponse {

@JsonFormat(shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd hh:mm:ss")
private LocalDateTime timestamp;
private int status;
private String error;
public LocalDateTime getTimestamp() {
return timestamp;
}
public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}

Create Global Exception Handler

package com.knf.dev.demo.exception;

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;
import java.time.LocalDateTime;

@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<CustomErrorResponse> globalExceptionHandler
(Exception ex, WebRequest request) {
CustomErrorResponse errors = new CustomErrorResponse();
errors.setTimestamp(LocalDateTime.now());
errors.setError(ex.getMessage());
errors.setStatus(HttpStatus.NOT_FOUND.value());
return new ResponseEntity<>(errors, HttpStatus.NOT_FOUND);
}
}
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.

Create User Controller

package com.knf.dev.demo.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.knf.dev.demo.entity.User;
import com.knf.dev.demo.exception.ResourceNotFoundException;
import com.knf.dev.demo.repository.UserRepository;
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;


@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/api/v1")
public class UserController {
@Autowired
private UserRepository userRepository;

// get all user
@GetMapping("/users")
public List<User> getAllUsers() {

return userRepository.findAll();
}

// create user rest API
@PostMapping("/users")
public User createUser(@RequestBody User user) {

return userRepository.save(user);
}

// get user by id rest api
@GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {

User user = userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException
("User not exist with id :" + id));

return ResponseEntity.ok(user);
}

// update user rest api
@PutMapping("/users/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id,
@RequestBody User userDetails) {

User user = userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException
("User not exist with id :" + id));
user.setFirstName(userDetails.getFirstName());
user.setLastName(userDetails.getLastName());
user.setEmailId(userDetails.getEmailId());
User updatedUser = userRepository.save(user);

return ResponseEntity.ok(updatedUser);
}

// delete user rest api
@DeleteMapping("/users/{id}")
public ResponseEntity<Map<String, Boolean>> deleteUser
(@PathVariable Long id) {

User user = userRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException
("User not exist with id :" + id));

userRepository.delete(user);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);

return ResponseEntity.ok(response);
}
}
  • Enable CORS at the controller level using the @CrossOrigin annotation.
  • Spring @RestController annotation is used to create RESTful web services using Spring MVC. Spring RestController takes care of mapping request data to the defined request handler method. Once response body is generated from the handler method, it converts it to JSON response.
  • @RequestMapping is used to map web requests onto specific handler classes and/or handler methods. @RequestMapping can be applied to the controller class as well as methods.
  • We can use the @Autowired to mark a dependency which Spring is going to resolve and inject.
  • @GetMapping annotation for mapping HTTP GET requests onto specific handler methods.
  • @PostMapping annotation for mapping HTTP POST requests onto specific handler methods.
  • @PutMapping annotation for mapping HTTP PUT requests onto specific handler methods.
  • @DeleteMapping annotation for mapping HTTP DELETE requests onto specific handler methods.
  • @RequestBody annotation is used to indicating a method parameter should be bind to the body of the HTTP request. Internally, this annotation uses HTTP Message converters to convert the body of HTTP requests to domain objects.
  • @PathVariable annotation used on a method argument to bind it to the value of a URI template variable.

Run the application - Application.java

package com.knf.dev.demo;

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

@SpringBootApplication
public class Application {

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

}
Application is the entry point that sets up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning.

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


Step 2: mvn clean install


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


OR 


Run this Spring boot application from 

  • IntelliJ IDEA IDE by right click - Run 'Application.main()' 
  • Eclipse/STS - You can right click the project or the Application.java file and run as java application or Spring boot application.


Add User-

Update User-

Fetch all User-

Get User by Id-

Delete User-

Popular posts from this blog

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

Java Stream API - How to convert List of objects to another List of objects using Java streams?

Registration and Login with Spring Boot + Spring Security + Thymeleaf

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

ReactJS, Spring Boot JWT Authentication Example

Top 5 Java ORM tools - 2024

Java - Blowfish Encryption and decryption Example

Spring boot video streaming example-HTML5

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