🔎하고싶은것

유저중 한명이 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 은 클라이언트 측에 보낼 메세지이다.

 

 

 

 

참고가 되었던 사이트

 

https://velog.io/@leui9179/WebSocket%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-%EC%B1%84%ED%8C%85-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-1

 

 

 

복사했습니다!