본문 바로가기
Spring

[Spring] WebSocket을 이용해 채팅 기능 구현

by jane.dev 2021. 11. 8.
반응형
Socket 
클라이언트의 요청이 들어오면 서버가 응답하는 단방향으로 이루어지는 HTTP 통신과는 다르게
소켓은 서버와 클라이언트가 양방향으로 데이터를 주고 받을 수 있는 통신
보통 스트리밍이나 채팅처럼 실시간으로 데이터를 주고 받을 때 사용

 

웹소켓을 구현하는 데 필요한 라이브러리 추가

Spring Websocket

 

Jackson Databind

 

socket-context.xml 을 생성해 

Namespaces에서 websocket 체크하고

 

<beans>
    <websocket:handlers allowed-origins="*">
        <websocket:mapping handler="handlerChat" path="/chat"/>
        <websocket:sockjs websocket-enabled="true" />
    </websocket:handlers>
    <bean id="handlerChat" class="org.ict.chat.HandlerChat" />
</beans>

핸들러 추가해서 '/chat'주소로 요청이 들어오면 handleChat이 채팅창을 생성하도록 함

 

web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml
        /WEB-INF/spring/socket-context.xml<!-- 추가 -->
    </param-value>
</context-param>

생성한 socket-context.xml을 인식하도록 작성

 

HandlerChat.java

TextWebSocketHandler를 상속

@Component
public class HandlerChat extends TextWebSocketHandler {
	private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>();

	// 채팅방 입장
    	// afterConnectionEstablished: 신규 사용자가 접속하면 작동하는 메서드로 사용자의 session을 저장 및 식별
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    	
        	// 리스트에 채팅방에 접속한 사용자 세션 저장
        	sessionList.add(session);
        	System.out.println("사용자 세션리스트: " + sessionList);
		
		// 모든 세션에 채팅 전달
		for(int i = 0; i < sessionList.size(); i++) {
			// 사용자가 접속시마다 sesssionList에서 한명씩 s에 저장
			WebSocketSession s = sessionList.get(i);
			
			// 연결된 접속자에 'xxx님이 입장하셨습니다.'라는 안내메세지 전달
			s.sendMessage(new TextMessage(session.getId() + "님이 입장했습니다."));
		}
	}

	// 채팅 발신
    	// handleTextMessage: 한 사용자가 메세지를 서버로 전달하면 같은 채팅방 다른 사용자에게 전달해주는 메서드
	@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()));
			System.out.println(message);
		}
	}

	// 채팅방 퇴장
    	// afterConnectionClosed: 사용자가 접속 종료시 안내하는 메서드로 해당 사용자가 채팅방을 나가면 감지
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		// 채팅방에서 퇴장한 사용자 세션을 리스트에서 제거
		sessionList.remove(session);
		System.out.println("퇴장한 사용자 확인: " + status);
	
		// 모든 세션에 채팅 전달
		for(int i = 0; i < sessionList.size(); i++) {
			WebSocketSession s = sessionList.get(i);
			s.sendMessage(new TextMessage(session.getId() + "님이 퇴장했습니다."));
		}
	}
}

 

chat.jsp

채팅창 생성

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/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);
			}
		},
		_sendMessage: function(str){
			this._socket.send(str);
		}
	};
</script>
<script>
$(window).on('load', function(){
	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="send" onclick="webSocket.sendChat()" />
	</div>
</body>

 

채팅방