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"])

박영준·2023년 8월 28일
0

Troubleshooting

목록 보기
17/43

1. 발생한 에러 메시지

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"])

2. 발생 원인

채팅 기능에서 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에서 조회한 데이터를 형태가 달랐기 때문이었다.

3. 해결법

수전 전

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();
    }
}
  • Message 객체는 createdAt 필드를 가지고 있기 때문에, 이 방식으로 조회할 경우 createdAt 가 함께 조회된다.

수정 후

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;
    }
}
profile
개발자로 거듭나기!

0개의 댓글