From 0a7df9d694122ab748f86e8b940dbcb31d12e71f Mon Sep 17 00:00:00 2001 From: BAEK0111 Date: Thu, 1 Jan 2026 16:03:07 +0900 Subject: [PATCH 1/6] =?UTF-8?q?refactor/#231=20-=20=EC=B1=84=ED=8C=85=20Co?= =?UTF-8?q?ntroller=20=EB=AA=85=EC=84=B8=EC=97=90=20=EB=A7=9E=EA=B2=8C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/controller/ChatController.java | 60 ++----------------- 1 file changed, 5 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java index 53af1a40..0353ef35 100644 --- a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java +++ b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java @@ -28,11 +28,7 @@ public class ChatController { private final ChatService chatService; private final SimpMessagingTemplate simpMessagingTemplate; -// private final PresenceTracker presenceTracker; -// private final MessageRepository messageRepository; -// private final MemberRepository memberRepository; private final BlockService blockService; -// private final NotificationCommandService notificationCommandService; @Operation( summary = "채팅방을 생성하는 API", @@ -53,7 +49,7 @@ public BaseResponse createChatRoom( description = "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/API-1d71197c19ed819f8f70fb437e9ce62b?p=2241197c19ed816993c3c5ae17d6f099&pm=s) 채팅방 목록을 조회합니다.\n" ) @GetMapping("/rooms") - public BaseResponse> getChatRoomList( + public BaseResponse> getChatRoomList( @AuthenticationPrincipal PrincipalDetails pd ) { Long memberId = pd.getMember().getId(); @@ -70,13 +66,10 @@ public BaseResponse> ) @MessageMapping("/send") public void handleMessage(@Payload ChatRequestDTO.ChatMessageRequestDTO request) { - - // 1. 서비스 호출 (모든 비즈니스 로직 위임) + // 1. 서비스 호출 MessageHandlingResult result = chatService.handleMessage(request); - // 2. [항상 전송] 채팅방 메시지 전송 simpMessagingTemplate.convertAndSend("/sub/chat/" + request.getRoomId(), result.sendMessageResponseDTO()); - // 3. [조건부 전송] 채팅방 목록 업데이트 전송 if (result.hasRoomUpdates()) { simpMessagingTemplate.convertAndSendToUser( @@ -87,49 +80,6 @@ public void handleMessage(@Payload ChatRequestDTO.ChatMessageRequestDTO request) } } -// @Transactional -// @MessageMapping("/send") -// public void handleMessage(@Payload ChatRequestDTO.ChatMessageRequestDTO request) { -// // 먼저 접속 여부 확인 후 unreadCount 계산 -// boolean receiverInRoom = presenceTracker.isInRoom(request.getReceiverId(), request.getRoomId()); -// int unreadForSender = receiverInRoom ? 0 : 1; -// request.setUnreadCountForSender(unreadForSender); -// -// ChatResponseDTO.SendMessageResponseDTO saved = chatService.handleMessage(request); -// simpMessagingTemplate.convertAndSend("/sub/chat/" + request.getRoomId(), saved); -// -// if (!receiverInRoom) { -// Long totalUnreadCount = messageRepository.countUnreadMessagesByRoomAndReceiver( -// request.getRoomId(), -// request.getReceiverId() -// ); -// -// ChatRoomUpdateDTO updateDTO = ChatRoomUpdateDTO.builder() -// .roomId(request.getRoomId()) -// .lastMessage(saved.message()) -// .lastMessageTime(saved.sentAt()) -// .unreadCount(totalUnreadCount) -// .build(); -// -// simpMessagingTemplate.convertAndSendToUser( -// request.getReceiverId().toString(), -// "/queue/updates", -// updateDTO -// ); -// Member sender = memberRepository.findById(request.getSenderId()).orElse(null); -// String senderName; -// if (sender.getRole()== UserRole.ADMIN) { -// senderName = sender.getAdminProfile().getName(); -// } else { -// senderName = sender.getPartnerProfile().getName(); -// } -// -// log.info(">>>>>>>>메시지 전송은 될걸"); -// notificationCommandService.sendChat(request.getReceiverId(), request.getRoomId(), senderName, request.getMessage()); -// log.info(">>>>>>>>알림이 가나"); -// } -// } - @Operation( summary = "메시지 읽음 처리 API", description = "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed800eab45c35073761c97?v=2241197c19ed8134b64f000cc26c5d31&p=2241197c19ed81ffa771cb18ab157b54&pm=s) 메시지를 읽음처리합니다.\n"+ @@ -178,7 +128,7 @@ public BaseResponse leaveChattingR @Operation( summary = "상대방을 차단하는 API" + "상대방을 차단합니다. 메시지를 주고받을 수 없습니다.", - description = "# [v1.0 (2025-09-25)]() 상대방을 차단합니다.\n"+ + description = "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed804ba3dbf57ba36860c4) 상대방을 차단합니다.\n"+ "- memberId: Request Body, Long\n" ) @PostMapping("/block") @@ -193,7 +143,7 @@ public BaseResponse block( @Operation( summary = "상대방을 차단했는지 확인하는 API" + "상대방을 차단했는지 여부를 알려줍니다.", - description = "# [v1.0 (2025-09-25)]() 상대방을 차단했는지 검사합니다.\n"+ + description = "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80769521eab9660ac53f) 상대방을 차단했는지 검사합니다.\n"+ "- memberId: Request Body, Long\n" ) @GetMapping("/check/block/{opponentId}") @@ -208,7 +158,7 @@ public BaseResponse checkBlock( @Operation( summary = "상대방을 차단 해제하는 API" + "상대방을 차단해제합니다. 앞으로 다시 메시지를 주고받을 수 있습니다.", - description = "# [v1.0 (2025-09-25)]() 상대방을 차단 해제합니다.\n"+ + description = "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80b6a93fcbe277fc934c?pvs=74) 상대방을 차단 해제합니다.\n"+ "- memberId: Request Body, Long\n" ) @DeleteMapping("/unblock") From e57359d7d8ad96035a4095a013234bb0e1ce267d Mon Sep 17 00:00:00 2001 From: BAEK0111 Date: Thu, 1 Jan 2026 16:11:09 +0900 Subject: [PATCH 2/6] =?UTF-8?q?refactor/#231=20-=20=EC=B1=84=ED=8C=85=20Co?= =?UTF-8?q?ntroller=20=EB=AA=85=EC=84=B8=EC=97=90=20=EB=A7=9E=EA=B2=8C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/chat/controller/ChatController.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java index 0353ef35..210cdb84 100644 --- a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java +++ b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java @@ -33,7 +33,7 @@ public class ChatController { @Operation( summary = "채팅방을 생성하는 API", description = "# [v1.0 (2025-08-05)](https://clumsy-seeder-416.notion.site/2241197c19ed80c38871ec77deced713) 채팅방을 생성합니다.\n"+ - "- storeId: Request Body, Long\n" + + "- adminId: Request Body, Long\n" + "- partnerId: Request Body, Long\n" ) @PostMapping("/rooms") @@ -62,7 +62,8 @@ public BaseResponse> getChatRoomList( "- roomId: Request Body, Long\n" + "- senderId: Request Body, Long\n"+ "- receiverId: Request Body, Long\n" + - "- message: Request Body, String\n" + "- message: Request Body, String\n" + + "- unreadCountForSender: Request Body, int\n" ) @MessageMapping("/send") public void handleMessage(@Payload ChatRequestDTO.ChatMessageRequestDTO request) { @@ -129,7 +130,7 @@ public BaseResponse leaveChattingR summary = "상대방을 차단하는 API" + "상대방을 차단합니다. 메시지를 주고받을 수 없습니다.", description = "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed804ba3dbf57ba36860c4) 상대방을 차단합니다.\n"+ - "- memberId: Request Body, Long\n" + "- opponentId: Request Body, Long\n" ) @PostMapping("/block") public BaseResponse block( @@ -144,7 +145,7 @@ public BaseResponse block( summary = "상대방을 차단했는지 확인하는 API" + "상대방을 차단했는지 여부를 알려줍니다.", description = "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80769521eab9660ac53f) 상대방을 차단했는지 검사합니다.\n"+ - "- memberId: Request Body, Long\n" + "- opponentId: Request Body, Long\n" ) @GetMapping("/check/block/{opponentId}") public BaseResponse checkBlock( @@ -159,7 +160,7 @@ public BaseResponse checkBlock( summary = "상대방을 차단 해제하는 API" + "상대방을 차단해제합니다. 앞으로 다시 메시지를 주고받을 수 있습니다.", description = "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed80b6a93fcbe277fc934c?pvs=74) 상대방을 차단 해제합니다.\n"+ - "- memberId: Request Body, Long\n" + "- opponentId: Request Body, Long\n" ) @DeleteMapping("/unblock") public BaseResponse unblock( @@ -173,8 +174,7 @@ public BaseResponse unblock( @Operation( summary = "차단한 대상을 조회합니다." + "본인이 차단한 대상을 모두 조회합니다.", - description = "# [v1.0 (2025-09-25)]() 차단한 대상을 조회합니다..\n"+ - "- memberId: Request Body, Long\n" + description = "# [v1.0 (2025-09-25)](https://clumsy-seeder-416.notion.site/2db1197c19ed8000b047d9857bcbbb2f) 차단한 대상을 조회합니다..\n" ) @GetMapping("/blockList") public BaseResponse> getBlockList( From d4f4ddc7bada58637224e92c8ca5616c74af990d Mon Sep 17 00:00:00 2001 From: BAEK0111 Date: Thu, 1 Jan 2026 20:59:12 +0900 Subject: [PATCH 3/6] =?UTF-8?q?refactor/#231=20-=20=EC=B1=84=ED=8C=85=20DT?= =?UTF-8?q?O=20->=20record=20=EB=B3=80=EA=B2=BD=20&=20=EC=BB=A8=EB=B2=84?= =?UTF-8?q?=ED=84=B0=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/controller/ChatController.java | 4 +- .../domain/chat/converter/BlockConverter.java | 51 -------- .../domain/chat/converter/ChatConverter.java | 121 ------------------ .../domain/chat/dto/BlockRequestDTO.java | 8 +- .../domain/chat/dto/BlockResponseDTO.java | 81 +++++++++--- .../domain/chat/dto/ChatMessageDTO.java | 38 +++--- .../domain/chat/dto/ChatRequestDTO.java | 30 ++--- .../domain/chat/dto/ChatResponseDTO.java | 84 ++++++++---- .../chat/dto/ChatRoomListResultDTO.java | 50 ++++++-- .../domain/chat/dto/ChatRoomUpdateDTO.java | 26 +++- .../chat/dto/MessageHandlingResult.java | 7 - .../domain/chat/entity/ChattingRoom.java | 7 + .../server/domain/chat/entity/Message.java | 34 +++++ .../domain/chat/service/BlockServiceImpl.java | 14 +- .../domain/chat/service/ChatServiceImpl.java | 59 ++++----- .../service/PartnershipServiceImpl.java | 9 +- 16 files changed, 290 insertions(+), 333 deletions(-) delete mode 100644 src/main/java/com/assu/server/domain/chat/converter/BlockConverter.java delete mode 100644 src/main/java/com/assu/server/domain/chat/converter/ChatConverter.java diff --git a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java index 210cdb84..cc19fdb1 100644 --- a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java +++ b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java @@ -70,7 +70,7 @@ public void handleMessage(@Payload ChatRequestDTO.ChatMessageRequestDTO request) // 1. 서비스 호출 MessageHandlingResult result = chatService.handleMessage(request); // 2. [항상 전송] 채팅방 메시지 전송 - simpMessagingTemplate.convertAndSend("/sub/chat/" + request.getRoomId(), result.sendMessageResponseDTO()); + simpMessagingTemplate.convertAndSend("/sub/chat/" + request.roomId(), result.sendMessageResponseDTO()); // 3. [조건부 전송] 채팅방 목록 업데이트 전송 if (result.hasRoomUpdates()) { simpMessagingTemplate.convertAndSendToUser( @@ -138,7 +138,7 @@ public BaseResponse block( @RequestBody BlockRequestDTO.BlockMemberRequestDTO request ) { Long memberId = pd.getMember().getId(); - return BaseResponse.onSuccess(SuccessStatus._OK, blockService.blockMember(memberId, request.getOpponentId())); + return BaseResponse.onSuccess(SuccessStatus._OK, blockService.blockMember(memberId, request.opponentId())); } @Operation( diff --git a/src/main/java/com/assu/server/domain/chat/converter/BlockConverter.java b/src/main/java/com/assu/server/domain/chat/converter/BlockConverter.java deleted file mode 100644 index aea2bebc..00000000 --- a/src/main/java/com/assu/server/domain/chat/converter/BlockConverter.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.assu.server.domain.chat.converter; - -import com.assu.server.domain.chat.dto.BlockResponseDTO; -import com.assu.server.domain.chat.entity.Block; -import com.assu.server.domain.common.enums.UserRole; -import com.assu.server.domain.member.entity.Member; - -import java.util.List; -import java.util.stream.Collectors; - -public class BlockConverter { - public static BlockResponseDTO.BlockMemberDTO toBlockDTO(Long blockedId, String blockedName) { - return BlockResponseDTO.BlockMemberDTO.builder() - .memberId(blockedId) - .name(blockedName) - .build(); - } - - public static BlockResponseDTO.CheckBlockMemberDTO toCheckBlockDTO(Long blockedId, String blockedName, boolean blocked) { - return BlockResponseDTO.CheckBlockMemberDTO.builder() - .memberId(blockedId) - .name(blockedName) - .blocked(blocked) - .build(); - } - - public static BlockResponseDTO.BlockMemberDTO toBlockedMemberDTO(Block block) { - // Block 엔티티에서 차단된 사용자(Member) 정보를 꺼냅니다. - Member blockedMember = block.getBlocked(); - UserRole blockedRole = blockedMember.getRole(); - String blockedName; - if (blockedRole == UserRole.ADMIN) { - blockedName = blockedMember.getAdminProfile().getName(); - } else { - blockedName = blockedMember.getPartnerProfile().getName(); - } - - return BlockResponseDTO.BlockMemberDTO.builder() - .memberId(blockedMember.getId()) - .name(blockedName) // 또는 getNickname() 등 실제 필드명 사용 - .blockDate(block.getCreatedAt()) - .build(); - } - - public static List toBlockedMemberListDTO(List blockList) { - return blockList.stream() - .map(BlockConverter::toBlockedMemberDTO) // 각 Block 객체에 대해 위 헬퍼 메소드를 호출 - .collect(Collectors.toList()); - } - -} diff --git a/src/main/java/com/assu/server/domain/chat/converter/ChatConverter.java b/src/main/java/com/assu/server/domain/chat/converter/ChatConverter.java deleted file mode 100644 index 1d38eae3..00000000 --- a/src/main/java/com/assu/server/domain/chat/converter/ChatConverter.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.assu.server.domain.chat.converter; - -import com.assu.server.domain.admin.entity.Admin; -import com.assu.server.domain.chat.entity.enums.MessageType; -import com.assu.server.domain.member.entity.Member; -import com.assu.server.domain.chat.dto.ChatMessageDTO; -import com.assu.server.domain.chat.dto.ChatRequestDTO; -import com.assu.server.domain.chat.dto.ChatResponseDTO; -import com.assu.server.domain.chat.dto.ChatRoomListResultDTO; -import com.assu.server.domain.chat.entity.ChattingRoom; -import com.assu.server.domain.chat.entity.Message; - -import com.assu.server.domain.partner.entity.Partner; - -import java.util.List; -import java.util.stream.Collectors; - -public class ChatConverter { - - // 채팅방 리스트 아이템 하나 - public static ChatRoomListResultDTO toChatRoomResultDTO(ChatRoomListResultDTO request) { - return ChatRoomListResultDTO.builder() - .roomId(request.getRoomId()) - .lastMessage(request.getLastMessage()) - .lastMessageTime(request.getLastMessageTime()) - .unreadMessagesCount(request.getUnreadMessagesCount()) - .opponentId(request.getOpponentId()) - .opponentName(request.getOpponentName()) - .opponentProfileImage(request.getOpponentProfileImage()) - .phoneNumber(request.getPhoneNumber()) - .build(); - } - - // 리스트 변환 - public static List toChatRoomListResultDTO(List dto) { - return dto.stream() - .map(ChatConverter::toChatRoomResultDTO) - .collect(Collectors.toList()); - } - - public static ChattingRoom toCreateChattingRoom(Admin admin, Partner partner) { - return ChattingRoom.builder() - .admin(admin) - .partner(partner) - .build(); - } - - public static ChatResponseDTO.CreateChatRoomResponseDTO toCreateChatRoomIdDTO(ChattingRoom room) { - return ChatResponseDTO.CreateChatRoomResponseDTO.builder() - .roomId(room.getId()) - .adminViewName(room.getPartner().getName()) - .partnerViewName(room.getAdmin().getName()) - .isNew(true) - .build(); - } - - public static ChatResponseDTO.CreateChatRoomResponseDTO toEnterChatRoomDTO(ChattingRoom room) { - return ChatResponseDTO.CreateChatRoomResponseDTO.builder() - .roomId(room.getId()) - .adminViewName(room.getPartner().getName()) - .partnerViewName(room.getAdmin().getName()) - .isNew(false) - .build(); - } - - public static Message toMessageEntity(ChatRequestDTO.ChatMessageRequestDTO request, ChattingRoom room, Member sender, Member receiver) { - return Message.builder() - .chattingRoom(room) - .sender(sender) - .receiver(receiver) - .message(request.getMessage()) - .unreadCount(request.getUnreadCountForSender()) - .type(MessageType.TEXT) - .build(); - } - - public static Message toGuideMessageEntity(ChatRequestDTO.ChatMessageRequestDTO request, ChattingRoom room, Member sender, Member receiver) { - return Message.builder() - .chattingRoom(room) - .sender(sender) - .receiver(receiver) - .message(request.getMessage()) - .unreadCount(0) - .type(MessageType.GUIDE) - .build(); - } - - public static ChatResponseDTO.SendMessageResponseDTO toSendMessageDTO(Message message) { - return ChatResponseDTO.SendMessageResponseDTO.builder() - .messageId(message.getId()) - .roomId(message.getChattingRoom().getId()) - .senderId(message.getSender().getId()) - .receiverId(message.getReceiver().getId()) - .message(message.getMessage()) - .sentAt(message.getCreatedAt()) - .messageType(message.getType()) - .unreadCountForSender(message.getUnreadCount()) - .build(); - } - -// public static ChatMessageDTO toChatMessageDTO(Message message, Long currentUserId) { -// return ChatMessageDTO.builder() -// .messageId(message.getId()) -// .message(message.getMessage()) -// .sendTime(message.getCreatedAt()) -// .isRead(message.isRead()) -// .isMyMessage(message.getSender().getId().equals(currentUserId)) -// .build(); -// } - - public static ChatResponseDTO.ChatHistoryResponseDTO toChatHistoryDTO( - Long roomId, - List messages) { - - // ③ 최종 DTO 빌드 - return ChatResponseDTO.ChatHistoryResponseDTO.builder() - .roomId(roomId) - .messages(messages) - .build(); - } -} diff --git a/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java b/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java index 938b4f8f..8daa97db 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java @@ -5,9 +5,7 @@ public class BlockRequestDTO { - @Getter - @Setter - public static class BlockMemberRequestDTO { - private Long opponentId; - } + public record BlockMemberRequestDTO( + Long opponentId + ) {} } diff --git a/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java b/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java index e13d1db8..93db756c 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java @@ -1,32 +1,81 @@ package com.assu.server.domain.chat.dto; +import com.assu.server.domain.chat.entity.Block; +import com.assu.server.domain.common.enums.UserRole; +import com.assu.server.domain.member.entity.Member; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; public class BlockResponseDTO { - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class BlockMemberDTO { - private Long memberId; - private String name; - private LocalDateTime blockDate; + public record BlockMemberDTO ( + Long memberId, + String name, + LocalDateTime blockDate + ) { + public static BlockMemberDTO toBlockDTO( + Long blockedId, + String blockedName + ) { + return new BlockMemberDTO( + blockedId, + blockedName, + LocalDateTime.now() + ); + } + + public static BlockMemberDTO toBlockedMemberDTO( + Block block + ) { + Member blockedMember = block.getBlocked(); + UserRole blockedRole = blockedMember.getRole(); + String blockedName; + if (blockedRole == UserRole.ADMIN) { + blockedName = blockedMember.getAdminProfile().getName(); + } else { + blockedName = blockedMember.getPartnerProfile().getName(); + } + + return new BlockMemberDTO( + blockedMember.getId(), + blockedName, + block.getCreatedAt() + ); + } + + public static List toBlockedMemberListDTO( + List blockList + ) { + return blockList.stream() + .map(BlockResponseDTO.BlockMemberDTO::toBlockedMemberDTO) + .collect(Collectors.toList()); + } + } - @Getter - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class CheckBlockMemberDTO { - private Long memberId; - private String name; - private boolean blocked; + + public record CheckBlockMemberDTO ( + Long memberId, + String name, + boolean blocked + ) { + public static CheckBlockMemberDTO toCheckBlockDTO( + Long blockedId, + String blockedName, + boolean blocked + ) { + return new CheckBlockMemberDTO( + blockedId, + blockedName, + blocked + ); + } } } diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java index 9886cba2..834f9223 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java @@ -3,34 +3,26 @@ import com.assu.server.domain.chat.entity.enums.MessageType; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - import java.time.LocalDateTime; -@Getter -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class ChatMessageDTO { - @JsonIgnore - private Long roomId; - // 메시지 삭제 시 사용 가능 - private Long messageId; +public record ChatMessageDTO( + @JsonIgnore + Long roomId, + // 메시지 삭제 시 사용 가능 + Long messageId, - private String message; - private LocalDateTime sendTime; + String message, + LocalDateTime sendTime, - @JsonProperty("unreadCountForSender") - private Integer unreadCount; + @JsonProperty("unreadCountForSender") + Integer unreadCount, - @JsonProperty("isRead") - private boolean isRead; + @JsonProperty("isRead") + boolean isRead, - @JsonProperty("isMyMessage") - private boolean isMyMessage; + @JsonProperty("isMyMessage") + boolean isMyMessage, - private MessageType messageType; + MessageType messageType +){ } diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java index c5180559..77f2a605 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java @@ -7,21 +7,17 @@ import lombok.Setter; public class ChatRequestDTO { - @Getter - public static class CreateChatRoomRequestDTO { - private Long adminId; - private Long partnerId; - } - @Getter - @Setter - @AllArgsConstructor - @NoArgsConstructor - public static class ChatMessageRequestDTO { - private Long roomId; - private Long senderId; - private Long receiverId; - private String message; - private int unreadCountForSender; - } -} \ No newline at end of file + public record CreateChatRoomRequestDTO( + Long adminId, + Long partnerId + ) {} + + public record ChatMessageRequestDTO( + Long roomId, + Long senderId, + Long receiverId, + String message + ) {} + +} diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java index 9a8f3d97..eef0acfa 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java @@ -1,5 +1,7 @@ package com.assu.server.domain.chat.dto; +import com.assu.server.domain.chat.entity.ChattingRoom; +import com.assu.server.domain.chat.entity.Message; import com.assu.server.domain.chat.entity.enums.MessageType; import com.fasterxml.jackson.annotation.JsonFormat; import com.google.protobuf.Enum; @@ -13,19 +15,31 @@ public class ChatResponseDTO { // 채팅방 목록 조회 - @Getter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class CreateChatRoomResponseDTO { - private Long roomId; - private String adminViewName; - private String partnerViewName; - private Boolean isNew; + public record CreateChatRoomResponseDTO( + Long roomId, + String adminViewName, + String partnerViewName, + Boolean isNew + ) { + public static CreateChatRoomResponseDTO toCreateChatRoomIdDTO(ChattingRoom room) { + return new CreateChatRoomResponseDTO( + room.getId(), + room.getPartner().getName(), + room.getAdmin().getName(), + true + ); + } + public static CreateChatRoomResponseDTO toEnterChatRoomDTO(ChattingRoom room) { + return new CreateChatRoomResponseDTO( + room.getId(), + room.getPartner().getName(), + room.getAdmin().getName(), + false + ); + } } // 메시지 전송 - @Builder public record SendMessageResponseDTO( Long messageId, Long roomId, @@ -42,6 +56,23 @@ public SendMessageResponseDTO withUnreadCountForSender(Integer count) { messageId, roomId, senderId, receiverId, message, messageType, sentAt, count ); } + + public static SendMessageResponseDTO toSendMessageDTO( + Message message + ) { + return new SendMessageResponseDTO( + message.getId(), + message.getChattingRoom().getId(), + message.getSender().getId(), + message.getReceiver().getId(), + message.getMessage(), + message.getType(), + message.getCreatedAt(), + message.getUnreadCount() + ); + + + } } // 메시지 읽음 처리 @@ -54,23 +85,26 @@ public record ReadMessageResponseDTO( ) {} // 채팅방 들어갔을 때 조회 - @Getter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class ChatHistoryResponseDTO { - private Long roomId; - private List messages; + public record ChatHistoryResponseDTO( + Long roomId, + List messages + ) { + public static ChatHistoryResponseDTO toChatHistoryDTO( + Long roomId, + List messages) { + return new ChatHistoryResponseDTO( + roomId, + messages + ); + } } - @Getter - @NoArgsConstructor - @AllArgsConstructor - @Builder - public static class LeaveChattingRoomResponseDTO { - private Long roomId; - private boolean isLeftSuccessfully; - private boolean isRoomDeleted; + public record LeaveChattingRoomResponseDTO( + Long roomId, + boolean isLeftSuccessfully, + boolean isRoomDeleted + ) { + } } diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java index 4e57cb8c..6f547287 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java @@ -6,18 +6,42 @@ import lombok.NoArgsConstructor; import java.time.LocalDateTime; +import java.util.List; +import java.util.stream.Collectors; -@Getter -@Builder -@AllArgsConstructor -@NoArgsConstructor -public class ChatRoomListResultDTO { - private Long roomId; - private String lastMessage; - private LocalDateTime lastMessageTime; - private Long unreadMessagesCount; - private Long opponentId; - private String opponentName; - private String opponentProfileImage; - private String phoneNumber; +public record ChatRoomListResultDTO( + Long roomId, + String lastMessage, + LocalDateTime lastMessageTime, + Long unreadMessagesCount, + Long opponentId, + String opponentName, + String opponentProfileImage, + String phoneNumber + +) { + // 채팅방 리스트 아이템 하나 + public static ChatRoomListResultDTO toChatRoomResultDTO( + ChatRoomListResultDTO dto + ) { + return new ChatRoomListResultDTO( + dto.roomId, + dto.lastMessage, + dto.lastMessageTime, + dto.unreadMessagesCount, + dto.opponentId, + dto.opponentName, + dto.opponentProfileImage, + dto.phoneNumber + ); + } + + // 채팅방 리스트 변환 + public static List toChatRoomListResultDTO ( + List dto + ) { + return dto.stream() + .map(ChatRoomListResultDTO::toChatRoomResultDTO) + .collect(Collectors.toList()); + } } diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java index b83ee0c0..24a14263 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java @@ -5,11 +5,23 @@ import java.time.LocalDateTime; -@Getter -@Builder -public class ChatRoomUpdateDTO { - private Long roomId; - private String lastMessage; - private LocalDateTime lastMessageTime; - private Long unreadCount; // 해당 채팅방의 총 안읽은 메시지 수 +public record ChatRoomUpdateDTO( + Long roomId, + String lastMessage, + LocalDateTime lastMessageTime, + Long unreadCount // 해당 채팅방의 총 안읽은 메시지 수 +) { + public static ChatRoomUpdateDTO toChatRoomUpdateDTO( + Long roomId, + String lastMessage, + LocalDateTime lastMessageTime, + Long unreadCount + ) { + return new ChatRoomUpdateDTO( + roomId, + lastMessage, + lastMessageTime, + unreadCount + ); + } } diff --git a/src/main/java/com/assu/server/domain/chat/dto/MessageHandlingResult.java b/src/main/java/com/assu/server/domain/chat/dto/MessageHandlingResult.java index 56c142e9..43f73a66 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/MessageHandlingResult.java +++ b/src/main/java/com/assu/server/domain/chat/dto/MessageHandlingResult.java @@ -5,22 +5,15 @@ public record MessageHandlingResult( ChatRoomUpdateDTO chatRoomUpdateDTO, Long receiverId ) { - - // 정적 팩토리 메소드 1 public static MessageHandlingResult of(ChatResponseDTO.SendMessageResponseDTO sendMessageDTO) { - // record의 기본 생성자를 호출합니다. return new MessageHandlingResult(sendMessageDTO, null, null); } - // 정적 팩토리 메소드 2 public static MessageHandlingResult withUpdates(ChatResponseDTO.SendMessageResponseDTO sendMessageDTO, ChatRoomUpdateDTO updateDTO, Long receiverId) { - // record의 기본 생성자를 호출합니다. return new MessageHandlingResult(sendMessageDTO, updateDTO, receiverId); } - // 헬퍼(Helper) 메소드 public boolean hasRoomUpdates() { - // record는 'get' 접두사 없는 접근자(chatRoomUpdateDTO())를 사용합니다. return chatRoomUpdateDTO != null; } } \ No newline at end of file diff --git a/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java b/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java index e88c405e..bcec1a05 100644 --- a/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java +++ b/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java @@ -64,4 +64,11 @@ public void setAdmin(Admin admin) { public void setPartner(Partner partner) { this.partner = partner; } + + public static ChattingRoom toCreateChattingRoom(Admin admin, Partner partner) { + return ChattingRoom.builder() + .admin(admin) + .partner(partner) + .build(); + } } \ No newline at end of file diff --git a/src/main/java/com/assu/server/domain/chat/entity/Message.java b/src/main/java/com/assu/server/domain/chat/entity/Message.java index ba06e811..94193f6f 100644 --- a/src/main/java/com/assu/server/domain/chat/entity/Message.java +++ b/src/main/java/com/assu/server/domain/chat/entity/Message.java @@ -1,5 +1,6 @@ package com.assu.server.domain.chat.entity; +import com.assu.server.domain.chat.dto.ChatRequestDTO; import com.assu.server.domain.member.entity.Member; import com.assu.server.domain.chat.entity.enums.MessageType; @@ -51,4 +52,37 @@ public void markAsRead() { this.isRead = true; this.unreadCount = 0; } + + public static Message toMessageEntity( + ChatRequestDTO.ChatMessageRequestDTO request, + ChattingRoom room, + Member sender, + Member receiver, + int unreadForSender + ) { + return Message.builder() + .chattingRoom(room) + .sender(sender) + .receiver(receiver) + .message(request.message()) + .unreadCount(unreadForSender) + .type(MessageType.TEXT) + .build(); + } + + public static Message toGuideMessageEntity( + ChatRequestDTO.ChatMessageRequestDTO request, + ChattingRoom room, + Member sender, + Member receiver + ) { + return Message.builder() + .chattingRoom(room) + .sender(sender) + .receiver(receiver) + .message(request.message()) + .unreadCount(0) + .type(MessageType.GUIDE) + .build(); + } } \ No newline at end of file diff --git a/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java b/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java index b9edc568..babd36fa 100644 --- a/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java +++ b/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java @@ -1,7 +1,5 @@ package com.assu.server.domain.chat.service; -import com.assu.server.domain.chat.converter.BlockConverter; -import com.assu.server.domain.chat.converter.ChatConverter; import com.assu.server.domain.chat.dto.BlockResponseDTO; import com.assu.server.domain.chat.entity.Block; import com.assu.server.domain.chat.repository.BlockRepository; @@ -13,9 +11,7 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; - import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -59,7 +55,7 @@ public BlockResponseDTO.BlockMemberDTO blockMember(Long blockerId, Long blockedI blockRepository.save(block); - return BlockConverter.toBlockDTO(blockedId, blockedName); + return BlockResponseDTO.BlockMemberDTO.toBlockDTO(blockedId, blockedName); } @Override @@ -81,10 +77,10 @@ public BlockResponseDTO.CheckBlockMemberDTO checkBlock(Long blockerId, Long bloc } if (blockRepository.existsBlockRelationBetween(blocker, blocked)) { - return BlockConverter.toCheckBlockDTO(blockedId, blockedName, true); + return BlockResponseDTO.CheckBlockMemberDTO.toCheckBlockDTO(blockedId, blockedName, true); } else { - return BlockConverter.toCheckBlockDTO(blockedId, blockedName, false); + return BlockResponseDTO.CheckBlockMemberDTO.toCheckBlockDTO(blockedId, blockedName, false); } } @@ -108,7 +104,7 @@ public BlockResponseDTO.BlockMemberDTO unblockMember(Long blockerId, Long blocke // Transactional 환경에서는 Dirty-checking으로 delete 쿼리가 나갑니다. blockRepository.deleteByBlockerAndBlocked(blocker, blocked); - return BlockConverter.toBlockDTO(blockedId, blockedName); + return BlockResponseDTO.BlockMemberDTO.toBlockDTO(blockedId, blockedName); } @Transactional @@ -119,6 +115,6 @@ public List getMyBlockList(Long blockerId) { List blockList = blockRepository.findByBlocker(blocker); - return BlockConverter.toBlockedMemberListDTO(blockList); + return BlockResponseDTO.BlockMemberDTO.toBlockedMemberListDTO(blockList); } } diff --git a/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java b/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java index c3e25581..adb27cf9 100644 --- a/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java +++ b/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java @@ -2,7 +2,6 @@ import com.assu.server.domain.admin.entity.Admin; import com.assu.server.domain.admin.repository.AdminRepository; -import com.assu.server.domain.chat.converter.ChatConverter; import com.assu.server.domain.chat.dto.*; import com.assu.server.domain.chat.entity.ChattingRoom; import com.assu.server.domain.chat.entity.Message; @@ -48,14 +47,14 @@ public class ChatServiceImpl implements ChatService { public List getChatRoomList(Long memberId) { List chatRoomList = chatRepository.findChattingRoomsByMemberId(memberId); - return ChatConverter.toChatRoomListResultDTO(chatRoomList); + return ChatRoomListResultDTO.toChatRoomListResultDTO(chatRoomList); } @Override public ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.CreateChatRoomRequestDTO request, Long memberId) { - Long adminId = request.getAdminId(); - Long partnerId = request.getPartnerId(); + Long adminId = request.adminId(); + Long partnerId = request.partnerId(); Admin admin = adminRepository.findById(adminId) .orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ADMIN)); @@ -72,7 +71,7 @@ public ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.C boolean isExist = chatRepository.checkChattingRoomByAdminIdAndPartnerId(admin.getId(), partner.getId()); if(!isExist) { - ChattingRoom room = ChatConverter.toCreateChattingRoom(admin, partner); + ChattingRoom room = ChattingRoom.toCreateChattingRoom(admin, partner); room.updateStatus(ActivationStatus.ACTIVE); @@ -83,10 +82,10 @@ public ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.C admin.getName() ); ChattingRoom savedRoom = chatRepository.save(room); - return ChatConverter.toCreateChatRoomIdDTO(savedRoom); + return ChatResponseDTO.CreateChatRoomResponseDTO.toCreateChatRoomIdDTO(savedRoom); } else { ChattingRoom existChatRoom = chatRepository.findChattingRoomByAdminIdAndPartnerId(admin.getId(), partner.getId()); - return ChatConverter.toEnterChatRoomDTO(existChatRoom); + return ChatResponseDTO.CreateChatRoomResponseDTO.toEnterChatRoomDTO(existChatRoom); } } @@ -115,41 +114,39 @@ public ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.C @Transactional public MessageHandlingResult handleMessage(ChatRequestDTO.ChatMessageRequestDTO request) { // 1. 유효성 검사 (기존 로직) - ChattingRoom room = chatRepository.findById(request.getRoomId()) + ChattingRoom room = chatRepository.findById(request.roomId()) .orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ROOM)); - Member sender = memberRepository.findById(request.getSenderId()) + Member sender = memberRepository.findById(request.senderId()) .orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_MEMBER)); - Member receiver = memberRepository.findById(request.getReceiverId()) + Member receiver = memberRepository.findById(request.receiverId()) .orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_MEMBER)); // 2. 컨트롤러에서 가져온 비즈니스 로직 (접속 확인) - boolean receiverInRoom = presenceTracker.isInRoom(request.getReceiverId(), request.getRoomId()); + boolean receiverInRoom = presenceTracker.isInRoom(request.receiverId(), request.roomId()); int unreadForSender = receiverInRoom ? 0 : 1; - request.setUnreadCountForSender(unreadForSender); // 3. 메시지 저장 (기존 로직) - Message message = ChatConverter.toMessageEntity(request, room, sender, receiver); + Message message = Message.toMessageEntity(request, room, sender, receiver, unreadForSender); Message saved = messageRepository.saveAndFlush(message); log.info("saved message id={}, roomId={}, senderId={}, receiverId={}", saved.getId(), room.getId(), sender.getId(), receiver.getId()); - ChatResponseDTO.SendMessageResponseDTO savedDTO = ChatConverter.toSendMessageDTO(saved); + ChatResponseDTO.SendMessageResponseDTO savedDTO = ChatResponseDTO.SendMessageResponseDTO.toSendMessageDTO(saved); // 4. 컨트롤러에서 가져온 비즈니스 로직 (수신자 부재 시) if (!receiverInRoom) { // 4-1. 안 읽은 수 계산 Long totalUnreadCount = messageRepository.countUnreadMessagesByRoomAndReceiver( - request.getRoomId(), - request.getReceiverId() + request.roomId(), + request.receiverId() ); // 4-2. 채팅방 목록 업데이트 DTO 생성 - ChatRoomUpdateDTO updateDTO = ChatRoomUpdateDTO.builder() - .roomId(request.getRoomId()) - .lastMessage(savedDTO.message()) - .lastMessageTime(savedDTO.sentAt()) - .unreadCount(totalUnreadCount) - .build(); + ChatRoomUpdateDTO updateDTO = ChatRoomUpdateDTO.toChatRoomUpdateDTO( + request.roomId(), + savedDTO.message(), + savedDTO.sentAt(), + totalUnreadCount); // 4-3. 발신자 이름 찾기 (기존 컨트롤러 로직) String senderName; @@ -160,10 +157,10 @@ public MessageHandlingResult handleMessage(ChatRequestDTO.ChatMessageRequestDTO } // 4-4. 알림 전송 - notificationCommandService.sendChat(request.getReceiverId(), request.getRoomId(), senderName, request.getMessage()); + notificationCommandService.sendChat(request.receiverId(), request.roomId(), senderName, request.message()); // 5. [업데이트 포함] 결과 반환 - return MessageHandlingResult.withUpdates(savedDTO, updateDTO, request.getReceiverId()); + return MessageHandlingResult.withUpdates(savedDTO, updateDTO, request.receiverId()); } // 5. [일반 메시지] 결과 반환 @@ -175,18 +172,18 @@ public MessageHandlingResult handleMessage(ChatRequestDTO.ChatMessageRequestDTO @Transactional public ChatResponseDTO.SendMessageResponseDTO sendGuideMessage(ChatRequestDTO.ChatMessageRequestDTO request) { // 유효성 검사 - ChattingRoom room = chatRepository.findById(request.getRoomId()) + ChattingRoom room = chatRepository.findById(request.roomId()) .orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_ROOM)); - Member sender = memberRepository.findById(request.getSenderId()) + Member sender = memberRepository.findById(request.senderId()) .orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_MEMBER)); - Member receiver = memberRepository.findById(request.getReceiverId()) + Member receiver = memberRepository.findById(request.receiverId()) .orElseThrow(() -> new DatabaseException(ErrorStatus.NO_SUCH_MEMBER)); - Message message = ChatConverter.toGuideMessageEntity(request, room, sender, receiver); + Message message = Message.toGuideMessageEntity(request, room, sender, receiver); Message saved = messageRepository.saveAndFlush(message); - ChatResponseDTO.SendMessageResponseDTO responseDTO = ChatConverter.toSendMessageDTO(saved); - simpMessagingTemplate.convertAndSend("/sub/chat/" + request.getRoomId(), responseDTO); + ChatResponseDTO.SendMessageResponseDTO responseDTO = ChatResponseDTO.SendMessageResponseDTO.toSendMessageDTO(saved); + simpMessagingTemplate.convertAndSend("/sub/chat/" + request.roomId(), responseDTO); return responseDTO; } @@ -215,7 +212,7 @@ public ChatResponseDTO.ChatHistoryResponseDTO readHistory(Long roomId, Long memb List allMessages = messageRepository.findAllMessagesByRoomAndMemberId(room.getId(), memberId); - return ChatConverter.toChatHistoryDTO(room.getId(), allMessages); + return ChatResponseDTO.ChatHistoryResponseDTO.toChatHistoryDTO(room.getId(), allMessages); } @Override diff --git a/src/main/java/com/assu/server/domain/partnership/service/PartnershipServiceImpl.java b/src/main/java/com/assu/server/domain/partnership/service/PartnershipServiceImpl.java index 76679a2b..8fabad4b 100644 --- a/src/main/java/com/assu/server/domain/partnership/service/PartnershipServiceImpl.java +++ b/src/main/java/com/assu/server/domain/partnership/service/PartnershipServiceImpl.java @@ -266,8 +266,7 @@ public PartnershipResponseDTO.UpdateResponseDTO updatePartnershipStatus(Long par chattingRoom.getId(), partnerId, adminId, - guideMessage, - 0 + guideMessage ); chatService.sendGuideMessage(guideMessageRequest); notificationService.sendChat(adminId, chattingRoom.getId(), partner.getName(), guideMessage); @@ -278,8 +277,7 @@ public PartnershipResponseDTO.UpdateResponseDTO updatePartnershipStatus(Long par chattingRoom.getId(), adminId, partnerId, - guideMessage, - 0 + guideMessage ); chatService.sendGuideMessage(guideMessageRequest); notificationService.sendChat(partnerId, chattingRoom.getId(), admin.getName(), guideMessage); @@ -407,8 +405,7 @@ public PartnershipResponseDTO.CreateDraftResponseDTO createDraftPartnership(Part chattingRoom.getId(), admin.getId(), partner.getId(), - guideMessage, - 0 + guideMessage ); // 5. 완성된 DTO를 사용해서 안내 메시지를 전송합니다. From 2e82dc53e7b5396e5256fd5e7c546dd57e4e9c7b Mon Sep 17 00:00:00 2001 From: BAEK0111 Date: Thu, 1 Jan 2026 21:30:49 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor/#231=20-=20=EC=B1=84=ED=8C=85=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20imp?= =?UTF-8?q?ort=EB=AC=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/domain/chat/controller/ChatController.java | 8 ++------ .../com/assu/server/domain/chat/dto/BlockRequestDTO.java | 3 --- .../assu/server/domain/chat/dto/BlockResponseDTO.java | 4 ---- .../com/assu/server/domain/chat/dto/ChatMessageDTO.java | 1 + .../com/assu/server/domain/chat/dto/ChatRequestDTO.java | 6 ------ .../com/assu/server/domain/chat/dto/ChatResponseDTO.java | 6 +----- .../server/domain/chat/dto/ChatRoomListResultDTO.java | 5 ----- .../assu/server/domain/chat/dto/ChatRoomUpdateDTO.java | 3 --- .../com/assu/server/domain/chat/entity/ChattingRoom.java | 1 - .../java/com/assu/server/domain/chat/entity/Message.java | 9 +++++---- .../server/domain/chat/service/BlockServiceImpl.java | 1 + .../com/assu/server/domain/chat/service/ChatService.java | 1 - .../assu/server/domain/chat/service/ChatServiceImpl.java | 2 +- 13 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java index cc19fdb1..fef05e7a 100644 --- a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java +++ b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java @@ -1,23 +1,19 @@ package com.assu.server.domain.chat.controller; import com.assu.server.domain.chat.dto.*; -import com.assu.server.domain.chat.repository.MessageRepository; import com.assu.server.domain.chat.service.BlockService; import com.assu.server.domain.chat.service.ChatService; -import com.assu.server.domain.member.repository.MemberRepository; -import com.assu.server.domain.notification.service.NotificationCommandService; +import com.assu.server.global.apiPayload.BaseResponse; import com.assu.server.global.apiPayload.code.status.SuccessStatus; -import com.assu.server.global.util.PresenceTracker; import com.assu.server.global.util.PrincipalDetails; import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; -import com.assu.server.global.apiPayload.BaseResponse; -import org.springframework.messaging.simp.SimpMessagingTemplate; import java.util.List; diff --git a/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java b/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java index 8daa97db..9ff823b2 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java @@ -1,8 +1,5 @@ package com.assu.server.domain.chat.dto; -import lombok.Getter; -import lombok.Setter; - public class BlockRequestDTO { public record BlockMemberRequestDTO( diff --git a/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java b/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java index 93db756c..961ffc84 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java @@ -3,10 +3,6 @@ import com.assu.server.domain.chat.entity.Block; import com.assu.server.domain.common.enums.UserRole; import com.assu.server.domain.member.entity.Member; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; import java.time.LocalDateTime; import java.util.List; diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java index 834f9223..93676fd8 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatMessageDTO.java @@ -3,6 +3,7 @@ import com.assu.server.domain.chat.entity.enums.MessageType; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; + import java.time.LocalDateTime; public record ChatMessageDTO( diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java index 77f2a605..5efc956e 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java @@ -1,11 +1,5 @@ package com.assu.server.domain.chat.dto; -import com.assu.server.domain.chat.entity.enums.MessageType; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; - public class ChatRequestDTO { public record CreateChatRoomRequestDTO( diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java index eef0acfa..d66f6b6a 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java @@ -4,11 +4,7 @@ import com.assu.server.domain.chat.entity.Message; import com.assu.server.domain.chat.entity.enums.MessageType; import com.fasterxml.jackson.annotation.JsonFormat; -import com.google.protobuf.Enum; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; + import java.time.LocalDateTime; import java.util.List; diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java index 6f547287..d161b976 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java @@ -1,10 +1,5 @@ package com.assu.server.domain.chat.dto; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.NoArgsConstructor; - import java.time.LocalDateTime; import java.util.List; import java.util.stream.Collectors; diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java index 24a14263..ce872d84 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java @@ -1,8 +1,5 @@ package com.assu.server.domain.chat.dto; -import lombok.Builder; -import lombok.Getter; - import java.time.LocalDateTime; public record ChatRoomUpdateDTO( diff --git a/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java b/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java index bcec1a05..a2931830 100644 --- a/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java +++ b/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java @@ -4,7 +4,6 @@ import com.assu.server.domain.common.entity.BaseEntity; import com.assu.server.domain.common.enums.ActivationStatus; import com.assu.server.domain.partner.entity.Partner; - import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/src/main/java/com/assu/server/domain/chat/entity/Message.java b/src/main/java/com/assu/server/domain/chat/entity/Message.java index 94193f6f..5faa607d 100644 --- a/src/main/java/com/assu/server/domain/chat/entity/Message.java +++ b/src/main/java/com/assu/server/domain/chat/entity/Message.java @@ -1,13 +1,14 @@ package com.assu.server.domain.chat.entity; import com.assu.server.domain.chat.dto.ChatRequestDTO; -import com.assu.server.domain.member.entity.Member; import com.assu.server.domain.chat.entity.enums.MessageType; - import com.assu.server.domain.common.entity.BaseEntity; - +import com.assu.server.domain.member.entity.Member; import jakarta.persistence.*; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; @Entity @Getter diff --git a/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java b/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java index babd36fa..86b25a38 100644 --- a/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java +++ b/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java @@ -11,6 +11,7 @@ import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; + import java.util.List; @Service diff --git a/src/main/java/com/assu/server/domain/chat/service/ChatService.java b/src/main/java/com/assu/server/domain/chat/service/ChatService.java index 10c84fbb..a2b3fd83 100644 --- a/src/main/java/com/assu/server/domain/chat/service/ChatService.java +++ b/src/main/java/com/assu/server/domain/chat/service/ChatService.java @@ -10,7 +10,6 @@ public interface ChatService { List getChatRoomList(Long memberId); ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.CreateChatRoomRequestDTO request, Long memberId); -// ChatResponseDTO.SendMessageResponseDTO handleMessage(ChatRequestDTO.ChatMessageRequestDTO request); MessageHandlingResult handleMessage(ChatRequestDTO.ChatMessageRequestDTO request); ChatResponseDTO.ReadMessageResponseDTO readMessage(Long roomId, Long memberId); ChatResponseDTO.ChatHistoryResponseDTO readHistory(Long roomId, Long memberId); diff --git a/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java b/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java index adb27cf9..e5844763 100644 --- a/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java +++ b/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java @@ -7,9 +7,9 @@ import com.assu.server.domain.chat.entity.Message; import com.assu.server.domain.chat.repository.ChatRepository; import com.assu.server.domain.chat.repository.MessageRepository; +import com.assu.server.domain.common.enums.ActivationStatus; import com.assu.server.domain.common.enums.UserRole; import com.assu.server.domain.member.entity.Member; -import com.assu.server.domain.common.enums.ActivationStatus; import com.assu.server.domain.member.repository.MemberRepository; import com.assu.server.domain.notification.service.NotificationCommandService; import com.assu.server.domain.partner.entity.Partner; From d7a34fa0b8aa458bbfa3b7cbce1eae63a37fdb96 Mon Sep 17 00:00:00 2001 From: BAEK0111 Date: Sun, 18 Jan 2026 19:42:34 +0900 Subject: [PATCH 5/6] =?UTF-8?q?refactor/#231=20-=20=EC=B1=84=ED=8C=85=20?= =?UTF-8?q?=EB=B8=8C=EB=A1=9C=EC=BB=A4=20=EB=B3=80=EA=B2=BD=20(SimpleMessa?= =?UTF-8?q?geBroker=20->=20Redis=20Pub/Sub)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/CertifyWebSocketConfig.java | 37 ----- .../domain/chat/config/WebSocketConfig.java | 93 ----------- .../chat/controller/ChatController.java | 10 +- .../chat/redis/RedisMessageSubscriber.java | 57 +++++++ .../domain/chat/redis/RedisPublisher.java | 22 +++ .../server/global/config/RedisConfig.java | 19 +++ .../server/global/config/WebSocketConfig.java | 54 +++++++ src/main/resources/redisChattingTest.html | 150 ++++++++++++++++++ 8 files changed, 306 insertions(+), 136 deletions(-) delete mode 100644 src/main/java/com/assu/server/domain/certification/config/CertifyWebSocketConfig.java delete mode 100644 src/main/java/com/assu/server/domain/chat/config/WebSocketConfig.java create mode 100644 src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java create mode 100644 src/main/java/com/assu/server/domain/chat/redis/RedisPublisher.java create mode 100644 src/main/java/com/assu/server/global/config/WebSocketConfig.java create mode 100644 src/main/resources/redisChattingTest.html diff --git a/src/main/java/com/assu/server/domain/certification/config/CertifyWebSocketConfig.java b/src/main/java/com/assu/server/domain/certification/config/CertifyWebSocketConfig.java deleted file mode 100644 index 56da642a..00000000 --- a/src/main/java/com/assu/server/domain/certification/config/CertifyWebSocketConfig.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.assu.server.domain.certification.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.config.ChannelRegistration; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.web.socket.WebSocketHandler; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; - -import lombok.RequiredArgsConstructor; - -// @EnableWebSocketMessageBroker -// @Configuration -// @RequiredArgsConstructor -// public class CertifyWebSocketConfig implements WebSocketMessageBrokerConfigurer { -// -// private final StompAuthChannelInterceptor stompAuthChannelInterceptor; -// @Override -// public void configureMessageBroker(MessageBrokerRegistry config) { -// config.enableSimpleBroker("/certification"); // 인증현황을 받아보기 위한 구독 주소 -// config.setApplicationDestinationPrefixes("/app"); // 클라이언트가 인증 요청을 보내는 주소 -// } -// -// @Override -// public void registerStompEndpoints(StompEndpointRegistry registry) { -// registry.addEndpoint("/ws-certify").setAllowedOriginPatterns("*"); // 클라이언트 WebSocket 연결 주소 -// // .setAllowedOriginPatterns("http://10.0.2.2:8080", "ws://10.0.2.2:8080");// CORS 허용 -// } -// -// @Override -// public void configureClientInboundChannel(ChannelRegistration registration) { -// registration.interceptors(stompAuthChannelInterceptor); -// } -// -// } diff --git a/src/main/java/com/assu/server/domain/chat/config/WebSocketConfig.java b/src/main/java/com/assu/server/domain/chat/config/WebSocketConfig.java deleted file mode 100644 index 8026ce34..00000000 --- a/src/main/java/com/assu/server/domain/chat/config/WebSocketConfig.java +++ /dev/null @@ -1,93 +0,0 @@ -// package com.assu.server.domain.chat.config; -// -// import org.springframework.context.annotation.Configuration; -// import org.springframework.messaging.simp.config.ChannelRegistration; -// import org.springframework.messaging.simp.config.MessageBrokerRegistry; -// import org.springframework.web.socket.config.annotation.*; -// -// @Configuration -// @EnableWebSocketMessageBroker -// public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { -// -// @Override -// public void registerStompEndpoints(StompEndpointRegistry registry) { -// registry.addEndpoint("/ws") // 클라이언트 WebSocket 연결 지점 -// .setAllowedOriginPatterns( -// "*", -// "https://assu.shop", -// "http://localhost:63342", -// "http://localhost:5173", // Vite 기본 -// "http://localhost:3000", // CRA/Next 기본 -// "http://127.0.0.1:*", -// "http://192.168.*.*:*"); // 같은 LAN의 실제 기기 테스트용// fallback for old browsers -// // 같은 LAN의 실제 기기 테스트용 -// // fallback for old browsers -// -// // ✅ 모바일/안드로이드용 (네이티브 WebSocket) -// registry.addEndpoint("/ws") -// .setAllowedOriginPatterns("*"); // wss 사용 시 TLS 세팅 -// } -// -// @Override -// public void configureMessageBroker(MessageBrokerRegistry registry) { -// registry.setApplicationDestinationPrefixes("/pub"); // 클라이언트가 보내는 prefix -// registry.enableSimpleBroker("/sub"); // 서버가 보내는 prefix -// } -// } -package com.assu.server.domain.chat.config; - -import org.springframework.context.annotation.Configuration; -import org.springframework.messaging.simp.config.ChannelRegistration; -import org.springframework.messaging.simp.config.MessageBrokerRegistry; -import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; -import org.springframework.web.socket.config.annotation.StompEndpointRegistry; -import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; - -import com.assu.server.domain.certification.config.StompAuthChannelInterceptor; - -import lombok.RequiredArgsConstructor; - -@Configuration -@EnableWebSocketMessageBroker -@RequiredArgsConstructor -public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { - - private final StompAuthChannelInterceptor stompAuthChannelInterceptor; - - @Override - public void registerStompEndpoints(StompEndpointRegistry registry) { - - registry.addEndpoint("/ws") // 클라이언트 WebSocket 연결 지점 - .setAllowedOriginPatterns( - "*", - "https://assu.shop", - "http://localhost:63342", - "http://localhost:5173", // Vite 기본 - "http://localhost:3000", // CRA/Next 기본 - "http://127.0.0.1:*", - "http://192.168.*.*:*"); - // 채팅용 엔드포인트 - - // 인증용 엔드포인트 - registry.addEndpoint("/ws-certify") - .setAllowedOriginPatterns("*"); - - - } - - @Override - public void configureMessageBroker(MessageBrokerRegistry registry) { - // 채팅용 - registry.setApplicationDestinationPrefixes("/pub"); - registry.enableSimpleBroker("/sub"); - - // 인증용 추가 - registry.setApplicationDestinationPrefixes("/pub", "/app"); // 둘 다 추가 - registry.enableSimpleBroker("/sub", "/certification"); // 둘 다 추가 - } - - @Override - public void configureClientInboundChannel(ChannelRegistration registration) { - registration.interceptors(stompAuthChannelInterceptor); - } -} \ No newline at end of file diff --git a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java index fef05e7a..7243da90 100644 --- a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java +++ b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java @@ -1,6 +1,7 @@ package com.assu.server.domain.chat.controller; import com.assu.server.domain.chat.dto.*; +import com.assu.server.domain.chat.redis.RedisPublisher; import com.assu.server.domain.chat.service.BlockService; import com.assu.server.domain.chat.service.ChatService; import com.assu.server.global.apiPayload.BaseResponse; @@ -25,6 +26,7 @@ public class ChatController { private final ChatService chatService; private final SimpMessagingTemplate simpMessagingTemplate; private final BlockService blockService; + private final RedisPublisher redisPublisher; @Operation( summary = "채팅방을 생성하는 API", @@ -66,14 +68,10 @@ public void handleMessage(@Payload ChatRequestDTO.ChatMessageRequestDTO request) // 1. 서비스 호출 MessageHandlingResult result = chatService.handleMessage(request); // 2. [항상 전송] 채팅방 메시지 전송 - simpMessagingTemplate.convertAndSend("/sub/chat/" + request.roomId(), result.sendMessageResponseDTO()); + redisPublisher.publishChatMessage(request.roomId(), result.sendMessageResponseDTO()); // 3. [조건부 전송] 채팅방 목록 업데이트 전송 if (result.hasRoomUpdates()) { - simpMessagingTemplate.convertAndSendToUser( - result.receiverId().toString(), - "/queue/updates", - result.chatRoomUpdateDTO() - ); + redisPublisher.publishChatRoomUpdate(result.receiverId(), result.chatRoomUpdateDTO()); } } diff --git a/src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java b/src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java new file mode 100644 index 00000000..fa79b38b --- /dev/null +++ b/src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java @@ -0,0 +1,57 @@ +package com.assu.server.domain.chat.redis; + +import com.assu.server.domain.chat.dto.ChatResponseDTO; +import com.assu.server.domain.chat.dto.ChatRoomUpdateDTO; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.connection.Message; +import org.springframework.data.redis.connection.MessageListener; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.messaging.simp.SimpMessagingTemplate; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class RedisMessageSubscriber implements MessageListener { + + private final SimpMessagingTemplate messagingTemplate; + private final RedisTemplate redisTemplate; + private final ObjectMapper objectMapper; + + @Override + public void onMessage(Message message, byte[] pattern) { + try { + // RedisTemplate의 Serializer를 통해 byte[]를 String으로 변환 + String publishMessage = redisTemplate.getStringSerializer().deserialize(message.getBody()); + String channel = redisTemplate.getStringSerializer().deserialize(message.getChannel()); + + if (channel == null || publishMessage == null) return; + + if (channel.startsWith("chat.room.")) { + // 채팅방 메시지 + handleChatMessage(channel, publishMessage); + } else if (channel.startsWith("user.update.")) { + // 채팅 목록 업데이트 + handleUserUpdate(channel, publishMessage); + } + } catch (Exception e) { + log.error("Redis 메시지 처리 실패 {}", e.getMessage()); + } + } + + private void handleChatMessage(String channel, String jsonMessage) throws Exception { + String roomId = channel.substring("chat.room.".length()); + ChatResponseDTO.SendMessageResponseDTO messageDto = + objectMapper.readValue(jsonMessage, ChatResponseDTO.SendMessageResponseDTO.class); + messagingTemplate.convertAndSend("/sub/chat/" + roomId, messageDto); + } + + public void handleUserUpdate(String channel, String jsonMessage) throws Exception { + String userId = channel.substring("user.update.".length()); + ChatRoomUpdateDTO updateDTO = + objectMapper.readValue(jsonMessage, ChatRoomUpdateDTO.class); + messagingTemplate.convertAndSend("/sub/chat/list/" + userId, updateDTO); + } +} diff --git a/src/main/java/com/assu/server/domain/chat/redis/RedisPublisher.java b/src/main/java/com/assu/server/domain/chat/redis/RedisPublisher.java new file mode 100644 index 00000000..5c5931f9 --- /dev/null +++ b/src/main/java/com/assu/server/domain/chat/redis/RedisPublisher.java @@ -0,0 +1,22 @@ +package com.assu.server.domain.chat.redis; + +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class RedisPublisher { + + private final RedisTemplate redisTemplate; + + // 채팅방 메시지 발행 + public void publishChatMessage(Long roomId, Object message) { + redisTemplate.convertAndSend("chat.room." + roomId, message); + } + + // 채팅 목록 업데이트 발행 + public void publishChatRoomUpdate(Long userId, Object updateDto) { + redisTemplate.convertAndSend("user.update." + userId, updateDto); + } +} diff --git a/src/main/java/com/assu/server/global/config/RedisConfig.java b/src/main/java/com/assu/server/global/config/RedisConfig.java index 135c0c87..49c54e39 100644 --- a/src/main/java/com/assu/server/global/config/RedisConfig.java +++ b/src/main/java/com/assu/server/global/config/RedisConfig.java @@ -1,5 +1,6 @@ package com.assu.server.global.config; +import com.assu.server.domain.chat.redis.RedisMessageSubscriber; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @@ -9,11 +10,15 @@ import org.springframework.context.annotation.Profile; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.PatternTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration @RequiredArgsConstructor +@EnableRedisRepositories @Profile("!test") public class RedisConfig { @@ -38,4 +43,18 @@ public RedisTemplate redisTemplate(RedisConnectionFactory redisC return redisTemplate; } + @Bean + public RedisMessageListenerContainer redisMessageListenerContainer( + RedisConnectionFactory redisConnectionFactory, + RedisMessageSubscriber subscriber + ) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(redisConnectionFactory); + + container.addMessageListener(subscriber, new PatternTopic("chat.room.*")); + container.addMessageListener(subscriber, new PatternTopic("user.update.*")); + + return container; + } + } \ No newline at end of file diff --git a/src/main/java/com/assu/server/global/config/WebSocketConfig.java b/src/main/java/com/assu/server/global/config/WebSocketConfig.java new file mode 100644 index 00000000..7e669ccb --- /dev/null +++ b/src/main/java/com/assu/server/global/config/WebSocketConfig.java @@ -0,0 +1,54 @@ +package com.assu.server.global.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.ChannelRegistration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; + +import com.assu.server.domain.certification.config.StompAuthChannelInterceptor; + +import lombok.RequiredArgsConstructor; + +@Configuration +@EnableWebSocketMessageBroker +@RequiredArgsConstructor +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + private final StompAuthChannelInterceptor stompAuthChannelInterceptor; + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + + registry.addEndpoint("/ws") // 클라이언트 WebSocket 연결 지점 + .setAllowedOriginPatterns( + "*", + "https://assu.shop", + "http://localhost:63342", + "http://localhost:5173", // Vite 기본 + "http://localhost:3000", // CRA/Next 기본 + "http://127.0.0.1:*", + "http://192.168.*.*:*"); + // 채팅용 엔드포인트 + + // 인증용 엔드포인트 + registry.addEndpoint("/ws-certify") + .setAllowedOriginPatterns("*"); + + + } + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + // 채팅용 & 인증용 합치기 + registry.enableSimpleBroker("/sub","/queue", "/certification"); + registry.setApplicationDestinationPrefixes("/pub", "/app"); // 둘 다 추가 + registry.setUserDestinationPrefix("/user"); + } + + @Override + public void configureClientInboundChannel(ChannelRegistration registration) { + registration.interceptors(stompAuthChannelInterceptor); + } +} \ No newline at end of file diff --git a/src/main/resources/redisChattingTest.html b/src/main/resources/redisChattingTest.html new file mode 100644 index 00000000..45862ff6 --- /dev/null +++ b/src/main/resources/redisChattingTest.html @@ -0,0 +1,150 @@ + + + + + Redis Pub/Sub 채팅 테스트 + + + + + + +
+
+

🚀 연결 설정

+ + + + + +
+ +

💬 메시지 전송

+ + + + + + + + + + + + + +
+ +
+

📜 실시간 로그

+
+
+
+ + + + \ No newline at end of file From 05e6d25a3aa11eae9bb87b34c84053a5b8cf96a3 Mon Sep 17 00:00:00 2001 From: BAEK0111 Date: Sun, 22 Feb 2026 16:38:19 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor/#231=20-=20=EB=A9=94=EC=86=8C?= =?UTF-8?q?=EB=93=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?-=20RequestDTO=20schema=20=EC=84=A4=EB=AA=85=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20=EA=B0=80=EB=8F=85=EC=84=B1=20=EC=A2=8B?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/controller/ChatController.java | 8 +++---- .../domain/chat/dto/BlockRequestDTO.java | 6 ++++++ .../domain/chat/dto/BlockResponseDTO.java | 10 ++++----- .../domain/chat/dto/ChatRequestDTO.java | 21 +++++++++++++++++++ .../domain/chat/dto/ChatResponseDTO.java | 13 ++++-------- .../chat/dto/ChatRoomListResultDTO.java | 6 +++--- .../domain/chat/dto/ChatRoomUpdateDTO.java | 2 +- .../domain/chat/entity/ChattingRoom.java | 2 +- ...isher.java => ChattingRedisPublisher.java} | 2 +- .../chat/redis/RedisMessageSubscriber.java | 2 +- .../domain/chat/service/BlockServiceImpl.java | 10 ++++----- .../domain/chat/service/ChatServiceImpl.java | 19 +++++++++-------- 12 files changed, 62 insertions(+), 39 deletions(-) rename src/main/java/com/assu/server/domain/chat/redis/{RedisPublisher.java => ChattingRedisPublisher.java} (94%) diff --git a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java index 7243da90..23abe274 100644 --- a/src/main/java/com/assu/server/domain/chat/controller/ChatController.java +++ b/src/main/java/com/assu/server/domain/chat/controller/ChatController.java @@ -1,7 +1,7 @@ package com.assu.server.domain.chat.controller; import com.assu.server.domain.chat.dto.*; -import com.assu.server.domain.chat.redis.RedisPublisher; +import com.assu.server.domain.chat.redis.ChattingRedisPublisher; import com.assu.server.domain.chat.service.BlockService; import com.assu.server.domain.chat.service.ChatService; import com.assu.server.global.apiPayload.BaseResponse; @@ -26,7 +26,7 @@ public class ChatController { private final ChatService chatService; private final SimpMessagingTemplate simpMessagingTemplate; private final BlockService blockService; - private final RedisPublisher redisPublisher; + private final ChattingRedisPublisher chattingRedisPublisher; @Operation( summary = "채팅방을 생성하는 API", @@ -68,10 +68,10 @@ public void handleMessage(@Payload ChatRequestDTO.ChatMessageRequestDTO request) // 1. 서비스 호출 MessageHandlingResult result = chatService.handleMessage(request); // 2. [항상 전송] 채팅방 메시지 전송 - redisPublisher.publishChatMessage(request.roomId(), result.sendMessageResponseDTO()); + chattingRedisPublisher.publishChatMessage(request.roomId(), result.sendMessageResponseDTO()); // 3. [조건부 전송] 채팅방 목록 업데이트 전송 if (result.hasRoomUpdates()) { - redisPublisher.publishChatRoomUpdate(result.receiverId(), result.chatRoomUpdateDTO()); + chattingRedisPublisher.publishChatRoomUpdate(result.receiverId(), result.chatRoomUpdateDTO()); } } diff --git a/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java b/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java index 9ff823b2..2de91f52 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/BlockRequestDTO.java @@ -1,8 +1,14 @@ package com.assu.server.domain.chat.dto; +import io.swagger.v3.oas.annotations.media.Schema; +import org.jetbrains.annotations.NotNull; + public class BlockRequestDTO { + @Schema(description = "채팅 차단 DTO") public record BlockMemberRequestDTO( + @Schema(description = "차단할 사용자 ID", example = "12") + @NotNull Long opponentId ) {} } diff --git a/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java b/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java index 961ffc84..cdf8b2c7 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/BlockResponseDTO.java @@ -15,7 +15,7 @@ public record BlockMemberDTO ( String name, LocalDateTime blockDate ) { - public static BlockMemberDTO toBlockDTO( + public static BlockMemberDTO of( Long blockedId, String blockedName ) { @@ -26,7 +26,7 @@ public static BlockMemberDTO toBlockDTO( ); } - public static BlockMemberDTO toBlockedMemberDTO( + public static BlockMemberDTO from( Block block ) { Member blockedMember = block.getBlocked(); @@ -45,11 +45,11 @@ public static BlockMemberDTO toBlockedMemberDTO( ); } - public static List toBlockedMemberListDTO( + public static List fromList( List blockList ) { return blockList.stream() - .map(BlockResponseDTO.BlockMemberDTO::toBlockedMemberDTO) + .map(BlockResponseDTO.BlockMemberDTO::from) .collect(Collectors.toList()); } @@ -61,7 +61,7 @@ public record CheckBlockMemberDTO ( String name, boolean blocked ) { - public static CheckBlockMemberDTO toCheckBlockDTO( + public static CheckBlockMemberDTO of( Long blockedId, String blockedName, boolean blocked diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java index 5efc956e..c7ff3998 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRequestDTO.java @@ -1,16 +1,37 @@ package com.assu.server.domain.chat.dto; +import io.swagger.v3.oas.annotations.media.Schema; +import org.jetbrains.annotations.NotNull; + public class ChatRequestDTO { + @Schema(description = "채팅방 생성 요청 DTO") public record CreateChatRoomRequestDTO( + @Schema(description = "사장님 id", example = "2") + @NotNull Long adminId, + + @Schema(description = "파트너 id", example = "12") + @NotNull Long partnerId ) {} + @Schema(description = "채팅 메시지 요청 DTO") public record ChatMessageRequestDTO( + @Schema(description = "채팅방 id", example = "1") + @NotNull Long roomId, + + @Schema(description = "보내는 사람 id", example = "12") + @NotNull Long senderId, + + @Schema(description = "받는 사람 id", example = "2") + @NotNull Long receiverId, + + @Schema(description = "메시지 내용", example = "안녕하세요") + @NotNull String message ) {} diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java index d66f6b6a..adfe5284 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatResponseDTO.java @@ -17,7 +17,7 @@ public record CreateChatRoomResponseDTO( String partnerViewName, Boolean isNew ) { - public static CreateChatRoomResponseDTO toCreateChatRoomIdDTO(ChattingRoom room) { + public static CreateChatRoomResponseDTO fromNewRoom(ChattingRoom room) { return new CreateChatRoomResponseDTO( room.getId(), room.getPartner().getName(), @@ -25,7 +25,7 @@ public static CreateChatRoomResponseDTO toCreateChatRoomIdDTO(ChattingRoom room) true ); } - public static CreateChatRoomResponseDTO toEnterChatRoomDTO(ChattingRoom room) { + public static CreateChatRoomResponseDTO fromExistingRoom(ChattingRoom room) { return new CreateChatRoomResponseDTO( room.getId(), room.getPartner().getName(), @@ -47,13 +47,8 @@ public record SendMessageResponseDTO( LocalDateTime sentAt, Integer unreadCountForSender ) { - public SendMessageResponseDTO withUnreadCountForSender(Integer count) { - return new SendMessageResponseDTO( - messageId, roomId, senderId, receiverId, message, messageType, sentAt, count - ); - } - public static SendMessageResponseDTO toSendMessageDTO( + public static SendMessageResponseDTO from( Message message ) { return new SendMessageResponseDTO( @@ -85,7 +80,7 @@ public record ChatHistoryResponseDTO( Long roomId, List messages ) { - public static ChatHistoryResponseDTO toChatHistoryDTO( + public static ChatHistoryResponseDTO of( Long roomId, List messages) { return new ChatHistoryResponseDTO( diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java index d161b976..4eb7a5f6 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomListResultDTO.java @@ -16,7 +16,7 @@ public record ChatRoomListResultDTO( ) { // 채팅방 리스트 아이템 하나 - public static ChatRoomListResultDTO toChatRoomResultDTO( + public static ChatRoomListResultDTO of( ChatRoomListResultDTO dto ) { return new ChatRoomListResultDTO( @@ -32,11 +32,11 @@ public static ChatRoomListResultDTO toChatRoomResultDTO( } // 채팅방 리스트 변환 - public static List toChatRoomListResultDTO ( + public static List ofList( List dto ) { return dto.stream() - .map(ChatRoomListResultDTO::toChatRoomResultDTO) + .map(ChatRoomListResultDTO::of) .collect(Collectors.toList()); } } diff --git a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java index ce872d84..45eb6eec 100644 --- a/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java +++ b/src/main/java/com/assu/server/domain/chat/dto/ChatRoomUpdateDTO.java @@ -8,7 +8,7 @@ public record ChatRoomUpdateDTO( LocalDateTime lastMessageTime, Long unreadCount // 해당 채팅방의 총 안읽은 메시지 수 ) { - public static ChatRoomUpdateDTO toChatRoomUpdateDTO( + public static ChatRoomUpdateDTO of( Long roomId, String lastMessage, LocalDateTime lastMessageTime, diff --git a/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java b/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java index a2931830..e4b102da 100644 --- a/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java +++ b/src/main/java/com/assu/server/domain/chat/entity/ChattingRoom.java @@ -64,7 +64,7 @@ public void setPartner(Partner partner) { this.partner = partner; } - public static ChattingRoom toCreateChattingRoom(Admin admin, Partner partner) { + public static ChattingRoom of(Admin admin, Partner partner) { return ChattingRoom.builder() .admin(admin) .partner(partner) diff --git a/src/main/java/com/assu/server/domain/chat/redis/RedisPublisher.java b/src/main/java/com/assu/server/domain/chat/redis/ChattingRedisPublisher.java similarity index 94% rename from src/main/java/com/assu/server/domain/chat/redis/RedisPublisher.java rename to src/main/java/com/assu/server/domain/chat/redis/ChattingRedisPublisher.java index 5c5931f9..4725be4c 100644 --- a/src/main/java/com/assu/server/domain/chat/redis/RedisPublisher.java +++ b/src/main/java/com/assu/server/domain/chat/redis/ChattingRedisPublisher.java @@ -6,7 +6,7 @@ @Service @RequiredArgsConstructor -public class RedisPublisher { +public class ChattingRedisPublisher { private final RedisTemplate redisTemplate; diff --git a/src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java b/src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java index fa79b38b..d51fba2e 100644 --- a/src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java +++ b/src/main/java/com/assu/server/domain/chat/redis/RedisMessageSubscriber.java @@ -48,7 +48,7 @@ private void handleChatMessage(String channel, String jsonMessage) throws Except messagingTemplate.convertAndSend("/sub/chat/" + roomId, messageDto); } - public void handleUserUpdate(String channel, String jsonMessage) throws Exception { + private void handleUserUpdate(String channel, String jsonMessage) throws Exception { String userId = channel.substring("user.update.".length()); ChatRoomUpdateDTO updateDTO = objectMapper.readValue(jsonMessage, ChatRoomUpdateDTO.class); diff --git a/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java b/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java index 86b25a38..3150f8d4 100644 --- a/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java +++ b/src/main/java/com/assu/server/domain/chat/service/BlockServiceImpl.java @@ -56,7 +56,7 @@ public BlockResponseDTO.BlockMemberDTO blockMember(Long blockerId, Long blockedI blockRepository.save(block); - return BlockResponseDTO.BlockMemberDTO.toBlockDTO(blockedId, blockedName); + return BlockResponseDTO.BlockMemberDTO.of(blockedId, blockedName); } @Override @@ -78,10 +78,10 @@ public BlockResponseDTO.CheckBlockMemberDTO checkBlock(Long blockerId, Long bloc } if (blockRepository.existsBlockRelationBetween(blocker, blocked)) { - return BlockResponseDTO.CheckBlockMemberDTO.toCheckBlockDTO(blockedId, blockedName, true); + return BlockResponseDTO.CheckBlockMemberDTO.of(blockedId, blockedName, true); } else { - return BlockResponseDTO.CheckBlockMemberDTO.toCheckBlockDTO(blockedId, blockedName, false); + return BlockResponseDTO.CheckBlockMemberDTO.of(blockedId, blockedName, false); } } @@ -105,7 +105,7 @@ public BlockResponseDTO.BlockMemberDTO unblockMember(Long blockerId, Long blocke // Transactional 환경에서는 Dirty-checking으로 delete 쿼리가 나갑니다. blockRepository.deleteByBlockerAndBlocked(blocker, blocked); - return BlockResponseDTO.BlockMemberDTO.toBlockDTO(blockedId, blockedName); + return BlockResponseDTO.BlockMemberDTO.of(blockedId, blockedName); } @Transactional @@ -116,6 +116,6 @@ public List getMyBlockList(Long blockerId) { List blockList = blockRepository.findByBlocker(blocker); - return BlockResponseDTO.BlockMemberDTO.toBlockedMemberListDTO(blockList); + return BlockResponseDTO.BlockMemberDTO.fromList(blockList); } } diff --git a/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java b/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java index e5844763..df4d52da 100644 --- a/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java +++ b/src/main/java/com/assu/server/domain/chat/service/ChatServiceImpl.java @@ -47,7 +47,7 @@ public class ChatServiceImpl implements ChatService { public List getChatRoomList(Long memberId) { List chatRoomList = chatRepository.findChattingRoomsByMemberId(memberId); - return ChatRoomListResultDTO.toChatRoomListResultDTO(chatRoomList); + return ChatRoomListResultDTO.ofList(chatRoomList); } @Override @@ -71,7 +71,7 @@ public ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.C boolean isExist = chatRepository.checkChattingRoomByAdminIdAndPartnerId(admin.getId(), partner.getId()); if(!isExist) { - ChattingRoom room = ChattingRoom.toCreateChattingRoom(admin, partner); + ChattingRoom room = ChattingRoom.of(admin, partner); room.updateStatus(ActivationStatus.ACTIVE); @@ -82,10 +82,10 @@ public ChatResponseDTO.CreateChatRoomResponseDTO createChatRoom(ChatRequestDTO.C admin.getName() ); ChattingRoom savedRoom = chatRepository.save(room); - return ChatResponseDTO.CreateChatRoomResponseDTO.toCreateChatRoomIdDTO(savedRoom); + return ChatResponseDTO.CreateChatRoomResponseDTO.fromNewRoom(savedRoom); } else { ChattingRoom existChatRoom = chatRepository.findChattingRoomByAdminIdAndPartnerId(admin.getId(), partner.getId()); - return ChatResponseDTO.CreateChatRoomResponseDTO.toEnterChatRoomDTO(existChatRoom); + return ChatResponseDTO.CreateChatRoomResponseDTO.fromExistingRoom(existChatRoom); } } @@ -131,7 +131,7 @@ public MessageHandlingResult handleMessage(ChatRequestDTO.ChatMessageRequestDTO log.info("saved message id={}, roomId={}, senderId={}, receiverId={}", saved.getId(), room.getId(), sender.getId(), receiver.getId()); - ChatResponseDTO.SendMessageResponseDTO savedDTO = ChatResponseDTO.SendMessageResponseDTO.toSendMessageDTO(saved); + ChatResponseDTO.SendMessageResponseDTO savedDTO = ChatResponseDTO.SendMessageResponseDTO.from(saved); // 4. 컨트롤러에서 가져온 비즈니스 로직 (수신자 부재 시) if (!receiverInRoom) { @@ -142,11 +142,12 @@ public MessageHandlingResult handleMessage(ChatRequestDTO.ChatMessageRequestDTO ); // 4-2. 채팅방 목록 업데이트 DTO 생성 - ChatRoomUpdateDTO updateDTO = ChatRoomUpdateDTO.toChatRoomUpdateDTO( + ChatRoomUpdateDTO updateDTO = ChatRoomUpdateDTO.of( request.roomId(), savedDTO.message(), savedDTO.sentAt(), - totalUnreadCount); + totalUnreadCount + ); // 4-3. 발신자 이름 찾기 (기존 컨트롤러 로직) String senderName; @@ -182,7 +183,7 @@ public ChatResponseDTO.SendMessageResponseDTO sendGuideMessage(ChatRequestDTO.Ch Message message = Message.toGuideMessageEntity(request, room, sender, receiver); Message saved = messageRepository.saveAndFlush(message); - ChatResponseDTO.SendMessageResponseDTO responseDTO = ChatResponseDTO.SendMessageResponseDTO.toSendMessageDTO(saved); + ChatResponseDTO.SendMessageResponseDTO responseDTO = ChatResponseDTO.SendMessageResponseDTO.from(saved); simpMessagingTemplate.convertAndSend("/sub/chat/" + request.roomId(), responseDTO); return responseDTO; @@ -212,7 +213,7 @@ public ChatResponseDTO.ChatHistoryResponseDTO readHistory(Long roomId, Long memb List allMessages = messageRepository.findAllMessagesByRoomAndMemberId(room.getId(), memberId); - return ChatResponseDTO.ChatHistoryResponseDTO.toChatHistoryDTO(room.getId(), allMessages); + return ChatResponseDTO.ChatHistoryResponseDTO.of(room.getId(), allMessages); } @Override