본문 바로가기
Spring

Spring Websocket

by chief_sac 2021. 5. 29.
반응형

메이븐 라이브러리 불러오기

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
        <version>${org.springframework-version}</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>
  • 웹소켓은 데이터 이동방식이 JSON형식이라 jackson이 필요함
  • 미들웨어는 8.5이상 지원
  • 스프링은 2.5버전 이상 지원되고
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:websocket="http://www.springframework.org/schema/websocket"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket-4.3.xsd">

    <websocket:handlers allowed-origins="*" >
        <websocket:mapping handler="handlerChat" path="/chat" />
        <websocket:sockjs websocket-enabled="true" />
    </websocket:handlers>

    <bean id="handlerChat" class="com.chat.handler.HandlerChat" />

</beans>

하위 컨테이너에 bean 설정해줘야한다

@Component
public class HandlerChat extends TextWebSocketHandler {

    // 세션리스트를 담을 List(나중에는 세션접속자의 정보까지 들고와야해서 Map으로 바꿔야함)
    private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>();

    // 클라이언트가 처음 접속했을때(init역할)
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {

        // 채팅방에 접속한 사용자 세션을 리스트에 저장
        sessionList.add(session);

        // 모든 세션에 채팅 전달
        for (int i = 0; i < sessionList.size(); i++) {
            WebSocketSession s = sessionList.get(i);
            s.sendMessage(new TextMessage(session.getId() + "님이 입장 했습니다."));
        }
    }

    // 클라이언트에서 메세지가 전달되면
    // 서버에서 모든 클라이언트에 전송
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {

        // 모든 세션에 채팅 전달
        for (int i = 0; i < sessionList.size(); i++) {
            WebSocketSession s = sessionList.get(i);
            s.sendMessage(new TextMessage(session.getId() + " : " + message.getPayload()));
        }
    }

    // 클라이언트가 연결을 끊음 처리
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {

        // 채팅방에서 퇴장한 사용자 세션을 리스트에서 제거
        sessionList.remove(session);

        // 모든 세션에 연결종료채팅 전달
        for (int i = 0; i < sessionList.size(); i++) {
            WebSocketSession s = sessionList.get(i);
            s.sendMessage(new TextMessage(session.getId() + "님이 퇴장 했습니다."));
        }

    }
}

새로운 세션이 접속하거나 메세지를 전송하면 socket핸들러에서 제어해서 메세지를 보낸다

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>웹소켓 채팅</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.4.0/sockjs.js"></script>
    <script type="text/javascript">
        var webSocket = {
            init: function(param) {
                this._url = param.url;
                this._initSocket();
            },
            sendChat: function() {
                this._sendMessage($('#message').val());
                $('#message').val('');
            },
            // 메세지 데이터가 들어오면 그 메세지를 보여줌
            receiveMessage: function(str) {
                $('#divChatData').append('<div>' + str + '</div>');                
            },
            // 소켓에연결되지않음
            closeMessage: function(str) {
                $('#divChatData').append('<div>' + '연결 끊김 : ' + str + '</div>');
            },
            //소켓연결종료
            disconnect: function() {
                this._socket.close();
            },
            // 소켓연결
            _initSocket: function() {
                this._socket = new SockJS(this._url);
                this._socket.onmessage = function(evt) {
                    webSocket.receiveMessage(evt.data);
                };
                // 종료이벤트
                this._socket.onclose = function(evt) {
                    //(나갔다는 메세지를 출력)
                    webSocket.closeMessage(evt.data);
                }
            },
            // 메세지가입력되면 HandlerChat.java로 문자를 모냄
            _sendMessage: function(str) {
                this._socket.send(str);
            }
        };
    </script>    
    <script type="text/javascript">
        $(document).ready(function() {
            /* 서버의 url주로를 가져와서 init메소드에 넣어주면서 접속한다 */
            webSocket.init({ url: '<c:url value="/chat" />' });            
        });
    </script>
</head>
<body>
    <div style="width: 800px; height: 700px; padding: 10px; border: solid 1px #e1e3e9;">
        <div id="divChatData"></div>
    </div>
    <div style="width: 100%; height: 10%; padding: 10px;">
        <input type="text" id="message" size="110" onkeypress="if(event.keyCode==13){webSocket.sendChat();}" />
        <input type="button" id="btnSend" value="채팅 전송" onclick="webSocket.sendChat()" />
    </div>
</body>
</html>

JSP에서 필요한 JS로 소켓 호출인데 여기서는 메세지 처리가 text이지만 JSON형태로 다양한 정보를 전달가능하다

속성의 종류

 

STOMP

websocket에서의 거의 유일한 단점은 클라이언트에서 전송받을수 있는 메세지가 규격이 없음인데  양 피어에서의 메세지를 합의하고 합의된 형식에 따라 메세지를 파싱하는 식으로 보안하다 STOMP라는 것을 알게되었다 stomp 는 상위와 같이 프레임 구조 가 명확하게 정의되어 있고, 발행/구독 형태의 메시지 전송 구조를 갖기 때문에 전송에 관련된 양 피어가 독립적으로 동작할 수 있는 구조를 갖는다 나중에 따로 한번 다뤄보려고 한다.

반응형

'Spring' 카테고리의 다른 글

VO와 DTO란(VO vs DTO 차이)  (0) 2021.07.25
Reactive Stream 리액티브 스트림이란.  (0) 2021.07.10
Batch Job(일괄처리프로그램)  (0) 2021.07.01
IOC(DI)컨테이너  (0) 2021.05.29
Spring에서 모듈(컨테이너)  (0) 2021.04.24