Java 8 date/time type java.time.LocalDateTime
not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.sparta.toogo.domain.message.dto.MessageDto["createdAt"])
채팅 기능에서 Redis 와 DB 를 이용해서, look aside cache 전략을 사용했다.
그러나,
Redis 에서는 다음과 같은 형태로 저장되고
{
"sender": "닉네임1",
"roomId": "f4dfb832-21c4-48f6-8de7-658dc295a6dc",
"receiver": "닉네임2",
"message": "안녕"
}
DB 에는 다음과 같은 형태로 저장됐다.
{
"id": 1,
"createdAt": "2023-08-28 13:47:13.746070"
"sender": "닉네임1",
"roomId": "f4dfb832-21c4-48f6-8de7-658dc295a6dc",
"receiver": "닉네임2",
"message": "안녕",
"sentTime": null
}
이때, createdAt 부분이 문제였다.
두 저장소에 서로 다른 형태로 데이터를 저장해두고, Redis 에 데이터가 없으면 DB 에서 찾아서 조회하게 되는데
Redis에서 조회한 데이터와 DB에서 조회한 데이터를 형태가 달랐기 때문이었다.
MessageService
// 채팅 조회
public List<MessageDto> loadMessage(String roomId) {
List<MessageDto> messageList = new ArrayList<>();
// Redis 에서 해당 채팅방의 메시지 100개 가져오기
List<MessageDto> redisMessageList = redisTemplateMessage.opsForList().range(roomId, 0, 99);
// Redis 에서 가져온 메시지가 없다면, DB 에서 메시지 100개 가져오기
if (redisMessageList == null || redisMessageList.isEmpty()) {
List<Message> dbMessageList = messageRepository.findTop100ByRoomIdOrderByCreatedAtAsc(roomId);
for (Message message : dbMessageList) {
MessageDto messageDto = new MessageDto(message); // 잘못된 부분!
messageList.add(messageDto);
redisTemplateMessage.setValueSerializer(new Jackson2JsonRedisSerializer<>(Message.class)); // 직렬화
redisTemplateMessage.opsForList().rightPush(roomId, messageDto); // redis 저장
}
} else {
messageList.addAll(redisMessageList);
}
return messageList;
}
MessageDto
@Getter
@Setter
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MessageDto implements Serializable {
private String sender;
private String roomId;
private String receiver;
private String message;
private String sentTime;
private LocalDateTime createdAt; // 최신 메시지 전송 시간
public MessageDto(Message message) {
this.sender = message.getSender();
this.roomId = message.getRoomId();
this.receiver = message.getReceiver();
this.message = message.getMessage();
this.sentTime = message.getSentTime();
}
}
MessageService
// 채팅 조회
public List<MessageDto> loadMessage(String roomId) {
List<MessageDto> messageList = new ArrayList<>();
// Redis 에서 해당 채팅방의 메시지 100개 가져오기
List<MessageDto> redisMessageList = redisTemplateMessage.opsForList().range(roomId, 0, 99);
// Redis 에서 가져온 메시지가 없다면, DB 에서 메시지 100개 가져오기
if (redisMessageList == null || redisMessageList.isEmpty()) {
List<Message> dbMessageList = messageRepository.findTop100ByRoomIdOrderByCreatedAtAsc(roomId);
for (Message message : dbMessageList) {
MessageDto messageDto = new MessageDto(message); // 잘못된 부분!
messageList.add(messageDto);
redisTemplateMessage.setValueSerializer(new Jackson2JsonRedisSerializer<>(Message.class)); // 직렬화
redisTemplateMessage.opsForList().rightPush(roomId, messageDto); // redis 저장
}
} else {
messageList.addAll(redisMessageList);
}
return messageList;
}
MessageDto
@Getter
@Setter
@NoArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class MessageDto implements Serializable {
private String sender;
private String roomId;
private String receiver;
private String message;
private String sentTime;
private LocalDateTime createdAt; // 최신 메시지 전송 시간
// 채팅 조회
public MessageDto(String sender, String roomId, String receiver, String message, String sentTime) {
this.sender = sender;
this.roomId = roomId;
this.receiver = receiver;
this.message = message;
this.sentTime = sentTime;
}
}