Spring與WebSocket的整合

環境

  • jdk1.8
  • tomcat 7
  • spring4.0.5

2  pom.xml的配置

2.1 引入Spring相關的配置

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>4.0.5.RELEASE</spring.version>
	</properties>
       <dependencies>
       <!-- spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>
</dependencies>

2.2 websocket相關的配置

<dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.3.3</version>
        </dependency>
		<dependency>  
		   <groupId>org.springframework</groupId>  
		   <artifactId>spring-websocket</artifactId>  
		   <version>4.0.5.RELEASE</version>  
		</dependency>  
		<dependency>  
		   <groupId>org.springframework</groupId>  
		   <artifactId>spring-messaging</artifactId>  
		   <version>4.0.5.RELEASE</version>  
		</dependency> 

3 編寫WebSocketConfig、HandshakeInterceptor與WebSocketHander

3.1 WebSocketConfig

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
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
@EnableWebMvc
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
    	
    	/**
    	 * 支持websocket 的 connection
    	 */
        registry.addHandler(new WebSocketHander(),"/websocket").addInterceptors(new HandshakeInterceptor());
        
        /**
         * 不支持websocket的connenction,採用sockjs
         */
        registry.addHandler(new WebSocketHander(),"/sockjs/websocket").addInterceptors(new HandshakeInterceptor()).withSockJS();
    }
}

3.2 HandshakeInterceptor

import java.util.Map;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.socket.WebSocketHandler;
public class HandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor {

	/**
	 * Interceptor before hander 
	 */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {

    }
}

3.3 WebSocketHander

import java.io.IOException;
import java.util.ArrayList;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;

public class WebSocketHander implements WebSocketHandler {
  
   private static final Logger logger = org.slf4j.LoggerFactory.getLogger(WebSocketHander.class);
	
    private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>();

    /**
     * after connection establish
     */
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        logger.info("connect success...");
        users.add(session);
    }

    /**
     * process the received message 
     */
    @Override
    public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception {
    	sendMessageToUsers(new TextMessage(webSocketMessage.getPayload() + "hello"));
    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {
        if(webSocketSession.isOpen()){
            webSocketSession.close();
        }
        logger.info("connenction error,close the connection...");
        users.remove(webSocketSession);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {
        logger.info("close the connenction..."+closeStatus.toString());
        users.remove(webSocketSession);
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
    /**
     * 給所有在線用戶發送消息
     *
     * @param message
     */
    public void sendMessageToUsers(TextMessage message) {
        for (WebSocketSession user : users) {
            try {
                if (user.isOpen()) {
                    user.sendMessage(message);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }}

4 頁面
<span style="font-weight: normal;"><%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
	String path = request.getContextPath();
	String basePath = request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head lang="en">
    <meta charset="UTF-8">
    <script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
    <!-- 新 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">
    <!-- 可選的Bootstrap主題文件(一般不用引入) -->
    <link rel="stylesheet" href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
    <!-- jQuery文件。務必在bootstrap.min.js 之前引入 -->
    <script src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
    <!--<script type="text/javascript" src="js/jquery-1.7.2.js"></script>-->
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="http://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
    <title>webSocket測試</title>
    <script type="text/javascript">
        $(function(){
            var websocket;
            if ('WebSocket' in window) {
                alert("WebSocket");
                websocket = new WebSocket("ws://localhost:8080/項目名稱/websocket");
            } else if ('MozWebSocket' in window) {
                alert("MozWebSocket");
                websocket = new MozWebSocket("ws://echo");
            } else {
                alert("SockJS");
                websocket = new SockJS("http://localhost:8080/<span style="font-family: Arial, Helvetica, sans-serif;">項目名稱</span><span style="font-family: Arial, Helvetica, sans-serif;">/sockjs/websocket");</span>
            }
            websocket.onopen = function (evnt) {
                $("#tou").html("鏈接服務器成功!")
            };
            websocket.onmessage = function (evnt) {
                $("#msg").html($("#msg").html() + "<br/>" + evnt.data);
            };
            websocket.onerror = function (evnt) {
            };
            websocket.onclose = function (evnt) {
                $("#tou").html("與服務器斷開了鏈接!")
            }
            $('#send').bind('click', function() {
                send();
            });
            function send(){
                if (websocket != null) {
                    var message = document.getElementById('message').value;
                    websocket.send(message);
                } else {
                    alert('未與服務器鏈接.');
                }
            }
        });
    </script>

</head>
<body>

<div class="page-header" id="tou">
    webSocket及時聊天Demo程序
</div>
<div class="well" id="msg">
</div>
<div class="col-lg">
    <div class="input-group">
        <input type="text" class="form-control" placeholder="發送信息..." id="message">
      <span class="input-group-btn">
        <button class="btn btn-default" type="button" id="send" >發送</button>
      </span>
    </div><!-- /input-group -->
</div><!-- /.col-lg-6 -->
</div><!-- /.row -->
</body>

</html></span>
現象:輸入字符,服務器對輸入的字符加上“hello”返回!

5. 錯誤

5.1Async support must be enabled on a servlet and for all filters involved in async request processing

如果直接運行,基本上會包上面的錯誤,我們還需要在web.xml中做如下的配置
<web-app version="3.0" 
xmlns="http://java.sun.com/xml/ns/javaee" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
然後在這個servlet中加入:
<async-supported>true</async-supported>
如下:
	<servlet>
		<servlet-name>presto-engine</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:presto_servlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
		<async-supported>true</async-supported>
	</servlet>
同時在各個filter也要加入async-supported

5.2 The extension [x-webkit-deflate-frame] is not supported
在HandshakeInterceptor的beforeHandshake方法中加入
  <span style="font-size:10px;font-weight: normal;">@Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
    	/**
    	 * This is a bug,bug fix:The extension [x-webkit-deflate-frame] is not supported
    	 */
    	if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
    		request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
        }
        return true;
    }</span>



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章