프로젝트

자프실 프로젝트-3

aerimi-code 2025. 11. 29. 14:20

 

채팅히스토리를 불러오는 코드가 구현

유저가 입장했을 때 그 전 메시지들을 로딩해서 불러오기. (msgDB사용)

 

구현 방식

내 ID를 보고 권한 확인, ID 수집 후 이름 매핑, DB 엔티티를 DTO로 변환

 

 

// 1. 요청한 유저(나)의 ID를 찾음
ChatUserEntity me = userRepository.findByUserName(username)...

// 2. DB에서 내가 볼 권한이 있는 메시지만 싹 긁어옴
List<MessageEntity> historyEntities = messageRepository.findHistoryByUserId(me.getId());

=> 전체채팅+내가 보낸 귓속말+ 내가 받은 귓속말만 필터링에해서 긁어옴

 

 

ID를 String으로 쉽게 쓰자.

Set<Long> userIds = new HashSet<>();
for (MessageEntity msg : historyEntities) {
    userIds.add(msg.getSenderId()); // 보낸 사람 ID
    if (msg.getRecipientId() != null) {
        userIds.add(msg.getRecipientId()); // 받는 사람 ID (귓속말인 경우)
    }
}

 

 

  • 설명: 가져온 메시지들이 100개라면, 그 안에 포함된 보낸 사람/받는 사람의 ID(숫자)를 전부 모읍니다.
  • Set을 쓰는 이유: 중복을 제거하기 위해서입니다. (예: 철수가 메시지를 10번 보냈어도, ID 조회는 1번만 하면 되니까요.)
// 4. ID 목록으로 유저 정보를 한 방에 조회 (SELECT * FROM users WHERE id IN (...))
List<ChatUserEntity> users = userRepository.findAllById(userIds);

// 5. 조회된 정보를 Map으로 변환 (Key: ID, Value: 이름)
Map<Long, String> userNameMap = users.stream()
        .collect(Collectors.toMap(ChatUserEntity::getId, ChatUserEntity::getUserName));

 

 

왜 이렇게 하나요? (N+1 문제 해결)

  • 만약 이 과정 없이 아래 반복문에서 userRepository.findById(msg.getSenderId())를 매번 호출한다면?
  • 메시지가 100개면 DB 조회가 100번 더 일어납니다. (엄청 느려짐)
  • 위 코드는 단 1번의 쿼리로 필요한 모든 이름을 가져와 메모리(Map)에 올려두고 꺼내 쓰는 방식입니다. 속도가 비약적으로 빠릅니다.

 

DTO로 변환하기

List<ChatMessageResponse> responseList = historyEntities.stream()
        .map(msg -> {
            // Map에서 ID에 해당하는 이름을 O(1) 속도로 아주 빠르게 찾음
            String senderName = userNameMap.getOrDefault(msg.getSenderId(), "(알수없음)");
            
            // ... (받는 사람 이름 찾기 및 타입 결정) ...

            // Entity(DB용 객체) -> Response(화면용 객체) 변환
            return toResponse(msg, senderName, recipientName, type);
        })
        .collect(Collectors.toList());

 

 

요약: 

  1. 권한 확인: 내 ID를 기준으로 볼 수 있는 메시지만 DB에서 가져옵니다.
  2. ID 수집: 메시지에 포함된 작성자/수신자 ID를 Set으로 중복 없이 모읍니다.
  3. 이름 매핑: DB를 한 번만 다녀와서 이름을 가져오고, Map을 이용해 ID와 이름을 연결합니다. (이름을 쉽게 쓰려고 String 객체들을 미리 준비하는 과정)
  4. DTO 변환: DB 형태의 데이터(ID 위주)를 화면 형태의 데이터(이름 위주)로 바꿔서 리스트를 만듭니다.

->대용량 트래픽에서도 DB 부하를 최소화할 수 있는 아주 효율적인 "Bulk Fetch" 패턴