<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>