2018. 4. 18. 21:54
반응형

스프링 프레임워크 웹소켓을 이용하여 채팅창을 만들 수 있다.

이클립스(STS)에서 Spring Legacy Project를 만든 다음 진행한다.

spring 버전은 4.3.8로 맞추고 자바 버전은 1.8로 설정했다.

https://github.com/juragi/spring-chat


우선 pom.xml에 다음을 추가한다.


<dependency>
	<groupId>com.fasterxml.jackson.core</groupId>
	<artifactId>jackson-databind</artifactId>
	<version>2.8.4</version>
</dependency>

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

EchoHandler와 WebSocketConfig를 추가한다.
com.chat.config 패키지를 만들어 같은 곳에 넣었다.

EchoHandler.java
package com.chat.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

public class EchoHandler extends TextWebSocketHandler {
	
	private List<WebSocketSession> sessionList = new ArrayList<WebSocketSession>();
	
	@Override
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		sessionList.add(session);
	}
	
	@Override
	protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
		for(WebSocketSession sess: sessionList) {
			sess.sendMessage(new TextMessage(session.getId()+": "+message.getPayload()));
		}
	}
	
	@Override
	public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
		sessionList.remove(session);
	}
}

WebSocketConfig.java
package com.chat.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{
	@Autowired
	private EchoHandler echoHandler;

	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(echoHandler, "/echo");
	}
	
	
}

servlet-config.xml에 다음을 추가한다.

<beans:bean id="echoHandler" class="com.chat.config.EchoHandler"/>

<websocket:handlers>
	<websocket:mapping handler="echoHandler" path="/echo"/>
	<websocket:sockjs/>
</websocket:handlers>


다음 링크에서 sockjs.min.js 파일을 다운받아서 resources 폴더에 넣는다.

https://github.com/sockjs/sockjs-client/tree/master/dist


home.jsp를 다음과 같이 작성한다.

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
	<title>Home</title>
	<meta charset="UTF-8"/>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
	<script src="resources/sockjs.min.js"></script>
</head>
<body>
	<form id="chatForm">
		<input type="text" id="message"/>
		<button>send</button>
	</form>
	<div id="chat"></div>
	<script>
		$(document).ready(function(){
			$("#chatForm").submit(function(event){
				event.preventDefault();
				sock.send($("#message").val());
				$("#message").val('').focus();
			});
		});
		
		var sock = new SockJS("/echo");
		sock.onmessage = function(e){
			$("#chat").append(e.data + "<br/>");
		}
		
		sock.onclose = function(){
			$("#chat").append("연결 종료");
		}
		
	</script>
</body>
</html>

실행할 때 톰캣 Web Modules Path를 /로 바꾼 다음 실행해야 잘된다.
localhost:8080/echo로 접속했을 때 Welcome to SockJS! 메세지가 나오면 설정에 성공한 것으로 볼 수 있다.

컨트롤러를 딱히 수정하지 않았다면 localhost:8080/ 으로 가면 조촐한 채팅 화면이 보일 것이다.
브라우저에서 탭을 2개 띄워서 채팅창에 입력해보면 채팅이 이루어지는 것을 알 수 있다.


로컬에서는 잘되는데 서버에 올리면 잘 안되는 경우가 있다.
그럴때는 다음의 시도를 해보는게 좋아보인다.

servlet 버전을 3으로 올리고 <sevlet> 태그안에 <async-supported> 태그를 추가한다.

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">
<servlet>
	<servlet-name>appServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
	<async-supported>true</async-supported>
</servlet>
<filter>
	<filter-name>httpPutFormFilter</filter-name>
	<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
	<async-supported>true</async-supported>
</filter>

pom.xml의 서블릿 버전도 바꿔준다.

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>javax.servlet-api</artifactId>
	<version>3.1.0</version>
	<scope>provided</scope>
</dependency>


WebSocketConfig.java 파일을 다음과 같이 수정한다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer{
	@Autowired
	private EchoHandler echoHandler;

	@Override
	public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
		registry.addHandler(echoHandler, "/echo").setAllowedOrigins("*").withSockJS()
		.setInterceptors(new HttpSessionHandshakeInterceptor())
		.setClientLibraryUrl("http://localhost:8080/resources/sockjs.min.js");
	}
	
}


반응형