Bael 4779 (#13465)
* first commit for Spring Data Redis TTL * BAEL-4779: Removed incorrect module * removed mvn wrapper * Reduced wait time to check expiration * J17 -> J11 * spring boot redis added to JDK 9 and above profile * pulled latest from master * restored from master * resolved from master * Update pom.xml * Update pom.xml * using Collections api available in J15 * updated Integration test class name --------- Co-authored-by: s9m33r <no-reply> Co-authored-by: Loredana Crusoveanu <lore.crusoveanu@gmail.com>
This commit is contained in:
+13
@@ -0,0 +1,13 @@
|
||||
package com.baelding.springbootredis;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SpringBootRedisApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SpringBootRedisApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.baelding.springbootredis.config;
|
||||
|
||||
import com.baelding.springbootredis.model.Session;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisKeyExpiredEvent;
|
||||
import org.springframework.data.redis.core.RedisKeyValueAdapter;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.core.convert.KeyspaceConfiguration;
|
||||
import org.springframework.data.redis.core.convert.MappingConfiguration;
|
||||
import org.springframework.data.redis.core.index.IndexConfiguration;
|
||||
import org.springframework.data.redis.core.mapping.RedisMappingContext;
|
||||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@Configuration
|
||||
@EnableRedisRepositories(enableKeyspaceEvents = RedisKeyValueAdapter.EnableKeyspaceEvents.ON_STARTUP)
|
||||
@Slf4j
|
||||
public class RedisConfiguration {
|
||||
@Bean
|
||||
public RedisTemplate<String, Session> getRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
|
||||
RedisTemplate<String, Session> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(redisConnectionFactory);
|
||||
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisMappingContext keyValueMappingContext() {
|
||||
return new RedisMappingContext(new MappingConfiguration(new IndexConfiguration(), new MyKeyspaceConfiguration()));
|
||||
}
|
||||
|
||||
public static class MyKeyspaceConfiguration extends KeyspaceConfiguration {
|
||||
|
||||
@Override
|
||||
protected Iterable<KeyspaceSettings> initialConfiguration() {
|
||||
KeyspaceSettings keyspaceSettings = new KeyspaceSettings(Session.class, "session");
|
||||
keyspaceSettings.setTimeToLive(60L);
|
||||
return Collections.singleton(keyspaceSettings);
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
public static class SessionExpiredEventListener {
|
||||
@EventListener
|
||||
public void handleRedisKeyExpiredEvent(RedisKeyExpiredEvent<Session> event) {
|
||||
Session expiredSession = (Session) event.getValue();
|
||||
assert expiredSession != null;
|
||||
log.info("Session with key={} has expired", expiredSession.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.baelding.springbootredis.controller;
|
||||
|
||||
import com.baelding.springbootredis.dto.SessionCreateRequest;
|
||||
import com.baelding.springbootredis.model.Session;
|
||||
import com.baelding.springbootredis.service.cache.session.SessionCache;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/v1/sessions")
|
||||
public class SessionController {
|
||||
private static final String LOCATION_HEADER_VALUE_FORMAT = "/v1/sessions/%s";
|
||||
|
||||
@Autowired
|
||||
private SessionCache sessionCache;
|
||||
|
||||
@GetMapping
|
||||
public List<Session> getAllSessions() {
|
||||
return sessionCache.getAllSessions();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public Session getSession(@PathVariable("id") String id) {
|
||||
return sessionCache.getSession(id);
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<Session> createASession(@RequestBody SessionCreateRequest sessionCreateRequest) {
|
||||
Session createdSession = sessionCache.createASession(Session.builder().expirationInSeconds(sessionCreateRequest.getExpirationInSeconds()).build());
|
||||
|
||||
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
headers.set(HttpHeaders.LOCATION, String.format(LOCATION_HEADER_VALUE_FORMAT, createdSession.getId()));
|
||||
|
||||
return new ResponseEntity<>(createdSession, new HttpHeaders(headers), HttpStatus.CREATED);
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.baelding.springbootredis.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SessionCreateRequest {
|
||||
private Long expirationInSeconds;
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baelding.springbootredis.exception.session;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.NOT_FOUND)
|
||||
public class SessionNotFoundException extends RuntimeException {
|
||||
private static final String MESSAGE_FORMAT = "Session with id=%s doesn't exists!";
|
||||
public SessionNotFoundException(String id) {
|
||||
super(String.format(MESSAGE_FORMAT, id));
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.baelding.springbootredis.model;
|
||||
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.redis.core.RedisHash;
|
||||
import org.springframework.data.redis.core.TimeToLive;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@EqualsAndHashCode
|
||||
@RedisHash(timeToLive = 60L)
|
||||
public class Session {
|
||||
@Id
|
||||
private String id;
|
||||
@TimeToLive
|
||||
private Long expirationInSeconds;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.baelding.springbootredis.repository;
|
||||
|
||||
import com.baelding.springbootredis.model.Session;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface SessionRepository extends CrudRepository<Session, String> {
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.baelding.springbootredis.service.cache.session;
|
||||
|
||||
import com.baelding.springbootredis.exception.session.SessionNotFoundException;
|
||||
import com.baelding.springbootredis.model.Session;
|
||||
import com.baelding.springbootredis.repository.SessionRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Service
|
||||
public class RedisSessionCache implements SessionCache {
|
||||
@Autowired
|
||||
private SessionRepository sessionRepository;
|
||||
|
||||
@Override
|
||||
public Session createASession(Session session) {
|
||||
return sessionRepository.save(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session getSession(String id) {
|
||||
return sessionRepository.findById(id).orElseThrow(() -> new SessionNotFoundException(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Session> getAllSessions() {
|
||||
return Stream.iterate(sessionRepository.findAll().iterator(), Iterator::hasNext, UnaryOperator.identity()).map(Iterator::next).collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.baelding.springbootredis.service.cache.session;
|
||||
|
||||
import com.baelding.springbootredis.model.Session;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface SessionCache {
|
||||
Session createASession(Session session);
|
||||
Session getSession(String id);
|
||||
List<Session> getAllSessions();
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user