正如你可能已经看到的,Spring Framework 4.0 第一个里程碑版本已经宣布,且我们已经发布了早期的WebSocket支持。为什么WebSocket重要呢?在web上,需要在客户端(典型如浏览器)和服务器间进行高频率低延迟的消息交换是在应用中必不可少的,它使有效的,双向的通信成为可能。常见的例子包括交易,游戏,协作,数据可视化,其他的一系列场景和用例将随时间而增加。
搭建运行环境
测试环境
spring 4.2.4
tomcat 7.0.47+
Springmvc环境的搭建
1、 引入spring-framework-4.2.4.RELEASE/libs下面的相关jar包
2、配置web.xml,引入springmvc的支持
<?xml version="1.0" encoding="UTF-8"?>
<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">
<display-name>springsocket</display-name>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
3、 创建springmvc.xml配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="contentType" value="text/html" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<context:component-scan base-package="cn.xiaoyu.springsocket,cn.xiaoyu.socket" />
<!-- HandlerMapping-处理请求映射 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<!-- HandlerAdapter接口-处理请求的映射 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
</beans>
4、 测试首页
创建HelloWorldController类,来测试环境是否搭建成功
@Controller
@RequestMapping(value = "/")
public class HelloWorldController {
@RequestMapping(value="/index", method = {RequestMethod.GET})
public String login(Model model){
model.addAttribute("message", "Hello Roin!");
return "index";
}
}
springWebsocket工程搭建
WebSocketConfig类
@Configuration
@EnableWebSocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements
WebSocketConfigurer {
public WebSocketConfig() {
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 用来注册websocket server实现类,第二个参数是访问websocket的地址
registry.addHandler(systemWebSocketHandler(), "/webSocketServer").addInterceptors(new HandshakeInterceptor());
// 使用Sockjs的注册方法
registry.addHandler(systemWebSocketHandler(), "/sockjs/webSocketServer").addInterceptors(new HandshakeInterceptor()).withSockJS();
System.out.println("注册spring websocket成功!");
}
@Bean
public WebSocketHandler systemWebSocketHandler() {
return new SystemWebSocketHandler();
}
}
SystemWebSocketHandler类
@Component
public class SystemWebSocketHandler implements WebSocketHandler {
private static final List<WebSocketSession> sessions = new ArrayList<WebSocketSession>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("链接webSocket成功");
sessions.add(session);
session.sendMessage(new TextMessage("服务端链接成功!"));
}
@Override
public void handleMessage(WebSocketSession wss, WebSocketMessage<?> wsm) throws Exception {
// TextMessage returnMessage = new TextMessage(wss.getId() + ":" + wsm.getPayload());
TextMessage returnMessage = new TextMessage("用户"+wss.getId()+"说:" + wsm.getPayload());
System.out.println(returnMessage.toString());
// wss.sendMessage(returnMessage);
for (WebSocketSession session : sessions) {
session.sendMessage(returnMessage);
}
}
@Override
public void handleTransportError(WebSocketSession wss, Throwable thrwbl) throws Exception {
if(wss.isOpen()){
wss.close();
}
System.out.println("WebSocket出错!");
}
@Override
public void afterConnectionClosed(WebSocketSession wss, CloseStatus cs) throws Exception {
System.out.println("WebSocket关闭!");
}
@Override
public boolean supportsPartialMessages() {
return false;
}
}
HandshakeInterceptor类
@Component
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
System.out.println("握手前...");
return super.beforeHandshake(request, response, wsHandler, attributes);
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
System.out.println("握手后...");
super.afterHandshake(request, response, wsHandler, ex);
}
}
index.jsp页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<base href="<%=basePath%>">
<script type="text/javascript" src="js/jquery.js"></script>
<script src="//cdn.bootcss.com/sockjs-client/1.0.3/sockjs.js"></script>
<script>
var websocket;
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost/springsocket/webSocketServer");
} else if ('MozWebSocket' in window) {
websocket = new MozWebSocket("ws://localhost/springsocket/webSocketServer");
} else {
websocket = new SockJS("http://localhost/springsocket/sockjs/webSocketServer");
}
websocket.onopen = function (evnt) {
$("#msgcount").append("WebSocket链接开始!<br/>");
};
websocket.onmessage = function (evnt) {
$("#msgcount").append(evnt.data+"<br/>");
};
websocket.onerror = function (evnt) {
$("#msgcount").append("WebSocket链接出错!<br/>");
};
websocket.onclose = function (evnt) {
$("#msgcount").append("WebSocket链接关闭!<br/>");
};
function send() {
websocket.send($("#msg").val());
}
</script>
</head>
<body>${message}
<hr/>
<textarea rows="5" cols="20" id="msg"></textarea>
<br>
<button onclick="send()">发送</button>
<hr />
<div id="msgcount"></div>
</body>
</html>
这样发布之后,WebSocket就可以运行了,运行图如下:
项目结构图如下:
错误处理
如果在ie8上面运行的话会出现如下的错误:
java.lang.IllegalStateException: A SockJsMessageCodec is required but not available
此时,需要引入Jackson相关的三个jar包:jackson-databind-2.6.4.jar, jackson-core-2.6.4.jar, jackson-annotations-2.6.4.jar这样就可以重新发布了!