diff --git a/build.gradle.kts b/build.gradle.kts index 7192cc2d..aeefb0b6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,6 +27,7 @@ repositories { dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-websocket") implementation("org.springframework.boot:spring-boot-starter-security") testImplementation("org.springframework.security:spring-security-test") compileOnly("org.projectlombok:lombok") diff --git a/src/main/java/com/back/domain/websocket/config/WebSocketConfig.java b/src/main/java/com/back/domain/websocket/config/WebSocketConfig.java new file mode 100644 index 00000000..af0cf877 --- /dev/null +++ b/src/main/java/com/back/domain/websocket/config/WebSocketConfig.java @@ -0,0 +1,36 @@ +package com.back.domain.websocket.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.simp.config.MessageBrokerRegistry; +import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; +import org.springframework.web.socket.config.annotation.StompEndpointRegistry; +import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; + +@Configuration +@EnableWebSocketMessageBroker +public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { + + /** + * 메시지 브로커 설정 + * - /topic: 1:N 브로드캐스트 (방 채팅) + * - /queue: 1:1 메시지 (개인 DM) + * - /app: 클라이언트에서 서버로 메시지 전송 시 prefix + */ + @Override + public void configureMessageBroker(MessageBrokerRegistry config) { + config.enableSimpleBroker("/topic", "/queue"); + config.setApplicationDestinationPrefixes("/app"); + config.setUserDestinationPrefix("/user"); + } + + /** + * STOMP 엔드포인트 등록 + * 클라이언트가 WebSocket 연결을 위해 사용할 엔드포인트 + */ + @Override + public void registerStompEndpoints(StompEndpointRegistry registry) { + registry.addEndpoint("/ws") + .setAllowedOriginPatterns("*") // 모든 도메인 허용 (개발용) + .withSockJS(); // SockJS 사용 + } +} diff --git a/src/main/java/com/back/domain/websocket/controller/WebSocketTestController.java b/src/main/java/com/back/domain/websocket/controller/WebSocketTestController.java new file mode 100644 index 00000000..4e1d8539 --- /dev/null +++ b/src/main/java/com/back/domain/websocket/controller/WebSocketTestController.java @@ -0,0 +1,65 @@ +package com.back.domain.websocket.controller; + +import com.back.global.common.dto.RsData; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +@RequestMapping("/api/websocket") +public class WebSocketTestController { // WebSocket 기능 테스트용 REST 컨트롤러 + + // WebSocket 서버 상태 확인 + @GetMapping("/health") + public ResponseEntity>> healthCheck() { + log.info("WebSocket 헬스체크 요청"); + + Map data = new HashMap<>(); + data.put("service", "WebSocket"); + data.put("status", "running"); + data.put("timestamp", LocalDateTime.now()); + data.put("endpoints", Map.of( + "websocket", "/ws", + "chat", "/app/rooms/{roomId}/chat", + "join", "/app/rooms/{roomId}/join", + "leave", "/app/rooms/{roomId}/leave" + )); + + return ResponseEntity + .status(HttpStatus.OK) + .body(RsData.success("WebSocket 서비스가 정상 동작중입니다.", data)); + } + + // WebSocket 연결 정보 제공 + @GetMapping("/info") + public ResponseEntity>> getConnectionInfo() { + log.info("WebSocket 연결 정보 요청"); + + Map connectionInfo = new HashMap<>(); + connectionInfo.put("websocketUrl", "/ws"); + connectionInfo.put("sockjsSupport", true); + connectionInfo.put("stompVersion", "1.2"); + connectionInfo.put("subscribeTopics", Map.of( + "roomChat", "/topic/rooms/{roomId}/chat", + "privateMessage", "/user/queue/messages", + "notifications", "/user/queue/notifications" + )); + connectionInfo.put("sendDestinations", Map.of( + "roomChat", "/app/rooms/{roomId}/chat", + "joinRoom", "/app/rooms/{roomId}/join", + "leaveRoom", "/app/rooms/{roomId}/leave" + )); + + return ResponseEntity + .status(HttpStatus.OK) + .body(RsData.success("WebSocket 연결 정보", connectionInfo)); + } +} \ No newline at end of file diff --git a/src/main/java/com/back/global/entity/BaseEntity.java b/src/main/java/com/back/global/entity/BaseEntity.java index 935cef49..772d8e1b 100644 --- a/src/main/java/com/back/global/entity/BaseEntity.java +++ b/src/main/java/com/back/global/entity/BaseEntity.java @@ -16,7 +16,7 @@ public abstract class BaseEntity { private Long id; @CreatedDate - private LocalDateTime createAt; + private LocalDateTime createdAt; @LastModifiedDate private LocalDateTime updatedAt;