Skip to content

Commit

Permalink
feat: RedisService and Cache IssueService
Browse files Browse the repository at this point in the history
  • Loading branch information
thutasann committed Jan 12, 2025
1 parent c630578 commit d1efd99
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.15.2</version> <!-- Match your Jackson version -->
</dependency>

<dependency>
<groupId>com.razorpay</groupId>
<artifactId>razorpay-java</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.thutasann.project_management_backend.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

@Configuration
public class JacksonConfig {

// Define the date format to use for LocalDate serialization/deserialization
private static final String DATE_FORMAT = "yyyy-MM-dd";
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT);

@Bean
public ObjectMapper objectMapper() {
// Create an ObjectMapper instance
ObjectMapper mapper = new ObjectMapper();

// Register the JavaTimeModule for handling Java 8 date/time types
JavaTimeModule module = new JavaTimeModule();

// Customize LocalDate serialization/deserialization
module.addSerializer(LocalDate.class, new LocalDateSerializer(DATE_FORMATTER));
module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DATE_FORMATTER));

mapper.registerModule(module);

return mapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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
Expand All @@ -18,9 +19,16 @@ public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();

// Connection Factory
template.setConnectionFactory(connectionFactory);

// Key serializer
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());

// Value serializer
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

return template;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.thutasann.project_management_backend.service.project.IProjectService;
import com.thutasann.project_management_backend.service.user.IUserService;
import com.thutasann.project_management_backend.utilities.CustomLogger;
import com.thutasann.project_management_backend.utilities.RedisService;

@Service
public class IssueService implements IIssueService {
Expand All @@ -30,12 +31,28 @@ public class IssueService implements IIssueService {
@Autowired
private CustomLogger logger;

@Autowired
private RedisService redisService;

@Override
public Issue getIssueById(Long issueId) throws Exception {

String key = "issue-cache-by-id:" + issueId;

Issue cachedIssue = redisService.getCachedData(key, Issue.class);

if (cachedIssue != null) {
logger.logInfo("Issue cache hit" + key);
return cachedIssue;
}

Optional<Issue> issue = issueRepo.findById(issueId);
if (issue.isPresent()) {
return issue.get();
Issue issueResult = issue.get();
redisService.cacheData(key, issueResult, 60);
return issueResult;
}

logger.logInfo("Issue not found with Id: " + issueId);
throw new Exception("Issue not found with Id: " + issueId);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.thutasann.project_management_backend.utilities;

import java.time.Duration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

/**
* Redis Service
*/
@Service
public class RedisService {

private static final Logger logger = LoggerFactory.getLogger(RedisService.class);

@Autowired
private RedisTemplate<String, Object> redisTemplate;

private final ObjectMapper objectMapper;

public RedisService(RedisTemplate<String, String> redisTemplate) {
this.objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
}

/**
* Cache data with a specific key and TTL.
*
* @param key The Redis key
* @param data The data to cache
* @param ttl The time-to-live in seconds
*/
public void cacheData(String key, Object data, long ttl) {
try {
String jsonData = objectMapper.writeValueAsString(data);
redisTemplate.opsForValue().set(key, jsonData, Duration.ofSeconds(ttl));
logger.info("Data cached with key: {}", key);
} catch (JsonProcessingException e) {
logger.error("Error serializing data for caching with key: {}", key, e);
}
}

/**
* Retrieve cached data by key.
*
* @param key The Redis key
* @return The cached object or null if not found or deserialization fails
*/
public <T> T getCachedData(String key, Class<T> type) {
try {
String jsonData = (String) redisTemplate.opsForValue().get(key);
if (jsonData != null) {
logger.info("Cache hit for key: {}", key);
return objectMapper.readValue(jsonData, type); // Type-safe deserialization
}
} catch (JsonProcessingException e) {
logger.error("Error deserializing cached data for key: {}", key, e);
}
return null;
}

/**
* Evict a specific cache by key.
*
* @param key The Redis key
*/
public void evictCache(String key) {
redisTemplate.delete(key);
logger.info("Cache evicted for key: {}", key);
}

/**
* Delete Cached Data
*
* @param key - Key
*/
public void deleteCachedData(String key) {
redisTemplate.delete(key);
}

/**
* Increment Key
*
* @param key - Key
* @param delta - Delta
* @return Increment key
*/
public Long incrementKey(String key, long delta) {
return redisTemplate.opsForValue().increment(key, delta);
}

/**
* Set with Conditional Check
*
* @param key - Key
* @param value - Value
* @param timeoutInSeconds - timeoutSeconds
* @return Boolean Value
*/
@SuppressWarnings("null")
public boolean setIfAbsent(String key, Object value, long timeoutInSeconds) {
return redisTemplate.opsForValue().setIfAbsent(key, value, Duration.ofSeconds(timeoutInSeconds));
}
}

0 comments on commit d1efd99

Please sign in to comment.