Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

채팅 메세지 송/수신 API 구현 #62

Merged
merged 13 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.webjars:stomp-websocket:2.3.3-1'
implementation 'org.webjars:sockjs-client:1.1.2'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'com.mysql:mysql-connector-j'
compileOnly 'org.projectlombok:lombok'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package kr.co.fastcampus.yanabada.common.config;

import org.springframework.context.annotation.Configuration;
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;

@Configuration
@EnableWebSocketMessageBroker
public class WebSockConfig implements WebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/sub");
config.setApplicationDestinationPrefixes("/pub");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-stomp").setAllowedOrigins("*").withSockJS();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;
import kr.co.fastcampus.yanabada.common.response.ResponseBody;
import kr.co.fastcampus.yanabada.domain.chat.dto.ReceivedChatMessage;
import kr.co.fastcampus.yanabada.domain.chat.dto.request.ChatRoomModifyRequest;
import kr.co.fastcampus.yanabada.domain.chat.dto.request.ChatRoomSaveRequest;
import kr.co.fastcampus.yanabada.domain.chat.dto.response.ChatMessageInfoResponse;
Expand All @@ -10,6 +11,8 @@
import kr.co.fastcampus.yanabada.domain.chat.dto.response.ChatRoomSummaryResponse;
import kr.co.fastcampus.yanabada.domain.chat.service.ChatService;
import lombok.RequiredArgsConstructor;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -26,6 +29,15 @@ public class ChatController {

private final ChatService chatService;

private final SimpMessagingTemplate messagingTemplate;

@MessageMapping("/message")
public void message(ReceivedChatMessage message) {
messagingTemplate.convertAndSend(
"/sub/chatroom/" + message.chatRoomCode(), chatService.saveChatMessage(message)
Programmer-may marked this conversation as resolved.
Show resolved Hide resolved
);
}

@PostMapping
public ResponseBody<ChatRoomInfoResponse> getOrAddChatRoom(
@RequestBody ChatRoomSaveRequest request
Expand All @@ -35,7 +47,6 @@ public ResponseBody<ChatRoomInfoResponse> getOrAddChatRoom(

@GetMapping
public ResponseBody<List<ChatRoomSummaryResponse>> getChatRooms(
//Principal 을 통해 로그인한 멤버 id를 가져올 예정
) {
Long memberId = 1L;
return ResponseBody.ok(chatService.getChatRooms(memberId));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package kr.co.fastcampus.yanabada.domain.chat.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Positive;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import kr.co.fastcampus.yanabada.domain.chat.entity.ChatMessage;
import kr.co.fastcampus.yanabada.domain.chat.entity.ChatRoom;
import kr.co.fastcampus.yanabada.domain.member.entity.Member;

public record ReceivedChatMessage(
@Size(min = 18, max = 18, message = "유효하지 않은 채팅방 코드입니다.")
@Pattern(regexp = "^[0-9a-f]+$", message = "유효하지 않은 채팅방 코드입니다.")
Programmer-may marked this conversation as resolved.
Show resolved Hide resolved
String chatRoomCode,
@NotNull(message = "전송자 ID는 필수로 입력하셔야 합니다.")
@Positive(message = "전송자 ID는 양수이어야 합니다.")
Long sendId,
@NotBlank(message = "메세지 내용이 없습니다.")
@Size(max = 255, message = "메세지 내용은 255자를 넘을 수 없습니다.")
String content
) {

public ChatMessage toEntity(
ChatRoom chatRoom,
Member sender,
LocalDateTime sendDateTime
) {
return ChatMessage.create(
chatRoom,
sender,
content,
sendDateTime
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package kr.co.fastcampus.yanabada.domain.chat.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import kr.co.fastcampus.yanabada.domain.chat.entity.ChatRoom;
import kr.co.fastcampus.yanabada.domain.member.entity.Member;
import lombok.Builder;

@Builder
public record SendChatMessage(
String chatRoomCode,
Long sendId,
String senderNickname,
String senderProfileImage,
String content,
@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
LocalDateTime sendTime
) {

public static SendChatMessage from(
ChatRoom chatRoom,
Member sender,
String content,
LocalDateTime sendTime
) {
return SendChatMessage.builder()
.chatRoomCode(chatRoom.getCode())
.sendId(sender.getId())
.senderNickname(sender.getNickName())
.senderProfileImage(sender.getImageUrl())
.content(content)
.sendTime(sendTime)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public record ChatMessageInfoResponse(
LocalDateTime sendDateTime
) {

public static ChatMessageInfoResponse create(
public static ChatMessageInfoResponse from(
Member sender, String content, LocalDateTime sendDateTime
) {
return ChatMessageInfoResponse.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public record ChatRoomModifyResponse(
Long updatedMemberId
) {

public static ChatRoomModifyResponse create(String chatRoomCode, Long updatedMemberId) {
public static ChatRoomModifyResponse from(String chatRoomCode, Long updatedMemberId) {
return ChatRoomModifyResponse.builder()
.chatRoomCode(chatRoomCode)
.updatedMemberId(updatedMemberId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public record ChatRoomSummaryResponse(
Integer unreadMessageCount
) {

public static ChatRoomSummaryResponse create(
public static ChatRoomSummaryResponse from(
String chatRoomCode,
Member partner,
ChatMessage message,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import kr.co.fastcampus.yanabada.common.exception.CannotNegotiateOwnProductException;
import kr.co.fastcampus.yanabada.common.exception.IncorrectChatRoomMember;
import kr.co.fastcampus.yanabada.common.exception.NegotiationNotPossibleException;
import kr.co.fastcampus.yanabada.domain.chat.dto.ReceivedChatMessage;
import kr.co.fastcampus.yanabada.domain.chat.dto.SendChatMessage;
import kr.co.fastcampus.yanabada.domain.chat.dto.request.ChatRoomModifyRequest;
import kr.co.fastcampus.yanabada.domain.chat.dto.request.ChatRoomSaveRequest;
import kr.co.fastcampus.yanabada.domain.chat.dto.response.ChatMessageInfoResponse;
Expand Down Expand Up @@ -113,7 +116,7 @@ private ChatRoomSummaryResponse createChatRoomSummaryResponse(
List<ChatMessage> messages,
int unreadCount
) {
return ChatRoomSummaryResponse.create(
return ChatRoomSummaryResponse.from(
chatRoom.getCode(),
partner,
messages.get(messages.size() - 1),
Expand Down Expand Up @@ -153,7 +156,7 @@ public List<ChatMessageInfoResponse> getChatRoomMessages(Long memberId, String c
Member member = memberRepository.getMember(memberId);
checkChatRoomMember(chatRoom, member);
return chatRoom.getMessages().stream()
.map(message -> ChatMessageInfoResponse.create(
.map(message -> ChatMessageInfoResponse.from(
message.getSender(), message.getContent(), message.getSendDateTime()
))
.toList();
Expand All @@ -170,7 +173,7 @@ public ChatRoomModifyResponse updateChatRoom(Long memberId, ChatRoomModifyReques
ChatRoom chatRoom = chatRoomRepository.getChatroom(request.chatRoomCode());
Member member = memberRepository.getMember(memberId);
updateLastCheckTime(chatRoom, member);
return ChatRoomModifyResponse.create(chatRoom.getCode(), memberId);
return ChatRoomModifyResponse.from(chatRoom.getCode(), memberId);
}

private void updateLastCheckTime(ChatRoom chatRoom, Member member) {
Expand All @@ -196,13 +199,17 @@ public ChatRoomModifyResponse modifyOrDeleteChatRoom(
} else {
handleBuyerAction(chatRoom);
}
return ChatRoomModifyResponse.create(chatRoom.getCode(), memberId);
return ChatRoomModifyResponse.from(chatRoom.getCode(), memberId);
}

private boolean isSeller(Member member, ChatRoom chatRoom) {
return member.equals(chatRoom.getSeller());
}

private boolean isBuyer(Member member, ChatRoom chatRoom) {
return member.equals(chatRoom.getBuyer());
}

private void handleSellerAction(ChatRoom chatRoom) {
if (chatRoom.getHasBuyerLeft()) {
chatRoomRepository.delete(chatRoom);
Expand All @@ -218,4 +225,35 @@ private void handleBuyerAction(ChatRoom chatRoom) {
chatRoom.updateHasBuyerLeft(true);
}
}

@Transactional
public SendChatMessage saveChatMessage(ReceivedChatMessage message) {
ChatRoom chatRoom = chatRoomRepository.getChatroom(message.chatRoomCode());
Member sender = memberRepository.getMember(message.sendId());
LocalDateTime sendTime = LocalDateTime.now();
checkChatRoomMember(chatRoom, sender);
updateMemberPresenceStatus(chatRoom, sender);
addMessageToChatRoom(chatRoom, message, sender, sendTime);
return createSendChatMessage(chatRoom, sender, message, sendTime);
}

private void addMessageToChatRoom(
ChatRoom chatRoom, ReceivedChatMessage message, Member sender, LocalDateTime sendTime
) {
chatRoom.addChatMessage(message.toEntity(chatRoom, sender, sendTime));
}

private void updateMemberPresenceStatus(ChatRoom chatRoom, Member sender) {
if (isSeller(sender, chatRoom) && chatRoom.getHasSellerLeft()) {
chatRoom.updateHasSellerLeft(false);
} else if (isBuyer(sender, chatRoom) && chatRoom.getHasBuyerLeft()) {
chatRoom.updateHasBuyerLeft(false);
}
}

private SendChatMessage createSendChatMessage(
ChatRoom chatRoom, Member sender, ReceivedChatMessage message, LocalDateTime sendTime
) {
return SendChatMessage.from(chatRoom, sender, message.content(), sendTime);
}
}
Loading