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服務端:
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;
}
}
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;
}
}
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;
}
}
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;
}