Spring4 reference中websocket的使用是建立在Spring MVC之上的,其实spring websocket并不依赖于Spring MVC。
The above is for use in Spring MVC applications and should be included
in the configuration of a DispatcherServlet.
However, Spring’s WebSocket support does not depend on Spring MVC.
It is relatively simple to integrate a WebSocketHandler into other HTTP serving environments
with the help of WebSocketHttpRequestHandler.
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.0</modelVersion>
<groupId>net.aty.websocket</groupId>
<artifactId>SpringWebsocketDemo</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>SpringWebsocketDemo Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.2.4.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringWebsocketDemo</finalName>
</build>
</project>
web.xml配置如下:
<?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">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>websocket</servlet-name>
<servlet-class>net.aty.websocket.MyServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>websocket</servlet-name>
<url-pattern>/websocket.connection</url-pattern>
</servlet-mapping>
</web-app>
root-context.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
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">
<bean id="myHandler" class="net.aty.websocket.MyHandler" />
<bean id="myInterceptor" class="net.aty.websocket.MyWebSocketHandshakeInterceptor" />
</beans>
package net.aty.websocket;
import java.util.Map;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class MyHandler extends TextWebSocketHandler {
@Override
public void afterConnectionEstablished(WebSocketSession session)
throws Exception {
System.out.println("connection established");
WebSocketSessionUtil.add(getUserNameFromSession(session), session);
}
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
throws Exception {
System.out.println("receive a message." + message);
WebSocketSessionUtil.broadcast(message);
}
@Override
public void handleTransportError(WebSocketSession session,
Throwable exception) throws Exception {
WebSocketSessionUtil.remove(getUserNameFromSession(session));
}
@Override
public void afterConnectionClosed(WebSocketSession session,
CloseStatus closeStatus) throws Exception {
System.out.println("conection closed." + closeStatus);
WebSocketSessionUtil.add(getUserNameFromSession(session), session);
}
@Override
public boolean supportsPartialMessages() {
return false;
}
private String getUserNameFromSession(WebSocketSession session) {
Map<String, Object> params = session.getAttributes();
return params.get("userName").toString();
}
}
package net.aty.websocket;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor;
public class MyWebSocketHandshakeInterceptor extends
HttpSessionHandshakeInterceptor {
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse, WebSocketHandler wsHandler,
Map<String, Object> attributes) throws Exception {
System.out.println("hi get request.");
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) serverHttpRequest;
HttpServletRequest request = servletRequest.getServletRequest();
String userName = request.getParameter("userName");
attributes.put("userName", userName);
System.out.println("a client userName=" + userName);
super.beforeHandshake(serverHttpRequest, serverHttpResponse, wsHandler,
attributes);
return true;
}
@Override
public void afterHandshake(ServerHttpRequest request,
ServerHttpResponse response, WebSocketHandler wsHandler,
Exception ex) {
super.afterHandshake(request, response, wsHandler, ex);
}
}
package net.aty.websocket;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
public class WebSocketSessionUtil {
private static Map<String, WebSocketSession> clients = new ConcurrentHashMap<>();
public static void add(String userName, WebSocketSession session) {
clients.put(userName, session);
}
public static WebSocketSession get(String userName) {
return clients.get(userName);
}
public static void remove(String userName) {
clients.remove(userName);
}
public static void broadcast(TextMessage message)
throws Exception {
Set<String> allUsers = clients.keySet();
for (String name : allUsers) {
WebSocketSession session = clients.get(name);
session.sendMessage(message);
}
}
}
package net.aty.websocket;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.support.WebSocketHttpRequestHandler;
public class MyServlet extends HttpServlet {
private static final long serialVersionUID = 1954401864181530442L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
ApplicationContext context = WebApplicationContextUtils
.getWebApplicationContext(req.getServletContext());
WebSocketHttpRequestHandler handler = new WebSocketHttpRequestHandler(
context.getBean("myHandler", MyHandler.class));
List<HandshakeInterceptor> interceptors = new ArrayList<HandshakeInterceptor>();
interceptors.add(context.getBean("myInterceptor",
MyWebSocketHandshakeInterceptor.class));
handler.setHandshakeInterceptors(interceptors);
handler.handleRequest(req, resp);
}
}
websocket.html代码如下:
<head>
<script src="js/jquery-1.11.1.js"></script>
<script>
$(function() {
// 浏览器上的websocket对象,用来和服务端通信.
var socket = null;
$("#login").click(
function() {
var userName = $("#userName").val();
if ($.trim(userName) == "") {
return;
}
// 创建websocket对象
socket = new WebSocket(
'ws://localhost:8080/SpringWebsocketDemo/websocket.connection?userName='
+ userName);
registerEvent();
});
$("#logout").click(function() {
socket.close();
});
$("#send").click(function() {
socket.send($("#message").val());
});
function registerEvent() {
socket.onopen = function(event) {
$("#messagePanel").append(
"<div>websocket open successfully.</div>");
}
socket.onmessage = function(event) {
$("#messagePanel").append("<div>msg=" + event.data + "</div>");
};
socket.onclose = function(event) {
$("#messagePanel").append(
"<div>websocket close successfully.</div>");
};
}
});
</script>
<style>
.card {
margin: 20px;
}
</style>
</head>
<body>
<div class="card">
userName:<input id="userName" value="" placeholder="input your name" />
<button id="login">login</button>
<button id="logout">logout</button>
</div>
<div class="card">
message:<input id="message" value="" placeholder="input your message" />
<button id="send">send</button>
</div>
<div class="card" id="messagePanel"></div>
</body>
war包部署到Tomcat7.0.62下,可以看到2个chrome客户端能够收到彼此的信息。
后台的Tomcat也打印出了相应的日志:
我们在没有引入Spring MVC的情况下,实现了Spring WebSocket编程,但是却比较麻烦体现在2个方面:
1.我们必须记录所有的websocket客户端,然后将消息广播给所有客户端。
2.必须手动创建WebSocketHandler和HandshakeInterceptor等对象,无法在spring.xml中配置。
所以我们还是使用SpringMVC+Websocket吧,会给编程带来很大的便利。