아래와 같은 redis와 스프링 세션 연동 작업을 하다가 연결이 안 되는 문제가 발생 했다.
build.gralde
//redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-session-data-redis'
컨트롤러
@RestController
public class AuthController {
// Create Jackson ObjectMapper
String HOME_VIEW_COUNT = "HOME_VIEW_COUNT";
@GetMapping("/")
public String hello(Principal principal, HttpSession session) throws JsonProcessingException {
incrementCount(session , HOME_VIEW_COUNT);
return "hello this is session ";// + principal.getName();
}
@GetMapping("/count")
public String count(HttpSession session){
return "HOME_VIEW_COUNT : " + session.getAttribute(HOME_VIEW_COUNT);
}
private void incrementCount(HttpSession session, String attr){
var homeViewCount = session.getAttribute(attr) == null ? 0 : (Integer) session.getAttribute(attr);
session.setAttribute(attr, homeViewCount += 1);
}
}
3.application.properties
#### Spring Session
#### spring.session.jdbc.initialize-schema = none
spring.session.store-type=redis
#### Redis
spring.redis.host=localhost
spring.redis.port=6379
이슈발생
[2]의 Spring 공식문서 9.2.1 Connecting to Redis 항목에서는 application.properties
에 커넥션 정보만 추가해주면 자동으로 연결 된다고 한다. 하지만 정작 날아오는 세션 값을 보니 톰캣의 jsessionid
가 리턴 됐다.
spring session과 연동이 안 돼서 톰캣의 jsessionid
가 리턴 된 것 같은데 대체 왜 spring session이 연동이 안 됐을까.
1. 테스트 코드로 Redis connection을 먼저 확인
@Test
@DisplayName("redis connection 테스트")
public void redisConnectionTest(){
////redis connection infor
String redisHost = "localhost";
int redisPort = 6379;
String redisPassword = null;
RedisClient redisClient = null;
StatefulRedisConnection<String, String> connection = null;
//// connect
redisClient = RedisClient.create("redis://" + redisHost + ":" + redisPort);
connection = redisClient.connect();
//// 패스워드 체크
//if (redisPassword != null && !redisPassword.isEmpty()) {
// connection.sync().auth(redisPassword);
//}
//// 테스트 go go
String serverInfo = connection.sync().info();
String testKey = "test_key";
String testValue = "test_value";
connection.sync().set(testKey, testValue);
String retrievedValue = connection.sync().get(testKey);
//// assert
assert connection.isOpen() : "Connection to Redis failed";
//// Close the connection when done
if (connection != null) connection.close();
if (redisClient != null) redisClient.shutdown();
}
테스트는 통과 했고,
로컬에 기동 된 레디스에 값도 잘 들어간다. 즉, redis에 직접 연결은 된다. spring session에서 접근이 안 되는 것 같은데 테스트 해보자.
2. Spring Session 연동 테스트
test를 위한 컨트롤러 추가
@Controller
@EnableRedisHttpSession
public class TestSessionController {
@GetMapping("/setTestSessionAttribute")
@ResponseBody
public String setSessionAttribute(HttpSession session) {
session.setAttribute("test_key", "test_value");
return "Session attribute set";
}
}
spring session test 케이스
@SpringBootTest
@AutoConfigureMockMvc
public class RedisSpringSessionConnection {
@Autowired
private MockMvc mockMvc;
@Test
public void testSetAndGetSessionAttribute() throws Exception {
// Set session attribute
ResultActions setResult = mockMvc.perform(get("/setTestSessionAttribute"));
setResult.andExpect(status().isOk())
.andExpect(content().string("Session attribute set"));
}
}
[2]의 9.2.1 Connecting to Redis에서는 application.properties
에 커넥션 정보만 추가해주면 자동으로 연결 된다고 하는데, 위 테스트가 계속 깨져서 확인해보니 RedisConnectionFactory를 찾을 수 없다는 에러가 뜬다.
그래서 아래 RedisConfig를 추가해줬다.
redis config 파일
@Configuration
@EnableRedisHttpSession
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory();
}
}
이제 spring-session 값이 redis에 들어가는 걸 확인 할 수 있다. 마지막으로 클라이언트로 날아오는 쿠키값을 확인해보면,
JSessionid에서 spring session의 디폴트값인 session으로 바뀌어 있고,
외부 저장소 레디스에 세션이 저장 되어 서버를 재기동 해도 view_count가 그대로 나온다.
[1] https://docs.spring.io/spring-session/reference/guides/boot-redis.html
[2] https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#data.nosql.redis.connecting