Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Building a RESTful CRUD API with Spring Boot and Redis

Tech May 10 4

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.

  1. Create Resource: Send a POST request to http://localhost:8080/v1/customers with a JSON body:

    {
      "customerId": 101,
      "fullName": "John Doe",
      "loyaltyPoints": 500
    }
    
  2. Retrieve Resource: Send a GET request to http://localhost:8080/v1/customers/101. The server will return the JSON object stored in Redis.

  3. Verify in Redis: Use the Redis CLI command get 101 to view the serialized JSON data stored in the memory store.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.