📘Spring Boot 에서 WebSocket 생성하여 Postman 으로 테스트하기
/ws?userId=1 형식으로 WebSocket 연결, 세션에 userId 매핑/**
* WebSocket 설정 클래스입니다.
* Spring 에서 WebSocket 서버를 활성화하고, 특정 엔드포인트(`/ws`)에 WebSocket 핸들러를 등록합니다.
*/
@Configuration
@EnableWebSocket
@RequiredArgsConstructor
public class WebSocketConfig implements WebSocketConfigurer {
private final WebSocketHandler handler;
/**
* WebSocket 핸들러를 특정 엔드포인트에 등록합니다.
* 클라이언트는 /ws 경로로 WebSocket 연결을 시도할 수 있습니다.
*
* @param registry WebSocket 핸들러를 등록할 수 있는 레지스트리 객체
*/
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(handler, "/ws")
.setAllowedOriginPatterns("*");
}
}
@EnableWebSocket 없으면 spring 에서 webSocket 으로 판단 불가/ws 경로로 WebSocket 연결을 시도*) 설정이 적용되어 있음@Component
public class WebSocketHandler extends TextWebSocketHandler {
// userId → session 매핑 저장소
private final Map<Long, WebSocketSession> userSessions = new ConcurrentHashMap<>();
//Json 타입 변경
private final ObjectMapper objectMapper = new ObjectMapper();
/**
* 클라이언트와 WebSocket 연결이 성공적으로 수립되었을 때 호출됩니다.
* 사용자 ID를 쿼리 파라미터에서 추출하고 세션을 매핑에 저장합니다.
*
* @param session 연결된 클라이언트의 세션
*/
@Override
public void afterConnectionEstablished(@NonNull WebSocketSession session) {
Long userId = extractUserIdFromQuery(session);
userSessions.put(userId, session);
}
/**
* 클라이언트와의 WebSocket 연결이 종료되었을 때 호출됩니다.
* 연결이 종료된 세션을 userSessions 맵에서 제거합니다.
*
* @param session 종료된 세션
* @param status 종료 상태 정보
*/
@Override
public void afterConnectionClosed(@NonNull WebSocketSession session, @NonNull CloseStatus status) {
userSessions.values().removeIf(s -> s.getId().equals(session.getId()));
}
/**
* 서버에서 특정 사용자에게 알림 메시지를 전송합니다.
* 세션이 유효하고 열려 있는 경우에만 메시지를 전송합니다.
*
* @param message 전송할 알림 메시지 (userId, content, timestamp 포함)
* @throws IOException 메시지 전송 실패 시 예외 발생
*/
public void sendToUser(NotificationMessage message) throws IOException {
WebSocketSession session = userSessions.get(message.userId());
if (session != null && session.isOpen()) {
String json = objectMapper.writeValueAsString(message);
session.sendMessage(new TextMessage(json));
}
}
/**
* WebSocket 연결 URI 의 쿼리 파라미터에서 userId를 추출합니다.
* 예: /ws?userId=33 → 33 추출
*
* @param session 연결된 세션
* @return 추출된 사용자 ID
*/
private Long extractUserIdFromQuery(WebSocketSession session) {
String query = Objects.requireNonNull(session.getUri()).getQuery();
return Long.parseLong(query.split("=")[1]);
}
}
/ws?userId=1 형식으로 접속하며, 쿼리에서 userId 추출해 세션에 매핑함@Component
@RequiredArgsConstructor
public class NotificationSender {
private final WebSocketHandler webSocketHandler;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void send(NotificationMessage message) {
webSocketHandler.sendToUser(message);
}
}
WebSocketHandler 로 전달//WebSocket 으로 보내는 DTO
public record NotificationMessage(
Long userId,
String content,
String timestamp) {




