WebSocket客户端:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocketDemo</title>
</head>
<body>
<P id="message">暂无消息<br/></P>
</body>
<script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket,使用ws或者wss协议访问服务端
if("WebSocket" in window) {
websocket = new WebSocket("ws://localhost:8080/demo/websocket")
alert("浏览器支持WebSocket");
} else {
alert("浏览器不支持支持WebSocket");
}
//连接发生错误的回调方法
websocket.onerror = function() {
alert("WebSocket连接发生错误")
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function() {
alert("WebSocket连接成功")
setMessageInnerHTML("WebSocket连接成功");
//发送消息
websocket.send("hello server");
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
alert("后台响应消息:" + event.data);
setMessageInnerHTML(event.data);
websocket.close();
}
//连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("WebSocket连接关闭");
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function() {
closeWebSocket();
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
//将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
</script>
</html>
WebSocket服务端:
-
WebSocket配置(注解方式):
package com.demo.websocket.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import com.demo.websocket.handler.CustomWebSocketHandler;
import com.demo.websocket.intercepter.WebSocketHandshakeIntercept;
@Configuration
@EnableWebSocket
@EnableWebMvc
public class WebSocketConfig implements WebSocketConfigurer {
/**
* 将 WebSocket 处理器添加到注册中心
*/
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(getWebSocketHandler(), "/websocket")
.addInterceptors(new WebSocketHandshakeIntercept()).setAllowedOrigins("*");
}
/**
* 获取WebSocket处理器,可以根据业务需要自定义处理器
*/
@Bean
public WebSocketHandler getWebSocketHandler() {
return new CustomWebSocketHandler();
}
/**
* 调整处理异常的优先级
*/
@Bean
public HandlerExceptionResolver handlerExceptionResolver() {
List<HandlerExceptionResolver> exceptionResolvers = new ArrayList<HandlerExceptionResolver>();
HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite();
composite.setOrder(10);
composite.setExceptionResolvers(exceptionResolvers);
return composite;
}
}
-
WebSocket拦截器:
package com.demo.websocket.intercepter;
import java.util.Map;
import javax.servlet.http.HttpSession;
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.HandshakeInterceptor;
import com.demo.websocket.util.WebSocketSessionUtils;
public class WebSocketHandshakeIntercept implements HandshakeInterceptor {
/**
* 设置sessionId
*/
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Map<String, Object> attributes) throws Exception {
HttpSession session = getSession(serverHttpRequest);
if (session != null) {
String sessionId = (String) session.getAttribute("sessionId");
if (sessionId == null) {
sessionId = WebSocketSessionUtils.getUUID();
}
attributes.put("sessionId", sessionId);
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
WebSocketHandler webSocketHandler, Exception exception) {
}
private HttpSession getSession(ServerHttpRequest serverHttpRequest) {
if (serverHttpRequest instanceof ServletServerHttpRequest) {
ServletServerHttpRequest servletServerHttpRequest = (ServletServerHttpRequest) serverHttpRequest;
return servletServerHttpRequest.getServletRequest().getSession(true);
}
return null;
}
}
-
WebSocket处理器:
package com.demo.websocket.handler;
import java.util.concurrent.TimeUnit;
import org.apache.commons.collections.MapUtils;
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;
import com.demo.websocket.util.WebSocketSessionUtils;
public class CustomWebSocketHandler implements WebSocketHandler {
/**
* 建立连接之后的操作
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
WebSocketSessionUtils.add(sessionId, session);
}
/**
* 异常处理
*/
@Override
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
WebSocketSessionUtils.remove(sessionId);
}
/**
* 关闭连接之后的操作
*/
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
WebSocketSessionUtils.remove(sessionId);
}
/**
* 处理消息
*/
@Override
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
if (message instanceof TextMessage) {
// 获取前端发送的消息
String msg = message.getPayload().toString();
System.out.println("已收到消息:" + msg);
String sessionId = MapUtils.getString(session.getAttributes(), "sessionId");
// 等待10s,模拟后台处理消息
TimeUnit.SECONDS.sleep(10);
if (WebSocketSessionUtils.exists(sessionId)) {
// 如果存在此sessionId,则向其发送应答消息
WebSocketSessionUtils.sendMessage(sessionId, "hello client");
}
}
}
/**
* 是否处理分片消息
*/
@Override
public boolean supportsPartialMessages() {
return false;
}
}
-
WebSocket会话管理工具:
package com.demo.websocket.util;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
public class WebSocketSessionUtils {
/**
* session缓存
*/
private static Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
/**
* 保存连接
*/
public static void add(String sessionId, WebSocketSession session) {
sessions.put(sessionId, session);
}
/**
* 获取连接
*/
public static WebSocketSession get(String sessionId) {
return sessions.get(sessionId);
}
/**
* 移除连接
*/
public static void remove(String sessionId) {
sessions.remove(sessionId);
}
/**
* 清空连接
*/
public static void clear() {
sessions.clear();
}
/**
* 获取连接数
*/
public static int getconnections() {
return sessions.size();
}
/**
* 是否存在
*/
public static boolean exists(String sessionId) {
if (sessions.containsKey(sessionId)) {
return true;
}
return false;
}
/**
* 发送消息到客户端
*/
public static void sendMessage(String sessionId, String message) {
if (sessionId == null || !exists(sessionId)) {
throw new NullPointerException(sessionId);
}
WebSocketSession session = get(sessionId);
try {
session.sendMessage(new TextMessage(message));
} catch (IOException e) {
remove(sessionId);
e.printStackTrace();
}
}
/**
* 获得UUID
*/
public static String getUUID() {
return UUID.randomUUID().toString().replaceAll("-", "");
}
}
依赖配置:
<!-- spring相关包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>4.3.18.RELEASE</version>
</dependency>
注意:
- 如果使用Nginx代理服务器,需要在配置文件中添加超时配置
location / {
proxy_read_timeout 3600s;
}