spring与websocket整合
首先spring必须用4.0以上,
依赖包:
1 <dependency> 2 <groupId>com.fasterxml.jackson.core</groupId> 3 <artifactId>jackson-annotations</artifactId> 4 <version>2.3.0</version> 5 </dependency> 6 <dependency> 7 <groupId>com.fasterxml.jackson.core</groupId> 8 <artifactId>jackson-core</artifactId> 9 <version>2.3.1</version> 10 </dependency> 11 <dependency> 12 <groupId>com.fasterxml.jackson.core</groupId> 13 <artifactId>jackson-databind</artifactId> 14 <version>2.3.3</version> 15 </dependency> 16 <dependency> 17 <groupId>org.springframework</groupId> 18 <artifactId>spring-websocket</artifactId> 19 <version>4.0.5.RELEASE</version> 20 </dependency> 21 <dependency> 22 <groupId>org.springframework</groupId> 23 <artifactId>spring-messaging</artifactId> 24 <version>4.0.5.RELEASE</version> 25 </dependency>
编写WebSocketConfig、HandshakeInterceptor与WebSocketHander
1 import org.springframework.context.annotation.Configuration; 2 import org.springframework.web.servlet.config.annotation.EnableWebMvc; 3 import org.springframework.web.socket.config.annotation.EnableWebSocket; 4 import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 5 import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 6 7 @Configuration 8 @EnableWebMvc 9 @EnableWebSocket 10 public class WebSocketConfig implements WebSocketConfigurer { 11 @Override 12 public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { 13 14 /** 15 * 支持websocket 的 connection 16 */ 17 registry.addHandler(new WebSocketHander(),"/websocket").addInterceptors(new HandshakeInterceptor()); 18 19 /** 20 * 不支持websocket的connenction,采用sockjs 21 */ 22 registry.addHandler(new WebSocketHander(),"/sockjs/websocket").addInterceptors(new HandshakeInterceptor()).withSockJS(); 23 } 24 }
1 import java.util.Map; 2 3 import org.springframework.http.server.ServerHttpRequest; 4 import org.springframework.http.server.ServerHttpResponse; 5 import org.springframework.web.socket.WebSocketHandler; 6 public class HandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor { 7 8 /** 9 * Interceptor before hander 10 */ 11 @Override 12 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception { 13 return true; 14 } 15 16 @Override 17 public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) { 18 19 } 20 }
1 import java.io.IOException; 2 import java.util.ArrayList; 3 4 import javax.annotation.Resource; 5 6 import org.slf4j.Logger; 7 import org.springframework.web.socket.CloseStatus; 8 import org.springframework.web.socket.TextMessage; 9 import org.springframework.web.socket.WebSocketHandler; 10 import org.springframework.web.socket.WebSocketMessage; 11 import org.springframework.web.socket.WebSocketSession; 12 13 public class WebSocketHander implements WebSocketHandler { 14 15 private static final Logger logger = org.slf4j.LoggerFactory.getLogger(WebSocketHander.class); 16 17 private static final ArrayList<WebSocketSession> users = new ArrayList<WebSocketSession>(); 18 19 /** 20 * after connection establish 21 */ 22 public void afterConnectionEstablished(WebSocketSession session) throws Exception { 23 logger.info("connect success..."); 24 users.add(session); 25 } 26 27 /** 28 * process the received message 29 */ 30 @Override 31 public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage<?> webSocketMessage) throws Exception { 32 sendMessageToUsers(new TextMessage(webSocketMessage.getPayload() + "hello")); 33 } 34 35 @Override 36 public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception { 37 if(webSocketSession.isOpen()){ 38 webSocketSession.close(); 39 } 40 logger.info("connenction error,close the connection..."); 41 users.remove(webSocketSession); 42 } 43 44 @Override 45 public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception { 46 logger.info("close the connenction..."+closeStatus.toString()); 47 users.remove(webSocketSession); 48 } 49 50 @Override 51 public boolean supportsPartialMessages() { 52 return false; 53 } 54 /** 55 * 给所有在线用户发送消息 56 * 57 * @param message 58 */ 59 public void sendMessageToUsers(TextMessage message) { 60 for (WebSocketSession user : users) { 61 try { 62 if (user.isOpen()) { 63 user.sendMessage(message); 64 } 65 } catch (IOException e) { 66 e.printStackTrace(); 67 } 68 } 69 } 70 }
前端页面js
1 <script type="text/javascript"> 2 $(function(){ 3 var websocket; 4 if ('WebSocket' in window) { 5 alert("WebSocket"); 6 websocket = new WebSocket("ws://localhost:8080/项目名称/websocket"); 7 } else if ('MozWebSocket' in window) { 8 alert("MozWebSocket"); 9 websocket = new MozWebSocket("ws://echo"); 10 } else { 11 alert("SockJS"); 12 websocket = new SockJS("http://localhost:8080/<span style="font-family: Arial, Helvetica, sans-serif;">项目名称</span><span style="font-family: Arial, Helvetica, sans-serif;">/sockjs/websocket");</span> 13 } 14 websocket.onopen = function (evnt) { 15 $("#tou").html("链接服务器成功!") 16 }; 17 websocket.onmessage = function (evnt) { 18 $("#msg").html($("#msg").html() + "<br/>" + evnt.data); 19 }; 20 websocket.onerror = function (evnt) { 21 }; 22 websocket.onclose = function (evnt) { 23 $("#tou").html("与服务器断开了链接!") 24 } 25 $('#send').bind('click', function() { 26 send(); 27 }); 28 function send(){ 29 if (websocket != null) { 30 var message = document.getElementById('message').value; 31 websocket.send(message); 32 } else { 33 alert('未与服务器链接.'); 34 } 35 } 36 }); 37 </script>
可能出现的错误:
Async support must be enabled on a servlet and for all filters involved in async request processing
如果直接运行,基本上会包上面的错误,我们还需要在web.xml中做如下的配置
<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">
但是2.5的webapp也可以
然后在这个servlet中加入:
1 <async-supported>true</async-supported>
如:
1 <servlet> 2 <servlet-name>presto-engine</servlet-name> 3 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 4 <init-param> 5 <param-name>contextConfigLocation</param-name> 6 <param-value>classpath:presto_servlet.xml</param-value> 7 </init-param> 8 <load-on-startup>1</load-on-startup> 9 <async-supported>true</async-supported> 10 </servlet>
The extension [x-webkit-deflate-frame] is not supported
在HandshakeInterceptor的beforeHandshake方法中加入
1 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception { 2 /** 3 * This is a bug,bug fix:The extension [x-webkit-deflate-frame] is not supported 4 */ 5 if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")) { 6 request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate"); 7 } 8 return true; 9 }