Spring 4에서부터 지원되는 WebSocket 설정 및 테스트 예제
개요
Spring 4버전 부터 지원되는 웹소켓을 테스트해본다
프로그램을 실행하고 wsclient.jsp가 호출되면 웹소켓 서버에 접속되도록 하였으며 채팅 메시지를 입력하고 엔터키를 치면 서버로 메시지가 전송되어 다시 클라이언트 자신에게 되돌아 온 메시지가 화면에 출력되도록 하여 기본 기능을 테스트한다
테스트 환경
JDK 1.8
Tomcat 8
Spring 4.0.9
Eclipse, STS, Maven
필요한 라이브러리
개발환경이 제대로 작동하고 HelloController 등의 기본 MVC 가 실행된다면, 아래의 라이브러리를 더 추가하여 웹소켓을 테스트해 볼 수 있다
pom.xml 에 웹소켓을 위한 라이브러리를 등록한다
<!-- WebSocket Start--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.0.9.RELEASE</version> </dependency> <!-- WebSocket End-->
이 외에도 JSTL, Oracle 등이 필요하다면 해당 라이브러리를 검색하여 설치하면 된다
<dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.1.0.7.0</version> </dependency>
서블릿 설정파일 ( 웹소켓 설정은 적색 혹은 볼드체로 표시함 )
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Process annotations on registered beans like @Autowired... -->
<context:annotation-config/>
<!-- Enables the Spring MVC @Controller programming model -->
<mvc:annotation-driven />
<context:component-scan base-package="org.kdea.java" />
<context:component-scan base-package="org.kdea.service" />
<context:component-scan base-package="org.kdea.exception" />
<context:component-scan base-package="org.kdea.interceptor" />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
<beans:property name="contentType" value="text/html; charset=UTF-8"/>
</beans:bean>
<beans:bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<beans:property name="basename" value="messages/messages"/>
</beans:bean>
<beans:bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />
<beans:bean id="echoHandler" class="org.kdea.websocket.EchoHandler"/>
<websocket:handlers>
<websocket:mapping handler="echoHandler" path="/echo-ws" />
</websocket:handlers>
</beans:beans>
웹소켓 핸들러 클래스
package org.kdea.websocket; import org.springframework.web.socket.*; import org.springframework.web.socket.handler.TextWebSocketHandler; public class EchoHandler extends TextWebSocketHandler { // 웹소켓 서버측에 텍스트 메시지가 접수되면 호출되는 메소드 @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { String payloadMessage = (String) message.getPayload(); System.out.println("서버에 도착한 메시지:"+payloadMessage); session.sendMessage(new TextMessage("ECHO : " + payloadMessage)); } // 웹소켓 서버에 클라이언트가 접속하면 호출되는 메소드 @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { super.afterConnectionEstablished(session); System.out.println("클라이언트 접속됨"); } // 클라이언트가 접속을 종료하면 호출되는 메소드 @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { super.afterConnectionClosed(session, status); System.out.println("클라이언트 접속해제"); } // 메시지 전송시나 접속해제시 오류가 발생할 때 호출되는 메소드 @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { super.handleTransportError(session, exception); System.out.println("전송오류 발생"); } }
웹소켓 서버측에 접속하여 메시지를 전송/수신하는 클라이언트 코드( webapp/wsclient.jsp )
아래의 jsp에 웹브라우저로 접속할 때는 반드시 서버의 IP 주소로 접속해야 한다
( 예, 웹브라우저의 주소창에 http://192.168.8.32:8088/SpringWeb/wsclient.jsp )
<%@ page 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 charset="utf-8"> <title>Websocket Client</title> <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.4.min.js"></script> <script type="text/javascript"> $(function () { var url = window.location.host;//웹브라우저의 주소창의 포트까지 가져옴 var pathname = window.location.pathname; /* '/'부터 오른쪽에 있는 모든 경로*/ var appCtx = pathname.substring(0, pathname.indexOf("/",2)); var root = url+appCtx; //alert(root); //var ws = new WebSocket("ws://192.168.0.100:8081/SpringWeb/echo-ws"); var ws = new WebSocket("ws://"+root+"/echo-ws"); ws.onopen = function () { $('#chatStatus').text('Info: connection opened.'); $('input[name=chatInput]').on('keydown', function(evt){ if(evt.keyCode==13){ var msg = $('input[name=chatInput]').val(); ws.send(msg); $('input[name=chatInput]').val(''); } }); }; ws.onmessage = function (event) { $('textarea').eq(0).prepend(event.data+'\n'); }; ws.onclose = function (event) { $('#chatStatus').text('Info: connection closed.'); }; }); </script> </head> <body> <p> <div id='chatStatus'></div> <textarea name="chatMsg" rows="5" cols="40"></textarea> <p> 메시지 입력 : <input type="text" name="chatInput"> </body> </html>