In this tutorial, you will learn how to build two Spring Boot microservices with REST APIs, perform CRUD operations, and communicate between services. We will create employee-service and department-service, where the employee-service
performs CRUD operations on employee data, and department-service
communicates with employee-service
to retrieve employee details using FeignClient.
What You’ll Learn:
- Building CRUD REST APIs with Spring Boot.
- Communicating between two microservices using REST.
- Using Java 21 and Jakarta EE for entity management.
- Following constructor-based dependency injection (best practice).
Introduction to Spring Boot REST APIs
In a microservices architecture, each service exposes its own REST API. Each microservice has its own database and logic, and services communicate via HTTP, ensuring loose coupling and scalability.
Prerequisites
Before starting, ensure that you have the following tools installed:
- JDK 21 or later
- Maven (to build the project)
- MySQL or an in-memory database like H2
- Postman or curl (to test the REST APIs)
- IDE (IntelliJ IDEA, Eclipse, etc.)
Step 1: Create the Projects
We will create two microservices:
- employee-service: Manages CRUD operations for employee data.
- department-service: Communicates with
employee-service
to retrieve employee data.
Step 2: Set Up employee-service
2.1 Create the Project
Go to Spring Initializr and generate a Spring Boot project with the following dependencies:
- Spring Web
- Spring Data JPA
- MySQL Driver (or H2 Database for simplicity)
- Lombok
Make sure to select the latest Java version: Java 21.
2.2 Configure application.properties
In the src/main/resources/application.properties
file, configure the MySQL or H2 database for employee-service
.
For MySQL:
spring.datasource.url=jdbc:mysql://localhost:3306/employees_db
spring.datasource.username=root
spring.datasource.password=yourpassword
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
server.port=8081
Update the above database connection properties as per your MySQL set up.
For H2:
spring.datasource.url=jdbc:h2:mem:employees_db
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
server.port=8081
2.3 Create the Employee Entity
Define the Employee
entity with the following content:
package com.example.employeeservice.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String department;
}
Explanation:
- jakarta.persistence replaces javax.persistence (no deprecated
javax
). - Lombok is used for boilerplate code like getters, setters, constructors, etc.
2.4 Create Employee Repository
Create a JpaRepository
for the Employee
entity.
package com.example.employeeservice.repository;
import com.example.employeeservice.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
2.5 Create Employee Service
Create a service class to handle business logic for CRUD operations using constructor-based dependency injection (best practice).
package com.example.employeeservice.service;
import com.example.employeeservice.entity.Employee;
import com.example.employeeservice.repository.EmployeeRepository;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
public EmployeeService(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
public Employee saveEmployee(Employee employee) {
return employeeRepository.save(employee);
}
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
public Optional<Employee> getEmployeeById(Long id) {
return employeeRepository.findById(id);
}
public void deleteEmployee(Long id) {
employeeRepository.deleteById(id);
}
}
Explanation:
- Constructor-based dependency injection is used for
EmployeeRepository
inEmployeeService
.
2.6 Create REST Controller
Create a REST controller to expose the CRUD REST APIs and Use constructor-based dependency injection to inject EmployeeService.
import com.example.employeeservice.entity.Employee;
import com.example.employeeservice.service.EmployeeService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private final EmployeeService employeeService;
public EmployeeController(EmployeeService employeeService) {
this.employeeService = employeeService;
}
@PostMapping
public Employee addEmployee(@RequestBody Employee employee) {
return employeeService.saveEmployee(employee);
}
@GetMapping
public List<Employee> getAllEmployees() {
return employeeService.getAllEmployees();
}
@GetMapping("/{id}")
public Employee getEmployeeById(@PathVariable Long id) {
return employeeService.getEmployeeById(id).orElse(null);
}
@DeleteMapping("/{id}")
public String deleteEmployee(@PathVariable Long id) {
employeeService.deleteEmployee(id);
return "Employee deleted with id: " + id;
}
}
Explanation:
- REST endpoints for creating, retrieving, and deleting employees are exposed.
2.7 Create a Dockerfile
Create a Dockerfile
for employee-service
:
FROM openjdk:21-jdk-alpine
WORKDIR /app
COPY target/employee-service-0.0.1-SNAPSHOT.jar employee-service.jar
EXPOSE 8081
ENTRYPOINT ["java", "-jar", "employee-service.jar"]
Step 3: Set Up department-service
3.1 Create the Project
Go to Spring Initializr and generate another Spring Boot project with the following dependencies:
- Spring Web
- Spring Boot Actuator
- OpenFeign (for inter-service communication)
3.2 Configure application.properties
Configure the department-service
to communicate with employee-service
.
server.port=8082
spring.application.name=department-service
employee.service.url=http://localhost:8081/employees
Explanation:
- employee.service.url: Defines the URL for communicating with
employee-service
.
3.3 Create Feign Client
Create a Feign client to communicate with employee-service
.
package com.example.departmentservice.client;
import com.example.departmentservice.model.Employee;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import java.util.List;
@FeignClient(name = "employee-service", url = "${employee.service.url}")
public interface EmployeeClient {
@GetMapping
List<Employee> getAllEmployees();
@GetMapping("/{id}")
Employee getEmployeeById(@PathVariable Long id);
}
3.4 Create Employee Model
Create an Employee
model in department-service
to match the structure in employee-service
.
package com.example.departmentservice.model;
public class Employee {
private Long id;
private String name;
private String department;
// Constructors, getters, and setters
}
3.5 Create Department Service
Create the DepartmentService
to handle the logic for retrieving employee data from employee-service
.
package com.example.departmentservice.service;
import com.example.departmentservice.client.EmployeeClient;
import com.example.departmentservice.model.Employee;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class DepartmentService {
private final EmployeeClient employeeClient;
public DepartmentService(EmployeeClient employeeClient) {
this.employeeClient = employeeClient;
}
public List<Employee> getAllEmployees() {
return employeeClient.getAllEmployees();
}
public Employee getEmployeeById(Long id) {
return employeeClient.getEmployeeById(id);
}
}
3.6 Create REST Controller
Create a REST controller in department-service
to fetch employee details from employee-service
.
package com.example.departmentservice.controller;
import com.example.departmentservice.model.Employee;
import com.example.departmentservice.service.DepartmentService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/departments")
public class DepartmentController {
private final DepartmentService departmentService;
public DepartmentController(DepartmentService departmentService) {
this.departmentService = departmentService;
}
@GetMapping("/employees")
public List<Employee> getAllEmployees() {
return departmentService.getAllEmployees();
}
@GetMapping("/employees/{id}")
public Employee getEmployeeById(@PathVariable Long id) {
return departmentService.getEmployeeById(id);
}
}
3.7 Create a Dockerfile
Create a Dockerfile
for department-service
:
FROM openjdk:21-jdk-alpine
WORKDIR /app
COPY target/department-service-0.0.1-SNAPSHOT.jar department-service.jar
EXPOSE 8082
ENTRYPOINT ["java", "-jar", "department-service.jar"]
Step 4: Build Docker Images
Navigate to the root directories of each service and run the following commands to build Docker images:
For employee-service
:
mvn clean package
docker build -t employee-service .
For department-service
:
mvn clean package
docker build -t department-service .
Step 5: Set Up Docker Compose
Create a docker-compose.yml
file to run both microservices:
version: '3.8'
services:
employee-service:
image: employee-service
build:
context: ./employee-service
ports:
- "8081:8081"
networks:
- microservices-net
department-service:
image: department-service
build:
context: ./department-service
ports:
- "8082:8082"
networks:
- microservices-net
networks:
microservices-net:
driver: bridge
Step 6: Run Docker Compose
Navigate to the directory containing the docker-compose.yml
file and run the following command:
docker-compose up --build
This will build and start both microservices.
Step 7: Test the REST Endpoints
You can use Postman or curl to test the endpoints.
- Create an Employee:
curl -X POST http://localhost:8081/employees \
-H "Content-Type: application/json" \
-d '{"name":"John Doe", "department":"Engineering"}'
- Get All Employees (from department-service):
curl http://localhost:8082/departments/employees
- Get Employee by ID (from department-service):
curl http://localhost:8082/departments/employees/1
These endpoints will allow you to test CRUD operations and inter-service communication.
Conclusion
You’ve successfully built two Spring Boot microservices with REST APIs using Java 21 and Jakarta EE. The services use constructor-based dependency injection, and department-service
communicates with employee-service
using FeignClient.
Comments
Post a Comment
Leave Comment