diff --git a/src/main/java/capstone/facefriend/chat/config/ChatConfig.java b/src/main/java/capstone/facefriend/chat/config/ChatConfig.java index d54818d4ba..b9cde28468 100644 --- a/src/main/java/capstone/facefriend/chat/config/ChatConfig.java +++ b/src/main/java/capstone/facefriend/chat/config/ChatConfig.java @@ -1,6 +1,9 @@ package capstone.facefriend.chat.config; +import capstone.facefriend.chat.controller.interceptor.FilterChannelInterceptor; +import org.springframework.beans.factory.annotation.Autowired; 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.EnableWebSocket; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; @@ -12,6 +15,13 @@ @EnableWebSocketMessageBroker public class ChatConfig implements WebSocketMessageBrokerConfigurer { + @Autowired + private FilterChannelInterceptor filterChannelInterceptor; + + public ChatConfig(FilterChannelInterceptor filterChannelInterceptor) { + this.filterChannelInterceptor = filterChannelInterceptor; + } + // sockJS Fallback을 이용해 노출할 endpoint 설정 @Override public void registerStompEndpoints(StompEndpointRegistry registry) { @@ -31,5 +41,9 @@ public void configureMessageBroker(MessageBrokerRegistry registry) { // 클라이언트->서버로 발행하는 메세지에 대한 endpoint 설정 : 구독에 대한 메세지 registry.setApplicationDestinationPrefixes("/pub"); } -} + @Override + public void configureClientInboundChannel(ChannelRegistration registration){ + registration.interceptors(filterChannelInterceptor); + } +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/config/RedisConfig.java b/src/main/java/capstone/facefriend/chat/config/RedisConfig.java index dd8851deef..07af53c8f7 100644 --- a/src/main/java/capstone/facefriend/chat/config/RedisConfig.java +++ b/src/main/java/capstone/facefriend/chat/config/RedisConfig.java @@ -1,11 +1,9 @@ package capstone.facefriend.chat.config; - import capstone.facefriend.chat.service.RedisSubscriber; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -13,14 +11,16 @@ import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.data.redis.listener.RedisMessageListenerContainer; import org.springframework.data.redis.listener.adapter.MessageListenerAdapter; +import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration -@RequiredArgsConstructor +@EnableRedisRepositories public class RedisConfig { @Value("${spring.data.redis.host}") private String redisHost; @@ -68,6 +68,13 @@ public RedisTemplate redisTemplate(RedisConnectionFactory redisC return redisTemplate; } + @Bean + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { + StringRedisTemplate redisTemplate = new StringRedisTemplate(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + return redisTemplate; + } + @Bean public MessageListenerAdapter listenerAdapter(RedisSubscriber subscriber) { return new MessageListenerAdapter(subscriber, "sendMessage"); diff --git a/src/main/java/capstone/facefriend/chat/controller/ChatRoomController.java b/src/main/java/capstone/facefriend/chat/controller/ChatRoomController.java index 3ccfb34806..6f9d82155a 100644 --- a/src/main/java/capstone/facefriend/chat/controller/ChatRoomController.java +++ b/src/main/java/capstone/facefriend/chat/controller/ChatRoomController.java @@ -2,11 +2,12 @@ import capstone.facefriend.auth.controller.support.AuthMember; import capstone.facefriend.chat.service.ChatRoomService; +import capstone.facefriend.chat.service.dto.chatroom.ChatRoomEnterResponse; +import capstone.facefriend.chat.service.dto.chatroom.ChatRoomExitResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.Map; @@ -22,4 +23,30 @@ ResponseEntity> getChatRoomList( ) { return ResponseEntity.ok(chatRoomService.getChatRoomList(memberId)); } + + @PostMapping("/room/{roomId}/enter") + public ResponseEntity enterChatRoom( + @PathVariable("roomId") Long roomId, + @AuthMember Long memberId, + @RequestParam(required = false, defaultValue = "0", value = "page") int pageNo + ){ + return ResponseEntity.ok(chatRoomService.enterRoom(roomId, memberId)); + } + + @PostMapping("/room/{roomId}/exit") + public ResponseEntity exitChatRoom( + @PathVariable("roomId") Long roomId, + @AuthMember Long memberId + ){ + return ResponseEntity.ok(chatRoomService.exitRoom(roomId, memberId)); + } + + @PostMapping("/room/{roomId}/left") + public ResponseEntity leftChatRoom( + @PathVariable("roomId") Long roomId, + @AuthMember Long memberId + ){ + return ResponseEntity.ok(chatRoomService.leftRoom(roomId, memberId)); + } + } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/controller/MessageController.java b/src/main/java/capstone/facefriend/chat/controller/MessageController.java index 6ea040fa1a..6eaa0715be 100644 --- a/src/main/java/capstone/facefriend/chat/controller/MessageController.java +++ b/src/main/java/capstone/facefriend/chat/controller/MessageController.java @@ -1,18 +1,20 @@ package capstone.facefriend.chat.controller; +import capstone.facefriend.auth.controller.support.AuthMember; import capstone.facefriend.auth.infrastructure.JwtProvider; +import capstone.facefriend.chat.service.MessageService; import capstone.facefriend.chat.service.dto.heart.HeartReplyRequest; -import capstone.facefriend.chat.service.dto.message.MessageRequest; import capstone.facefriend.chat.service.dto.heart.SendHeartRequest; -import capstone.facefriend.chat.service.MessageService; +import capstone.facefriend.chat.service.dto.message.MessageListResponse; +import capstone.facefriend.chat.service.dto.message.MessageRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.ResponseEntity; import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.simp.stomp.StompHeaderAccessor; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @RestController @Slf4j @@ -21,15 +23,36 @@ public class MessageController { private static final String BEARER_PREFIX = "Bearer "; private final MessageService messageService; - private final MappingJackson2HttpMessageConverter converter; private final JwtProvider jwtProvider; - @MessageMapping("/test") - @SendTo("/sub/test") - public String test() { - return "테스트 메시지"; + @MessageMapping("/stomp/connect") + public void enterApp( + StompHeaderAccessor headerAccessor + ){ + String authorizationHeader = headerAccessor.getFirstNativeHeader("Authorization"); + String token = authorizationHeader.substring(BEARER_PREFIX.length()); + Long memberId = jwtProvider.extractId(token); + messageService.enterApplication(memberId); } + @PostMapping("/stomp/disconnect") + public String exitApp( + @AuthMember Long memberId + ){ + String msg = messageService.exitApplication(memberId); + return msg; + } + + @GetMapping("/chat/{roomId}/messages") + public ResponseEntity> getMessagesPage( + @PathVariable("roomId") Long roomId, + @AuthMember Long memberId, + @RequestParam(required = false, defaultValue = "1", value = "page") int pageNo + ){ + return ResponseEntity.ok(messageService.getMessagePage(roomId, memberId,pageNo)); + } + + @MessageMapping("/chat/messages") public void message( StompHeaderAccessor headerAccessor, diff --git a/src/main/java/capstone/facefriend/chat/controller/interceptor/FilterChannelInterceptor.java b/src/main/java/capstone/facefriend/chat/controller/interceptor/FilterChannelInterceptor.java new file mode 100644 index 0000000000..bf1be7aad9 --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/controller/interceptor/FilterChannelInterceptor.java @@ -0,0 +1,96 @@ +package capstone.facefriend.chat.controller.interceptor; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.simp.stomp.StompCommand; +import org.springframework.messaging.simp.stomp.StompHeaderAccessor; +import org.springframework.messaging.support.ChannelInterceptor; +import org.springframework.messaging.support.MessageHeaderAccessor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class FilterChannelInterceptor implements ChannelInterceptor { + + private static final String BEARER_PREFIX = "Bearer "; + + @Override + public Message preSend(Message message, MessageChannel channel) { + + log.info("Stomp Handler 실행"); + StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); + StompHeaderAccessor headerAccessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); + + StompCommand command = headerAccessor.getCommand(); + String destination = headerAccessor.getDestination(); + String subscribeUrl = headerAccessor.getSubscriptionId(); + String sessionId = headerAccessor.getSessionId(); + Object payload = message.getPayload(); + String messageHeaders = String.valueOf(accessor.getMessageHeaders()); + String messageType = String.valueOf(accessor.getMessageType()); + + log.info("Command: {}", command); + log.info("Destination: {}", destination); + log.info("Subscription ID: {}", subscribeUrl); + log.info("Session ID: {}", sessionId); + log.info("Payload: {}", payload.toString()); + log.info("Message Type: {}", messageType); + log.info("Message Headers: {}", messageHeaders.toString()); + + + String authorizationHeader = headerAccessor.getFirstNativeHeader("Authorization"); + if (headerAccessor.getCommand() == StompCommand.CONNECT) { + log.info("Command: {}", command); + log.info("Destination: {}", destination); + log.info("Subscription ID: {}", subscribeUrl); + log.info("Session ID: {}", sessionId); + log.info("Payload: {}", payload.toString()); + log.info("Message Type: {}", messageType); + log.info("Message Headers: {}", messageHeaders.toString()); +// String token = authorizationHeader.substring(BEARER_PREFIX.length()); +// log.info("token: {}", token); +// if (token == null) try { +// throw new AccessDeniedException(""); +// } catch (AccessDeniedException e) { +// throw new RuntimeException(e); +// } + } + + if (headerAccessor.getCommand() == StompCommand.SUBSCRIBE) { + log.info("Command: {}", command); + log.info("Destination: {}", destination); + log.info("Subscription ID: {}", subscribeUrl); + log.info("Session ID: {}", sessionId); + log.info("Payload: {}", payload.toString()); + log.info("Message Type: {}", messageType); + log.info("Message Headers: {}", messageHeaders.toString()); + } + + if (headerAccessor.getCommand() == StompCommand.DISCONNECT) { + log.info("Command: {}", command); + log.info("Destination: {}", destination); + log.info("Subscription ID: {}", subscribeUrl); + log.info("Session ID: {}", sessionId); + log.info("Payload: {}", payload.toString()); + log.info("Message Type: {}", messageType); + log.info("Message Headers: {}", messageHeaders.toString()); + } + + + if (headerAccessor.getCommand() == StompCommand.SEND) { + log.info("Command: {}", command); + log.info("Destination: {}", destination); + log.info("Subscription ID: {}", subscribeUrl); + log.info("Session ID: {}", sessionId); + log.info("Payload: {}", payload.toString()); + log.info("Message Type: {}", messageType); + log.info("Message Headers: {}", messageHeaders.toString()); + } + + + return message; + } +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/domain/ChatRoomInfo.java b/src/main/java/capstone/facefriend/chat/domain/ChatRoomInfo.java new file mode 100644 index 0000000000..4b65746935 --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/domain/ChatRoomInfo.java @@ -0,0 +1,25 @@ +package capstone.facefriend.chat.domain; + +import jakarta.persistence.Column; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; + +import java.time.LocalDateTime; + +@Getter +@Setter +@NoArgsConstructor +@RedisHash("ChatRoom") +@Slf4j +public class ChatRoomInfo { + @Id + private String chatRoomInfoId; + + @Column(name = "enterTime", nullable = false) + private LocalDateTime enterTime; + +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/domain/SocketInfo.java b/src/main/java/capstone/facefriend/chat/domain/SocketInfo.java new file mode 100644 index 0000000000..50674ddfab --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/domain/SocketInfo.java @@ -0,0 +1,19 @@ +package capstone.facefriend.chat.domain; + +import jakarta.persistence.Column; +import lombok.*; +import org.springframework.data.annotation.Id; +import org.springframework.data.redis.core.RedisHash; + +import java.time.LocalDateTime; + +@Data +@NoArgsConstructor +@RedisHash("SocketInfo") +public class SocketInfo { + @Id + private Long memberId; + + @Column(name = "connectTime", nullable = false) + private LocalDateTime connectTime; +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/exception/ChatExceptionType.java b/src/main/java/capstone/facefriend/chat/exception/ChatExceptionType.java index afea94e745..0606db047d 100644 --- a/src/main/java/capstone/facefriend/chat/exception/ChatExceptionType.java +++ b/src/main/java/capstone/facefriend/chat/exception/ChatExceptionType.java @@ -9,15 +9,7 @@ public enum ChatExceptionType implements ExceptionType { INVALID_ACCESS(Status.FORBIDDEN, 5003, "본인의 계정이 아닙니다."), UNAUTHORIZED(Status.UNAUTHORIZED, 5005, "접근 정보가 잘못되었습니다."), ALREADY_CHATROOM(Status.BAD_REQUEST, 5006, "이미 존재하는 채팅방입니다."), - WRONG_PASSWORD(Status.BAD_REQUEST, 5007, "잘못된 비밀번호입니다."), - EXPIRED_ACCESS_TOKEN(Status.BAD_REQUEST, 5008, "만료된 액세스 토큰이므로 재발급해야 합니다."), - INVALID_ACCESS_TOKEN(Status.BAD_REQUEST, 5009, "유효하지 않은 액세스 토큰이므로 재발급해야 합니다."), - INVALID_REFRESH_TOKEN(Status.BAD_REQUEST, 5010, "유효하지 않은 리프레시 토큰입니다. 토큰 재발급이 불가능합니다."), - ACCESS_TOKEN_IS_IN_BLACKLIST(Status.BAD_REQUEST, 5011, "액세스 토큰이 로그아웃 처리되었습니다. 재로그인하시기 바랍니다."), - NOT_VERIFIED(Status.BAD_REQUEST, 5012, "본인 인증을 먼저 완료해야 합니다."), - PASSWORDS_NOT_EQUAL(Status.BAD_REQUEST, 5013, "재설정하는 비밀번호들이 동일하지 않습니다."), - WRONG_TEMPORARY_PASSWORD(Status.BAD_REQUEST, 5014, "임시 비밀번호가 올바르지 않습니다."), - NOT_FOUND_GENDER(Status.NOT_FOUND, 5015, "일치하는 성별이 없습니다.") + ; private final Status status; private final int exceptionCode; diff --git a/src/main/java/capstone/facefriend/chat/repository/ChatMessageRepository.java b/src/main/java/capstone/facefriend/chat/repository/ChatMessageRepository.java index f6a20281f5..ea4b3b3ddf 100644 --- a/src/main/java/capstone/facefriend/chat/repository/ChatMessageRepository.java +++ b/src/main/java/capstone/facefriend/chat/repository/ChatMessageRepository.java @@ -1,11 +1,16 @@ package capstone.facefriend.chat.repository; import capstone.facefriend.chat.domain.ChatMessage; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import java.time.LocalDateTime; +import java.util.List; + public interface ChatMessageRepository extends JpaRepository { ChatMessage findFirstByChatRoomIdOrderBySendTimeDesc(Long roomId); ChatMessage save(ChatMessage chatMessage); - + List findChatMessagesByChatRoom_IdAndSendTimeBefore(Long roomId, LocalDateTime time, Pageable pageable); + List findChatMessagesByChatRoomId(Long roomId); } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/repository/ChatRoomInfoRedisRepository.java b/src/main/java/capstone/facefriend/chat/repository/ChatRoomInfoRedisRepository.java new file mode 100644 index 0000000000..c8262c8ad0 --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/repository/ChatRoomInfoRedisRepository.java @@ -0,0 +1,10 @@ +package capstone.facefriend.chat.repository; + +import capstone.facefriend.chat.domain.ChatRoomInfo; +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; + +public interface ChatRoomInfoRedisRepository extends CrudRepository { + Optional findById(String chatRoomInfoId); +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/repository/ChatRoomMemberRepository.java b/src/main/java/capstone/facefriend/chat/repository/ChatRoomMemberRepository.java index 7cb178a2ad..a1a738303a 100644 --- a/src/main/java/capstone/facefriend/chat/repository/ChatRoomMemberRepository.java +++ b/src/main/java/capstone/facefriend/chat/repository/ChatRoomMemberRepository.java @@ -1,23 +1,18 @@ package capstone.facefriend.chat.repository; -import capstone.facefriend.chat.domain.ChatRoom; import capstone.facefriend.chat.domain.ChatRoomMember; -import io.lettuce.core.dynamic.annotation.Param; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import java.util.List; import java.util.Optional; public interface ChatRoomMemberRepository extends JpaRepository { - Optional findByChatRoom(ChatRoom chatRoom); - + Optional findByChatRoomId(Long roomId); @Query("SELECT c FROM ChatRoomMember c WHERE c.sender.id = :senderId AND c.receiver.id = :receiverId") Optional findBySenderAndReceiver(@Param("senderId") Long senderId, @Param("receiverId") Long receiverId); - - // Optional findChatRoomMemberBySenderAAndReceiver(Member sender, Member receiver); ChatRoomMember save(ChatRoomMember chatRoomMember); - Optional> findAllBySenderId(Long senderId); Optional> findAllByReceiverId(Long senderId); } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/repository/SocketInfoRedisRepository.java b/src/main/java/capstone/facefriend/chat/repository/SocketInfoRedisRepository.java new file mode 100644 index 0000000000..4d5591d1ed --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/repository/SocketInfoRedisRepository.java @@ -0,0 +1,8 @@ +package capstone.facefriend.chat.repository; + +import capstone.facefriend.chat.domain.SocketInfo; +import org.springframework.data.repository.CrudRepository; + +public interface SocketInfoRedisRepository extends CrudRepository { + +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/ChatRoomService.java b/src/main/java/capstone/facefriend/chat/service/ChatRoomService.java index 2bc79438c0..43f7626e21 100644 --- a/src/main/java/capstone/facefriend/chat/service/ChatRoomService.java +++ b/src/main/java/capstone/facefriend/chat/service/ChatRoomService.java @@ -2,20 +2,25 @@ import capstone.facefriend.chat.domain.ChatMessage; import capstone.facefriend.chat.domain.ChatRoom; +import capstone.facefriend.chat.domain.ChatRoomInfo; import capstone.facefriend.chat.domain.ChatRoomMember; +import capstone.facefriend.chat.exception.ChatException; +import capstone.facefriend.chat.exception.ChatExceptionType; import capstone.facefriend.chat.repository.ChatMessageRepository; +import capstone.facefriend.chat.repository.ChatRoomInfoRedisRepository; import capstone.facefriend.chat.repository.ChatRoomMemberRepository; -import capstone.facefriend.chat.service.dto.chatroom.ChatRoomEmptyResponse; -import capstone.facefriend.chat.service.dto.chatroom.ChatRoomHeartResponse; -import capstone.facefriend.chat.service.dto.chatroom.ChatRoomMessageResponse; -import capstone.facefriend.chat.service.dto.chatroom.ChatRoomOpenResponse; -import capstone.facefriend.chat.service.dto.heart.GetSendHeartResponse; +import capstone.facefriend.chat.repository.ChatRoomRepository; +import capstone.facefriend.chat.service.dto.chatroom.*; import capstone.facefriend.member.domain.member.Member; +import capstone.facefriend.member.domain.member.MemberRepository; +import capstone.facefriend.member.exception.member.MemberException; +import capstone.facefriend.member.exception.member.MemberExceptionType; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -25,11 +30,20 @@ @Slf4j @RequiredArgsConstructor public class ChatRoomService { - + private final ChatRoomRepository chatRoomRepository; private final ChatRoomMemberRepository chatRoomMemberRepository; private final ChatMessageRepository chatMessageRepository; + private final ChatRoomInfoRedisRepository chatRoomInfoRedisRepository; + private final MemberRepository memberRepository; private static final String EMPTY_MESSAGE = "채팅을 시작하지 않았습니다."; private static final String OPEN_MESSAGE = "채팅을 시작해보세요!"; + private static final String CLOSE_MESSAGE = "상대방이 떠났습니다."; + + private Member findMemberById(Long memberId) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new MemberException(MemberExceptionType.NOT_FOUND)); + return member; + } private List findAllChatRoomMemberBySenderId(Long memberId) { return chatRoomMemberRepository.findAllBySenderId(memberId).orElse(new ArrayList<>()); @@ -39,6 +53,28 @@ private List findAllChatRoomMemberByReceiverId(Long memberId) { return chatRoomMemberRepository.findAllByReceiverId(memberId).orElse(new ArrayList<>()); } + private ChatRoomInfo findChatRoomInfo(String chatRoomInfoId) { + ChatRoomInfo chatRoomInfo = chatRoomInfoRedisRepository.findById(chatRoomInfoId) + .orElseThrow(()-> new ChatException(ChatExceptionType.NOT_FOUND)); + return chatRoomInfo; + } + + private ChatRoom findRoomById(Long roomId) { + ChatRoom chatRoom = chatRoomRepository.findById(roomId) + .orElseThrow(()-> new ChatException(ChatExceptionType.NOT_FOUND)); + return chatRoom; + } + + private ChatRoomMember findChatRoomMemberByChatRoomId(Long roomId) { + ChatRoomMember chatRoomMember = chatRoomMemberRepository.findByChatRoomId(roomId) + .orElseThrow(()-> new ChatException(ChatExceptionType.NOT_FOUND)); + return chatRoomMember; + } + + private List findChatRoomMessageByChatRoomId(Long roomId) { + return chatMessageRepository.findChatMessagesByChatRoomId(roomId); + } + @Transactional public Map getChatRoomList(Long memberId) { @@ -57,36 +93,129 @@ public Map getChatRoomList(Long memberId) { List chatRoomsMessage = new ArrayList<>(); List chatRoomsHeart = new ArrayList<>(); List chatRoomsOpen = new ArrayList<>(); + List chatRoomClose = new ArrayList<>(); + + Member member = findMemberById(memberId); for (ChatRoomMember chatRoomMember : chatRoomMemberList) { ChatRoom.Status status = chatRoomMember.getChatRoom().getStatus(); if (status == ChatRoom.Status.set) { - GetSendHeartResponse sendHeartResponse = new GetSendHeartResponse(); - sendHeartResponse.setType("Heart"); - sendHeartResponse.setRoomId(chatRoomMember.getChatRoom().getId()); - sendHeartResponse.setSenderId(chatRoomMember.getSender().getId()); - sendHeartResponse.setReceiveId(chatRoomMember.getReceiver().getId()); - sendHeartResponse.setSenderName(chatRoomMember.getSender().getBasicInfo().getNickname()); - ChatRoomHeartResponse chatRoomHeartResponse = ChatRoomHeartResponse.of(chatRoomMember, sendHeartResponse); + Member sender = identifySender(chatRoomMember, memberId); + Boolean isSender = isSender(chatRoomMember, memberId); + ChatRoomHeartResponse chatRoomHeartResponse = ChatRoomHeartResponse.of(member, sender, chatRoomMember.getChatRoom(), isSender); chatRoomsHeart.add(chatRoomHeartResponse); } else if (status == ChatRoom.Status.progress) { + Member sender = identifySender(chatRoomMember, memberId); ChatMessage chatMessage = chatMessageRepository.findFirstByChatRoomIdOrderBySendTimeDesc(chatRoomMember.getChatRoom().getId()); - ChatRoomMessageResponse chatRoomResponse = ChatRoomMessageResponse.of(chatRoomMember, chatMessage); + ChatRoomMessageResponse chatRoomResponse = ChatRoomMessageResponse.of(member, sender, chatRoomMember.getChatRoom(), chatMessage); chatRoomsMessage.add(chatRoomResponse); } else if (status == ChatRoom.Status.open) { - Member Sender = chatRoomMember.getSender(); - ChatRoomOpenResponse chatRoomOpenResponse = ChatRoomOpenResponse.of(Sender.getId(), Sender.getBasicInfo().getNickname(), OPEN_MESSAGE); + Member sender = identifySender(chatRoomMember, memberId); + ChatRoomOpenResponse chatRoomOpenResponse = ChatRoomOpenResponse.of(member, sender, chatRoomMember.getChatRoom(), OPEN_MESSAGE); chatRoomsOpen.add(chatRoomOpenResponse); + } else if (status == ChatRoom.Status.close) { + Member leftMember = identifyLeftMember(memberId, chatRoomMember); + if (member != leftMember) { + ChatRoomCloseResponse chatRoomCloseResponse = ChatRoomCloseResponse.of(member, chatRoomMember.getChatRoom(), CLOSE_MESSAGE); + chatRoomClose.add(chatRoomCloseResponse); + } } } chatRooms.put("chatRoomHeartList", chatRoomsHeart); chatRooms.put("chatRoomMessageList", chatRoomsMessage); chatRooms.put("chatRoomOpenList", chatRoomsOpen); + chatRooms.put("chatRoomCloseList", chatRoomClose); return chatRooms; } + + public ChatRoomEnterResponse enterRoom(Long roomId, Long memberId) { + String chatRoomInfoId = roomId + "/member/" + memberId; + ChatRoomInfo chatRoomInfo = new ChatRoomInfo(); + chatRoomInfo.setChatRoomInfoId(chatRoomInfoId); + chatRoomInfo.setEnterTime(LocalDateTime.now()); + chatRoomInfoRedisRepository.save(chatRoomInfo); + return ChatRoomEnterResponse.of(roomId, memberId, chatRoomInfo); + } + + public ChatRoomExitResponse exitRoom(Long roomId, Long memberId) { + String chatRoomInfoId = roomId + "/member/" + memberId; + ChatRoomInfo chatRoomInfo = findChatRoomInfo(chatRoomInfoId); + chatRoomInfoRedisRepository.delete(chatRoomInfo); + LocalDateTime exitChatRoomTime = LocalDateTime.now(); + return ChatRoomExitResponse.of(roomId, memberId, exitChatRoomTime); + } + + @Transactional + public String leftRoom(Long roomId, Long memberId) { + ChatRoom chatRoom = findRoomById(roomId); + ChatRoom.Status status = chatRoom.getStatus(); + ChatRoomMember chatRoomMember = findChatRoomMemberByChatRoomId(roomId); + Member member = findMemberById(memberId); + Member leftMember = identifyLeftMember(memberId, chatRoomMember); + if (status== ChatRoom.Status.close) { + if (member != leftMember) { + chatRoomMemberRepository.delete(chatRoomMember); + chatRoomRepository.delete(chatRoom); + return "채팅방을 떠났습니다."; + } else { + return "이미 떠난 채팅방입니다."; + } + } + List chatMessages = findChatRoomMessageByChatRoomId(roomId); + log.info("FindChatRoomIdChatMessage:{}", chatMessages.toString()); + if(!chatMessages.isEmpty()){ + chatMessageRepository.deleteAll(chatMessages); + } + if (chatRoomMember.getSender() == member) { + chatRoomMember.setSenderExist(false); + } else if (chatRoomMember.getReceiver() == member){ + chatRoomMember.setReceiverExist(false); + } else { + return "속해있지 않은 채팅방입니디."; + } + chatRoom.setStatus(ChatRoom.Status.close); + chatRoomRepository.save(chatRoom); + chatRoomMemberRepository.save(chatRoomMember); + return "채팅방을 떠났습니다"; + } + + private Member identifySender(ChatRoomMember chatRoomMember, Long memberId) { + Member member = findMemberById(memberId); + if (member.getId().equals(chatRoomMember.getSender().getId())) { + return chatRoomMember.getReceiver(); + } else { + return chatRoomMember.getSender(); + } + } + + private Member identifyLeftMember(Long memberId, ChatRoomMember chatRoomMember) { + Member member = findMemberById(memberId); + if (chatRoomMember.getSender() == member) { + if (chatRoomMember.isSenderExist()){ + return chatRoomMember.getReceiver(); + } else { + return member; + } + } else { + if (chatRoomMember.isReceiverExist()) { + return chatRoomMember.getSender(); + } else { + return member; + } + } + } + + private Boolean isSender(ChatRoomMember chatRoomMember, Long memberId) { + Member member = findMemberById(memberId); + if (member.getId().equals(chatRoomMember.getSender().getId())) { + return true; + } else { + return false; + } + } } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/MessageService.java b/src/main/java/capstone/facefriend/chat/service/MessageService.java index 831f589008..25abd5de20 100644 --- a/src/main/java/capstone/facefriend/chat/service/MessageService.java +++ b/src/main/java/capstone/facefriend/chat/service/MessageService.java @@ -1,15 +1,12 @@ package capstone.facefriend.chat.service; -import capstone.facefriend.chat.domain.ChatMessage; -import capstone.facefriend.chat.domain.ChatRoom; -import capstone.facefriend.chat.domain.ChatRoomMember; +import capstone.facefriend.chat.domain.*; import capstone.facefriend.chat.exception.ChatException; import capstone.facefriend.chat.exception.ChatExceptionType; -import capstone.facefriend.chat.repository.ChatMessageRepository; -import capstone.facefriend.chat.repository.ChatRoomMemberRepository; -import capstone.facefriend.chat.repository.ChatRoomRepository; +import capstone.facefriend.chat.repository.*; import capstone.facefriend.chat.service.dto.heart.HeartReplyRequest; import capstone.facefriend.chat.service.dto.heart.SendHeartResponse; +import capstone.facefriend.chat.service.dto.message.MessageListResponse; import capstone.facefriend.chat.service.dto.message.MessageRequest; import capstone.facefriend.chat.service.dto.message.MessageResponse; import capstone.facefriend.member.domain.member.Member; @@ -18,6 +15,9 @@ import capstone.facefriend.member.exception.member.MemberExceptionType; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.messaging.simp.SimpMessagingTemplate; @@ -25,19 +25,23 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; @Service @Slf4j @RequiredArgsConstructor public class MessageService { - private final ChatMessageRepository chatMessageRepository; private final ChatRoomMemberRepository chatRoomMemberRepository; private final MemberRepository memberRepository; private final ChatRoomRepository chatRoomRepository; - private final RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate; private final ChannelTopic channelTopic; - private final SimpMessagingTemplate messagingTemplate; + private final SocketInfoRedisRepository socketInfoRedisRepository; + private final SimpMessagingTemplate simpMessagingTemplate; + private final ChatRoomInfoRedisRepository chatRoomInfoRedisRepository; private Member findMemberById(Long memberId) { Member member = memberRepository.findById(memberId) @@ -51,22 +55,39 @@ private ChatRoom findRoomById(Long roomId) { return chatRoom; } - private ChatRoomMember findSenderReceiver(Long senderId, Long receiveId) { + private ChatRoomMember findSenderReceiver(Long senderId, Long receiveId) { ChatRoomMember chatRoomMember = chatRoomMemberRepository.findBySenderAndReceiver(senderId, receiveId) .orElseThrow(()-> new ChatException(ChatExceptionType.NOT_FOUND)); return chatRoomMember; } + private ChatRoomMember findChatRoomMemberByChatRoomId(Long roomId) { + ChatRoomMember chatRoomMember = chatRoomMemberRepository.findByChatRoomId(roomId) + .orElseThrow(()-> new ChatException(ChatExceptionType.NOT_FOUND)); + return chatRoomMember; + } + + private SocketInfo findSocketInfo(Long memberId) { + SocketInfo socketInfo = socketInfoRedisRepository.findById(memberId) + .orElseThrow(()-> new ChatException(ChatExceptionType.NOT_FOUND)); + return socketInfo; + } + + private ChatRoomInfo findChatRoomInfo(String chatRoomInfoId) { + ChatRoomInfo chatRoomInfo = chatRoomInfoRedisRepository.findById(chatRoomInfoId) + .orElseThrow(()-> new ChatException(ChatExceptionType.NOT_FOUND)); + return chatRoomInfo; + } @Transactional public void sendMessage(MessageRequest messageRequest, Long senderId) { Member sender = findMemberById(senderId); Member receiver = findMemberById(messageRequest.getReceiveId()); - ChatRoomMember chatRoomMember = findSenderReceiver(sender.getId(), receiver.getId()); ChatRoom chatRoom = findRoomById(messageRequest.getRoomId()); if (chatRoom.getStatus() == ChatRoom.Status.open) { chatRoom.setStatus(ChatRoom.Status.progress); + ChatRoomMember chatRoomMember = findChatRoomMemberByChatRoomId(chatRoom.getId()); chatRoomRepository.save(chatRoom); chatRoomMemberRepository.save(chatRoomMember); } else if ((chatRoom.getStatus() == ChatRoom.Status.close)) { @@ -93,6 +114,7 @@ public void sendMessage(MessageRequest messageRequest, Long senderId) { messageResponse.setSenderId(senderId); messageResponse.setReceiveId(receiver.getId()); messageResponse.setSenderNickname(sender.getBasicInfo().getNickname()); + messageResponse.setSenderFaceInfoS3Url(sender.getFaceInfo().getOriginS3url()); messageResponse.setContent(chatMessage.getContent()); messageResponse.setType("message"); messageResponse.setCreatedAt(chatMessage.getSendTime()); @@ -105,8 +127,6 @@ public void sendMessage(MessageRequest messageRequest, Long senderId) { } @Transactional public void sendHeart(Long senderId, Long receiveId) { - - ChatRoom chatRoom = ChatRoom.builder() .status(ChatRoom.Status.set) .isPublic(false) @@ -125,8 +145,8 @@ public void sendHeart(Long senderId, Long receiveId) { .chatRoom(chatRoom) .sender(sender) .receiver(receiver) - .isSenderExist(false) - .isReceiverExist(false) + .isSenderExist(true) + .isReceiverExist(true) .isSenderPublic(false) .isReceiverPublic(false) .build(); @@ -172,6 +192,91 @@ public void heartReply(HeartReplyRequest heartReplyRequest, Long receiveId) { String destination = "/sub/chat/" + sender.getId(); // 메시지 전송 - messagingTemplate.convertAndSend(destination, message); + simpMessagingTemplate.convertAndSend(destination, message); + } + + + @Transactional + public void enterApplication(Long memberId) { + SocketInfo socketInfo = new SocketInfo(); + socketInfo.setMemberId(memberId); + socketInfo.setConnectTime(LocalDateTime.now()); + socketInfoRedisRepository.save(socketInfo); + if (isExistUnReadMessage(memberId)) { + sendSentMessage(memberId); + } + + if(isExistUnSendHeart(memberId)) { + sendSentHeart(memberId); + } + } + + @Transactional + public String exitApplication(Long memberId) { + SocketInfo socketInfo = findSocketInfo(memberId); + socketInfoRedisRepository.delete(socketInfo); + return "성공"; + } + + public List getMessagePage(Long roomId, Long memberId, int pageNo) { + pageNo = pageNo - 1; + int pageSize = 20; + Sort sort = Sort.by(Sort.Direction.DESC, "sendTime"); + Pageable pageable = PageRequest.of(pageNo, pageSize, sort); + String chatRoomInfoId = roomId + "/member/" + memberId; + ChatRoomInfo chatRoomInfo = findChatRoomInfo(chatRoomInfoId); + LocalDateTime time = chatRoomInfo.getEnterTime(); + List chatMessagePage = chatMessageRepository.findChatMessagesByChatRoom_IdAndSendTimeBefore(roomId, time, pageable); + List messageListResponses = new ArrayList<>(); + for (ChatMessage chatMessage : chatMessagePage){ + MessageListResponse messageListResponse = MessageListResponse.of(chatMessage); + messageListResponses.add(messageListResponse); + } + return messageListResponses; + } + + private Boolean isExistUnReadMessage(Long memberId) { + Boolean isUnRead = redisTemplate.hasKey("/sub/chat/" + memberId + "message"); + log.info(isUnRead.toString()); + return !isUnRead; + } + + private Boolean isExistUnSendHeart(Long memberId) { + Boolean isUnRead = redisTemplate.hasKey("/sub/chat/" + memberId + "SendHeart"); + log.info(isUnRead.toString()); + return !isUnRead; + } + + private void sendSentMessage(Long receiveId) { + String topic = channelTopic.getTopic(); + String destination = "/sub/chat" + receiveId + "message"; + Long messagesListSize = redisTemplate.opsForList().size(destination); + log.info(messagesListSize.toString()); + log.info("messageList: {}", redisTemplate.opsForList().range(destination, 0, -1)); + + if (messagesListSize > 0) { + for (Long i = messagesListSize; i > 0; i--) { + // 맵으로 받음 + LinkedHashMap map = (LinkedHashMap) redisTemplate.opsForList().rightPop(destination); + MessageResponse messageResponse = (MessageResponse) map.get(destination); + log.info("messageResponse: {}", messageResponse.toString()); + redisTemplate.convertAndSend(topic, messageResponse); + } + } + } + + private void sendSentHeart(Long receiveId) { + String topic = channelTopic.getTopic(); + String destination = "/sub/chat" + receiveId + "heart"; + Long messagesListSize = redisTemplate.opsForList().size(destination); + log.info("SendHeartListSize: {}", messagesListSize.toString()); + if (messagesListSize > 0) { + for (Long i = messagesListSize; i > 0; i--) { + LinkedHashMap map = (LinkedHashMap) redisTemplate.opsForList().rightPop(destination); + SendHeartResponse sendHeartResponse = (SendHeartResponse) map.get(destination); + log.info("messageResponse: {}", sendHeartResponse.toString()); + redisTemplate.convertAndSend(topic, sendHeartResponse); + } + } } } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/RedisSubscriber.java b/src/main/java/capstone/facefriend/chat/service/RedisSubscriber.java index 6b9de1fcb4..af3b1cf2aa 100644 --- a/src/main/java/capstone/facefriend/chat/service/RedisSubscriber.java +++ b/src/main/java/capstone/facefriend/chat/service/RedisSubscriber.java @@ -1,19 +1,23 @@ package capstone.facefriend.chat.service; -import capstone.facefriend.chat.service.dto.message.GetMessageResponse; +import capstone.facefriend.chat.domain.SocketInfo; import capstone.facefriend.chat.service.dto.heart.GetSendHeartResponse; -import capstone.facefriend.chat.service.dto.message.MessageResponse; import capstone.facefriend.chat.service.dto.heart.SendHeartResponse; +import capstone.facefriend.chat.service.dto.message.GetMessageResponse; +import capstone.facefriend.chat.service.dto.message.MessageResponse; 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.ListOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.messaging.simp.SimpMessageSendingOperations; import org.springframework.stereotype.Service; import java.io.IOException; +import java.util.List; +import java.util.Objects; @Slf4j @RequiredArgsConstructor @@ -21,7 +25,7 @@ public class RedisSubscriber implements MessageListener { private final ObjectMapper objectMapper; - private final RedisTemplate redisTemplate; + private final RedisTemplate redisTemplate; private final SimpMessageSendingOperations messagingTemplate; @Override @@ -32,21 +36,61 @@ public void onMessage(Message message, byte[] pattern) { String publishMessage = (String) redisTemplate.getStringSerializer().deserialize(message.getBody()); if (publishMessage.contains("message")) { + log.info(publishMessage); MessageResponse messageResponse = objectMapper.readValue(publishMessage, MessageResponse.class); - + log.info(messageResponse.toString()); GetMessageResponse chatMessageResponse = new GetMessageResponse(messageResponse); + log.info(chatMessageResponse.toString()); + if (isExistSubscriber(messageResponse.getReceiveId())) { + messagingTemplate.convertAndSend("/sub/chat/" + messageResponse.getReceiveId(), chatMessageResponse); + } else { + saveUnReadMessage("/sub/chat" + messageResponse.getReceiveId() + "message", messageResponse); + } - messagingTemplate.convertAndSend("/sub/chat/" + messageResponse.getReceiveId(), chatMessageResponse); } else if (publishMessage.contains("Heart")) { SendHeartResponse sendHeartResponse = objectMapper.readValue(publishMessage, SendHeartResponse.class); GetSendHeartResponse chatSendHeartResponse = new GetSendHeartResponse(sendHeartResponse); + if (isExistSubscriber(chatSendHeartResponse.getReceiveId())) { + messagingTemplate.convertAndSend("/sub/chat/" + sendHeartResponse.getReceiveId(), chatSendHeartResponse); + } else { + saveUnReadHeart("/sub/chat" + sendHeartResponse.getReceiveId() + "heart", sendHeartResponse); + } - messagingTemplate.convertAndSend("/sub/chat/" + sendHeartResponse.getReceiveId(), chatSendHeartResponse); } } catch (IOException e) { throw new RuntimeException("Failed to process message", e); } } + + private Boolean isExistSubscriber(Long memberId) { + log.info("isExistSubscriber 호출"); + Boolean isMember = redisTemplate.opsForSet().isMember("SocketInfo", memberId); + log.info("Socket: " + memberId); + log.info("SocketInfo: " + isMember); + + return isMember; + } + + + + private void saveUnReadMessage(String destination, MessageResponse messageResponse) { + Boolean isUnRead = redisTemplate.hasKey(destination); + log.info(isUnRead.toString()); + if (isUnRead) { + redisTemplate.opsForList().rightPush(destination, messageResponse); + } else { + redisTemplate.opsForList().rightPush(destination, messageResponse); + } + } + + private void saveUnReadHeart(String destination, SendHeartResponse sendHeartResponse) { + Boolean isUnRead = redisTemplate.hasKey(destination); + if (isUnRead) { + redisTemplate.opsForList().rightPush(destination, sendHeartResponse); + } else { + redisTemplate.opsForList().rightPush(destination, sendHeartResponse); + } + } } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomCloseResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomCloseResponse.java new file mode 100644 index 0000000000..3051a5d98e --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomCloseResponse.java @@ -0,0 +1,24 @@ +package capstone.facefriend.chat.service.dto.chatroom; + +import capstone.facefriend.chat.domain.ChatRoom; +import capstone.facefriend.member.domain.member.Member; + +public record ChatRoomCloseResponse( + Long memberId, + String memberNickname, + String memberGeneratedS3url, + String memberOriginS3url, + ChatRoom chatRoom, + String message +) { + public static ChatRoomCloseResponse of(Member member, ChatRoom chatRoom, String message) { + return new ChatRoomCloseResponse( + member.getId(), + member.getBasicInfo().getNickname(), + member.getFaceInfo().getGeneratedS3url(), + member.getFaceInfo().getOriginS3url(), + chatRoom, + message + ); + } +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomEnterResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomEnterResponse.java new file mode 100644 index 0000000000..8b64273412 --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomEnterResponse.java @@ -0,0 +1,19 @@ +package capstone.facefriend.chat.service.dto.chatroom; + +import capstone.facefriend.chat.domain.ChatRoomInfo; + +import java.time.LocalDateTime; + +public record ChatRoomEnterResponse( + Long roomId, + Long memberId, + LocalDateTime enterTime +) { + public static ChatRoomEnterResponse of(Long roomId, Long memberId, ChatRoomInfo chatRoomInfo) { + return new ChatRoomEnterResponse( + roomId, + memberId, + chatRoomInfo.getEnterTime() + ); + } +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomExitResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomExitResponse.java new file mode 100644 index 0000000000..6884b1da1d --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomExitResponse.java @@ -0,0 +1,19 @@ +package capstone.facefriend.chat.service.dto.chatroom; + +import capstone.facefriend.chat.domain.ChatRoomInfo; + +import java.time.LocalDateTime; + +public record ChatRoomExitResponse( + Long roomId, + Long memberId, + LocalDateTime enterTime +) { + public static ChatRoomExitResponse of(Long roomId, Long memberId, LocalDateTime exitTime) { + return new ChatRoomExitResponse( + roomId, + memberId, + exitTime + ); + } +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomHeartResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomHeartResponse.java index d3a9457690..341fc1f584 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomHeartResponse.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomHeartResponse.java @@ -1,22 +1,33 @@ package capstone.facefriend.chat.service.dto.chatroom; import capstone.facefriend.chat.domain.ChatRoom; -import capstone.facefriend.chat.domain.ChatRoomMember; -import capstone.facefriend.chat.service.dto.heart.GetSendHeartResponse; +import capstone.facefriend.member.domain.member.Member; public record ChatRoomHeartResponse ( - Long sender, - Long receiver, + Long memberId, + String memberNickname, + String memberGeneratedS3url, + String memberOriginS3url, + Long senderId, + String senderNickname, + String senderGeneratedS3url, + String senderOriginS3url, ChatRoom chatRoom, - GetSendHeartResponse sendHeart + Boolean isSender ) { - public static ChatRoomHeartResponse of(ChatRoomMember chatRoomMember, GetSendHeartResponse sendHeartResponse) { + public static ChatRoomHeartResponse of(Member member, Member sender, ChatRoom chatRoom, Boolean isSender) { return new ChatRoomHeartResponse( - chatRoomMember.getSender().getId(), - chatRoomMember.getReceiver().getId(), - chatRoomMember.getChatRoom(), - sendHeartResponse + member.getId(), + member.getBasicInfo().getNickname(), + member.getFaceInfo().getGeneratedS3url(), + member.getFaceInfo().getOriginS3url(), + sender.getId(), + sender.getBasicInfo().getNickname(), + sender.getFaceInfo().getGeneratedS3url(), + sender.getFaceInfo().getOriginS3url(), + chatRoom, + isSender ); } } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomMessageResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomMessageResponse.java index 9d037bd3b4..cd4287dd5d 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomMessageResponse.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomMessageResponse.java @@ -2,31 +2,33 @@ import capstone.facefriend.chat.domain.ChatMessage; import capstone.facefriend.chat.domain.ChatRoom; -import capstone.facefriend.chat.domain.ChatRoomMember; - -import java.time.LocalDateTime; +import capstone.facefriend.member.domain.member.Member; public record ChatRoomMessageResponse( - Long sender, - Long receiver, - ChatRoom chatRoom, - String content, - LocalDateTime sendTime, + Long memberId, + String memberNickname, + String memberGeneratedFaceS3url, + String memberOriginFaceS3url, + Long senderId, String senderNickname, - String senderGeneratedFaceInfo, - String senderOriginalFaceInfo + String senderGeneratedFaceS3url, + String senderOriginFaceS3url, + ChatRoom chatRoom, + String content ){ - public static ChatRoomMessageResponse of(ChatRoomMember chatRoomMember, ChatMessage message) { + public static ChatRoomMessageResponse of(Member member, Member sender, ChatRoom chatRoom, ChatMessage message) { return new ChatRoomMessageResponse( - chatRoomMember.getSender().getId(), - chatRoomMember.getReceiver().getId(), - chatRoomMember.getChatRoom(), - message.getContent(), - message.getSendTime(), - message.getSender().getBasicInfo().getNickname(), - message.getSender().getFaceInfo().getGeneratedS3url(), - message.getSender().getFaceInfo().getOriginS3url() + member.getId(), + member.getBasicInfo().getNickname(), + member.getFaceInfo().getGeneratedS3url(), + member.getFaceInfo().getOriginS3url(), + sender.getId(), + sender.getBasicInfo().getNickname(), + sender.getFaceInfo().getGeneratedS3url(), + sender.getFaceInfo().getOriginS3url(), + chatRoom, + message.getContent() ); } } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomOpenResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomOpenResponse.java index 393f9a8880..a968a98ac5 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomOpenResponse.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/chatroom/ChatRoomOpenResponse.java @@ -1,14 +1,31 @@ package capstone.facefriend.chat.service.dto.chatroom; +import capstone.facefriend.chat.domain.ChatRoom; +import capstone.facefriend.member.domain.member.Member; + public record ChatRoomOpenResponse ( + Long memberId, + String memberNickname, + String memberGeneratedS3url, + String memberOriginS3url, Long senderId, String senderNickname, + String senderGeneratedS3url, + String senderOriginS3url, + ChatRoom chatRoom, String message ) { - public static ChatRoomOpenResponse of(Long senderId, String senderNickname, String message) { + public static ChatRoomOpenResponse of(Member member, Member sender, ChatRoom chatRoom, String message) { return new ChatRoomOpenResponse( - senderId, - senderNickname, + member.getId(), + member.getBasicInfo().getNickname(), + member.getFaceInfo().getGeneratedS3url(), + member.getFaceInfo().getOriginS3url(), + sender.getId(), + sender.getBasicInfo().getNickname(), + sender.getFaceInfo().getGeneratedS3url(), + sender.getFaceInfo().getOriginS3url(), + chatRoom, message ); } diff --git a/src/main/java/capstone/facefriend/chat/service/dto/heart/GetSendHeartResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/heart/GetSendHeartResponse.java index 69645c8461..28b2de256d 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/heart/GetSendHeartResponse.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/heart/GetSendHeartResponse.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; import lombok.NoArgsConstructor; -import lombok.Setter; import java.time.LocalDateTime; @@ -17,7 +16,7 @@ public class GetSendHeartResponse { private String type; private Long roomId; @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul") - private LocalDateTime createdAt; + private LocalDateTime sendTime; public GetSendHeartResponse(SendHeartResponse sendHeartResponse) { @@ -26,6 +25,6 @@ public GetSendHeartResponse(SendHeartResponse sendHeartResponse) { this.receiveId = sendHeartResponse.getReceiveId(); this.type = sendHeartResponse.getType(); this.roomId = sendHeartResponse.getRoomId(); - this.createdAt = sendHeartResponse.getCreatedAt(); + this.sendTime = sendHeartResponse.getCreatedAt(); } } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartRequest.java b/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartRequest.java index d659c4bb23..4176169283 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartRequest.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartRequest.java @@ -2,9 +2,13 @@ import lombok.Data; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; @Data +@Getter +@Setter +@NoArgsConstructor public class SendHeartRequest { private Long receiveId; } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartResponse.java index 438e842d61..205e578156 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartResponse.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/heart/SendHeartResponse.java @@ -18,5 +18,4 @@ public class SendHeartResponse implements Serializable { private String sessionId; @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul") private LocalDateTime createdAt; - } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/message/GetMessageResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/message/GetMessageResponse.java index 2b80749085..e096705661 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/message/GetMessageResponse.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/message/GetMessageResponse.java @@ -14,10 +14,11 @@ public class GetMessageResponse { private Long senderId; private Long receiveId; private String senderNickname; + private String senderFaceInfoS3Url; private String type; private String content; @JsonFormat(pattern = "yyyy-MM-dd hh:mm", timezone = "Asia/Seoul") - private LocalDateTime createdAt; + private LocalDateTime sendTime; private Boolean isRead; public GetMessageResponse(MessageResponse messageResponse) { @@ -25,9 +26,10 @@ public GetMessageResponse(MessageResponse messageResponse) { this.senderId = messageResponse.getSenderId(); this.receiveId = messageResponse.getReceiveId(); this.senderNickname = messageResponse.getSenderNickname(); + this.senderFaceInfoS3Url = messageResponse.getSenderFaceInfoS3Url(); this.type = messageResponse.getType(); this.content = messageResponse.getContent(); - this.createdAt = LocalDateTime.now(); + this.sendTime = messageResponse.getCreatedAt(); this.isRead = messageResponse.getIsRead(); } } \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/message/MessageListResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/message/MessageListResponse.java new file mode 100644 index 0000000000..f5e03c28ac --- /dev/null +++ b/src/main/java/capstone/facefriend/chat/service/dto/message/MessageListResponse.java @@ -0,0 +1,25 @@ +package capstone.facefriend.chat.service.dto.message; + +import capstone.facefriend.chat.domain.ChatMessage; + +import java.time.LocalDateTime; + +public record MessageListResponse( + Long senderId, + String senderNickname, + String senderOriginS3Url, + String senderGeneratedS3Url, + String content, + LocalDateTime sendTime +) { + public static MessageListResponse of (ChatMessage message) { + return new MessageListResponse( + message.getSender().getId(), + message.getSender().getBasicInfo().getNickname(), + message.getSender().getFaceInfo().getOriginS3url(), + message.getSender().getFaceInfo().getGeneratedS3url(), + message.getContent(), + message.getSendTime() + ); + } +} \ No newline at end of file diff --git a/src/main/java/capstone/facefriend/chat/service/dto/message/MessageResponse.java b/src/main/java/capstone/facefriend/chat/service/dto/message/MessageResponse.java index cb55138300..9236902bff 100644 --- a/src/main/java/capstone/facefriend/chat/service/dto/message/MessageResponse.java +++ b/src/main/java/capstone/facefriend/chat/service/dto/message/MessageResponse.java @@ -19,6 +19,7 @@ public class MessageResponse implements Serializable { private String content; private String type; private String senderNickname; + private String senderFaceInfoS3Url; @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "Asia/Seoul") private LocalDateTime createdAt; private Boolean isRead;