
Building a Spring Boot Application with Redis Caching for Customer CRUD Operations
In this tutorial, we will build a simple Customer CRUD application using Spring Boot. We’ll also implement Redis caching to improve performance by reducing database queries. The project will connect to a PostgreSQL database, and we’ll also configure Elasticsearch and Kafka for future scalability.
Prerequisites:
- Java 11 or above
- PostgreSQL installed
- Redis installed
Project Setup:
Step 1: Initialize a Spring Boot Project
You can create a Spring Boot project using Spring Initializr or your preferred method. Here’s what you need:
- Group:
com.example
- Artifact:
customer-redis-app
- Dependencies:
- Spring Web
- Spring Data JPA
- Spring Data Redis
- PostgreSQL Driver
- Lombok
Once you generate the project, it will provide you with a base structure. We will modify this to include our custom logic.
Step 2: Add Dependencies to pom.xml
Open the pom.xml
file and ensure the following dependencies are added:
<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.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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</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>
Step 3: Configure Application Properties
In the src/main/resources/application.properties
file, configure the necessary settings:
# Redis Configuration
spring.redis.host=localhost
spring.redis.port=6379
# PostgreSQL
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/spring-redis
spring.datasource.username=your_username
spring.datasource.password=your_password
# Konfigurasi JPA (Hibernate)
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
#spring.jpa.properties.hibernate.format_sql=true
#spring.jpa.show-sql=true
Make sure to adjust these configurations according to your local environment.
Step 4: Create the Redis Configuration Class
To use Redis for caching, create a RedisConfig
class.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
}
Step 5: Create the Customer Entity
The Customer
entity represents the data model for the application.
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;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
public class Customer implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
}
Step 6: Create the Customer DTO
We use a DTO (Data Transfer Object) to transfer data between layers in a clean way.
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CustomerDTO {
private Long id;
private String name;
private String email;
}
Step 7: Create the Customer Repository
The repository interface will handle database operations.
import org.springframework.data.jpa.repository.JpaRepository;
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
Step 8: Implement the Customer Service with Redis Caching
We will now create the service layer with Redis caching applied to the methods.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class CustomerService {
@Autowired
private CustomerRepository customerRepository;
@Cacheable(value = "customers", key = "#id")
public Optional<Customer> getCustomerById(Long id) {
return customerRepository.findById(id);
}
@Cacheable(value = "customers")
public List<Customer> getAllCustomers() {
return customerRepository.findAll();
}
@CachePut(value = "customers", key = "#customer.id")
public Customer createCustomer(Customer customer) {
return customerRepository.save(customer);
}
@CachePut(value = "customers", key = "#customer.id")
public Customer updateCustomer(Customer customer) {
return customerRepository.save(customer);
}
@CacheEvict(value = "customers", key = "#id")
public void deleteCustomer(Long id) {
customerRepository.deleteById(id);
}
}
Step 9: Create the Customer Controller
The controller will handle HTTP requests for the CRUD operations.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/customers")
public class CustomerController {
@Autowired
private CustomerService customerService;
@GetMapping("/{id}")
public ResponseEntity<CustomerDTO> getCustomerById(@PathVariable Long id) {
return customerService.getCustomerById(id)
.map(customer -> ResponseEntity.ok(convertToDto(customer)))
.orElse(ResponseEntity.notFound().build());
}
@GetMapping
public List<CustomerDTO> getAllCustomers() {
return customerService.getAllCustomers().stream()
.map(this::convertToDto)
.toList();
}
@PostMapping
public ResponseEntity<CustomerDTO> createCustomer(@RequestBody CustomerDTO customerDTO) {
Customer customer = convertToEntity(customerDTO);
return ResponseEntity.ok(convertToDto(customerService.createCustomer(customer)));
}
@PutMapping("/{id}")
public ResponseEntity<CustomerDTO> updateCustomer(@PathVariable Long id, @RequestBody CustomerDTO customerDTO) {
Customer customer = convertToEntity(customerDTO);
customer.setId(id);
return ResponseEntity.ok(convertToDto(customerService.updateCustomer(customer)));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteCustomer(@PathVariable Long id) {
customerService.deleteCustomer(id);
return ResponseEntity.noContent().build();
}
private CustomerDTO convertToDto(Customer customer) {
CustomerDTO dto = new CustomerDTO();
dto.setId(customer.getId());
dto.setName(customer.getName());
dto.setEmail(customer.getEmail());
return dto;
}
private Customer convertToEntity(CustomerDTO dto) {
Customer customer = new Customer();
customer.setName(dto.getName());
customer.setEmail(dto.getEmail());
return customer;
}
}
Step 10: Enable Caching in Spring Boot
Finally, we need to enable caching by adding the @EnableCaching
annotation in the main application class.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class CustomerRedisAppApplication {
public static void main(String[] args) {
SpringApplication.run(CustomerRedisAppApplication.class, args);
}
}
Step 11: Running the Application
To run the application, use the following command:
mvn spring-boot:run
You’ve successfully built a Spring Boot application with Customer CRUD operations and implemented Redis caching. The caching mechanism stores data in Redis, reducing the load on the PostgreSQL database. You can further enhance this project by integrating Kafka and Elasticsearch for messaging and searching capabilities.
The complete source code for this project is available on GitHub.
Happy Coding!