Skip to content

Commit

Permalink
MATE-151 : [FEAT] 메이트 채팅 저장소를 MySQL에서 MongoDB로 마이그레이션 (#141)
Browse files Browse the repository at this point in the history
* MATE-151 : [FEAT] 메이트 메세지 도큐먼트 생성

* MATE-151 : [FEAT] 메이트 메세지 클래스 삭제

* MATE-151 : [FEAT] 메이트 메세지의 MongoRepository 생성

* MATE-151 : [FEAT] 메이트 메세지의 응답 DTO의 보조 메서드 제거

* MATE-151 : [FEAT] 메이트 메세지의 응답 DTO 필드 변경

* MATE-151 : [FEAT] 메이트 채팅 메세지 서비스 코드 변경
- MongoDb 도큐먼트 사용으로 인한 반환값 변화에 따른 코드 수정

* MATE-151 : [FEAT] 메이트 채팅 메세지 조회 메서드 리팩토링

* MATE-151 : [FEAT] 불필요한 헬퍼 메서드 제거

* MATE-151 : [FEAT] 불필요한 html파일 제거

* MATE-151 : [FEAT] 메세지 리포지토리 메서드 이름 변경

* MATE-151 : [FEAT] 메세지 반환 DTO 수정으로 인한 테스트 환경 변경

* MATE-151 : [FEAT] 채팅방 멤버 조회 시 불필요한 검증 제거

* MATE-151 : [FEAT] 테스트 코드에 빈 오버라이딩 허용 설정

* MATE-151 : [FEAT] 테스트 코드에 빈 오버라이딩 허용 설정
  • Loading branch information
MisaSohee authored Jan 20, 2025
1 parent a3315b2 commit b43e97c
Show file tree
Hide file tree
Showing 13 changed files with 149 additions and 479 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.mate.domain.mateChat.document;

import com.example.mate.common.BaseTimeEntity;
import com.example.mate.domain.mateChat.message.MessageType;
import jakarta.persistence.Id;
import lombok.*;
import org.springframework.data.mongodb.core.mapping.Document;

import java.time.LocalDateTime;

@Document(collection = "mate_chat_message")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public class MateChatMessage extends BaseTimeEntity {
@Id
private String id;

private Long roomId;
private Long senderId;
private MessageType type;
private String content;
private LocalDateTime sendTime;
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
package com.example.mate.domain.mateChat.dto.request;

import com.example.mate.domain.mateChat.entity.MateChatMessage;
import com.example.mate.domain.mateChat.entity.MateChatRoom;
import com.example.mate.domain.mateChat.message.MessageType;
import com.example.mate.domain.member.entity.Member;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.*;

import java.time.LocalDateTime;

@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand All @@ -26,32 +20,4 @@ public class MateChatMessageRequest {

@NotBlank(message = "메시지 내용은 필수입니다.")
private String message;

public static MateChatMessage toEntity(MateChatRoom chatRoom, MateChatMessageRequest request, Member sender) {
return MateChatMessage.builder()
.mateChatRoom(chatRoom)
.sender(sender)
.type(MessageType.valueOf(request.getType()))
.content(request.getMessage())
.sendTime(LocalDateTime.now())
.build();
}

public static MateChatMessageRequest createEnterMessage(Long roomId, Long senderId, String nickname) {
return MateChatMessageRequest.builder()
.type(MessageType.ENTER.name())
.roomId(roomId)
.senderId(senderId)
.message(nickname + "님이 들어왔습니다.")
.build();
}

public static MateChatMessageRequest createLeaveMessage(Long roomId, Long senderId, String nickname) {
return MateChatMessageRequest.builder()
.type(MessageType.LEAVE.name())
.roomId(roomId)
.senderId(senderId)
.message(nickname + "님이 나갔습니다.")
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.example.mate.domain.mateChat.dto.response;

import com.example.mate.domain.file.FileUtils;
import com.example.mate.domain.mateChat.entity.MateChatMessage;
import com.example.mate.domain.mateChat.document.MateChatMessage;
import com.example.mate.domain.member.entity.Member;
import lombok.Builder;
import lombok.Getter;

Expand All @@ -10,24 +10,24 @@
@Getter
@Builder
public class MateChatMessageResponse {
private Long messageId;
private String messageId;
private Long roomId;
private Long senderId;
private String senderNickname;
private String senderImageUrl;
private String message;
private String messageType;
private String senderImageUrl;
private LocalDateTime sendTime;

public static MateChatMessageResponse of(MateChatMessage message) {
public static MateChatMessageResponse from(MateChatMessage message, Member sender) {
return MateChatMessageResponse.builder()
.messageId(message.getId())
.roomId(message.getMateChatRoom().getId())
.senderId(message.getSender().getId())
.senderNickname(message.getSender().getNickname())
.roomId(message.getRoomId())
.senderId(message.getSenderId())
.senderNickname(sender.getNickname())
.senderImageUrl(sender.getImageUrl())
.message(message.getContent())
.messageType(message.getType().getValue())
.senderImageUrl(FileUtils.getThumbnailImageUrl(message.getSender().getImageUrl()))
.sendTime(message.getSendTime())
.build();
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
package com.example.mate.domain.mateChat.event;

import com.example.mate.domain.mateChat.dto.request.MateChatMessageRequest;
import com.example.mate.domain.mateChat.message.MessageType;
import com.example.mate.domain.member.entity.Member;

public record MateChatEvent(Long chatRoomId, Member member, MessageType type) {
public static MateChatEvent from(Long chatRoomId, Member member, MessageType type) {
return new MateChatEvent(chatRoomId, member, type);
}

public MateChatMessageRequest toMessageRequest() {
String content = type == MessageType.ENTER ?
member.getNickname() + "님이 들어왔습니다." :
member.getNickname() + "님이 나갔습니다.";

return MateChatMessageRequest.builder()
.roomId(chatRoomId)
.senderId(member.getId())
.type(type.name())
.message(content)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
package com.example.mate.domain.mateChat.repository;

import com.example.mate.domain.mateChat.entity.MateChatMessage;
import com.example.mate.domain.mateChat.document.MateChatMessage;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;

import java.time.LocalDateTime;

public interface MateChatMessageRepository extends JpaRepository<MateChatMessage, Long> {

@Query("SELECT m FROM MateChatMessage m " +
"WHERE m.mateChatRoom.id = :roomId " +
"AND m.createdAt >= :enterTime " +
"ORDER BY m.createdAt DESC ")
Page<MateChatMessage> findByChatRoomIdAndCreatedAtAfterOrderByCreatedAtDesc(@Param("roomId") Long roomId,
@Param("enterTime") LocalDateTime enterTime,
Pageable pageable);
public interface MateChatMessageRepository extends MongoRepository<MateChatMessage, String> {
// 채팅방의 특정 시간 이후 메시지 조회 (페이징)
@Query("{ 'roomId': ?0, 'sendTime': { $gt: ?1 } }")
Page<MateChatMessage> findByRoomIdAndSendTimeAfter(
Long roomId,
LocalDateTime enterTime,
Pageable pageable
);
}
Original file line number Diff line number Diff line change
@@ -1,75 +1,108 @@
package com.example.mate.domain.mateChat.service;

import com.example.mate.common.error.CustomException;
import com.example.mate.common.error.ErrorCode;
import com.example.mate.domain.mateChat.document.MateChatMessage;
import com.example.mate.domain.mateChat.dto.request.MateChatMessageRequest;
import com.example.mate.domain.mateChat.dto.response.MateChatMessageResponse;
import com.example.mate.domain.mateChat.entity.MateChatMessage;
import com.example.mate.domain.mateChat.entity.MateChatRoom;
import com.example.mate.domain.mateChat.event.MateChatEvent;
import com.example.mate.domain.mateChat.message.MessageType;
import com.example.mate.domain.mateChat.repository.MateChatMessageRepository;
import com.example.mate.domain.mateChat.repository.MateChatRoomRepository;
import com.example.mate.domain.member.entity.Member;
import com.example.mate.domain.member.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

import static com.example.mate.common.error.ErrorCode.*;

@Slf4j
@Service
@RequiredArgsConstructor
public class MateChatMessageService {
private final MateChatRoomRepository chatRoomRepository;
private final MateChatMessageRepository chatMessageRepository;
private final MateChatMessageRepository chatMessageRepository; // 새로운 MongoDB 레포지토리
private final MemberRepository memberRepository;
private final SimpMessageSendingOperations messagingTemplate;

@Transactional
public void sendMessage(MateChatMessageRequest request) {
MateChatRoom chatRoom = findChatRoomById(request.getRoomId());

// 메시지 전송 가능 여부 검증
MateChatRoom chatRoom = chatRoomRepository.findById(request.getRoomId())
.orElseThrow(() -> new CustomException(CHAT_ROOM_NOT_FOUND));
if (!chatRoom.getIsMessageable()) {
throw new CustomException(ErrorCode.CHAT_ROOM_NOT_MESSAGEABLE);
throw new CustomException(CHAT_ROOM_NOT_MESSAGEABLE);
}

Member sender = findMemberById(request.getSenderId());
MateChatMessage chatMessage = chatMessageRepository.save(MateChatMessageRequest.toEntity(chatRoom, request, sender));
Member sender = memberRepository.findById(request.getSenderId())
.orElseThrow(() -> new CustomException(MEMBER_NOT_FOUND_BY_ID));

// MongoDB에 메시지 저장
MateChatMessage message = MateChatMessage.builder()
.roomId(chatRoom.getId())
.senderId(sender.getId())
.content(request.getMessage())
.type(MessageType.TALK)
.sendTime(LocalDateTime.now())
.build();

MateChatMessage savedMessage = chatMessageRepository.save(message);

// 마지막 메시지 정보 업데이트
chatRoom.updateLastChat(chatMessage.getContent());
chatRoom.updateLastChat(request.getMessage());

// 웹소켓으로 메시지 전송
messagingTemplate.convertAndSend(
"/sub/chat/mate/" + request.getRoomId(),
MateChatMessageResponse.of(chatMessage)
createMessageResponse(savedMessage, sender)
);
}

@Transactional
public void sendChatEventMessage(MateChatEvent event) {
MateChatRoom chatRoom = findChatRoomById(event.chatRoomId());
MateChatMessageRequest request = event.toMessageRequest();
MateChatRoom chatRoom = chatRoomRepository.findById(event.chatRoomId())
.orElseThrow(() -> new CustomException(CHAT_ROOM_NOT_FOUND));

MateChatMessage chatMessage = chatMessageRepository.save(
MateChatMessageRequest.toEntity(chatRoom, request, event.member())
);
Member sender = event.member();

chatRoom.updateLastChat(chatMessage.getContent());
String eventType = event.type() == MessageType.ENTER ?
"님이 입장하셨습니다." : "님이 퇴장하셨습니다.";
String eventMessage = sender.getNickname() + eventType;

// 이벤트 메시지 저장
MateChatMessage message = MateChatMessage.builder()
.roomId(chatRoom.getId())
.senderId(sender.getId())
.content(eventMessage)
.type(event.type())
.sendTime(LocalDateTime.now())
.build();

MateChatMessage savedMessage = chatMessageRepository.save(message);

// 채팅방 마지막 메시지 업데이트
chatRoom.updateLastChat(eventMessage);

messagingTemplate.convertAndSend(
"/sub/chat/mate/" + event.chatRoomId(),
MateChatMessageResponse.of(chatMessage)
createMessageResponse(savedMessage, sender)
);
}

private MateChatRoom findChatRoomById(Long roomId) {
return chatRoomRepository.findById(roomId)
.orElseThrow(() -> new CustomException(ErrorCode.CHAT_ROOM_NOT_FOUND));
}

private Member findMemberById(Long memberId) {
return memberRepository.findById(memberId)
.orElseThrow(() -> new CustomException(ErrorCode.MEMBER_NOT_FOUND_BY_ID));
private MateChatMessageResponse createMessageResponse(MateChatMessage message, Member sender) {
return MateChatMessageResponse.builder()
.messageId(message.getId())
.roomId(message.getRoomId())
.senderId(sender.getId())
.senderNickname(sender.getNickname())
.senderImageUrl(sender.getImageUrl())
.message(message.getContent())
.messageType(message.getType().getValue())
.sendTime(message.getSendTime())
.build();
}
}
Loading

0 comments on commit b43e97c

Please sign in to comment.