WebSocket(stomp) 를 사용한 실시간 알림

정윤서·2024년 1월 11일
0
post-custom-banner

build.gradle 추가

dependencies {
		implementation 'org.springframework.boot:spring-boot-starter-websocket'
        // ... 다른 의존성
}

Configuration 추가

@Configuration
@EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer {
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws").setAllowedOriginPatterns("*").withSockJS();
    }

    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
        registry.setApplicationDestinationPrefixes("/app");
    }
}

자바스크립트 라이브러리 추가

<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.4.0/sockjs.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>

먼저 YStest.html 파일에 테스트 유저의 정보를 담아 model에 추가해 테스트 유저 정보를 담은 버튼 하나를 만들었다.

@GetMapping("/YStest")
public String YStest(Model model) {
	// 테스트 유저의 username인 user로 테스트 유저를 찾아 모델에 target으로 추가
	SiteUser target = this.userService.getByUsername("user");
	model.addAttribute("target", target);
	return "YStest";
}
<button type="button" th:text="${target.nickName}" th:data-value="${target.username}" id="requestBtn"></button>
<input type="hidden" th:value="${user.username}" id="loginUser">
<input type="hidden" th:value="${user.nickName}" id="loginUserNick">

현재 버튼에는 테스트 유저의 정보가 담겨있고 input hidden 타입을 이용해 현재 로그인한 유저의 정보를 담았다.

그리고 버튼을 클릭하면 현재 로그인 한 유저가 테스트 유저에게 친구 신청을 보내는 알림을 띄울 수 있게 자바 스크립트에서 버튼에 클릭 이벤트를 추가했다.

$(function() {
  const socket = new SockJS("/ws"); // 서버에 지정된 경로(/ws)로 WebSocket 연결을 시도하게 함.
  const stompClient = Stomp.over(socket); // 메시지 전송을 위한 간단한 텍스트 기반 프로토콜
  var username = $('#requestBtn').data("value");
  var loginUser = $('#loginUser').val();
  var loginUserNick = $('#loginUserNick').val();
  
  $('#requestBtn').on('click', function () {
    if (stompClient) {
      stompClient.send("/app/friend/request", {}, JSON.stringify({sender : loginUser, receiver : username, senderNick : loginUserNick}));
    }
  });
});

stompClient를 사용해 서버와 클라이언트가 계속 메시지를 주고받게 되는데 'stompClient.send()'는 메서드를 통해 클라이언트에서 서버로 메시지를 보내고 stompClient.subscribe() 메서드를 통해 서버로부터 메시지를 받을 수 있다.

Configuration에서 클라이언트에서 서버로 보낼 때 사용하는 주소의 접두사를 "/app"으로 설정했기 때문에 컨트롤러로 보내는 주소를 작성할 때 "/app"을 먼저 적어주어야 한다.

이제 클라이언트로부터 받은 메시지를 처리할 함수를 작성한다.
@messageMapping을 사용해 특정 경로로 오는 메시지를 처리할 메서드를 지정한다.

// 애플리케이션에서 클라이언트에게 메시지를 보내는 데 사용
private final SimpMessageSendingOperations messagingTemplate;

// @Payload는 STOMP 메시지를 처리할 때 사용
// 클라이언트로부터 전송된 메시지의 본문을 메서드의 매개변수로 직접 매핑
@MessageMapping("/friend/request")
public void requestFriend(@Payload String username) {
	JSONObject jsonObject = new JSONObject(username);
    SiteUser sender = this.userService.getByUsername((String) jsonObject.get("sender"));
    SiteUser receiver = this.userService.getByUsername((String) jsonObject.get("receiver"));
	messagingTemplate.convertAndSend("/topic/friend/request/" + receiver.getUsername(), username);
}

Configuration에서 'registry.enableSimpleBroker("/topic")'을 설정해 줌으로써 "/topic"을 접두사로 사용하는 메시지 브로커를 활성화했다.

메시지 브로커(Message Broker) -> 메시지 기반의 시스템에서 메시지를 수신, 저장, 전달하는 중간자 역할을 한다.

이렇게 하면 다시 서버에서 클라이언트로 전송되는데, 다시 자바스크립트로 돌아와서 STOMP 클라이언트가 서버에 성공적으로 연결되었을 때 실행되는 콜백 함수를 정의한다.

stompClient.connect({}, function (frame) {
  stompClient.subscribe('/topic/friend/request/' + loginUser, function (notification) {
    const data = JSON.parse(notification.body);
	alert(data.senderNick + "님이 친구 요청을 보냈습니다.");
  });
});

서버에서 "/topic/friend/request/"로 메시지를 보냈기 때문에 이 주소를 구독(subscribe)하는 모든 클라이언트가 해당 메시지를 받게 된다.

이렇게 하고 현재 로그인 한 유저가 유저 버튼을 클릭하면

이렇게 실시간으로 메시지가 뜨게 된다.

post-custom-banner

0개의 댓글