🔎하고싶은것
유저중 한명이 POST,UPDATE,DELETE요청을 보내서 여행 일정을 변경하면
같은 세션에 있는 다른 유저들에게도 페이지 새로고침되어 변경사항이 보였으면 좋겠다!
🔎구현 방법
서버에서 클라이언트의 엔티티변경(POST,UPDATE,DELETE) 요청을 처리한 후
브로드캐스트하여 변경사항을 모든 클라이언트에게 알림
=> 웹소켓에 연결된 클라이언트는 메시지를 받을 때 페이지를 새로고침함
브로드캐스트❔❓
한 장치가 여러 장치에게 동시에 메세지를 전송하는 것을 의미하며
여기서는 웹소켓을 통해 서버에서 클라이언트들에게 동시에 메세지를 전송하는 방식을 의미한다.
브로드캐스트: 한 번의 메시지 전송으로 네트워크에 연결된 모든 장치(또는 지정된 그룹)에게 메시지를 전달하는 방식
멀티캐스트(Multicast): 선택된 일부 그룹에게만 메시지를 전송하는 방식
유니캐스트(Unicast): 한 대의 장치에서 특정한 한 대의 장치로만 메시지를 전송하는 방식
이제 코드로 구현해보자
build.gradle
// websocket 추가
implementation 'org.springframework.boot:spring-boot-starter-websocket'
WebSocketHandler 설정
public class WebSocketHandler extends TextWebSocketHandler {
private final Set<WebSocketSession> sessions = Collections.synchronizedSet(new HashSet<>());
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
}
public void broadcast(String message) {
synchronized (sessions) {
for (WebSocketSession session : sessions) {
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
throw new CustomLogicException(ExceptionCode.WEBSOCKET_IO_EXCEPTION);
}
}
}
}
}
Socket통신은 서버와 클라이언트가 일대다 관계를 맺기 때문에
서버에서 여러 클라이언트가 발송한 메시지를 처리해줄 handler가 필요하다.
이 클래스는 TextSocketHandler를 상속받아 웹소켓 연결을 관리하고, 메세지를 브로드캐스트하는 역할을 할 것이다.
각 부분들에 대해 자세히 살펴보자
sessions는 현재 연결된 웹소켓 세션들을 저장할 Set이다.
Collections.synchronizedSet을 사용하여 스레드를 안전하게 만든다. 즉, 여러 스레드가 동시에 이 set을 수정할 수 있다.
📌afterConnectionEstablished()
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
}
클라이언트가 웹소켓에 연결되었을 때 호출될 메서드이다
새로운 웹소켓 세션을 sessions에 추가하여, 새로운 클라이언트가 연결되었음을 기록한다.
📌afterConnectionClosed()
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
}
클라이언트가 웹소켓에서 연결을 끊었을 때 호출될 메서드이다.
연결이 종료된 웹소켓 세션을 sessions에서 제거하여, 더 이상 메시지를 보내지 않도록 한다.
📌broadcast()
public void broadcast(String message) {
synchronized (sessions) {
for (WebSocketSession session : sessions) {
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
throw new CustomLogicException(ExceptionCode.WEBSOCKET_IO_EXCEPTION);
}
}
}
}
전달된 메시지를 현재 연결된 모든 세션에 보내는 역할을 한다.
synchronized (sessions):
sessions 컬렉션을 안전하게 접근하기 위해 동기화한다.
여러 스레드가 동시에 이 메서드를 호출하더라도 컬렉션이 안전하게 유지된다.
sessions에 저장된 각 세션에 대해
session.sendMessage(new TextMessage(message))를 호출하여 메시지를 전송한다.
메시지를 전송하는 동안 IOException이 발생할 수 있으므로 예외를 캐치하여 에러를 던진다.
해당 프로젝트에서는 모든 예외를 Custom하여 사용하였다.
WebSocketConfig 설정
WebSocketChatHandler를 이용하여 Websocket을 활성화하기 위해 Config를 생성한다
@EnableWebSocket을 선언하여 Websocket을 활성화한다.
Websocket에 접속하기 위해 /ws으로 접속한다.
다른 서버에서도 접속할 수 있게 CORS를 모두 허용한다.
이제 클라이언트가 ws://localhost:8080/ws으로 커넥션을 연결하고 메시지를 통신할 수 있다.
ScheduleController
알리고싶은 부분에 핸들러에 만들어둔 broadcate 메서드를 이용해 브로드캐스팅한다.
이때 매개변수 안에 들어가는 String 은 클라이언트 측에 보낼 메세지이다.
참고가 되었던 사이트
'Spring' 카테고리의 다른 글
[Spring] Spring에서의 요청처리 흐름(+Spring Security/MVC의 에러 처리 위치) (0) | 2024.11.26 |
---|---|
[Spring Security] 401, 403 에러처리(Spring 3.xx) (13) | 2024.11.26 |
Spring 프로젝트에서 웹소켓 적용하기~!! 1탄 (5) | 2024.06.10 |
Google Oauth2 (0) | 2024.04.02 |
Pagination 조회 시의 Query tuning , 그리고 N+1 (2) | 2023.09.13 |