본문 바로가기

Spring 4/WebSocket

Spring 4 WebSocket example

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>