Search
Duplicate
📒

[Spring WebSocket] 03-2. Springboot/React에서 STOMP 사용하기

상태
미진행
수업
Spring Netty
주제
WebSocket
4 more properties
참고

Springboot

NOTE
이해를 돕기위한 예시 이미지 자료
implementation 'org.springframework.boot:spring-boot-starter-websocket'
Groovy
복사
Springboot - 의존성 추가
1.
클라이언트(Sender)가 메시지를 보내면 STOMP 통신을 통해 서버에 메시지가 전달됩니다.
2.
Controller@MessageMapping을 통해 메시지를 받습니다.
3.
Controller@SendTo를 사용하여 특정 주제를 구독하는 클라이언트에게 메시지를 보냅니다.

Springboot - WebSocket Config

NOTE
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { // server -> client // ex /plans/greeting (서버가 보냄) config.enableSimpleBroker("/client"); // client -> server // ex /send/hello (클라이언트가 보냄) config.setApplicationDestinationPrefixes("/server"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { // 클라이언트에서 socket 접속을 위한 경로 registry.addEndpoint("/share") .setAllowedOriginPatterns("*") .withSockJS(); } }
Java
복사
Springboot 예제 코드
// 해당 경로로 Socket 연결시킨다. const socket = new SockJS("http://localhost:8080/api/share"); const stompClient = Stomp.over(socket); // 해당 경로를 구독한다. stompClient.subscribe("/client/1/titleModify", (data) => { // ... }); // 해당 경로로 websocket을 보낸다. stompClient.send( "/server/1/title", // ... );
JavaScript
복사
React에서 실제로 연결시키는 예제 코드

@EnableWebSocketMessageBroker

@Configuration 클래스에 추가하여, WebSocket을 통한 브로커 메시징을 활성화하도록 한다.
WebSocketMessageBrokerConfiguration 인터페이스를 구현하여 WebSocket 설정을 사용자가 커스텀할 수 있다.

configureMessageBroker

‘/share’으로 시작하는 주제에 대한 메시지 브로드캐스팅을 활성화시킨다.
setApplicationDestinationPrefixes메시지 처리 메서드로 라우팅되는 수신 메시지의 접두사를 설정한다.

registerStompEndpoints

WebSocket 연결을 위한 endpoint을 구성한다
withSockJS()는 WebSocket을 지원하지 않는 클라이언트에 대한 옵션을 활성화한다.

Springboot - WebSocket 수신/전송

NOTE
@MessageMapping("/{planId}/title") @SendTo("/client/{planId}/titleModify") @Operation(summary = "일정 제목 수정") public ResponseEntity<Response<?>> titleModify(@Header(name = "Authorization") String accessToken, @DestinationVariable Long planId, @RequestBody PlanTitleDto planTitle) { // ... return ResponseEntity.ok(Response.of("", 200, "success")); }
Java
복사
Springboot 코드 (나중에 react코드에서 어떻게 받는지 참조)
@MessageMapping : client → sever로 응답 받는다.
@SendTo : server → client로 요청 보낸다.
// 받기 // stompClient.subscribe(destination, callback, headers(선택사항)); stompClient.subscribe("/client/1/titleModify", (data) => { setPlanData(JSON.parse(data.body)); }); // 보내기 stompClient.send( "/server/1/title", { Authorization: accessToken }, JSON.stringify({ title: "New Title" }) );
JavaScript
복사
React 코드
stompClient.subscribe : server → clinet로 응답 받는다
stompClient.send : client → server로 요청 보낸다

React

NOTE
유저 1이 이벤트를 일으킴
유저 2는 유저1이 일으키는 이벤트를 실시간으로 받음

React - SockJS, Stompjs이브러리 추가

NOTE
import Stomp from "stompjs"; import SockJS from "sockjs-client";
JavaScript
복사
SockJS는 애플리케이션이 WebSocket API를 사용하도록 하지만 코드를 변경할 필요 없이 런타임에 WebSocket이 아닌 대안으로 대처하는 것을 의미하며 이를 WebSocket Emulation을 이용한다고 합니다!
WebSocket을 지원하지 않는 브라우저라 할지라도, 다른 기술을 사용하여 지속성 있는 연결을 지원할 수 있도록 도와줍니다.
먼저 WebSocket 연결을 시도하지만 HTTP Streaming, Long-Polling과 같은 HTTP 기반의 다른 기술로 전환해 연결을 시도합니다.

React - stompClient 연결

NOTE
const socket = new SockJS(connectUrl); const stompClient = Stomp.over(socket); const connectWebSocket = () => { const socket = new SockJS(connectUrl); const stompClient = Stomp.over(socket); stompClient.connect( // 헤더 { 'Authorization': accessToken, }, () => { // 연결 성공시 이벤트 console.log("WebSocket connected"); setStompClient(stompClient); }, (error) => { // 연결 실패시 이벤트 console.error("WebSocket error: ", error); } ); };
JavaScript
복사
연결함수
useEffect(() => { connectPlan() // connectWebSocket(); // Cleanup function return () => { if (stompClient) { stompClient.disconnect(); } }; }, []);
JavaScript
복사
useEffect로 동작시킴

React - stompClient 구독(receiver)

NOTE
useEffect(() => { if (stompClient) { stompClient.subscribe(`/client/${planId}/title`, (data) => { // 일정 제목 수정 console.log(`일정 제목 수정`); setText("일정 제목 수정") }); stompClient.subscribe(`/client/${planId}/places/${planPlaceId}/stay-time`, (data) => { // 일정 장소 머무는 시간 수정 console.log(`일정 장소 머무는 시간 수정`); setText(`일정 장소 머무는 시간 수정`); }); // ... } }, [stompClient]);
JavaScript
복사
subscribe 경로들은 springboot에서 @SendTo로 보낼때 받아서 이벤트를 발생시킴

React - stompClient 보내기(send)

NOTE
const handleTitleModify = () => { stompClient.send( `/server/${planId}/title`, {Authorization: accessToken}, JSON.stringify({data: "data"}) ); }; const handlePlaceStayTimeModify = () => { setCount(+1); stompClient.send( `/server/${planId}/places/${planPlaceId}/title`, {Authorization: accessToken}, JSON.stringify({data: "data"}) ); };
JavaScript
복사
send( [경로], [헤더], [데이터] ), 이후 springboot에서 @MessageMapping에서 받음