Building a RESTful CRUD API with Spring Boot and Redis
Redis is an open-source, high-performance key-value database known for its versatility and speed. Key characteristics include data persistence by saving in-memory datasets to disk, support for multiple data structures such as strings, lists, sets, and hashes, and high availability via master-slave replication.
Environment Requirements
To implement this integration, the following environment is recommended:
- JDK: 1.8 or higher
- Spring Boot: 1.5.x or 2.x
- Redis: 3.2+ (Stable versions are typically even-numbered)
Project Dependencies
Include the following dependencies in you're pom.xml to enable Web and Redis support:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Application Configuration
Configure the Redis connection and connection pool settings in application.properties. If using a cluster, replace host/port with spring.redis.cluster.nodes.
# Redis basic settings
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
# Connection pool configuration
spring.redis.jedis.pool.max-active=10
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=2
spring.redis.jedis.pool.max-wait=2000ms
Redis Infrastructure Configuraton
While Spring Boot provides auto-configuration, defining a custom RedisTemplate allows for specific serialization strategies, ensuring that complex objeects are stored and retrieved correctly.
@Configuration
public class RedisDataSourceConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// Use String serialization for keys
StringRedisSerializer stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setHashKeySerializer(stringSerializer);
// Use JSON serialization for values
GenericJackson2JsonRedisSerializer jsonSerializer = new GenericJackson2JsonRedisSerializer();
template.setValueSerializer(jsonSerializer);
template.setHashValueSerializer(jsonSerializer);
template.afterPropertiesSet();
return template;
}
}
Data Model
Define a Customer entity that implements Serializable to facilitate data storage.
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
private Long customerId;
private String fullName;
private Integer loyaltyPoints;
public Customer() {}
// Standard getters and setters
public Long getCustomerId() { return customerId; }
public void setCustomerId(Long customerId) { this.customerId = customerId; }
public String getFullName() { return fullName; }
public void setFullName(String fullName) { this.fullName = fullName; }
public Integer getLoyaltyPoints() { return loyaltyPoints; }
public void setLoyaltyPoints(Integer loyaltyPoints) { this.loyaltyPoints = loyaltyPoints; }
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
Data Access Layer
The DAO layer interacts with Redis using the RedisTemplate. We map the unique ID of the customer as the key.
@Repository
public class CustomerRepository {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public void save(Customer customer) {
redisTemplate.opsForValue().set(String.valueOf(customer.getCustomerId()), customer);
}
public Customer findById(Long id) {
return (Customer) redisTemplate.opsForValue().get(String.valueOf(id));
}
public void update(Customer customer) {
save(customer);
}
public void delete(Long id) {
redisTemplate.delete(String.valueOf(id));
}
}
Service Layer
The service layer handles business logic and exception management.
@Service
public class CustomerService {
private static final Logger log = LoggerFactory.getLogger(CustomerService.class);
@Autowired
private CustomerRepository repository;
public boolean createCustomer(Customer customer) {
try {
repository.save(customer);
return true;
} catch (Exception e) {
log.error("Error creating customer: {}", e.getMessage());
return false;
}
}
public Customer getCustomer(Long id) {
return repository.findById(id);
}
public boolean removeCustomer(Long id) {
try {
repository.delete(id);
return true;
} catch (Exception e) {
log.error("Error deleting customer: {}", e.getMessage());
return false;
}
}
}
REST Controller
Expose the CRUD operations via standard RESTful endpoints using HTTP verbs (POST, GET, PUT, DELETE).
@RestController
@RequestMapping("/v1/customers")
public class CustomerController {
@Autowired
private CustomerService customerService;
@PostMapping
public String add(@RequestBody Customer customer) {
return customerService.createCustomer(customer) ? "Success" : "Failure";
}
@GetMapping("/{id}")
public Customer get(@PathVariable Long id) {
return customerService.getCustomer(id);
}
@PutMapping
public String update(@RequestBody Customer customer) {
return customerService.createCustomer(customer) ? "Updated" : "Update Failed";
}
@DeleteMapping("/{id}")
public String remove(@PathVariable Long id) {
return customerService.removeCustomer(id) ? "Deleted" : "Delete Failed";
}
}
API Testing
After starting the application, you can verify functionality using tools like cURL or Postman.
-
Create Resource: Send a
POSTrequest tohttp://localhost:8080/v1/customerswith a JSON body:{ "customerId": 101, "fullName": "John Doe", "loyaltyPoints": 500 } -
Retrieve Resource: Send a
GETrequest tohttp://localhost:8080/v1/customers/101. The server will return the JSON object stored in Redis. -
Verify in Redis: Use the Redis CLI command
get 101to view the serialized JSON data stored in the memory store.