In this tutorial, you will learn Spring boot basics and how to build step by step REST APIs using Spring boot.
Before understanding what is Spring boot, let's first take a look into what is Spring framework?
1. Spring Framework
- Spring’s dependency injection approach encourages writing testable code
- Easy to use but powerful database transaction management capabilities
- Spring simplifies integration with other Java frameworks like JPA/Hibernate ORM, Struts/JSF/etc. web frameworks
- State of the art Web MVC framework for building web applications
If Spring can automatically do it for me that would be awesome!!!.
Well, Spring Boot does what exactly you are looking for. It will do things automatically for you but allows you to override the defaults if you want to.
The Spring team created Spring Boot to address the complexity of the configuration.
2. What is Spring Boot?
Spring Boot is an opinionated framework that helps developers build Spring-based applications quickly and easily. The main goal of Spring Boot is to quickly create Spring-based applications without requiring developers to write the same boilerplate configuration again and again.
3. Key Spring Boot features
- Spring Boot starters
- Spring Boot autoconfiguration
- Elegant configuration management
- Spring Boot actuator
- Easy-to-use embedded servlet container support
3.1. Spring Boot Starters
3.2. Spring Boot Autoconfiguration
- Availability of a particular class in a classpath
- Presence or absence of a Spring bean
- Presence of a system property
- An absence of a configuration file
3.3. Elegant Configuration Management
3.4. Spring Boot Actuator
- Can view the application bean configuration details
- Can view the application URL mappings, environment details, and configuration parameter values
- Can view the registered health check metrics
3.5. Easy-to-Use Embedded Servlet Container Support
4. Different Ways to Create Spring Boot Project
5. Develop Spring Boot Application step by step and build few REST APIs
1. Creating spring boot application using spring initializr
Use the below details in the Spring boot creation:
Project Name: springboot-first-app
Project Type: Maven
Choose dependencies: Spring Web
Package name: com.springboot.app
2. Maven Dependencies
<?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>com.springboot.app</groupId>
<artifactId>springboot-first-app</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-first-app</name>
<description>Spring Boot First Application</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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. Spring Boot Hello World REST API
package com.springboot.first.app;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloWorldController {
// GET HTTP Method
// http://localhost:8080/hello-world
@GetMapping("/hello-world")
public String helloWorld() {
return "Hello World!";
}
}
- The above code uses Spring 4’s new @RestController annotation, which marks the class as a controller where every method returns a domain object instead of a view. It’s shorthand for @Controller and @ResponseBody rolled together.
- @GetMapping annotation for mapping HTTP GET requests onto specific handler methods. Specifically, @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET).
Run Spring Boot Application:
The below class SpringbootFirstAppApplication is the entry point that sets up the Spring Boot application. The @SpringBootApplication annotation enables auto-configuration and component scanning.
package com.springboot.first.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootFirstAppApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFirstAppApplication.class, args);
}
}
package com.springboot.first.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootFirstAppApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFirstAppApplication.class, args);
}
}
Run spring boot application from the IDE:
From your IDE, run the SpringbootFirstAppApplication.main() method as a standalone Java class that will start the embedded Tomcat server on port 8080 and point the browser to http://localhost:8080/.
Run spring boot application using the command line:
Just go to the root directory of the application and type the following command to run it -
$ mvn spring-boot:run
The application will start at Spring Boot’s default tomcat port 8080.
Just hit this link in a browser: http://localhost:8080/hello-world. You will able to see the response of this REST API in the browser.
4. Build Spring Boot REST API returns Java Bean
Let's first create a Student java bean class that the REST API want to return to the client:package com.springboot.first.app;
public class Student {
private String firstName;
private String lastName;
public Student(String firstName, String lastName) {
super();
this.firstName = firstName;
this.lastName = lastName;
}
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;
}
}
Let's create the StudentController class and the below code to it:import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
// http://localhost:8080/student
@GetMapping("/student")
public Student getStudent() {
return new Student("Ramesh", "Fadatare");
}
}
- The above code uses Spring 4’s new @RestController annotation, which marks the class as a controller where every method returns a domain object instead of a view. It’s shorthand for @Controller and @ResponseBody rolled together.
- @GetMapping annotation for mapping HTTP GET requests onto specific handler methods. Specifically, @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET).
- The Student object must be converted to JSON. Thanks to Spring’s HTTP message converter support, you don’t need to do this conversion manually. Because Jackson 2 is on the classpath, Spring’s MappingJackson2HttpMessageConverter is automatically chosen to convert the Student instance to JSON.
package com.springboot.first.app;
public class Student {
private String firstName;
private String lastName;
public Student(String firstName, String lastName) {
super();
this.firstName = firstName;
this.lastName = lastName;
}
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;
}
}
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
// http://localhost:8080/student
@GetMapping("/student")
public Student getStudent() {
return new Student("Ramesh", "Fadatare");
}
}
Run spring boot application from the IDE:
package com.springboot.first.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootFirstAppApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFirstAppApplication.class, args);
}
}
package com.springboot.first.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringbootFirstAppApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootFirstAppApplication.class, args);
}
}
From your IDE, run the SpringbootFirstAppApplication.main() method as a standalone Java class that will start the embedded Tomcat server on port 8080 and point the browser to http://localhost:8080/.
Just hit this link in a browser: http://localhost:8080/student. You will able to see the response of this REST API in the browser.
5. Build Spring Boot REST API returns List
In this section, we will build a simple Spring boot REST API which returns List object as JSON to the client.
import java.util.ArrayList;
import java.util.List;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
@GetMapping("/students")
public List<Student> getStudents(){
List<Student> students = new ArrayList<>();
students.add(new Student("Ramesh", "Fadatare"));
students.add(new Student("Tony", "Cena"));
students.add(new Student("Sanjay", "Jadhav"));
students.add(new Student("Ram", "Jadhav"));
students.add(new Student("Umesh", "Fadatare"));
return students;
}
}
- The above code uses Spring 4’s new @RestController annotation, which marks the class as a controller where every method returns a domain object instead of a view. It’s shorthand for @Controller and @ResponseBody rolled together.
- @GetMapping annotation for mapping HTTP GET requests onto specific handler methods. Specifically, @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET).
- The List of student objects must be converted to JSON. Thanks to Spring’s HTTP message converter support, you don’t need to do this conversion manually. Because Jackson 2 is on the classpath, Spring’s MappingJackson2HttpMessageConverter is automatically chosen to convert the List of student objects to JSON.
Run spring boot application from the IDE:
From your IDE, run the SpringbootFirstAppApplication.main() method as a standalone Java class that will start the embedded Tomcat server on port 8080 and point the browser to http://localhost:8080/.
Just hit this link in a browser: http://localhost:8080/students. You will able to see the response of this REST API in the browser.
6. Spring Boot REST API with Path Variable
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
// http://localhost:8080/student/1
// @PathVariable annotation
@GetMapping("/student/{firstName}/{lastName}/")
public Student studentPathVariable(@PathVariable("firstName") String firstName,
@PathVariable("lastName") String lastName) {
return new Student(firstName, lastName);
}
}
- The above code uses Spring 4’s new @RestController annotation, which marks the class as a controller where every method returns a domain object instead of a view. It’s shorthand for @Controller and @ResponseBody rolled together.
- @GetMapping annotation for mapping HTTP GET requests onto specific handler methods. Specifically, @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET).
- The Student object must be converted to JSON. Thanks to Spring’s HTTP message converter support, you don’t need to do this conversion manually. Because Jackson 2 is on the classpath, Spring’s MappingJackson2HttpMessageConverter is automatically chosen to convert the Student object to JSON.
- With the @PathVariable annotation, we bind the request URL template path variable to the method variable. For instance, with the /Ramesh/Fadatare/ URL, the "Ramesh" value is bound to the firstName variable and the "Fadatare" value to the lastName variable.
Run spring boot application from the IDE:
From your IDE, run the SpringbootFirstAppApplication.main() method as a standalone Java class that will start the embedded Tomcat server on port 8080 and point the browser to http://localhost:8080/.
Just hit this link in a browser: http://localhost:8080/student/Ramesh/Fadatare. You will be able to see the response of this REST API in the browser.
7. Build Spring Boot REST API with Request Param
In this section, we will build a simple Spring boot REST API that handles request or query parameters in the GET HTTP request.
In this example, we use the @RequestParam annotation to extract query parameters from the HTTP GET request.
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
// build rest API to handle query parameters
// http://localhost:8080/student/query?firstName=Ramesh&lastName=Fadatare
@GetMapping("/student/query")
public Student studentQueryParam(
@RequestParam(name = "firstName") String firstName,
@RequestParam(name = "lastName") String lastName) {
return new Student(firstName, lastName);
}
}
- The above code uses Spring 4’s new @RestController annotation, which marks the class as a controller where every method returns a domain object instead of a view. It’s shorthand for @Controller and @ResponseBody rolled together.
- @GetMapping annotation for mapping HTTP GET requests onto specific handler methods. Specifically, @GetMapping is a composed annotation that acts as a shortcut for @RequestMapping(method = RequestMethod.GET).
- The Student object must be converted to JSON. Thanks to Spring’s HTTP message converter support, you don’t need to do this conversion manually. Because Jackson 2 is on the classpath, Spring’s MappingJackson2HttpMessageConverter is automatically chosen to convert the Student object to JSON.
- With the @RequestParam annotation, we extract query parameters from the HTTP GET request.
6. Develop Spring Boot CRUD REST APIs with Hibernate and MySQL Database
Tools and technologies used:
- Java 17
- Spring Boot 3
- Spring Data JPA ( Hibernate)
- Lombok
- MySQL
- Eclipse STS
- Maven
- Tomcat
- Postman
1. Create Spring Boot Project
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, MySQL Driver, Lombok
Package name: net.javaguides.springboot
2. Maven Dependencies
<?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>Spring Boot RESTful Web Services</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.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. Spring Boot Project Architecture
We are going to use three-layer architecture in our Spring boot project:
4. Configure MySQL Database
Spring Boot tries to auto-configure a DataSource if spring-data-jpa dependency is in the classpath by reading the database configuration from the application.properties file.
So, we just have to add the configuration, and Spring Boot will take care of the rest.
Open the application.properties file and add the following properties to it.
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username = root
spring.datasource.password = root
## Hibernate Properties
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
You will need to create a database named demo in MySQL, and change the spring.datasource.username & spring.datasource.password properties as per your MySQL installation.
In the above properties file, the last two properties are for Hibernate. Spring Boot uses Hibernate as the default JPA implementation.
The property spring.jpa.hibernate.ddl-auto is used for database initialization. I’ve used the value “update” for this property.
5. Create JPA Entity - Employee
Let's create a new package called model inside net.javaguides.springboot and add a class named Employee.java with the following contents:
import jakarta.persistence.*;
import lombok.Data;
@Data
@Entity
@Table(name="employees")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "first_name", nullable = false)
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
}
6. Create Repository or DAO Layer - EmployeeRepository
The next thing we’re gonna do is create a repository to access an Employee’s data from the database.
The JpaRepository interface defines methods for all the CRUD operations on the entity, and a default implementation of the JpaRepository called SimpleJpaRepository.
Let’s create the repository now. First, create a new package called repository inside the base package net.javaguides.springboot. Then, create an interface called EmployeeRepository and extend it from JpaRepository -
import org.springframework.data.jpa.repository.JpaRepository;
import net.javaguides.springboot.model.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Long>{
}
7. Create Service Layer
7.1 Service Interface
Let's create a package called service inside base package net.javaguides.springboot. Create an EmployeeService interface with the following contents:
import java.util.List;
import net.javaguides.springboot.model.Employee;
public interface EmployeeService {
Employee saveEmployee(Employee employee);
List<Employee> getAllEmployees();
Employee getEmployeeById(long id);
Employee updateEmployee(Employee employee, long id);
void deleteEmployee(long id);
}
7.2 Service Interface Implementation
Let's create a package called impl inside package net.javaguides.springboot.service. Create an EmployeeServiceImpl class with the following contents:
import java.util.List;
import java.util.Optional;
import org.springframework.stereotype.Service;
import net.javaguides.springboot.exception.ResourceNotFoundException;
import net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.repository.EmployeeRepository;
import net.javaguides.springboot.service.EmployeeService;
@Service
public class EmployeeServiceImpl implements EmployeeService{
private EmployeeRepository employeeRepository;
public EmployeeServiceImpl(EmployeeRepository employeeRepository) {
super();
this.employeeRepository = employeeRepository;
}
@Override
public Employee saveEmployee(Employee employee) {
return employeeRepository.save(employee);
}
@Override
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
@Override
public Employee getEmployeeById(long id) {
// Optional<Employee> employee = employeeRepository.findById(id);
// if(employee.isPresent()) {
// return employee.get();
// }else {
// throw new ResourceNotFoundException("Employee", "Id", id);
// }
return employeeRepository.findById(id).orElseThrow(() ->
new ResourceNotFoundException("Employee", "Id", id));
}
@Override
public Employee updateEmployee(Employee employee, long id) {
// we need to check whether employee with given id is exist in DB or not
Employee existingEmployee = employeeRepository.findById(id).orElseThrow(
() -> new ResourceNotFoundException("Employee", "Id", id));
existingEmployee.setFirstName(employee.getFirstName());
existingEmployee.setLastName(employee.getLastName());
existingEmployee.setEmail(employee.getEmail());
// save existing employee to DB
employeeRepository.save(existingEmployee);
return existingEmployee;
}
@Override
public void deleteEmployee(long id) {
// check whether a employee exist in a DB or not
employeeRepository.findById(id).orElseThrow(() ->
new ResourceNotFoundException("Employee", "Id", id));
employeeRepository.deleteById(id);
}
}
8. Create Custom Exception
Let's create an exception package inside base package net.javaguides.springboot. Then create a ResourceNotFoundException custom exception and add the following contents to it:
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;
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;
}
}
9. Create Controller Layer
We’ll now create the REST APIs for creating, retrieving, updating, and deleting an Employee.
First, create a new package controller inside the base package net.javaguides.springboot. Then, create a new class EmployeeController.java with the following contents -
import java.util.List;
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 net.javaguides.springboot.model.Employee;
import net.javaguides.springboot.service.EmployeeService;
@RestController
@RequestMapping("/api/employees")
public class EmployeeController {
private EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
super();
this.employeeService = employeeService;
}
// build create employee REST API
@PostMapping()
public ResponseEntity<Employee> saveEmployee(@RequestBody Employee employee){
return new ResponseEntity<Employee>(employeeService.saveEmployee(employee), HttpStatus.CREATED);
}
// build get all employees REST API
@GetMapping
public List<Employee> getAllEmployees(){
return employeeService.getAllEmployees();
}
// build get employee by id REST API
// http://localhost:8080/api/employees/1
@GetMapping("{id}")
public ResponseEntity<Employee> getEmployeeById(@PathVariable("id") long employeeId){
return new ResponseEntity<Employee>(employeeService.getEmployeeById(employeeId), HttpStatus.OK);
}
// build update employee REST API
// http://localhost:8080/api/employees/1
@PutMapping("{id}")
public ResponseEntity<Employee> updateEmployee(@PathVariable("id") long id
,@RequestBody Employee employee){
return new ResponseEntity<Employee>(employeeService.updateEmployee(employee, id), HttpStatus.OK);
}
// build delete employee REST API
// http://localhost:8080/api/employees/1
@DeleteMapping("{id}")
public ResponseEntity<String> deleteEmployee(@PathVariable("id") long id){
// delete employee from DB
employeeService.deleteEmployee(id);
return new ResponseEntity<String>("Employee deleted successfully!.", HttpStatus.OK);
}
}
10. Run Spring Boot Application
We’ve successfully built all the APIs for our application. Let’s now run the app and test the APIs.
Just go to the root directory of the application and type the following command to run it -
$ mvn spring-boot:run
The application will start at Spring Boot’s default tomcat port 8080.
This is a wonderful tutorial - thank you so much!
ReplyDelete