diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java index f06c5bc53..919afb5cd 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/MessageService.java @@ -36,34 +36,69 @@ public class MessageService { @Transactional public Long create(final CreateMessageDto dto, final String profileImageAbsoluteUrl) { final ChatRoom chatRoom = chatRoomRepository.findById(dto.chatRoomId()) - .orElseThrow(() -> new ChatRoomNotFoundException( - "지정한 아이디에 대한 채팅방을 찾을 수 없습니다.")); + .orElseThrow(() -> new ChatRoomNotFoundException( + "지정한 아이디에 대한 채팅방을 찾을 수 없습니다." + )); + final Message persistMessage = psersistMessage(dto, chatRoom); + messageNotificationEventPublisher.publishEvent(new MessageNotificationEvent( + persistMessage, + profileImageAbsoluteUrl + )); + + return persistMessage.getId(); + } + + @Transactional + public ReadMessageDto create(final CreateMessageDto dto) { + final ChatRoom chatRoom = chatRoomRepository.findById(dto.chatRoomId()) + .orElseThrow(() -> new ChatRoomNotFoundException( + "지정한 아이디에 대한 채팅방을 찾을 수 없습니다." + )); + final Message message = psersistMessage(dto, chatRoom); + + return ReadMessageDto.of(message, chatRoom); + } + + private Message psersistMessage(final CreateMessageDto dto, final ChatRoom chatRoom) { final User writer = userRepository.findByIdWithProfileImage(dto.writerId()) - .orElseThrow(() -> new UserNotFoundException( - "지정한 아이디에 대한 발신자를 찾을 수 없습니다.")); + .orElseThrow(() -> new UserNotFoundException( + "지정한 아이디에 대한 발신자를 찾을 수 없습니다." + )); final User receiver = userRepository.findById(dto.receiverId()) - .orElseThrow(() -> new UserNotFoundException( - "지정한 아이디에 대한 수신자를 찾을 수 없습니다.")); + .orElseThrow(() -> new UserNotFoundException( + "지정한 아이디에 대한 수신자를 찾을 수 없습니다." + )); + validateReceiver(chatRoom, receiver); + + final Message message = dto.toEntity(chatRoom, writer, receiver); + + return messageRepository.save(message); + } + private void validateReceiver(final ChatRoom chatRoom, final User receiver) { if (!chatRoom.isChatAvailablePartner(receiver)) { throw new UnableToChatException("탈퇴한 사용자에게는 메시지 전송이 불가능합니다."); } + } - final Message message = dto.toEntity(chatRoom, writer, receiver); - - final Message persistMessage = messageRepository.save(message); - - messageNotificationEventPublisher.publishEvent(new MessageNotificationEvent(persistMessage, profileImageAbsoluteUrl)); + @Transactional + public ReadMessageDto createWithNotification(final CreateMessageDto dto, final String profileImageAbsoluteUrl) { + final ChatRoom chatRoom = chatRoomRepository.findById(dto.chatRoomId()) + .orElseThrow(() -> new ChatRoomNotFoundException( + "지정한 아이디에 대한 채팅방을 찾을 수 없습니다." + )); + final Message message = psersistMessage(dto, chatRoom); + messageNotificationEventPublisher.publishEvent(new MessageNotificationEvent(message, profileImageAbsoluteUrl)); - return persistMessage.getId(); + return ReadMessageDto.of(message, chatRoom); } public List readAllByLastMessageId(final ReadMessageRequest request) { final User reader = userRepository.findById(request.messageReaderId()) - .orElseThrow(() -> new UserNotFoundException("지정한 아이디에 대한 사용자를 찾을 수 없습니다.")); + .orElseThrow(() -> new UserNotFoundException("지정한 아이디에 대한 사용자를 찾을 수 없습니다.")); final ChatRoom chatRoom = chatRoomRepository.findById(request.chatRoomId()) - .orElseThrow(() -> new ChatRoomNotFoundException( - "지정한 아이디에 대한 채팅방을 찾을 수 없습니다.")); + .orElseThrow(() -> new ChatRoomNotFoundException( + "지정한 아이디에 대한 채팅방을 찾을 수 없습니다.")); if (request.lastMessageId() != null) { validateLastMessageId(request.lastMessageId()); @@ -82,8 +117,8 @@ public List readAllByLastMessageId(final ReadMessageRequest requ } return readMessages.stream() - .map(message -> ReadMessageDto.from(message, chatRoom)) - .toList(); + .map(message -> ReadMessageDto.of(message, chatRoom)) + .toList(); } private void validateLastMessageId(final Long lastMessageId) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadMessageDto.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadMessageDto.java index c6050ec9b..a198011e5 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadMessageDto.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/application/dto/ReadMessageDto.java @@ -14,7 +14,7 @@ public record ReadMessageDto( String contents ) { - public static ReadMessageDto from( + public static ReadMessageDto of( final Message message, final ChatRoom chatRoom ) { diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketChatSessions.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketChatSessions.java index 1817e9060..a98583c56 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketChatSessions.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketChatSessions.java @@ -5,6 +5,7 @@ import org.springframework.web.socket.WebSocketSession; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @Component @@ -27,6 +28,18 @@ public void add(final WebSocketSession session, final Long chatRoomId) { } } + public Set getSessionsByChatRoomId(final Long chatRoomId) { + final WebSocketSessions webSocketSessions = chatRoomSessions.get(chatRoomId); + + return webSocketSessions.getSessions(); + } + + public boolean containsByUserId(final Long chatRoomId, final Long userId) { + final WebSocketSessions webSocketSessions = chatRoomSessions.get(chatRoomId); + + return webSocketSessions.contains(userId); + } + public void remove(final WebSocketSession session) { final long chatRoomId = Long.parseLong(String.valueOf(session.getAttributes().get(ATTRIBUTE_KEY))); final WebSocketSessions webSocketSessions = chatRoomSessions.get(chatRoomId); diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketSessions.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketSessions.java index 42ada0659..56883c2c1 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketSessions.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/domain/WebSocketSessions.java @@ -27,4 +27,9 @@ public void remove(final WebSocketSession session) { public boolean containsValue(final WebSocketSession session) { return sessions.contains(session); } + + public boolean contains(final Long userId) { + return sessions.stream() + .anyMatch(session -> session.getAttributes().get("userId") == userId); + } } diff --git a/backend/ddang/src/main/java/com/ddang/ddang/chat/handler/ChatWebSocketHandleTextMessageProvider.java b/backend/ddang/src/main/java/com/ddang/ddang/chat/handler/ChatWebSocketHandleTextMessageProvider.java index 36f43f139..c5cb2371e 100644 --- a/backend/ddang/src/main/java/com/ddang/ddang/chat/handler/ChatWebSocketHandleTextMessageProvider.java +++ b/backend/ddang/src/main/java/com/ddang/ddang/chat/handler/ChatWebSocketHandleTextMessageProvider.java @@ -2,8 +2,8 @@ import com.ddang.ddang.chat.application.MessageService; import com.ddang.ddang.chat.application.dto.CreateMessageDto; +import com.ddang.ddang.chat.application.dto.ReadMessageDto; import com.ddang.ddang.chat.domain.WebSocketChatSessions; -import com.ddang.ddang.chat.domain.WebSocketSessions; import com.ddang.ddang.chat.handler.dto.ChatMessageDataDto; import com.ddang.ddang.chat.presentation.dto.request.CreateMessageRequest; import com.ddang.ddang.chat.presentation.dto.response.ReadMessageResponse; @@ -11,13 +11,13 @@ import com.ddang.ddang.websocket.handler.dto.SendMessagesDto; import com.ddang.ddang.websocket.handler.dto.SessionAttributeDto; import com.ddang.ddang.websocket.handler.dto.TextMessageType; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -37,31 +37,30 @@ public TextMessageType supportTextMessageType() { } @Override - public List handle(final WebSocketSession session, final Map data) throws Exception { + public List handle( + final WebSocketSession session, + final Map data + ) throws Exception { final SessionAttributeDto sessionAttribute = getSessionAttributes(session); final ChatMessageDataDto messageData = objectMapper.convertValue(data, ChatMessageDataDto.class); sessions.add(session, messageData.chatRoomId()); final Long senderId = sessionAttribute.userId(); final CreateMessageDto createMessageDto = createMessageDto(messageData, senderId); + final ReadMessageDto messageDto = createMessageDto(createMessageDto, sessionAttribute); - final Long messageId = messageService.create(createMessageDto, sessionAttribute.baseUrl()); - final Map chatRoomSessions = sessions.getChatRoomSessions(); - final WebSocketSessions webSocketSessions = chatRoomSessions.get(messageData.chatRoomId()); - final Set groupSessions = webSocketSessions.getSessions(); - final List sendMessagesDtos = new ArrayList<>(); - for (WebSocketSession currentSession : groupSessions) { - ReadMessageResponse response; - if (currentSession.getAttributes().get("userId") == senderId) { - response = new ReadMessageResponse(messageId, LocalDateTime.now(), true, messageData.contents()); - } else { - response = new ReadMessageResponse(messageId, LocalDateTime.now(), false, messageData.contents()); - } - final TextMessage textMessage = new TextMessage(objectMapper.writeValueAsString(response)); - sendMessagesDtos.add(new SendMessagesDto(session, textMessage)); + return createSendMessages(session, messageDto, senderId); + } + + private ReadMessageDto createMessageDto( + final CreateMessageDto createMessageDto, + final SessionAttributeDto sessionAttribute + ) { + if (sessions.containsByUserId(createMessageDto.chatRoomId(), createMessageDto.receiverId())) { + return messageService.create(createMessageDto); } - return sendMessagesDtos; + return messageService.createWithNotification(createMessageDto, sessionAttribute.baseUrl()); } private SessionAttributeDto getSessionAttributes(final WebSocketSession session) { @@ -79,6 +78,41 @@ private CreateMessageDto createMessageDto(final ChatMessageDataDto messageData, return CreateMessageDto.of(userId, messageData.chatRoomId(), request); } + private List createSendMessages( + final WebSocketSession session, + final ReadMessageDto messageDto, + final Long senderId + ) throws JsonProcessingException { + final Set groupSessions = sessions.getSessionsByChatRoomId(messageDto.chatRoomId()); + + final List sendMessagesDtos = new ArrayList<>(); + for (WebSocketSession currentSession : groupSessions) { + final TextMessage textMessage = createTextMessage(messageDto, senderId, currentSession); + sendMessagesDtos.add(new SendMessagesDto(session, textMessage)); + } + + return sendMessagesDtos; + } + + private TextMessage createTextMessage( + final ReadMessageDto messageDto, + final Long senderId, + final WebSocketSession session + ) throws JsonProcessingException { + final ReadMessageResponse response = ReadMessageResponse.of( + messageDto, + isMyMessage(session, senderId) + ); + + return new TextMessage(objectMapper.writeValueAsString(response)); + } + + private boolean isMyMessage(final WebSocketSession session, final Long senderId) { + final long userId = Long.parseLong(String.valueOf(session.getAttributes().get("userId"))); + + return senderId.equals(userId); + } + @Override public void remove(final WebSocketSession session) { sessions.remove(session);