1.導入maven依賴javascript
<!-- websocket --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>${spring.version}</version> </dependency>
2.建立類 HandshakeInterceptor 繼承 HttpSessionHandshakeInterceptorhtml
public class HandshakeInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { /** * 在攔截器內強行修改websocket協議,將部分瀏覽器不支持的 x-webkit-deflate-frame 擴展修改爲 * permessage-deflate */ if (request.getHeaders().containsKey("Sec-WebSocket-Extensions")) { request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate"); } String jspCode = ((ServletServerHttpRequest) request).getServletRequest().getParameter("jspCode"); if (jspCode != null) { attributes.put("jspCode", jspCode); } else { return false; } return true; } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { super.afterHandshake(request, response, wsHandler, ex); } }
3.建立類 MyWebSocketConfig 繼承 WebMvcConfigurerAdapter 並實現 WebSocketConfigurer前端
@Component @EnableWebMvc @EnableWebSocket public class MyWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { @Resource MyWebSocketHandler handler; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { // TODO Auto-generated method stub registry.addHandler(handler, "/websocket").addInterceptors(new HandshakeInterceptor()); registry.addHandler(handler, "/websocket/sockjs").addInterceptors(new HandshakeInterceptor()).withSockJS(); } }
4.建立類 MyWebSocketHandler 實現 WebSocketHandlerjava
@Component public class MyWebSocketHandler implements WebSocketHandler { public static final Map<String, WebSocketSession> userSocketSessionMap; static { userSocketSessionMap = new HashMap<String, WebSocketSession>(); } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { // TODO Auto-generated method stub String jspCode = session.getId() + "-" + (String) session.getHandshakeAttributes().get("jspCode"); if (userSocketSessionMap.get(jspCode) == null) { System.out.println("添加會話:" + jspCode); userSocketSessionMap.put(jspCode, session); } } @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { // TODO Auto-generated method stub session.sendMessage(message); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { // TODO Auto-generated method stub if (session.isOpen()) { session.close(); } Iterator<Entry<String, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator(); // 移除Socket會話 while (it.hasNext()) { Entry<String, WebSocketSession> entry = it.next(); if (entry.getValue().getId().equals(session.getId())) { userSocketSessionMap.remove(entry.getKey()); System.out.println("Socket會話已經移除:用戶ID:" + entry.getKey()); break; } } } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { // TODO Auto-generated method stub System.out.println("Websocket:" + session.getId() + "已經關閉"); Iterator<Entry<String, WebSocketSession>> it = userSocketSessionMap.entrySet().iterator(); // 移除Socket會話 while (it.hasNext()) { Entry<String, WebSocketSession> entry = it.next(); if (entry.getValue().getId().equals(session.getId())) { userSocketSessionMap.remove(entry.getKey()); System.out.println("Socket會話已經移除:用戶ID:" + entry.getKey()); break; } } } @Override public boolean supportsPartialMessages() { // TODO Auto-generated method stub return false; } }
5.前段使用web
<!-- websocket --> <script type="text/javascript"> $(function() { var jspCode = "${user.userId}"; var websocket; if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/ebcrawler/websocket?jspCode=" + jspCode); } else if ('MozWebSocket' in window) { websocket = new MozWebSocket("ws://localhost:8080/ebcrawler/websocket?jspCode=" + jspCode); } else { websocket = new SockJS("http://localhost:8080/ebcrawler/websocket/sockjs?jspCode=" + jspCode); } websocket.onopen = function(event) { $(".commonMsg").each(function() { $(this).html($(this).html() + "已鏈接<br/>") }); }; websocket.onmessage = function(event) { var data = event.data; var type = data.substring(0, data.indexOf("-")); var msg = data.substring(data.indexOf("-") + 1); if (type == "1") { $("#doneMsg").html($("#doneMsg").html() + msg + "<br/>"); } else if (type == "2") { $("#doingMsg").html(msg + "<br/>"); } else if (type == "3") { $("#errorMsg").html(msg + "<br/>" + $("#errorMsg").html()); } else { } }; websocket.onerror = function(event) { $(".commonMsg").each(function() { $(this).html($(this).html() + "websocket發生錯誤<br/>") }); }; websocket.onclose = function(event) { $(".commonMsg").each(function() { $(this).html($(this).html() + "已關閉<br/>") }); }; }); </script>
6.後端使用spring
//websocket發給前端 Iterator<Entry<String, WebSocketSession>> it = MyWebSocketHandler.userSocketSessionMap.entrySet().iterator(); // 發給同一userId的客戶端 while (it.hasNext()) { final Entry<String, WebSocketSession> entry = it.next(); String keyUserId = entry.getKey().substring(entry.getKey().indexOf("-") + 1); WebSocketSession session = entry.getValue(); if (session.isOpen() && keyUserId.equals(userId)) { try { if (session.isOpen()) { synchronized(session) { entry.getValue().sendMessage(new TextMessage(msg)); } } } catch (IOException e) { e.printStackTrace(); } } }
注意:當多線程發送消息時,同一個WebSocketSession一次只能發送條消息,因此須要用synchronize將session鎖住後端