From a1156ad7e67c1b04469ab30fe5038958aa5064e6 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 00:42:21 +0900 Subject: [PATCH 01/15] =?UTF-8?q?SB-239=20(feat)=20:ChatMessageRepository?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-239 (feat) :ChatMessageRepository 구현 1. MessageType 2. ChatMessageEntity 3. ChatMessageRepository --- .../db/domain/chat/enums/MessageType.java | 16 +++++++++ .../chat/message/ChatMessageEntity.java | 33 +++++++++++++++++++ .../chat/message/ChatMessageRepository.java | 10 ++++++ 3 files changed, 59 insertions(+) create mode 100644 db/src/main/java/db/domain/chat/enums/MessageType.java create mode 100644 db/src/main/java/db/domain/chat/message/ChatMessageEntity.java create mode 100644 db/src/main/java/db/domain/chat/message/ChatMessageRepository.java diff --git a/db/src/main/java/db/domain/chat/enums/MessageType.java b/db/src/main/java/db/domain/chat/enums/MessageType.java new file mode 100644 index 00000000..4da0b365 --- /dev/null +++ b/db/src/main/java/db/domain/chat/enums/MessageType.java @@ -0,0 +1,16 @@ +package db.domain.chat.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum MessageType { + ENTER("입장"), + QUIT("퇴장"), + TALK("대화") + ; + + private final String description; + +} \ No newline at end of file diff --git a/db/src/main/java/db/domain/chat/message/ChatMessageEntity.java b/db/src/main/java/db/domain/chat/message/ChatMessageEntity.java new file mode 100644 index 00000000..87e87d0b --- /dev/null +++ b/db/src/main/java/db/domain/chat/message/ChatMessageEntity.java @@ -0,0 +1,33 @@ +package db.domain.chat.message; + +import db.domain.chat.enums.MessageType; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.io.Serial; +import java.io.Serializable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "chat_message") +@SuperBuilder +public class ChatMessageEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id + private Long id; + private String message; // 메시지 내용 + private MessageType type; // 메시지 타입 + private Long chatRoomId; // 방 ID + private Long userId; // 발신자 ID + private String createdAt; + +} \ No newline at end of file diff --git a/db/src/main/java/db/domain/chat/message/ChatMessageRepository.java b/db/src/main/java/db/domain/chat/message/ChatMessageRepository.java new file mode 100644 index 00000000..8852e3c7 --- /dev/null +++ b/db/src/main/java/db/domain/chat/message/ChatMessageRepository.java @@ -0,0 +1,10 @@ +package db.domain.chat.message; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChatMessageRepository extends JpaRepository { + + List findAllByChatRoomId(Long chatRoomId); + +} From 2ccf9bbc0434bb62ea71da0bdf94013188a48824 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 00:43:10 +0900 Subject: [PATCH 02/15] =?UTF-8?q?SB-240=20(feat)=20:=20ChatRoomRepository?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-240 (feat) : ChatRoomRepository 구현 1. ChatRoomStatus 2. ChatRoomEntity 3. ChatRoomRepository --- .../db/domain/chat/enums/ChatRoomStatus.java | 17 ++++++++ .../db/domain/chat/room/ChatRoomEntity.java | 39 +++++++++++++++++++ .../domain/chat/room/ChatRoomRepository.java | 21 ++++++++++ 3 files changed, 77 insertions(+) create mode 100644 db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java create mode 100644 db/src/main/java/db/domain/chat/room/ChatRoomEntity.java create mode 100644 db/src/main/java/db/domain/chat/room/ChatRoomRepository.java diff --git a/db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java b/db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java new file mode 100644 index 00000000..bcfe1aa5 --- /dev/null +++ b/db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java @@ -0,0 +1,17 @@ +package db.domain.chat.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ChatRoomStatus { + + ACTIVATE(1, "활성화 채팅방", "활성화된 채팅방입니다."), + INACTIVATE(2, "비활성화 채팅방", "비활성화된 채팅방입니다.") + ; + + private final int current; + private final String status; + private final String description; +} diff --git a/db/src/main/java/db/domain/chat/room/ChatRoomEntity.java b/db/src/main/java/db/domain/chat/room/ChatRoomEntity.java new file mode 100644 index 00000000..78f49cf4 --- /dev/null +++ b/db/src/main/java/db/domain/chat/room/ChatRoomEntity.java @@ -0,0 +1,39 @@ +package db.domain.chat.room; + +import db.common.BaseEntity; +import db.domain.chat.enums.ChatRoomStatus; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "chat_room") +@SuperBuilder +public class ChatRoomEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Id + private Long id; + + private Long userId; // 구매자 id + + private Long usedGoodsId; // 중고 판매 글 ID + + private ChatRoomStatus status; + + private LocalDateTime createdAt; + +} diff --git a/db/src/main/java/db/domain/chat/room/ChatRoomRepository.java b/db/src/main/java/db/domain/chat/room/ChatRoomRepository.java new file mode 100644 index 00000000..7f55cbe6 --- /dev/null +++ b/db/src/main/java/db/domain/chat/room/ChatRoomRepository.java @@ -0,0 +1,21 @@ +package db.domain.chat.room; + +import java.util.List; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface ChatRoomRepository extends JpaRepository { + + Optional findFirstByUsedGoodsIdAndUserId(Long usedGoodsId, Long userId); + + List findAll(); + + void deleteById(Long id); + + Optional findFirstById(Long id); + + List findByUsedGoodsIdIn(List usedGoodsId); + + List findByUserId(Long userid); + +} From 3ecf532bba9f00f3b6253c455b15fd68af5018e5 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 00:50:26 +0900 Subject: [PATCH 03/15] =?UTF-8?q?SB-241=20(feat)=20:=20=EC=B1=84=ED=8C=85?= =?UTF-8?q?=20=ED=99=98=EA=B2=BD=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-241 (feat) : 채팅 환경 설정 1. build.gradle 2. RedisConfig 3. SecurityConfig - WHITE_LIST 에 "/chatting/**" 추가 4. WebSocketConfig --- warehouse/build.gradle | 4 ++ .../common/config/redis/RedisConfig.java | 52 +++++++++++++++++++ .../config/security/SecurityConfig.java | 2 +- .../config/websocket/WebSocketConfig.java | 27 ++++++++++ warehouse/src/main/resources/application.yml | 4 ++ 5 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 warehouse/src/main/java/warehouse/common/config/redis/RedisConfig.java create mode 100644 warehouse/src/main/java/warehouse/common/config/websocket/WebSocketConfig.java diff --git a/warehouse/build.gradle b/warehouse/build.gradle index 8cb97e13..90923198 100644 --- a/warehouse/build.gradle +++ b/warehouse/build.gradle @@ -27,6 +27,10 @@ dependencies { implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'org.springframework.boot:spring-boot-starter-websocket' + + implementation 'io.jsonwebtoken:jjwt-api:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.11.5' diff --git a/warehouse/src/main/java/warehouse/common/config/redis/RedisConfig.java b/warehouse/src/main/java/warehouse/common/config/redis/RedisConfig.java new file mode 100644 index 00000000..6fe06ecb --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/config/redis/RedisConfig.java @@ -0,0 +1,52 @@ +package warehouse.common.config.redis; + +import db.domain.chat.message.ChatMessageEntity; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.data.redis.serializer.GenericToStringSerializer; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@RequiredArgsConstructor +@Configuration +public class RedisConfig { + + /** + * redis pub/sub 메시지를 처리하는 listener 설정 + */ + @Bean + public RedisMessageListenerContainer redisMessageListener( + RedisConnectionFactory connectionFactory) { + RedisMessageListenerContainer container = new RedisMessageListenerContainer(); + container.setConnectionFactory(connectionFactory); + return container; + } + + /** + * ChatRoom 사용할 redisTemplate 설정 + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(connectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class)); // 모든 Object를 JSON으로 직렬화 + return redisTemplate; + } + + /** + * ChatMessage 사용할 redisTemplate 설정 + */ + @Bean + public RedisTemplate chatMessageRedisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(connectionFactory); + redisTemplate.setKeySerializer(new GenericToStringSerializer<>(Long.class)); + redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(ChatMessageEntity.class)); + return redisTemplate; + } +} \ No newline at end of file diff --git a/warehouse/src/main/java/warehouse/common/config/security/SecurityConfig.java b/warehouse/src/main/java/warehouse/common/config/security/SecurityConfig.java index 8f68831b..e0fa39d2 100644 --- a/warehouse/src/main/java/warehouse/common/config/security/SecurityConfig.java +++ b/warehouse/src/main/java/warehouse/common/config/security/SecurityConfig.java @@ -33,7 +33,7 @@ public class SecurityConfig { private final TokenService tokenService; private final List WHITE_LIST = List.of("/swagger-ui.html", "/swagger-ui/**", - "/v3/api-docs/**", "/open-api/**"); + "/v3/api-docs/**", "/open-api/**", "/chatting/**"); @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { diff --git a/warehouse/src/main/java/warehouse/common/config/websocket/WebSocketConfig.java b/warehouse/src/main/java/warehouse/common/config/websocket/WebSocketConfig.java new file mode 100644 index 00000000..4df4ac61 --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/config/websocket/WebSocketConfig.java @@ -0,0 +1,27 @@ +package warehouse.common.config.websocket; + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocket; +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 +@RequiredArgsConstructor +@EnableWebSocketMessageBroker +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + @Override + public void configureMessageBroker(MessageBrokerRegistry registry) { + registry.enableSimpleBroker("/sub"); + registry.setApplicationDestinationPrefixes("/pub"); + } + + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/chatting").setAllowedOrigins("*"); + //.withSockJS(); + } +} diff --git a/warehouse/src/main/resources/application.yml b/warehouse/src/main/resources/application.yml index 4c8e3625..53728d57 100644 --- a/warehouse/src/main/resources/application.yml +++ b/warehouse/src/main/resources/application.yml @@ -12,6 +12,10 @@ spring: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 1234 + data: + redis: + host: localhost + port: 6379 file: upload-dir: /Users/yeongwoonshin/Desktop/Baobab-SERVER/warehouse/src/main/resources/static/images/ path : /images/ From 5971b86dadb87848ef8ebb5a2e562dbceac26a24 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 00:59:18 +0900 Subject: [PATCH 04/15] =?UTF-8?q?SB-242=20(feat)=20:=20=EC=B1=84=ED=8C=85?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-242 (feat) : 채팅 예외 처리 구현 1. ChatErrorCode 2. ChatMessageNotFoundException 3. ChatRoomNotFoundException 4. ChatExceptionHandler --- .../warehouse/common/error/ChatErrorCode.java | 21 ++++++++++ .../exception/ChatExceptionHandler.java | 39 +++++++++++++++++++ .../chat/ChatMessageNotFoundException.java | 34 ++++++++++++++++ .../chat/ChatRoomExistsException.java | 34 ++++++++++++++++ .../chat/ChatRoomNotFoundException.java | 34 ++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java create mode 100644 warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java create mode 100644 warehouse/src/main/java/warehouse/common/exception/chat/ChatMessageNotFoundException.java create mode 100644 warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomExistsException.java create mode 100644 warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomNotFoundException.java diff --git a/warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java b/warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java new file mode 100644 index 00000000..24a57ee1 --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java @@ -0,0 +1,21 @@ +package warehouse.common.error; + +import global.errorcode.ErrorCodeIfs; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum ChatErrorCode implements ErrorCodeIfs { + + CHAT_ROOM_NOT_FOUND(HttpStatus.NOT_FOUND.value(), 1700, "채팅방이 존재하지 않습니다."), + CHAT_MESSAGE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), 1701, "채팅 메시지가 존재하지 않습니다."), + CHAT_ROOM_EXISTS(HttpStatus.BAD_REQUEST.value(), 1702, "이미 존재하는 채팅방 입니다."); + ; + + private final Integer httpCode; + private final Integer errorCode; + private final String description; + +} diff --git a/warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java b/warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java new file mode 100644 index 00000000..0f1628aa --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java @@ -0,0 +1,39 @@ +package warehouse.common.exception; + +import global.api.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import warehouse.common.error.ChatErrorCode; +import warehouse.common.exception.chat.ChatMessageNotFoundException; +import warehouse.common.exception.chat.ChatRoomExistsException; +import warehouse.common.exception.chat.ChatRoomNotFoundException; + +@Slf4j +@RestControllerAdvice +public class ChatExceptionHandler { + + @ExceptionHandler(value = ChatRoomNotFoundException.class) + public ResponseEntity> chatRoomNotFoundException(ChatRoomNotFoundException e) { + log.info("", e); + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(Api.ERROR(ChatErrorCode.CHAT_ROOM_NOT_FOUND)); + } + + @ExceptionHandler(value = ChatMessageNotFoundException.class) + public ResponseEntity> chatMessageNotFoundException(ChatMessageNotFoundException e) { + log.info("", e); + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(Api.ERROR(ChatErrorCode.CHAT_MESSAGE_NOT_FOUND)); + } + + @ExceptionHandler(value = ChatRoomExistsException.class) + public ResponseEntity> chatRoomExistsException(ChatRoomExistsException e) { + log.info("", e); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(Api.ERROR(ChatErrorCode.CHAT_ROOM_EXISTS)); + } + +} diff --git a/warehouse/src/main/java/warehouse/common/exception/chat/ChatMessageNotFoundException.java b/warehouse/src/main/java/warehouse/common/exception/chat/ChatMessageNotFoundException.java new file mode 100644 index 00000000..f94226ed --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/exception/chat/ChatMessageNotFoundException.java @@ -0,0 +1,34 @@ +package warehouse.common.exception.chat; + +import global.errorcode.ErrorCodeIfs; + +public class ChatMessageNotFoundException extends RuntimeException { + + private final ErrorCodeIfs errorCodeIfs; + private final String description; + + public ChatMessageNotFoundException(ErrorCodeIfs errorCodeIfs) { + super(errorCodeIfs.getDescription()); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatMessageNotFoundException(ErrorCodeIfs errorCodeIfs, String errorDescription) { + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + + public ChatMessageNotFoundException(ErrorCodeIfs errorCodeIfs, Throwable throwable) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatMessageNotFoundException(ErrorCodeIfs errorCodeIfs, Throwable throwable, + String errorDescription) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + +} diff --git a/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomExistsException.java b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomExistsException.java new file mode 100644 index 00000000..b7f32496 --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomExistsException.java @@ -0,0 +1,34 @@ +package warehouse.common.exception.chat; + +import global.errorcode.ErrorCodeIfs; + +public class ChatRoomExistsException extends RuntimeException { + + private final ErrorCodeIfs errorCodeIfs; + private final String description; + + public ChatRoomExistsException(ErrorCodeIfs errorCodeIfs) { + super(errorCodeIfs.getDescription()); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomExistsException(ErrorCodeIfs errorCodeIfs, String errorDescription) { + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + + public ChatRoomExistsException(ErrorCodeIfs errorCodeIfs, Throwable throwable) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomExistsException(ErrorCodeIfs errorCodeIfs, Throwable throwable, + String errorDescription) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + +} diff --git a/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomNotFoundException.java b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomNotFoundException.java new file mode 100644 index 00000000..ac822cfd --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomNotFoundException.java @@ -0,0 +1,34 @@ +package warehouse.common.exception.chat; + +import global.errorcode.ErrorCodeIfs; + +public class ChatRoomNotFoundException extends RuntimeException { + + private final ErrorCodeIfs errorCodeIfs; + private final String description; + + public ChatRoomNotFoundException(ErrorCodeIfs errorCodeIfs) { + super(errorCodeIfs.getDescription()); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomNotFoundException(ErrorCodeIfs errorCodeIfs, String errorDescription) { + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + + public ChatRoomNotFoundException(ErrorCodeIfs errorCodeIfs, Throwable throwable) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomNotFoundException(ErrorCodeIfs errorCodeIfs, Throwable throwable, + String errorDescription) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + +} From c3f243b424f2b01b9f6ef649a32cdf605a69c050 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 01:07:26 +0900 Subject: [PATCH 05/15] =?UTF-8?q?SB-243=20(feat)=20:=20Redis=20Publisher?= =?UTF-8?q?=20&=20Subscriber=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-243 (feat) : Redis Publisher & Subscriber 구현 1. RedisPublisher - /pub/chat 으로 발행 2. RedisSubscriber - /sub/chat/{chatRoomId} 로 구독 --- .../domain/chat/pusbsub/RedisPublisher.java | 25 +++++++++++ .../domain/chat/pusbsub/RedisSubscriber.java | 41 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisPublisher.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisSubscriber.java diff --git a/warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisPublisher.java b/warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisPublisher.java new file mode 100644 index 00000000..2c5b3e1e --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisPublisher.java @@ -0,0 +1,25 @@ +package warehouse.domain.chat.pusbsub; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.stereotype.Service; +import db.domain.chat.message.ChatMessageEntity; + +/** + * 채팅방에 입장하여 메시지를 작성하면 해당 메시지를 Redis Topic 에 발행하는 기능을 수행한다. + * 이 서비스를 통해 메시지를 발행하면 대기하고 있던 redis 구독 서비스가 메시지를 처리한다. + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class RedisPublisher { + + private final RedisTemplate redisTemplate; + + public void publish(ChannelTopic topic, ChatMessageEntity message){ + redisTemplate.convertAndSend(topic.getTopic(), message); + } + +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisSubscriber.java b/warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisSubscriber.java new file mode 100644 index 00000000..23b6f98d --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/pusbsub/RedisSubscriber.java @@ -0,0 +1,41 @@ +package warehouse.domain.chat.pusbsub; + +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.SimpMessageSendingOperations; +import org.springframework.stereotype.Service; +import warehouse.domain.chat.controller.model.request.ChatMessageRequest; + +/** + * Redis 에 메시지 발행이 될 때까지 대기하였다가 메시지가 발행되면 해당 메시지를 읽어 처리하는 서비스 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class RedisSubscriber implements MessageListener { + + private final ObjectMapper objectMapper; + private final RedisTemplate redisTemplate; + private final SimpMessageSendingOperations messagingTemplate; + + /** + * Redis 에서 메세지가 발행(publish)되면 대기하고 있던 onMessage 가 해당 메세지를 받아 처리 + */ + @Override + public void onMessage(Message message, byte[] pattern) { + try{ + // redis 에서 발행된 데이터를 받아 deserialize + String publishMessage = (String) redisTemplate.getStringSerializer().deserialize(message.getBody()); + // ChatMessage 객체로 매핑 + ChatMessageRequest chatMessage = objectMapper.readValue(publishMessage, ChatMessageRequest.class); + // WebSocket 구독자에게 채팅 메세지 Send + messagingTemplate.convertAndSend("/sub/chat/" + chatMessage.getChatRoomId(), chatMessage); + } catch (Exception e){ + log.error(e.getMessage()); + } + } +} From 3f3b3364949d19409b782b028a5f6926db774497 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 01:29:47 +0900 Subject: [PATCH 06/15] =?UTF-8?q?SB-244=20(feat)=20:=20ChatRoom=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-244 (feat) : ChatRoom 기능 구현 - 채팅방 생성 - 채팅방 조회 1. ChatBusiness 2. ChatApiController 3. ChatRoomResponse 4. MessageResponse 5. ChatConverter 6. ChatRdbService 7. ChatService 8. UsedGoodsService - getUsedGoodsListBy 메서드 추가 --- .../domain/chat/business/ChatBusiness.java | 81 +++++++++++ .../chat/controller/ChatApiController.java | 60 ++++++++ .../model/response/ChatRoomResponse.java | 21 +++ .../model/response/MessageResponse.java | 16 +++ .../domain/chat/converter/ChatConverter.java | 77 ++++++++++ .../domain/chat/service/ChatRdbService.java | 66 +++++++++ .../domain/chat/service/ChatService.java | 131 ++++++++++++++++++ .../usedgoods/service/UsedGoodsService.java | 7 + 8 files changed, 459 insertions(+) create mode 100644 warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatRoomResponse.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/controller/model/response/MessageResponse.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/service/ChatRdbService.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java diff --git a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java new file mode 100644 index 00000000..1e132ae3 --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java @@ -0,0 +1,81 @@ +package warehouse.domain.chat.business; + +import db.domain.chat.room.ChatRoomEntity; +import db.domain.usedgoods.UsedGoodsEntity; +import db.domain.usedgoods.enums.UsedGoodsStatus; +import global.annotation.Business; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import db.domain.chat.message.ChatMessageEntity; +import org.springframework.security.core.userdetails.User; +import warehouse.domain.chat.controller.model.request.ChatMessageRequest; +import warehouse.domain.chat.controller.model.response.ChatMessageResponse; +import warehouse.domain.chat.controller.model.response.ChatRoomResponse; +import warehouse.domain.chat.controller.model.response.MessageResponse; +import warehouse.domain.chat.converter.ChatConverter; +import warehouse.domain.chat.service.ChatService; +import warehouse.domain.usedgoods.service.UsedGoodsService; +import warehouse.domain.users.service.UsersService; + +@Business +@RequiredArgsConstructor +@Slf4j +public class ChatBusiness { + + private final ChatService chatService; + private final UsedGoodsService usedGoodsService; + private final UsersService usersService; + private final ChatConverter chatConverter; + + + /** + * 1. 구매자 ID 존재하는지 확인. + * 2. 채팅방이 이미 존재하는지 확인 -> 있으면 예외 + * 3. 채팅방 고유 ID 반환 + */ + public ChatRoomResponse createChatRoom(Long usedGoodsId, String email) { + + Long userId = usersService.getUserWithThrow(email).getId(); // 사용자 인증 + + chatService.existsChatRoomWithThrow(usedGoodsId, userId); // 채팅방이 존재하는지 확인 -> 있으면 error + + ChatRoomEntity chatRoomEntity = chatConverter.toEntity(usedGoodsId, userId); + + ChatRoomEntity createdChatRoom = chatService.createChatRoomBy(chatRoomEntity); // 채팅방 생성 + +// chatService.subscribe(createdChatRoom.getId()); // Topic 생성 후 채팅방 구독 -> 두 번 발송되는 문제 발생 + + return chatConverter.toResponse(createdChatRoom); + + } + public List findAllChatRoom() { // 테스트용 + List chatRoomEntity = chatService.findAllChatRoom(); + return chatConverter.toResponse(chatRoomEntity); + + } + + public MessageResponse quitChatRoom(Long chatRoomId) { // 채팅 비활성화 + ChatRoomEntity chatRoomEntity = chatService.getChatRoomBy(chatRoomId); + chatService.quitChatRoomBy(chatRoomEntity); + return chatConverter.toMessageResponse("채팅방이 비활성화 되었습니다."); + } + + public List getBuyerChatRoom(String email) { + Long userId = usersService.getUserWithThrow(email).getId(); // 사용자 인증 + List createdChatRooms = chatService.getChatRoomListBy(userId); + return chatConverter.toResponse(createdChatRooms); + } + + + public List getSellerChatRoom(String email) { + Long userId = usersService.getUserWithThrow(email).getId(); // 사용자 인증 + + List usedGoodsIdList = usedGoodsService.getUsedGoodsListBy(userId).stream() + .map(usedGoodsEntity -> usedGoodsEntity.getId()).toList(); + + List chatRoomEntityList = chatService.getChatRoomListBy(usedGoodsIdList); + + return chatConverter.toResponse(chatRoomEntityList); + } +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java new file mode 100644 index 00000000..1c176708 --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java @@ -0,0 +1,60 @@ +package warehouse.domain.chat.controller; + +import global.api.Api; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.messaging.handler.annotation.MessageMapping; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.User; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import warehouse.domain.chat.business.ChatBusiness; +import warehouse.domain.chat.controller.model.request.ChatMessageRequest; +import warehouse.domain.chat.controller.model.response.ChatMessageResponse; +import warehouse.domain.chat.controller.model.response.ChatRoomResponse; +import warehouse.domain.chat.controller.model.response.MessageResponse; + +@RequiredArgsConstructor +@RestController +@RequestMapping("/api/chat") +@Slf4j +public class ChatApiController { + + private final ChatBusiness chatBusiness; + + @GetMapping("/rooms") // 모든 채팅방 조회 test 용 + public Api> rooms() { + List responses = chatBusiness.findAllChatRoom(); + return Api.OK(responses); + } + + @PostMapping("/{usedGoodsId}") //채팅방 개설 -> 구매자가 + public Api enterChatRoom(@PathVariable Long usedGoodsId, + @AuthenticationPrincipal User user) { + ChatRoomResponse response = chatBusiness.createChatRoom(usedGoodsId, user.getUsername()); + return Api.OK(response); + } + + @PostMapping("/room/{chatRoomId}") // 채팅방 퇴장 + public Api quitChatRoom(@PathVariable Long chatRoomId) { + MessageResponse response = chatBusiness.quitChatRoom(chatRoomId); + return Api.OK(response); + } + + @GetMapping("/room/buy") // 구매 채팅방 조회 + public Api> getBuyerChatRoom(@AuthenticationPrincipal User user) { + List response = chatBusiness.getBuyerChatRoom(user.getUsername()); + return Api.OK(response); + } + + @GetMapping("/room/sell") // 판매 채팅방 조회 + public Api> getSellerChatRoom(@AuthenticationPrincipal User user) { + List response = chatBusiness.getSellerChatRoom(user.getUsername()); + return Api.OK(response); + } + +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatRoomResponse.java b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatRoomResponse.java new file mode 100644 index 00000000..ebfae892 --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatRoomResponse.java @@ -0,0 +1,21 @@ +package warehouse.domain.chat.controller.model.response; + +import db.domain.chat.enums.ChatRoomStatus; +import java.time.LocalDateTime; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatRoomResponse { + + private Long chatRoomId; + private Long usedGoodsId; // 중고 판매 글 ID + private ChatRoomStatus status; + private LocalDateTime createdAt; + +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/MessageResponse.java b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/MessageResponse.java new file mode 100644 index 00000000..0ae4ab91 --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/MessageResponse.java @@ -0,0 +1,16 @@ +package warehouse.domain.chat.controller.model.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class MessageResponse { + + String message; + +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java b/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java new file mode 100644 index 00000000..595b48cf --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java @@ -0,0 +1,77 @@ +package warehouse.domain.chat.converter; + +import db.domain.chat.room.ChatRoomEntity; +import db.domain.chat.enums.ChatRoomStatus; +import global.annotation.Converter; +import java.time.LocalDateTime; +import java.util.List; +import db.domain.chat.message.ChatMessageEntity; +import db.domain.chat.enums.MessageType; +import warehouse.domain.chat.controller.model.request.ChatMessageRequest; +import warehouse.domain.chat.controller.model.response.ChatMessageResponse; +import warehouse.domain.chat.controller.model.response.ChatRoomResponse; +import warehouse.domain.chat.controller.model.response.MessageResponse; + +@Converter +public class ChatConverter { + + public ChatRoomEntity toEntity(Long usedGoodsId, Long userId) { + return ChatRoomEntity.builder() + .userId(userId) + .createdAt(LocalDateTime.now()) + .usedGoodsId(usedGoodsId) + .status(ChatRoomStatus.ACTIVATE) + .build(); + } + + public ChatRoomResponse toResponse(ChatRoomEntity chatRoomEntity) { + return ChatRoomResponse.builder() + .chatRoomId(chatRoomEntity.getId()) + .usedGoodsId(chatRoomEntity.getUsedGoodsId()) + .status(chatRoomEntity.getStatus()) + .createdAt(chatRoomEntity.getCreatedAt()) + .build(); + } + + public List toResponse(List chatRoomEntityList) { + return chatRoomEntityList.stream().map(chatRoomEntity -> toResponse(chatRoomEntity)) + .toList(); + } + + public List toChatMessageResponse( + List chatMessageEntityList) { + return chatMessageEntityList.stream().map(chatMessageEntity -> ChatMessageResponse.builder() + .message(chatMessageEntity.getMessage()) + .type(chatMessageEntity.getType()) + .chatRoomId(chatMessageEntity.getChatRoomId()) + .userId(chatMessageEntity.getUserId()) + .createdAt(chatMessageEntity.getCreatedAt()) + .build()).toList(); + } + + public ChatMessageEntity toChatMessage(ChatMessageRequest message, Long userId) { + if (MessageType.ENTER.equals(message.getType())) { + message.setMessage("[알림]" + userId + "님이 입장하셨습니다."); + } else if (MessageType.QUIT.equals(message.getType())) { + message.setMessage("[알림]" + userId + "님이 퇴장하였습니다."); +// chatService.deleteChatRoomBy(message.getRoomId()); + } + + return ChatMessageEntity.builder() + .message(message.getMessage()) + .type(message.getType()) + .chatRoomId(message.getChatRoomId()) + .userId(userId) + .createdAt(String.valueOf(LocalDateTime.now())) + .build(); + } + + public MessageResponse toMessageResponse(String message) { + return MessageResponse.builder() + .message(message) + .build(); + + } + + +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/service/ChatRdbService.java b/warehouse/src/main/java/warehouse/domain/chat/service/ChatRdbService.java new file mode 100644 index 00000000..80c664ff --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/service/ChatRdbService.java @@ -0,0 +1,66 @@ +package warehouse.domain.chat.service; + +import db.domain.chat.message.ChatMessageEntity; +import db.domain.chat.message.ChatMessageRepository; +import db.domain.chat.room.ChatRoomRepository; +import db.domain.chat.room.ChatRoomEntity; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import warehouse.common.error.ChatErrorCode; +import warehouse.common.exception.chat.ChatMessageNotFoundException; +import warehouse.common.exception.chat.ChatRoomNotFoundException; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ChatRdbService { + + private final ChatRoomRepository chatRoomRepository; + private final ChatMessageRepository chatMessageRepository; + + public ChatRoomEntity getChatRoomBy(Long chatRoomId) { + return chatRoomRepository.findFirstById(chatRoomId) + .orElseThrow(() -> new ChatRoomNotFoundException(ChatErrorCode.CHAT_ROOM_NOT_FOUND)); + } + + public List getChatRoomListBy(Long userId) { + List chatRoomEntityList = chatRoomRepository.findByUserId(userId); + if (chatRoomEntityList.isEmpty()) { + throw new ChatRoomNotFoundException(ChatErrorCode.CHAT_ROOM_NOT_FOUND); + } + return chatRoomEntityList; + } + + public ChatRoomEntity getChatRoomBy(Long usedGoodsId, Long userId) { + return chatRoomRepository.findFirstByUsedGoodsIdAndUserId(usedGoodsId, userId) + .orElseThrow(() -> new ChatRoomNotFoundException(ChatErrorCode.CHAT_ROOM_NOT_FOUND)); + } + + public List getChatRoomBy(List usedGoodsIdList) { + List chatRoomEntityList = chatRoomRepository.findByUsedGoodsIdIn( + usedGoodsIdList); + if (chatRoomEntityList.isEmpty()) { + throw new ChatRoomNotFoundException(ChatErrorCode.CHAT_ROOM_NOT_FOUND); + } + return chatRoomEntityList; + } + + public List getChatMessageBy(Long chatRoomId) { + List chatMessageEntityList = chatMessageRepository.findAllByChatRoomId( + chatRoomId); + if(chatMessageEntityList.isEmpty()) { + throw new ChatMessageNotFoundException(ChatErrorCode.CHAT_MESSAGE_NOT_FOUND); + } + return chatMessageEntityList; + } + + public void saveChatRoom(List chatRoomEntityList) { + chatRoomRepository.saveAll(chatRoomEntityList); + } + + public void saveChatMessage(List chatMessageEntityList) { + chatMessageRepository.saveAll(chatMessageEntityList); + } +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java new file mode 100644 index 00000000..224d5053 --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java @@ -0,0 +1,131 @@ +package warehouse.domain.chat.service; + +import db.domain.chat.room.ChatRoomEntity; +import db.domain.chat.enums.ChatRoomStatus; +import jakarta.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.redis.core.HashOperations; +import org.springframework.data.redis.core.ListOperations; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.listener.ChannelTopic; +import org.springframework.data.redis.listener.PatternTopic; +import org.springframework.data.redis.listener.RedisMessageListenerContainer; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; +import db.domain.chat.message.ChatMessageEntity; +import warehouse.common.error.ChatErrorCode; +import warehouse.common.exception.chat.ChatRoomExistsException; +import warehouse.common.exception.chat.ChatRoomNotFoundException; +import warehouse.domain.chat.pusbsub.RedisPublisher; +import warehouse.domain.chat.pusbsub.RedisSubscriber; + +@Service +@RequiredArgsConstructor +@Slf4j +public class ChatService { + + private final ChatRdbService chatRdbService; + private final RedisMessageListenerContainer redisMessageListener; // 채팅방(topic)에 발행되는 메시지를 처리할 Listener + private final RedisSubscriber redisSubscriber; // 구독 처리 서비스 + private final RedisPublisher redisPublisher; // 발행 + private static final String CHAT_ROOMS = "CHAT_ROOM"; + private final RedisTemplate redisTemplate; + private final RedisTemplate chatMessageRedisTemplate; + + private HashOperations opsHashChatRoom; + private ListOperations opsListChatMessage; + + @PostConstruct + private void init() { + opsHashChatRoom = redisTemplate.opsForHash(); + opsListChatMessage = chatMessageRedisTemplate.opsForList(); + redisMessageListener.addMessageListener(redisSubscriber, new PatternTopic("*")); + } + + // TODO 테스트용 + public List findAllChatRoom() { + return opsHashChatRoom.entries(CHAT_ROOMS).values().stream().toList(); + } + + /** + * Redis 에 해당 채팅방 정보를 확인 Redis 에 채팅방 정보가 존재하지 않다면 RDB 에서 가져오고 Redis 에 저장 둘 다 존재하지 않을 경우 예외 발생 + */ + public ChatRoomEntity getChatRoomBy(Long chatRoomId) { + ChatRoomEntity chatRoomEntity = opsHashChatRoom.get(CHAT_ROOMS, chatRoomId); + if (chatRoomEntity == null) { + chatRoomEntity = chatRdbService.getChatRoomBy(chatRoomId); + opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + } + return chatRoomEntity; + } + + /** + * 판매 채팅방 조회 Redis 에 해당 채팅방 정보를 확인 Redis 에 채팅방 정보가 존재하지 않다면 RDB 에서 가져오고 Redis 에 저장 둘 다 존재하지 않을 + * 경우 예외 발생 + */ + public List getChatRoomListBy(List usedGoodsIdList) { + List chatRoomEntityList = opsHashChatRoom.entries(CHAT_ROOMS).values() + .stream() + .filter( + chatRoomEntity -> usedGoodsIdList.contains(chatRoomEntity.getUsedGoodsId())) + .toList(); + if (chatRoomEntityList.isEmpty()) { + chatRoomEntityList = chatRdbService.getChatRoomBy(usedGoodsIdList); + chatRoomEntityList.forEach(chatRoomEntity -> { + opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + }); + } + return chatRoomEntityList; + } + + /** + * 구매 채팅방 조회 Redis 에 해당 채팅방 정보를 확인 Redis 에 채팅방 정보가 존재하지 않다면 RDB 에서 가져오고 Redis 에 저장 둘 다 존재하지 않을 + * 경우 예외 발생 + */ + public List getChatRoomListBy(Long userId) { + List chatRoomEntityList = opsHashChatRoom.entries(CHAT_ROOMS).values() + .stream().filter(chatRoomEntity -> chatRoomEntity.getUserId().equals(userId)).toList(); + if (chatRoomEntityList.isEmpty()) { + chatRoomEntityList = chatRdbService.getChatRoomListBy(userId); + chatRoomEntityList.forEach(chatRoomEntity -> { + opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + }); + throw new ChatRoomNotFoundException(ChatErrorCode.CHAT_ROOM_NOT_FOUND); + } + return chatRoomEntityList; + } + + /** + * 채팅방 생성 : 서버간 채팅방 공유를 위해 redis hash 에 저장한다. + */ + public ChatRoomEntity createChatRoomBy(ChatRoomEntity chatRoomEntity) { + Long chatRoomId = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE; + chatRoomEntity.setId(chatRoomId); + opsHashChatRoom.put(CHAT_ROOMS, chatRoomId, chatRoomEntity); + return chatRoomEntity; + } + + // TODO 메서드명 추천 + /** + * usedGoodsId 와 userId 로 채팅방이 존재하는지 확인하고, 존재할 경우 예외 발생 Redis, RDB 둘 다 조회 + */ + public void existsChatRoomWithThrow(Long usedGoodsId, Long userId) { + boolean chatRoom = opsHashChatRoom.entries(CHAT_ROOMS).values().stream().anyMatch( + chatRoomEntity -> chatRoomEntity.getUsedGoodsId().equals(usedGoodsId) + && chatRoomEntity.getUserId().equals(userId)); + if (chatRoom) { + throw new ChatRoomExistsException(ChatErrorCode.CHAT_ROOM_EXISTS); + } + try { // TODO 로직 수정 + if (chatRdbService.getChatRoomBy(usedGoodsId, userId) != null) { + throw new ChatRoomExistsException(ChatErrorCode.CHAT_ROOM_EXISTS); + } + } catch (RuntimeException e) { + + } + } + diff --git a/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java b/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java index 9f0cca6c..8760e743 100644 --- a/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java +++ b/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java @@ -59,4 +59,11 @@ public List usedGoodsSearchBy(EntitySearchCondition condition) return searchList; } + public List getUsedGoodsListBy(Long userId) { + List usedGoodsList = usedGoodsRepository.findByUserId(userId); + if (usedGoodsList.isEmpty()) { + throw new UsedGoodsNotFoundException(UsedGoodsErrorCode.USED_GOODS_NOT_FOUND); + } + return usedGoodsList; + } } From ea4492dbb554f81b7369fb325a184c06da509681 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 01:37:17 +0900 Subject: [PATCH 07/15] =?UTF-8?q?SB-245=20(feat)=20:=20ChatMessage=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-245 (feat) : ChatMessage 기능 구현 1. ChatBusiness 2. ChatApiController - /sub/chat/{chatRoomId} 로 메시지 전송 3. ChatMessageResponse 4. ChatService --- .../domain/chat/business/ChatBusiness.java | 21 +++++++++++ .../chat/controller/ChatApiController.java | 19 ++++++++++ .../model/request/ChatMessageRequest.java | 19 ++++++++++ .../model/response/ChatMessageResponse.java | 21 +++++++++++ .../domain/chat/service/ChatService.java | 37 +++++++++++++++++++ 5 files changed, 117 insertions(+) create mode 100644 warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java create mode 100644 warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java diff --git a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java index 1e132ae3..59434321 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java +++ b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java @@ -49,6 +49,21 @@ public ChatRoomResponse createChatRoom(Long usedGoodsId, String email) { return chatConverter.toResponse(createdChatRoom); } + + public MessageResponse subscribeChatRoom(Long chatRoomId) { + chatService.subscribe(chatRoomId); + return chatConverter.toMessageResponse("채팅방 구독이 완료되었습니다."); + } + + public void sendChatMessage(ChatMessageRequest message, Long userId) { + +// Long userId = usersService.getUserWithThrow(email).getId(); + ChatMessageEntity chatMessageEntity = chatConverter.toChatMessage(message, null); + + chatService.sendChatMessage(chatMessageEntity); + + } + public List findAllChatRoom() { // 테스트용 List chatRoomEntity = chatService.findAllChatRoom(); return chatConverter.toResponse(chatRoomEntity); @@ -78,4 +93,10 @@ public List getSellerChatRoom(String email) { return chatConverter.toResponse(chatRoomEntityList); } + + public List getChatMessage(Long chatRoomId) { + List chatMessageEntityList = chatService.getChatMessage(chatRoomId); + return chatConverter.toChatMessageResponse(chatMessageEntityList); + } + } diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java index 1c176708..69947c8b 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java @@ -39,12 +39,25 @@ public Api enterChatRoom(@PathVariable Long usedGoodsId, return Api.OK(response); } + @PostMapping("/sub/{chatRoomId}") //구독 -> 판매자가 + public Api subscribeChatRoom(@PathVariable Long chatRoomId) { + MessageResponse response = chatBusiness.subscribeChatRoom(chatRoomId); + return Api.OK(response); + } + @PostMapping("/room/{chatRoomId}") // 채팅방 퇴장 public Api quitChatRoom(@PathVariable Long chatRoomId) { MessageResponse response = chatBusiness.quitChatRoom(chatRoomId); return Api.OK(response); } + @MessageMapping("/chat") // 채팅 전송 +// public void sendMessage(ChatMessageRequest, @AuthenticationPrincipal User user) { + public void sendMessage(ChatMessageRequest message) { + //TODO user 정보 인증 테스트는 클라이언트 쪽에서 진행해야 함 + chatBusiness.sendChatMessage(message, null); + } + @GetMapping("/room/buy") // 구매 채팅방 조회 public Api> getBuyerChatRoom(@AuthenticationPrincipal User user) { List response = chatBusiness.getBuyerChatRoom(user.getUsername()); @@ -57,4 +70,10 @@ public Api> getSellerChatRoom(@AuthenticationPrincipal Us return Api.OK(response); } + @GetMapping("/{chatRoomId}") // 채팅 메시지 조회 + public Api> getChatMessage(@PathVariable Long chatRoomId) { + List response = chatBusiness.getChatMessage(chatRoomId); + return Api.OK(response); + } + } diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java b/warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java new file mode 100644 index 00000000..8c159035 --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java @@ -0,0 +1,19 @@ +package warehouse.domain.chat.controller.model.request; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import db.domain.chat.enums.MessageType; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class ChatMessageRequest { + + private String message; // 메시지 내용 + private MessageType type; // 메시지 타입 //TODO MessageType 에 대한 기능 개발 필요 + private Long chatRoomId; // 방 ID + +} \ No newline at end of file diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java new file mode 100644 index 00000000..093af406 --- /dev/null +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java @@ -0,0 +1,21 @@ +package warehouse.domain.chat.controller.model.response; + +import db.domain.chat.enums.MessageType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class ChatMessageResponse { + + private String message; // 메시지 내용 + private MessageType type; // 메시지 타입 + private Long chatRoomId; // 방 ID + private Long userId; // 발신자 ID + private String createdAt; + +} diff --git a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java index 224d5053..1dbfb01a 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java +++ b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java @@ -109,6 +109,14 @@ public ChatRoomEntity createChatRoomBy(ChatRoomEntity chatRoomEntity) { return chatRoomEntity; } + /** + * 채팅방 입장 : redis 에 topic 을 만들고 pub/sub 통신을 하기 위해 리스너를 설정한다. + */ + public void subscribe(Long chatRoomId) { + ChannelTopic topic = new ChannelTopic(String.valueOf(chatRoomId)); + redisMessageListener.addMessageListener(redisSubscriber, topic); + } + // TODO 메서드명 추천 /** * usedGoodsId 와 userId 로 채팅방이 존재하는지 확인하고, 존재할 경우 예외 발생 Redis, RDB 둘 다 조회 @@ -129,3 +137,32 @@ public void existsChatRoomWithThrow(Long usedGoodsId, Long userId) { } } + /** + * Topic 을 구독한 사용자에게 message 전송 Redis 에 삽입 + */ + public void sendChatMessage(ChatMessageEntity message) { + ChannelTopic topic = new ChannelTopic(String.valueOf(message.getChatRoomId())); + Long chatMessageId = UUID.randomUUID().getMostSignificantBits() & Long.MAX_VALUE; + message.setId(chatMessageId); + redisPublisher.publish(topic, message); + opsListChatMessage.rightPush(message.getChatRoomId(), message); + } + + public void quitChatRoomBy(ChatRoomEntity chatRoomEntity) { + chatRoomEntity.setStatus(ChatRoomStatus.INACTIVATE); + opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + } + + /** + * 채팅 메시지 전체 조회 + */ + public List getChatMessage(Long chatRoomId) { + List chatMessageEntityList = opsListChatMessage.range(chatRoomId, 0, + -1); + if (chatMessageEntityList.isEmpty()) { + chatMessageEntityList = chatRdbService.getChatMessageBy(chatRoomId); + } + return chatMessageEntityList; + } + + From 7e47dd28337630d4e643710e5e44581cf94c4bcf Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 01:42:41 +0900 Subject: [PATCH 08/15] =?UTF-8?q?SB-246=20(feat)=20:=20=EC=B1=84=ED=8C=85?= =?UTF-8?q?=20DB=20=EA=B4=80=EB=A6=AC=20=EC=8A=A4=EC=BC=80=EC=A4=84?= =?UTF-8?q?=EB=9F=AC=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-246 (feat) : 채팅 DB 관리 스케줄러 구현 1. ChatService - 매주 토요일 오전 2시 주기적으로 실행 - ChatRoom & ChatMessage 데이터를 RDB 에 저장하고 Redis 에서 제거함 2. WarehouseApplication - @EnableScheduling 추가 --- .../java/warehouse/WarehouseApplication.java | 2 ++ .../domain/chat/service/ChatService.java | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/warehouse/src/main/java/warehouse/WarehouseApplication.java b/warehouse/src/main/java/warehouse/WarehouseApplication.java index 66d531be..18e06f25 100644 --- a/warehouse/src/main/java/warehouse/WarehouseApplication.java +++ b/warehouse/src/main/java/warehouse/WarehouseApplication.java @@ -5,6 +5,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.scheduling.annotation.EnableScheduling; import warehouse.domain.image.properties.FileStorageProperties; @OpenAPIDefinition(servers = {@Server(url = "https://baobab.run", description = "fx server 연습용 도메인")}) @@ -12,6 +13,7 @@ @EnableConfigurationProperties({ FileStorageProperties.class }) +@EnableScheduling public class WarehouseApplication { public static void main(String[] args) { diff --git a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java index 1dbfb01a..e9288427 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java +++ b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java @@ -166,3 +166,35 @@ public List getChatMessage(Long chatRoomId) { } + /** + * ChatRoom 정보와 ChatMessage 정보를 저정하고 캐시에서 삭제 + */ + @Scheduled(cron = "0 0 2 ? * 7") // 매주 토요일 오전 2시 저장 + private void saveRedisToRdb() { + // chatRoom 저장 + List chatRoomEntityList = opsHashChatRoom.values(CHAT_ROOMS); + chatRdbService.saveChatRoom(chatRoomEntityList); + + // chatMessage 저장 + List chatMessageEntityList = new ArrayList<>(); + chatRoomEntityList.forEach(chatRoomEntity -> { + List chatMessageList = opsListChatMessage.range( + chatRoomEntity.getId(), 0, -1); + if (chatMessageList != null) { + chatMessageEntityList.addAll(chatMessageList); + } + }); + chatRdbService.saveChatMessage(chatMessageEntityList); + this.deleteRedisData(); + } + + private void deleteRedisData() { + log.info("Delete redis data ..."); + List chatRoomEntityList = opsHashChatRoom.values(CHAT_ROOMS); + chatRoomEntityList.forEach(chatRoomEntity -> + opsListChatMessage.getOperations().delete(chatRoomEntity.getId()) + ); + opsHashChatRoom.getOperations().delete(CHAT_ROOMS); + } + +} From ebd083d5aeb9f2242f9a797585c3afa851e14d32 Mon Sep 17 00:00:00 2001 From: SEOB Date: Mon, 12 Aug 2024 01:44:36 +0900 Subject: [PATCH 09/15] =?UTF-8?q?SB-244=20(feat)=20:=20ChatRoom=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-244 (feat) : ChatRoom 기능 구현 1. UsedGoodsRepository - findByUserId 메서드 추가 --- db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java b/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java index 4c713350..ad68900c 100644 --- a/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java +++ b/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java @@ -1,6 +1,7 @@ package db.domain.usedgoods; import db.domain.usedgoods.enums.UsedGoodsStatus; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -8,4 +9,6 @@ public interface UsedGoodsRepository extends JpaRepository findFirstByIdAndStatus(Long usedGoodsId, UsedGoodsStatus status); + List findByUserId(Long userId); + } From dcfc64d7055719e1754b14b73ec8b9a269c0cbf4 Mon Sep 17 00:00:00 2001 From: SEOB Date: Tue, 13 Aug 2024 23:22:32 +0900 Subject: [PATCH 10/15] =?UTF-8?q?SB-247=20(feat)=20:=20ChatRoom=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-247 (feat) : ChatRoom 삭제 기능 구현 ChatRoomStatus 를 DELETED 로 변경 1. ChatApiController 2. ChatBusiness 3. ChatService - quitChatRoomBy() -> setChatRoomStatusBy() 로 메서드 변경 --- .../warehouse/domain/chat/business/ChatBusiness.java | 12 +++++++++++- .../domain/chat/controller/ChatApiController.java | 6 ++++++ .../warehouse/domain/chat/service/ChatService.java | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java index 59434321..2f2d1a61 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java +++ b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java @@ -70,12 +70,22 @@ public List findAllChatRoom() { // 테스트용 } + /** + * INACTIVATE 채팅방 -> 채팅 불가 -> 예외 + * TODO - chatRoom 에 관련된 sellerId 와 buyerId 만 사용하도록 해야 함 + */ public MessageResponse quitChatRoom(Long chatRoomId) { // 채팅 비활성화 ChatRoomEntity chatRoomEntity = chatService.getChatRoomBy(chatRoomId); - chatService.quitChatRoomBy(chatRoomEntity); + chatService.setChatRoomStatusBy(chatRoomEntity, ChatRoomStatus.INACTIVATE); return chatConverter.toMessageResponse("채팅방이 비활성화 되었습니다."); } + public MessageResponse deleteChatRoom(Long chatRoomId) { // 채팅 비활성화 + ChatRoomEntity chatRoomEntity = chatService.getChatRoomBy(chatRoomId); + chatService.setChatRoomStatusBy(chatRoomEntity, ChatRoomStatus.DELETED); + return chatConverter.toMessageResponse("채팅방이 삭제되었습니다."); + } + public List getBuyerChatRoom(String email) { Long userId = usersService.getUserWithThrow(email).getId(); // 사용자 인증 List createdChatRooms = chatService.getChatRoomListBy(userId); diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java index 69947c8b..f11ffa36 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java @@ -51,6 +51,12 @@ public Api quitChatRoom(@PathVariable Long chatRoomId) { return Api.OK(response); } + @PostMapping("/room/delete/{chatRoomId}") // 채팅방 삭제 + public Api deleteChatRoom(@PathVariable Long chatRoomId) { + MessageResponse response = chatBusiness.deleteChatRoom(chatRoomId); + return Api.OK(response); + } + @MessageMapping("/chat") // 채팅 전송 // public void sendMessage(ChatMessageRequest, @AuthenticationPrincipal User user) { public void sendMessage(ChatMessageRequest message) { diff --git a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java index e9288427..b6ab1de7 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java +++ b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java @@ -148,8 +148,8 @@ public void sendChatMessage(ChatMessageEntity message) { opsListChatMessage.rightPush(message.getChatRoomId(), message); } - public void quitChatRoomBy(ChatRoomEntity chatRoomEntity) { - chatRoomEntity.setStatus(ChatRoomStatus.INACTIVATE); + public void setChatRoomStatusBy(ChatRoomEntity chatRoomEntity, ChatRoomStatus status) { + chatRoomEntity.setStatus(status); opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); } From 1cab620d0b5da55f7c94841f6bea7adaaaf148cb Mon Sep 17 00:00:00 2001 From: SEOB Date: Wed, 14 Aug 2024 16:17:56 +0900 Subject: [PATCH 11/15] =?UTF-8?q?SB-247=20(feat)=20:=20ChatRoom=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-247 (feat) : ChatRoom 삭제 기능 제거 판매자 or 구매자 둘 중 하나가 삭제 신청 시 둘 다 리스트에 보이지 않는 경우가 있음 1. ChatApiController - 관련 메서드 제거 2. ChatBusiness - 관련 메서드 제거 --- .../java/warehouse/domain/chat/business/ChatBusiness.java | 5 +---- .../warehouse/domain/chat/controller/ChatApiController.java | 3 --- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java index 2f2d1a61..574bbac4 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java +++ b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java @@ -80,10 +80,7 @@ public MessageResponse quitChatRoom(Long chatRoomId) { // 채팅 비활성화 return chatConverter.toMessageResponse("채팅방이 비활성화 되었습니다."); } - public MessageResponse deleteChatRoom(Long chatRoomId) { // 채팅 비활성화 - ChatRoomEntity chatRoomEntity = chatService.getChatRoomBy(chatRoomId); - chatService.setChatRoomStatusBy(chatRoomEntity, ChatRoomStatus.DELETED); - return chatConverter.toMessageResponse("채팅방이 삭제되었습니다."); + return chatConverter.toMessageResponse("채팅방이 비활성화 되었습니다."); } public List getBuyerChatRoom(String email) { diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java index f11ffa36..215d6eaa 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java @@ -51,9 +51,6 @@ public Api quitChatRoom(@PathVariable Long chatRoomId) { return Api.OK(response); } - @PostMapping("/room/delete/{chatRoomId}") // 채팅방 삭제 - public Api deleteChatRoom(@PathVariable Long chatRoomId) { - MessageResponse response = chatBusiness.deleteChatRoom(chatRoomId); return Api.OK(response); } From 886368007612cc4baf11af4a1e73b56dcb643dd5 Mon Sep 17 00:00:00 2001 From: SEOB Date: Wed, 14 Aug 2024 16:26:34 +0900 Subject: [PATCH 12/15] =?UTF-8?q?SB-242=20(feat)=20:=20=EC=B1=84=ED=8C=85?= =?UTF-8?q?=20=EC=98=88=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-242 (feat) : 채팅 예외 처리 추가 1. ChatRoomAccessDeniedException - ChatRoom 접근 권한이 없을 때 2. ChatRoomInactivateException - ChatRoom 의 상태가 Inactive 일 때 3. SellerAndBuyerSameException - 판매자가 자신의 글에 채팅을 시도할 때 4. ChatRoomStatus - 동사형에서 형용사로 변수명 변경 --- .../db/domain/chat/enums/ChatRoomStatus.java | 4 +-- .../warehouse/common/error/ChatErrorCode.java | 5 ++- .../exception/ChatExceptionHandler.java | 30 ++++++++++++++-- .../chat/ChatRoomAccessDeniedException.java | 34 +++++++++++++++++++ .../chat/ChatRoomInactiveException.java | 34 +++++++++++++++++++ .../chat/SellerAndBuyerSameException.java | 34 +++++++++++++++++++ 6 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomAccessDeniedException.java create mode 100644 warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomInactiveException.java create mode 100644 warehouse/src/main/java/warehouse/common/exception/chat/SellerAndBuyerSameException.java diff --git a/db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java b/db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java index bcfe1aa5..ec73cbc7 100644 --- a/db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java +++ b/db/src/main/java/db/domain/chat/enums/ChatRoomStatus.java @@ -7,8 +7,8 @@ @AllArgsConstructor public enum ChatRoomStatus { - ACTIVATE(1, "활성화 채팅방", "활성화된 채팅방입니다."), - INACTIVATE(2, "비활성화 채팅방", "비활성화된 채팅방입니다.") + ACTIVE(1, "활성화 채팅방", "활성화된 채팅방입니다."), + INACTIVE(2, "비활성화 채팅방", "비활성화된 채팅방입니다.") ; private final int current; diff --git a/warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java b/warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java index 24a57ee1..597787dc 100644 --- a/warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java +++ b/warehouse/src/main/java/warehouse/common/error/ChatErrorCode.java @@ -11,7 +11,10 @@ public enum ChatErrorCode implements ErrorCodeIfs { CHAT_ROOM_NOT_FOUND(HttpStatus.NOT_FOUND.value(), 1700, "채팅방이 존재하지 않습니다."), CHAT_MESSAGE_NOT_FOUND(HttpStatus.NOT_FOUND.value(), 1701, "채팅 메시지가 존재하지 않습니다."), - CHAT_ROOM_EXISTS(HttpStatus.BAD_REQUEST.value(), 1702, "이미 존재하는 채팅방 입니다."); + CHAT_ROOM_EXISTS(HttpStatus.BAD_REQUEST.value(), 1702, "이미 존재하는 채팅방 입니다."), + SELLER_AND_BUYER_SAME(HttpStatus.BAD_REQUEST.value(), 1703, "판매자는 자신의 상품에 대해 채팅방을 생성할 수 없습니다."), + CHAT_ROOM_INACTIVE(HttpStatus.BAD_REQUEST.value(), 1704, "채팅방이 비활성화 되어 채팅 전송이 불가능합니다."), + CHAT_ROOM_ACCESS_DENIED(HttpStatus.BAD_REQUEST.value(), 1705, "채팅방 접근 권한이 존재하지 않습니다.") ; private final Integer httpCode; diff --git a/warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java b/warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java index 0f1628aa..0629e179 100644 --- a/warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java +++ b/warehouse/src/main/java/warehouse/common/exception/ChatExceptionHandler.java @@ -8,8 +8,11 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import warehouse.common.error.ChatErrorCode; import warehouse.common.exception.chat.ChatMessageNotFoundException; +import warehouse.common.exception.chat.ChatRoomAccessDeniedException; import warehouse.common.exception.chat.ChatRoomExistsException; +import warehouse.common.exception.chat.ChatRoomInactiveException; import warehouse.common.exception.chat.ChatRoomNotFoundException; +import warehouse.common.exception.chat.SellerAndBuyerSameException; @Slf4j @RestControllerAdvice @@ -23,7 +26,8 @@ public ResponseEntity> chatRoomNotFoundException(ChatRoomNotFoundExc } @ExceptionHandler(value = ChatMessageNotFoundException.class) - public ResponseEntity> chatMessageNotFoundException(ChatMessageNotFoundException e) { + public ResponseEntity> chatMessageNotFoundException( + ChatMessageNotFoundException e) { log.info("", e); return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(Api.ERROR(ChatErrorCode.CHAT_MESSAGE_NOT_FOUND)); @@ -36,4 +40,26 @@ public ResponseEntity> chatRoomExistsException(ChatRoomExistsExcepti .body(Api.ERROR(ChatErrorCode.CHAT_ROOM_EXISTS)); } -} + @ExceptionHandler(value = SellerAndBuyerSameException.class) + public ResponseEntity> sellerAndBuyerSameException(SellerAndBuyerSameException e) { + log.info("", e); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(Api.ERROR(ChatErrorCode.SELLER_AND_BUYER_SAME)); + } + + @ExceptionHandler(value = ChatRoomInactiveException.class) + public ResponseEntity> chatRoomInactiveException(ChatRoomInactiveException e) { + log.info("", e); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(Api.ERROR(ChatErrorCode.CHAT_ROOM_INACTIVE)); + } + + @ExceptionHandler(value = ChatRoomAccessDeniedException.class) + public ResponseEntity> chatRoomAccessDeniedException( + ChatRoomAccessDeniedException e) { + log.info("", e); + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(Api.ERROR(ChatErrorCode.CHAT_ROOM_ACCESS_DENIED)); + } + +} \ No newline at end of file diff --git a/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomAccessDeniedException.java b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomAccessDeniedException.java new file mode 100644 index 00000000..f0803875 --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomAccessDeniedException.java @@ -0,0 +1,34 @@ +package warehouse.common.exception.chat; + +import global.errorcode.ErrorCodeIfs; + +public class ChatRoomAccessDeniedException extends RuntimeException { + + private final ErrorCodeIfs errorCodeIfs; + private final String description; + + public ChatRoomAccessDeniedException(ErrorCodeIfs errorCodeIfs) { + super(errorCodeIfs.getDescription()); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomAccessDeniedException(ErrorCodeIfs errorCodeIfs, String errorDescription) { + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + + public ChatRoomAccessDeniedException(ErrorCodeIfs errorCodeIfs, Throwable throwable) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomAccessDeniedException(ErrorCodeIfs errorCodeIfs, Throwable throwable, + String errorDescription) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + +} diff --git a/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomInactiveException.java b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomInactiveException.java new file mode 100644 index 00000000..58b084e1 --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/exception/chat/ChatRoomInactiveException.java @@ -0,0 +1,34 @@ +package warehouse.common.exception.chat; + +import global.errorcode.ErrorCodeIfs; + +public class ChatRoomInactiveException extends RuntimeException { + + private final ErrorCodeIfs errorCodeIfs; + private final String description; + + public ChatRoomInactiveException(ErrorCodeIfs errorCodeIfs) { + super(errorCodeIfs.getDescription()); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomInactiveException(ErrorCodeIfs errorCodeIfs, String errorDescription) { + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + + public ChatRoomInactiveException(ErrorCodeIfs errorCodeIfs, Throwable throwable) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public ChatRoomInactiveException(ErrorCodeIfs errorCodeIfs, Throwable throwable, + String errorDescription) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + +} diff --git a/warehouse/src/main/java/warehouse/common/exception/chat/SellerAndBuyerSameException.java b/warehouse/src/main/java/warehouse/common/exception/chat/SellerAndBuyerSameException.java new file mode 100644 index 00000000..b877fde5 --- /dev/null +++ b/warehouse/src/main/java/warehouse/common/exception/chat/SellerAndBuyerSameException.java @@ -0,0 +1,34 @@ +package warehouse.common.exception.chat; + +import global.errorcode.ErrorCodeIfs; + +public class SellerAndBuyerSameException extends RuntimeException { + + private final ErrorCodeIfs errorCodeIfs; + private final String description; + + public SellerAndBuyerSameException(ErrorCodeIfs errorCodeIfs) { + super(errorCodeIfs.getDescription()); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public SellerAndBuyerSameException(ErrorCodeIfs errorCodeIfs, String errorDescription) { + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + + public SellerAndBuyerSameException(ErrorCodeIfs errorCodeIfs, Throwable throwable) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorCodeIfs.getDescription(); + } + + public SellerAndBuyerSameException(ErrorCodeIfs errorCodeIfs, Throwable throwable, + String errorDescription) { + super(throwable); + this.errorCodeIfs = errorCodeIfs; + this.description = errorDescription; + } + +} From 2a778c46e2971e5b41c0c8e6e7869996feec29a7 Mon Sep 17 00:00:00 2001 From: SEOB Date: Wed, 14 Aug 2024 17:18:10 +0900 Subject: [PATCH 13/15] =?UTF-8?q?SB-248=20(refactor)=20:=20=EC=B1=84?= =?UTF-8?q?=ED=8C=85=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-248 (refactor) : 채팅 시스템 로직 리팩토링 1. ChatApiController - 기존 enterChatRoom → createChatRoom 으로 메서드명 변경 - 채팅방 입장 메서드를 enterChatRoom 으로 만들어 구현 → 응답으로 메시지 리스트를 반환함 - sendMessage 메서드 → @MessageMapping 에서 @PostMapping 으로 변경 - 그 외 API 변경 2. ChatBusiness - createChatRoom() - validateSellerAndBuyerNotSameWithThrow 검증 로직 추가 → 판매자는 자신의 글에 채팅방을 만들 수 없다. - enterChatRoom() - validateUserAccessToChatRoom 검증 로직 추가 → 채팅방은 판매자와 구매자만 입장이 가능하도록 구현 - 입장 후 채팅방 구독 - 채팅 메시지 리스트 반환 - sendChatMessage() - checkChatRoomInactiveWithThrow 검증 로직 추가 → 채팅방의 상태가 ACTIVE 일때만 채팅 메시지 전송 가능 - quitChatRoom() - validateUserAccessToChatRoom 검증 로직 추가 → 채팅방은 판매자와 구매자만 퇴장할 수 있도록 구현 3. ChatConverter - toChatMessageResponse() → toChatMessageListResponse() 로 메서드명 변경 - toChatMessage() - 불필요한 MessageType 체크 제거 4. ChatService - ChatRdbService 에서 데이터를 가져오는 로직을 따로 private 메서드로 분리 5. UsedGoodsRepository - findFirstByInd() 메서드 추가 --- .../domain/usedgoods/UsedGoodsRepository.java | 1 + .../domain/chat/business/ChatBusiness.java | 115 ++++++++++++++---- .../chat/controller/ChatApiController.java | 51 ++++---- .../domain/chat/converter/ChatConverter.java | 12 +- .../domain/chat/service/ChatService.java | 55 +++++---- .../usedgoods/service/UsedGoodsService.java | 9 +- 6 files changed, 160 insertions(+), 83 deletions(-) diff --git a/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java b/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java index ad68900c..8d2ce130 100644 --- a/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java +++ b/db/src/main/java/db/domain/usedgoods/UsedGoodsRepository.java @@ -11,4 +11,5 @@ public interface UsedGoodsRepository extends JpaRepository findByUserId(Long userId); + Optional findFirstById(Long usedGoodsId); } diff --git a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java index 574bbac4..49f3c00e 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java +++ b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java @@ -1,14 +1,17 @@ package warehouse.domain.chat.business; +import db.domain.chat.enums.ChatRoomStatus; import db.domain.chat.room.ChatRoomEntity; -import db.domain.usedgoods.UsedGoodsEntity; import db.domain.usedgoods.enums.UsedGoodsStatus; import global.annotation.Business; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import db.domain.chat.message.ChatMessageEntity; -import org.springframework.security.core.userdetails.User; +import warehouse.common.error.ChatErrorCode; +import warehouse.common.exception.chat.ChatRoomAccessDeniedException; +import warehouse.common.exception.chat.ChatRoomInactiveException; +import warehouse.common.exception.chat.SellerAndBuyerSameException; import warehouse.domain.chat.controller.model.request.ChatMessageRequest; import warehouse.domain.chat.controller.model.response.ChatMessageResponse; import warehouse.domain.chat.controller.model.response.ChatRoomResponse; @@ -30,13 +33,18 @@ public class ChatBusiness { /** - * 1. 구매자 ID 존재하는지 확인. + * 1. 판매자가 자신의 글에 채팅을 할 수 없도록 제한 * 2. 채팅방이 이미 존재하는지 확인 -> 있으면 예외 - * 3. 채팅방 고유 ID 반환 + * 3. ChatRoom 반환 */ public ChatRoomResponse createChatRoom(Long usedGoodsId, String email) { - Long userId = usersService.getUserWithThrow(email).getId(); // 사용자 인증 + Long sellerId = usedGoodsService.getUsedGoodsBy(usedGoodsId) + .getUserId(); + + Long userId = usersService.getUserWithThrow(email).getId(); + + validateSellerAndBuyerNotSameWithThrow(sellerId, userId); // 판매자와 구매자가 동일하지 않음을 확인 chatService.existsChatRoomWithThrow(usedGoodsId, userId); // 채팅방이 존재하는지 확인 -> 있으면 error @@ -44,54 +52,77 @@ public ChatRoomResponse createChatRoom(Long usedGoodsId, String email) { ChatRoomEntity createdChatRoom = chatService.createChatRoomBy(chatRoomEntity); // 채팅방 생성 -// chatService.subscribe(createdChatRoom.getId()); // Topic 생성 후 채팅방 구독 -> 두 번 발송되는 문제 발생 - return chatConverter.toResponse(createdChatRoom); } - public MessageResponse subscribeChatRoom(Long chatRoomId) { + /** + * 1. chatRoomId & userId 로 채팅방 접근 권한 체크 + * 2. 채팅방 구독 + */ + public List enterChatRoom(Long chatRoomId, String email) { + + Long userId = usersService.getUserWithThrow(email).getId(); + + ChatRoomEntity chatRoomEntity = chatService.getChatRoomBy(chatRoomId); + + validateUserAccessToChatRoom(userId, chatRoomEntity); + chatService.subscribe(chatRoomId); - return chatConverter.toMessageResponse("채팅방 구독이 완료되었습니다."); + + List chatMessage = chatService.getChatMessage(chatRoomId); + + return chatConverter.toChatMessageListResponse(chatMessage); + } - public void sendChatMessage(ChatMessageRequest message, Long userId) { + /** + * 1. 채팅방 status 점검 + * 2. chatRoomId & userId 로 채팅방 접근 권한 체크 + * 3. 채팅 메시지 전송 + */ + public void sendChatMessage(ChatMessageRequest message, String email) { -// Long userId = usersService.getUserWithThrow(email).getId(); - ChatMessageEntity chatMessageEntity = chatConverter.toChatMessage(message, null); + Long userId = usersService.getUserWithThrow(email).getId(); - chatService.sendChatMessage(chatMessageEntity); + ChatRoomEntity chatRoomEntity = chatService.getChatRoomBy(message.getChatRoomId()); - } + checkChatRoomInactiveWithThrow(chatRoomEntity.getStatus()); // INACTIVE -> 예외 - public List findAllChatRoom() { // 테스트용 - List chatRoomEntity = chatService.findAllChatRoom(); - return chatConverter.toResponse(chatRoomEntity); + validateUserAccessToChatRoom(userId, chatRoomEntity); + + ChatMessageEntity chatMessageEntity = chatConverter.toChatMessage(message, userId); + + chatService.sendChatMessage(chatMessageEntity); } /** - * INACTIVATE 채팅방 -> 채팅 불가 -> 예외 - * TODO - chatRoom 에 관련된 sellerId 와 buyerId 만 사용하도록 해야 함 + * 1. chatRoomId & userId 로 채팅방 접근 권한 체크 + * 2. 채팅방 status -> INACTIVATE 로 변경 */ - public MessageResponse quitChatRoom(Long chatRoomId) { // 채팅 비활성화 + public MessageResponse quitChatRoom(Long chatRoomId, String email) { // 채팅 비활성화 + + Long userId = usersService.getUserWithThrow(email).getId(); + ChatRoomEntity chatRoomEntity = chatService.getChatRoomBy(chatRoomId); - chatService.setChatRoomStatusBy(chatRoomEntity, ChatRoomStatus.INACTIVATE); - return chatConverter.toMessageResponse("채팅방이 비활성화 되었습니다."); - } + + validateUserAccessToChatRoom(userId, chatRoomEntity); + + chatService.setChatRoomStatusBy(chatRoomEntity, ChatRoomStatus.INACTIVE); return chatConverter.toMessageResponse("채팅방이 비활성화 되었습니다."); } public List getBuyerChatRoom(String email) { - Long userId = usersService.getUserWithThrow(email).getId(); // 사용자 인증 + Long userId = usersService.getUserWithThrow(email).getId(); List createdChatRooms = chatService.getChatRoomListBy(userId); return chatConverter.toResponse(createdChatRooms); } public List getSellerChatRoom(String email) { - Long userId = usersService.getUserWithThrow(email).getId(); // 사용자 인증 + Long userId = usersService.getUserWithThrow(email).getId(); List usedGoodsIdList = usedGoodsService.getUsedGoodsListBy(userId).stream() .map(usedGoodsEntity -> usedGoodsEntity.getId()).toList(); @@ -101,9 +132,41 @@ public List getSellerChatRoom(String email) { return chatConverter.toResponse(chatRoomEntityList); } + // TODO - TEST 용 public List getChatMessage(Long chatRoomId) { List chatMessageEntityList = chatService.getChatMessage(chatRoomId); - return chatConverter.toChatMessageResponse(chatMessageEntityList); + return chatConverter.toChatMessageListResponse(chatMessageEntityList); + } + + + // TODO - TEST 용 + public List findAllChatRoom() { // 테스트용 + List chatRoomEntity = chatService.findAllChatRoom(); + return chatConverter.toResponse(chatRoomEntity); + + } + + // 판매자 또는 구매자의 권한 검증 + private void validateUserAccessToChatRoom(Long userId, ChatRoomEntity chatRoomEntity) { + Long usedGoodsId = chatRoomEntity.getUsedGoodsId(); + Long sellerId = usedGoodsService.getUsedGoodsBy(usedGoodsId).getUserId(); + if (!sellerId.equals(userId) && !chatRoomEntity.getUserId().equals(userId)) { + throw new ChatRoomAccessDeniedException(ChatErrorCode.CHAT_ROOM_ACCESS_DENIED); + } + } + + // 판매자와 구매자가 동일한지 검증 + private void validateSellerAndBuyerNotSameWithThrow(Long sellerId, Long userId) { + if (sellerId.equals(userId)) { + throw new SellerAndBuyerSameException(ChatErrorCode.SELLER_AND_BUYER_SAME); + } + } + + // 비활성화된 상태인지 확인 + private void checkChatRoomInactiveWithThrow(ChatRoomStatus status) { + if(status.equals(ChatRoomStatus.INACTIVE)) { + throw new ChatRoomInactiveException(ChatErrorCode.CHAT_ROOM_INACTIVE); + } } } diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java index 215d6eaa..d390118a 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java @@ -4,12 +4,12 @@ import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.core.userdetails.User; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import warehouse.domain.chat.business.ChatBusiness; @@ -26,54 +26,55 @@ public class ChatApiController { private final ChatBusiness chatBusiness; - @GetMapping("/rooms") // 모든 채팅방 조회 test 용 - public Api> rooms() { - List responses = chatBusiness.findAllChatRoom(); - return Api.OK(responses); - } - @PostMapping("/{usedGoodsId}") //채팅방 개설 -> 구매자가 - public Api enterChatRoom(@PathVariable Long usedGoodsId, + public Api createChatRoom(@PathVariable Long usedGoodsId, @AuthenticationPrincipal User user) { ChatRoomResponse response = chatBusiness.createChatRoom(usedGoodsId, user.getUsername()); return Api.OK(response); } - @PostMapping("/sub/{chatRoomId}") //구독 -> 판매자가 - public Api subscribeChatRoom(@PathVariable Long chatRoomId) { - MessageResponse response = chatBusiness.subscribeChatRoom(chatRoomId); - return Api.OK(response); - } - - @PostMapping("/room/{chatRoomId}") // 채팅방 퇴장 - public Api quitChatRoom(@PathVariable Long chatRoomId) { - MessageResponse response = chatBusiness.quitChatRoom(chatRoomId); + @PostMapping("/enter/{chatRoomId}") // 채팅방 입장 + public Api> enterChatRoom(@PathVariable Long chatRoomId, + @AuthenticationPrincipal User user) { + List response = chatBusiness.enterChatRoom(chatRoomId, + user.getUsername()); return Api.OK(response); } + @PostMapping("/quit/{chatRoomId}") // 채팅방 퇴장 + public Api quitChatRoom(@PathVariable Long chatRoomId, + @AuthenticationPrincipal User user) { + MessageResponse response = chatBusiness.quitChatRoom(chatRoomId, user.getUsername()); return Api.OK(response); } - @MessageMapping("/chat") // 채팅 전송 -// public void sendMessage(ChatMessageRequest, @AuthenticationPrincipal User user) { - public void sendMessage(ChatMessageRequest message) { - //TODO user 정보 인증 테스트는 클라이언트 쪽에서 진행해야 함 - chatBusiness.sendChatMessage(message, null); + @PostMapping("/message") + public void sendMessage(@RequestBody ChatMessageRequest message, @AuthenticationPrincipal User user) { + log.info(message.toString()); + chatBusiness.sendChatMessage(message, user.getUsername()); } - @GetMapping("/room/buy") // 구매 채팅방 조회 + @GetMapping("/buy") // 구매 채팅방 조회 public Api> getBuyerChatRoom(@AuthenticationPrincipal User user) { List response = chatBusiness.getBuyerChatRoom(user.getUsername()); return Api.OK(response); } - @GetMapping("/room/sell") // 판매 채팅방 조회 + @GetMapping("/sell") // 판매 채팅방 조회 public Api> getSellerChatRoom(@AuthenticationPrincipal User user) { List response = chatBusiness.getSellerChatRoom(user.getUsername()); return Api.OK(response); } - @GetMapping("/{chatRoomId}") // 채팅 메시지 조회 + // TODO - TEST 용 + @GetMapping("/rooms") // 모든 채팅방 조회 test 용 + public Api> rooms() { + List responses = chatBusiness.findAllChatRoom(); + return Api.OK(responses); + } + + // TODO - TEST 용 + @GetMapping("/{chatRoomId}") // 모든 채팅 메시지 조회 public Api> getChatMessage(@PathVariable Long chatRoomId) { List response = chatBusiness.getChatMessage(chatRoomId); return Api.OK(response); diff --git a/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java b/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java index 595b48cf..3e8d86bc 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java +++ b/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java @@ -20,7 +20,7 @@ public ChatRoomEntity toEntity(Long usedGoodsId, Long userId) { .userId(userId) .createdAt(LocalDateTime.now()) .usedGoodsId(usedGoodsId) - .status(ChatRoomStatus.ACTIVATE) + .status(ChatRoomStatus.ACTIVE) .build(); } @@ -38,7 +38,7 @@ public List toResponse(List chatRoomEntityList .toList(); } - public List toChatMessageResponse( + public List toChatMessageListResponse( List chatMessageEntityList) { return chatMessageEntityList.stream().map(chatMessageEntity -> ChatMessageResponse.builder() .message(chatMessageEntity.getMessage()) @@ -50,13 +50,6 @@ public List toChatMessageResponse( } public ChatMessageEntity toChatMessage(ChatMessageRequest message, Long userId) { - if (MessageType.ENTER.equals(message.getType())) { - message.setMessage("[알림]" + userId + "님이 입장하셨습니다."); - } else if (MessageType.QUIT.equals(message.getType())) { - message.setMessage("[알림]" + userId + "님이 퇴장하였습니다."); -// chatService.deleteChatRoomBy(message.getRoomId()); - } - return ChatMessageEntity.builder() .message(message.getMessage()) .type(message.getType()) @@ -73,5 +66,4 @@ public MessageResponse toMessageResponse(String message) { } - } diff --git a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java index b6ab1de7..67add241 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java +++ b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java @@ -19,7 +19,6 @@ import db.domain.chat.message.ChatMessageEntity; import warehouse.common.error.ChatErrorCode; import warehouse.common.exception.chat.ChatRoomExistsException; -import warehouse.common.exception.chat.ChatRoomNotFoundException; import warehouse.domain.chat.pusbsub.RedisPublisher; import warehouse.domain.chat.pusbsub.RedisSubscriber; @@ -57,15 +56,14 @@ public List findAllChatRoom() { public ChatRoomEntity getChatRoomBy(Long chatRoomId) { ChatRoomEntity chatRoomEntity = opsHashChatRoom.get(CHAT_ROOMS, chatRoomId); if (chatRoomEntity == null) { - chatRoomEntity = chatRdbService.getChatRoomBy(chatRoomId); - opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + chatRoomEntity = getChatRoomEntityFromRdb(chatRoomId); } return chatRoomEntity; } /** - * 판매 채팅방 조회 Redis 에 해당 채팅방 정보를 확인 Redis 에 채팅방 정보가 존재하지 않다면 RDB 에서 가져오고 Redis 에 저장 둘 다 존재하지 않을 - * 경우 예외 발생 + * 판매 채팅방 조회(Delete 제외) Redis 에 해당 채팅방 정보를 확인 Redis 에 채팅방 정보가 존재하지 않다면 RDB 에서 가져오고 Redis 에 저장 둘 다 + * 존재하지 않을 경우 예외 발생 */ public List getChatRoomListBy(List usedGoodsIdList) { List chatRoomEntityList = opsHashChatRoom.entries(CHAT_ROOMS).values() @@ -74,27 +72,20 @@ public List getChatRoomListBy(List usedGoodsIdList) { chatRoomEntity -> usedGoodsIdList.contains(chatRoomEntity.getUsedGoodsId())) .toList(); if (chatRoomEntityList.isEmpty()) { - chatRoomEntityList = chatRdbService.getChatRoomBy(usedGoodsIdList); - chatRoomEntityList.forEach(chatRoomEntity -> { - opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); - }); + chatRoomEntityList = getChatRoomEntityListFromRdb(usedGoodsIdList); } return chatRoomEntityList; } /** - * 구매 채팅방 조회 Redis 에 해당 채팅방 정보를 확인 Redis 에 채팅방 정보가 존재하지 않다면 RDB 에서 가져오고 Redis 에 저장 둘 다 존재하지 않을 - * 경우 예외 발생 + * 구매 채팅방 조회(Delete 제외) Redis 에 해당 채팅방 정보를 확인 Redis 에 채팅방 정보가 존재하지 않다면 RDB 에서 가져오고 Redis 에 저장 둘 다 + * 존재하지 않을 경우 예외 발생 */ public List getChatRoomListBy(Long userId) { List chatRoomEntityList = opsHashChatRoom.entries(CHAT_ROOMS).values() .stream().filter(chatRoomEntity -> chatRoomEntity.getUserId().equals(userId)).toList(); if (chatRoomEntityList.isEmpty()) { - chatRoomEntityList = chatRdbService.getChatRoomListBy(userId); - chatRoomEntityList.forEach(chatRoomEntity -> { - opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); - }); - throw new ChatRoomNotFoundException(ChatErrorCode.CHAT_ROOM_NOT_FOUND); + chatRoomEntityList = getChatRoomEntityListFromRdb(userId); } return chatRoomEntityList; } @@ -117,7 +108,6 @@ public void subscribe(Long chatRoomId) { redisMessageListener.addMessageListener(redisSubscriber, topic); } - // TODO 메서드명 추천 /** * usedGoodsId 와 userId 로 채팅방이 존재하는지 확인하고, 존재할 경우 예외 발생 Redis, RDB 둘 다 조회 */ @@ -128,13 +118,11 @@ public void existsChatRoomWithThrow(Long usedGoodsId, Long userId) { if (chatRoom) { throw new ChatRoomExistsException(ChatErrorCode.CHAT_ROOM_EXISTS); } - try { // TODO 로직 수정 + try { if (chatRdbService.getChatRoomBy(usedGoodsId, userId) != null) { throw new ChatRoomExistsException(ChatErrorCode.CHAT_ROOM_EXISTS); } - } catch (RuntimeException e) { - - } + } catch (RuntimeException e) {} } /** @@ -197,4 +185,29 @@ private void deleteRedisData() { opsHashChatRoom.getOperations().delete(CHAT_ROOMS); } + private ChatRoomEntity getChatRoomEntityFromRdb(Long chatRoomId) { + ChatRoomEntity chatRoomEntity; + chatRoomEntity = chatRdbService.getChatRoomBy(chatRoomId); + opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + return chatRoomEntity; + } + + private List getChatRoomEntityListFromRdb(List usedGoodsIdList) { + List chatRoomEntityList; + chatRoomEntityList = chatRdbService.getChatRoomBy(usedGoodsIdList).stream().toList(); + chatRoomEntityList.forEach(chatRoomEntity -> { + opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + }); + return chatRoomEntityList; + } + + private List getChatRoomEntityListFromRdb(Long userId) { + List chatRoomEntityList; + chatRoomEntityList = chatRdbService.getChatRoomListBy(userId).stream().toList(); + chatRoomEntityList.forEach(chatRoomEntity -> { + opsHashChatRoom.put(CHAT_ROOMS, chatRoomEntity.getId(), chatRoomEntity); + }); + return chatRoomEntityList; + } + } diff --git a/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java b/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java index 8760e743..8156bd38 100644 --- a/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java +++ b/warehouse/src/main/java/warehouse/domain/usedgoods/service/UsedGoodsService.java @@ -10,7 +10,9 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import warehouse.common.error.GoodsErrorCode; import warehouse.common.error.UsedGoodsErrorCode; +import warehouse.common.exception.goods.GoodsNotFoundException; import warehouse.common.exception.usedGoods.GoodsNotInUsedStatus; import warehouse.common.exception.usedGoods.UsedGoodsNotFoundException; @@ -32,6 +34,11 @@ public UsedGoodsEntity getUsedGoodsBy(Long usedGoodsId, UsedGoodsStatus status) () -> new GoodsNotInUsedStatus(UsedGoodsErrorCode.GOODS_NOT_IN_USED_STATUS)); } + public UsedGoodsEntity getUsedGoodsBy(Long usedGoodsId) { + return usedGoodsRepository.findFirstById(usedGoodsId).orElseThrow( + () -> new GoodsNotFoundException(GoodsErrorCode.GOODS_NOT_FOUND)); + } + public List getUsedGoodsListBy(List usedGoodsIdList, UsedGoodsStatus status) { return usedGoodsIdList.stream() @@ -53,7 +60,7 @@ public void setUsedGoodsStatusBy(List usedGoodsEntityList, public List usedGoodsSearchBy(EntitySearchCondition condition) { List searchList = queryUsedGoodsRepository.usedGoodsSearchBy(condition); - if(searchList.isEmpty()) { + if (searchList.isEmpty()) { throw new UsedGoodsNotFoundException(UsedGoodsErrorCode.USED_GOODS_NOT_FOUND); } return searchList; From 2717e1785c360a7c1e48fc2a56cd34ca1d455e2b Mon Sep 17 00:00:00 2001 From: SEOB Date: Thu, 22 Aug 2024 11:36:29 +0900 Subject: [PATCH 14/15] =?UTF-8?q?SB-248=20(refactor)=20:=20=EC=B1=84?= =?UTF-8?q?=ED=8C=85=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-248 (refactor) : 채팅 시스템 리팩토링 1. MessageType 제거 2. ChatMessageEntity - @Column 추가 3. ChatRoomEntity - @Column 추가 4. AsyncConfig - Bean 식별 오류로 인한 @Primary 추가 5. ChatApiController - Swagger @Operation 추가 6. ChatMessageResponse 7. ChatMessageRequest --- .../java/db/domain/chat/enums/MessageType.java | 16 ---------------- .../domain/chat/message/ChatMessageEntity.java | 10 ++++++++-- .../java/db/domain/chat/room/ChatRoomEntity.java | 10 ++++++++-- .../common/config/async/AsyncConfig.java | 2 ++ .../chat/controller/ChatApiController.java | 9 +++++++++ .../model/request/ChatMessageRequest.java | 2 -- .../model/response/ChatMessageResponse.java | 2 -- .../domain/chat/converter/ChatConverter.java | 7 ++----- .../domain/chat/service/ChatService.java | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) delete mode 100644 db/src/main/java/db/domain/chat/enums/MessageType.java diff --git a/db/src/main/java/db/domain/chat/enums/MessageType.java b/db/src/main/java/db/domain/chat/enums/MessageType.java deleted file mode 100644 index 4da0b365..00000000 --- a/db/src/main/java/db/domain/chat/enums/MessageType.java +++ /dev/null @@ -1,16 +0,0 @@ -package db.domain.chat.enums; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public enum MessageType { - ENTER("입장"), - QUIT("퇴장"), - TALK("대화") - ; - - private final String description; - -} \ No newline at end of file diff --git a/db/src/main/java/db/domain/chat/message/ChatMessageEntity.java b/db/src/main/java/db/domain/chat/message/ChatMessageEntity.java index 87e87d0b..3fd9c92e 100644 --- a/db/src/main/java/db/domain/chat/message/ChatMessageEntity.java +++ b/db/src/main/java/db/domain/chat/message/ChatMessageEntity.java @@ -1,6 +1,6 @@ package db.domain.chat.message; -import db.domain.chat.enums.MessageType; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; @@ -24,10 +24,16 @@ public class ChatMessageEntity implements Serializable { @Id private Long id; + + @Column(nullable = false) private String message; // 메시지 내용 - private MessageType type; // 메시지 타입 + + @Column(nullable = false) private Long chatRoomId; // 방 ID + + @Column(nullable = false) private Long userId; // 발신자 ID + private String createdAt; } \ No newline at end of file diff --git a/db/src/main/java/db/domain/chat/room/ChatRoomEntity.java b/db/src/main/java/db/domain/chat/room/ChatRoomEntity.java index 78f49cf4..47ff980c 100644 --- a/db/src/main/java/db/domain/chat/room/ChatRoomEntity.java +++ b/db/src/main/java/db/domain/chat/room/ChatRoomEntity.java @@ -1,8 +1,10 @@ package db.domain.chat.room; -import db.common.BaseEntity; import db.domain.chat.enums.ChatRoomStatus; +import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.io.Serial; @@ -10,7 +12,6 @@ import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Data; -import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; @@ -28,10 +29,15 @@ public class ChatRoomEntity implements Serializable { @Id private Long id; + @Column(nullable = false) private Long userId; // 구매자 id + @Column(nullable = false) + private Long usedGoodsId; // 중고 판매 글 ID + @Column(nullable = false) + @Enumerated(EnumType.STRING) private ChatRoomStatus status; private LocalDateTime createdAt; diff --git a/warehouse/src/main/java/warehouse/common/config/async/AsyncConfig.java b/warehouse/src/main/java/warehouse/common/config/async/AsyncConfig.java index d6e774c4..2fb1cf7e 100644 --- a/warehouse/src/main/java/warehouse/common/config/async/AsyncConfig.java +++ b/warehouse/src/main/java/warehouse/common/config/async/AsyncConfig.java @@ -3,6 +3,7 @@ import java.util.concurrent.Executor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @@ -10,6 +11,7 @@ @Configuration public class AsyncConfig { + @Primary @Bean(name = "imageUploadExecutor") public Executor imageUploadExecutor() { diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java index d390118a..ca94c151 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/ChatApiController.java @@ -1,6 +1,7 @@ package warehouse.domain.chat.controller; import global.api.Api; +import io.swagger.v3.oas.annotations.Operation; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -27,6 +28,7 @@ public class ChatApiController { private final ChatBusiness chatBusiness; @PostMapping("/{usedGoodsId}") //채팅방 개설 -> 구매자가 + @Operation(summary = "[채팅방 생성]", description = "물품 구매자가 채팅방을 생성함, ws://localhost:8080/chatting") public Api createChatRoom(@PathVariable Long usedGoodsId, @AuthenticationPrincipal User user) { ChatRoomResponse response = chatBusiness.createChatRoom(usedGoodsId, user.getUsername()); @@ -34,6 +36,7 @@ public Api createChatRoom(@PathVariable Long usedGoodsId, } @PostMapping("/enter/{chatRoomId}") // 채팅방 입장 + @Operation(summary = "[채팅방 입장]", description = "구독 - /sub/chat/{chatRoomId}") public Api> enterChatRoom(@PathVariable Long chatRoomId, @AuthenticationPrincipal User user) { List response = chatBusiness.enterChatRoom(chatRoomId, @@ -42,6 +45,7 @@ public Api> enterChatRoom(@PathVariable Long chatRoomI } @PostMapping("/quit/{chatRoomId}") // 채팅방 퇴장 + @Operation(summary = "[채팅방 퇴장]") public Api quitChatRoom(@PathVariable Long chatRoomId, @AuthenticationPrincipal User user) { MessageResponse response = chatBusiness.quitChatRoom(chatRoomId, user.getUsername()); @@ -49,18 +53,21 @@ public Api quitChatRoom(@PathVariable Long chatRoomId, } @PostMapping("/message") + @Operation(summary = "[message 전송]", description = "/pub/chat") public void sendMessage(@RequestBody ChatMessageRequest message, @AuthenticationPrincipal User user) { log.info(message.toString()); chatBusiness.sendChatMessage(message, user.getUsername()); } @GetMapping("/buy") // 구매 채팅방 조회 + @Operation(summary = "[구매 채팅방 조회]") public Api> getBuyerChatRoom(@AuthenticationPrincipal User user) { List response = chatBusiness.getBuyerChatRoom(user.getUsername()); return Api.OK(response); } @GetMapping("/sell") // 판매 채팅방 조회 + @Operation(summary = "[판매 채팅방 조회]") public Api> getSellerChatRoom(@AuthenticationPrincipal User user) { List response = chatBusiness.getSellerChatRoom(user.getUsername()); return Api.OK(response); @@ -68,6 +75,7 @@ public Api> getSellerChatRoom(@AuthenticationPrincipal Us // TODO - TEST 용 @GetMapping("/rooms") // 모든 채팅방 조회 test 용 + @Operation(summary = "[TEST 모든 채팅방 조회(redis)]") public Api> rooms() { List responses = chatBusiness.findAllChatRoom(); return Api.OK(responses); @@ -75,6 +83,7 @@ public Api> rooms() { // TODO - TEST 용 @GetMapping("/{chatRoomId}") // 모든 채팅 메시지 조회 + @Operation(summary = "[TEST chatRoomId 로 모든 채팅 조회]") public Api> getChatMessage(@PathVariable Long chatRoomId) { List response = chatBusiness.getChatMessage(chatRoomId); return Api.OK(response); diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java b/warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java index 8c159035..a2ee63e1 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/model/request/ChatMessageRequest.java @@ -4,7 +4,6 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import db.domain.chat.enums.MessageType; @Data @NoArgsConstructor @@ -13,7 +12,6 @@ public class ChatMessageRequest { private String message; // 메시지 내용 - private MessageType type; // 메시지 타입 //TODO MessageType 에 대한 기능 개발 필요 private Long chatRoomId; // 방 ID } \ No newline at end of file diff --git a/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java index 093af406..29555f13 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java +++ b/warehouse/src/main/java/warehouse/domain/chat/controller/model/response/ChatMessageResponse.java @@ -1,6 +1,5 @@ package warehouse.domain.chat.controller.model.response; -import db.domain.chat.enums.MessageType; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -13,7 +12,6 @@ public class ChatMessageResponse { private String message; // 메시지 내용 - private MessageType type; // 메시지 타입 private Long chatRoomId; // 방 ID private Long userId; // 발신자 ID private String createdAt; diff --git a/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java b/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java index 3e8d86bc..33ab4c85 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java +++ b/warehouse/src/main/java/warehouse/domain/chat/converter/ChatConverter.java @@ -1,12 +1,11 @@ package warehouse.domain.chat.converter; -import db.domain.chat.room.ChatRoomEntity; import db.domain.chat.enums.ChatRoomStatus; +import db.domain.chat.message.ChatMessageEntity; +import db.domain.chat.room.ChatRoomEntity; import global.annotation.Converter; import java.time.LocalDateTime; import java.util.List; -import db.domain.chat.message.ChatMessageEntity; -import db.domain.chat.enums.MessageType; import warehouse.domain.chat.controller.model.request.ChatMessageRequest; import warehouse.domain.chat.controller.model.response.ChatMessageResponse; import warehouse.domain.chat.controller.model.response.ChatRoomResponse; @@ -42,7 +41,6 @@ public List toChatMessageListResponse( List chatMessageEntityList) { return chatMessageEntityList.stream().map(chatMessageEntity -> ChatMessageResponse.builder() .message(chatMessageEntity.getMessage()) - .type(chatMessageEntity.getType()) .chatRoomId(chatMessageEntity.getChatRoomId()) .userId(chatMessageEntity.getUserId()) .createdAt(chatMessageEntity.getCreatedAt()) @@ -52,7 +50,6 @@ public List toChatMessageListResponse( public ChatMessageEntity toChatMessage(ChatMessageRequest message, Long userId) { return ChatMessageEntity.builder() .message(message.getMessage()) - .type(message.getType()) .chatRoomId(message.getChatRoomId()) .userId(userId) .createdAt(String.valueOf(LocalDateTime.now())) diff --git a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java index 67add241..bf0379d8 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java +++ b/warehouse/src/main/java/warehouse/domain/chat/service/ChatService.java @@ -157,7 +157,7 @@ public List getChatMessage(Long chatRoomId) { /** * ChatRoom 정보와 ChatMessage 정보를 저정하고 캐시에서 삭제 */ - @Scheduled(cron = "0 0 2 ? * 7") // 매주 토요일 오전 2시 저장 + @Scheduled(cron = "0 0 2 ? * 6") // 매주 토요일 오전 2시 저장 private void saveRedisToRdb() { // chatRoom 저장 List chatRoomEntityList = opsHashChatRoom.values(CHAT_ROOMS); From 6cc4d2cab969da229b2a73545d53f29ff45f394c Mon Sep 17 00:00:00 2001 From: shinyeongwoon Date: Fri, 23 Aug 2024 07:11:00 +0900 Subject: [PATCH 15/15] =?UTF-8?q?SB-283=20(!HOTFIX)=20:=20Users=20Module?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC=20=EC=A0=81=EC=9A=A9=20=EC=95=88=EB=90=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SB-283 (!HOTFIX) : Users Module 분리 적용 안됨 1. User Module 분리 적용 --- delivery/src/main/java/delivery/DeliveryApplication.java | 4 +++- users/src/main/java/users/UsersApplication.java | 2 +- warehouse/src/main/java/warehouse/WarehouseApplication.java | 2 +- .../java/warehouse/domain/chat/business/ChatBusiness.java | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/delivery/src/main/java/delivery/DeliveryApplication.java b/delivery/src/main/java/delivery/DeliveryApplication.java index 35ced1a3..fa31245b 100644 --- a/delivery/src/main/java/delivery/DeliveryApplication.java +++ b/delivery/src/main/java/delivery/DeliveryApplication.java @@ -1,9 +1,11 @@ package delivery; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.servers.Server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -//@OpenAPIDefinition(servers = {@Server(url = "https://baobab.run", description = "fx server 연습용 도메인")}) +@OpenAPIDefinition(servers = {@Server(url = "https://baobab.run", description = "fx server 연습용 도메인")}) @SpringBootApplication public class DeliveryApplication { diff --git a/users/src/main/java/users/UsersApplication.java b/users/src/main/java/users/UsersApplication.java index 5b0997ec..a26e0321 100644 --- a/users/src/main/java/users/UsersApplication.java +++ b/users/src/main/java/users/UsersApplication.java @@ -5,7 +5,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -//@OpenAPIDefinition(servers = {@Server(url = "https://baobab.run", description = "fx server 연습용 도메인")}) +@OpenAPIDefinition(servers = {@Server(url = "https://baobab.run", description = "fx server 연습용 도메인")}) @SpringBootApplication public class UsersApplication { public static void main(String[] args) { diff --git a/warehouse/src/main/java/warehouse/WarehouseApplication.java b/warehouse/src/main/java/warehouse/WarehouseApplication.java index 847780a2..18e06f25 100644 --- a/warehouse/src/main/java/warehouse/WarehouseApplication.java +++ b/warehouse/src/main/java/warehouse/WarehouseApplication.java @@ -8,7 +8,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; import warehouse.domain.image.properties.FileStorageProperties; -//@OpenAPIDefinition(servers = {@Server(url = "https://baobab.run", description = "fx server 연습용 도메인")}) +@OpenAPIDefinition(servers = {@Server(url = "https://baobab.run", description = "fx server 연습용 도메인")}) @SpringBootApplication @EnableConfigurationProperties({ FileStorageProperties.class diff --git a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java index 49f3c00e..9102e79e 100644 --- a/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java +++ b/warehouse/src/main/java/warehouse/domain/chat/business/ChatBusiness.java @@ -19,7 +19,7 @@ import warehouse.domain.chat.converter.ChatConverter; import warehouse.domain.chat.service.ChatService; import warehouse.domain.usedgoods.service.UsedGoodsService; -import warehouse.domain.users.service.UsersService; +import warehouse.domain.users.security.service.UsersService; @Business @RequiredArgsConstructor