참고
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에서 받음