一、测试环境
1. Tomcat8.0.18
2. JDK1.8
3. Spring4.1
二、新建一个SpringMVC的工程
1. 使用Maven新建一个web工程,添加SpringMVC和Spring websocket依赖,pom.xml文件如下
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>daybreakgroupId>
<artifactId>spring-websocketartifactId>
<packaging>warpackaging>
<version>0.0.1-SNAPSHOTversion>
<name>spring-websocket Maven Webappname>
<url>http://maven.apache.orgurl>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>3.8.1version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>4.1.4.RELEASEversion>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>2.1.0version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.1.0version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-websocketartifactId>
<version>4.1.4.RELEASEversion>
dependency>
dependencies>
<build>
<finalName>spring-websocketfinalName>
<defaultGoal>packagedefaultGoal>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-war-pluginartifactId>
<version>2.5version>
<configuration>
<webappDirectory>src/main/webappwebappDirectory>
<warSourceDirectory>targetwarSourceDirectory>
configuration>
plugin>
plugins>
build>
project>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/applicationContext-*.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<servlet>
<servlet-name>spring-websocketservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>/WEB-INF/applicationContext-servlet.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>spring-websocketservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
<welcome-file-list>
<welcome-file>/index.jspwelcome-file>
welcome-file-list>
web-app>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket-4.1.xsd">
<context:annotation-config/>
<mvc:annotation-driven />
<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class ="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter" />
list>
property>
bean>
<context:component-scan base-package="cn.com"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/view/"/>
<property name="suffix" value=".jsp"/>
bean>
beans>
三、配置Spring Websocket
1. 新建一个自己的HandShakeInterceptor类
HandShakeInterceptor是websocket握手拦截器,用于拦截websocket初始化连接的请求
package cn.com.websocket.hello;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class HelloHandler extends TextWebSocketHandler{
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
//接收到客户端消息时调用
System.out.println(“text message: ” + session.getId() + “-” + message.getPayload());
}
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
// 与客户端完成连接后调用
System.out.println(“afterConnectionEstablished”);
System.out.println(“getId:” + session.getId());
System.out.println(“getLocalAddress:” + session.getLocalAddress().toString());
System.out.println(“getTextMessageSizeLimit:” + session.getTextMessageSizeLimit());
System.out.println(“getUri:” + session.getUri().toString());
System.out.println(“getPrincipal:” + session.getPrincipal());
session.sendMessage(new TextMessage(“你好”.getBytes()));
}
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) throws Exception {
// 消息传输出错时调用
System.out.println(“handleTransportError”);
}
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus closeStatus) throws Exception {
// 一个客户端连接断开时关闭
System.out.println(“afterConnectionClosed”);
}
@Override
public boolean supportsPartialMessages() {
// TODO Auto-generated method stub
return false;
}
}
2. 新建一个自己的WebSocketHandler类
WebSocketHandler接口主要是用来与websocket客户端来进行交互的接口,Spring WebSocket提供了一些实现类,可以根据自己的需求进行选择与重写
package cn.com.websocket.hello;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class HelloHandler extends TextWebSocketHandler{
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
//接收到客户端消息时调用
System.out.println("text message: " + session.getId() + "-" + message.getPayload());
}
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
// 与客户端完成连接后调用
System.out.println("afterConnectionEstablished");
System.out.println("getId:" + session.getId());
System.out.println("getLocalAddress:" + session.getLocalAddress().toString());
System.out.println("getTextMessageSizeLimit:" + session.getTextMessageSizeLimit());
System.out.println("getUri:" + session.getUri().toString());
System.out.println("getPrincipal:" + session.getPrincipal());
session.sendMessage(new TextMessage("你好".getBytes()));
}
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) throws Exception {
// 消息传输出错时调用
System.out.println("handleTransportError");
}
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus closeStatus) throws Exception {
// 一个客户端连接断开时关闭
System.out.println("afterConnectionClosed");
}
@Override
public boolean supportsPartialMessages() {
// TODO Auto-generated method stub
return false;
}
}
<bean id="HelloHandler" class="cn.com.websocket.hello.HelloHandler"/>
<websocket:handlers>
<websocket:mapping path="/hello" handler="HelloHandler"/>
<websocket:handshake-interceptors>
<bean class="cn.com.websocket.hello.HandShakeInterceptor"/>
websocket:handshake-interceptors>
<websocket:sockjs/>
websocket:handlers>
<bean class="org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean">
<property name="maxTextMessageBufferSize" value="8192"/>
<property name="maxBinaryMessageBufferSize" value="8192"/>
bean>
注意上述配置中sockjs的开启配置,如果去掉这一配置,则表示不开启sockjs,那么javascript客户端的调用就要采用标准的HTML的WebSocketAPI。开启了sockjs,则要使用sockjs的javascript接口。
4. 部署启动tomcat
将上述的工程编译好后部署在tomcat中,一个websocket服务端就开始运行了
四、WebSocket的js客户端
1. 非sockjs客户端
在上述配置websocket中,如果不加入
这一配置,那么就采用HTML5的WebSocketAPI来进行通信,需要注意的是必须考虑浏览器是否支持,浏览器的支持情况如下:
示例代码如下:
<html>
<head>
<title>WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample)title>
<script src="./sockjs.js">script>
<script type="text/javascript">
var wsServer = 'ws://127.0.0.1:8080/test/hello';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) { onOpen(evt) };
websocket.onclose = function (evt) { onClose(evt) };
websocket.onmessage = function (evt) { onMessage(evt) };
websocket.onerror = function (evt) { onError(evt) };
function onOpen(evt) {
console.log("Connected to WebSocket server.");
}
function onClose(evt) {
console.log("Disconnected");
}
function onMessage(evt) {
console.log('Retrieved data from server: ' + evt.data);
}
function onError(evt) {
console.log('Error occured: ' + evt.data);
}
/*
var sock = new SockJS('http://localhost:8080/test/hello/test/1');
sock.onopen = function() {
console.log('open');
sock.send('test');
setTimeout(function(){sock.send('later');},3000);
};
sock.onmessage = function(e) {
console.log('message', e.data);
};
sock.onclose = function() {
console.log('close');
};*/
script>
head>
<body>
body>
html>
其中wsServer = ‘ws://127.0.0.1:8080/test/hello’中的地址要根据自己的实际情况来定,一般形式为:ws://域名:端口/应用路径/WebSocket配置的path。“应用路径”是应用部署在tomcat中的文件夹路径,“WebSocket配置的path”是配置文件中
这条配置项配置的路径。
将这个html页面放入tomcat中运行,在浏览器中访问这个html页面,可以查看浏览器的控制台日志:
WebSocket服务器后台输出入下图:
2. sockjs客户端
在上述配置websocket中,如果加入这一配置,则表示开启sockjs支持,那么js客户端就必须采用sockjs提供的javascript接口,代码如下:
WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample)
注意var sock = new SockJS(‘http://127.0.0.1:8080/test/hello‘);这里的地址是http地址,与上面的非sockjs不同。