友情提示: 消息推送的介紹能夠參考http://www.cnblogs.com/dahuandan/p/6816173.htmlcss
webSocket是爲解決客戶端與服務端實時通訊而產生的技術,其本質是使用一個TCP鏈接進行雙向通信,能夠用來Web服務端的消息推送,被IETF定義爲標準協議。html
相對於傳統的HTTP輪詢技術而言,webSocket是創建一次TCP鏈接進行客戶端與服務端的雙向通信,減小了傳統輪詢技術頻繁地向服務器發起請求,另外webSocket的Header相比HTTP的很是小。前端
Spring4.0版本以上java
tomcat8jquery
package demo; /** * webSocket常量 */ public class Constants { /** * http session 中 用戶名的key值 */ public static String SESSION_USERNAME = "session_username"; /** * websocket session 中 用戶名的key值 */ public static String WEBSOCKET_USERNAME = "websocket_username"; }
package demo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 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; /** * 註冊websocket */ @Configuration @EnableWebMvc @EnableWebSocket public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{ public void registerWebSocketHandlers(WebSocketHandlerRegistry reg) { String websocket_url = "/webSocketServer"; //設置websocket的地址 reg.addHandler(systemWebSocketHandler(), websocket_url) //註冊到Handler .addInterceptors(new WebSocketInterceptor()); //註冊到Interceptor //提供SockJS支持(主要是兼容ie8) String sockjs_url = "/sockjs/webSocketServer"; //設置sockjs的地址 reg.addHandler(systemWebSocketHandler(),sockjs_url ) //註冊到Handler .addInterceptors(new WebSocketInterceptor()) //註冊到Interceptor .withSockJS(); //支持sockjs協議 } @Bean public WebSocketHandler systemWebSocketHandler(){ return new MyWebSocketHandler(); } }
package demo; import java.util.Map; 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; /** * WebSocket握手攔截器 */ public class WebSocketInterceptor implements HandshakeInterceptor { //握手前 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Map<String, Object> attr) throws Exception { if (request instanceof ServletServerHttpRequest) { ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; String user = servletRequest.getServletRequest().getParameter("user"); attr.put(Constants.WEBSOCKET_USERNAME, user); } return true; } //握手後 public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler, Exception e) { } }
package demo; import java.io.IOException; import java.util.ArrayList; import java.util.List; 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; /** * WebSocket處理器 */ public class MyWebSocketHandler implements WebSocketHandler { /** * WebSocketSession容器 */ private static final List<WebSocketSession> users = new ArrayList<WebSocketSession>(); //創建鏈接後的函數 @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { users.add(session); } //消息處理 @Override public void handleMessage(WebSocketSession session, WebSocketMessage<?> ws_msg) throws Exception { // String user = (String)session.getAttributes().get(Constants.WEBSOCKET_USERNAME); sendMessageToUsers(new TextMessage("received at server: " + ws_msg.getPayload())); } //關閉鏈接後的函數 public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { users.remove(session); } //異常處理 @Override public void handleTransportError(WebSocketSession session, Throwable e) throws Exception { if(session.isOpen()) session.close(); users.remove(session); } @Override public boolean supportsPartialMessages() { return false; } /** * 給全部在線用戶發送消息 * @param message * @throws IOException */ public void sendMessageToUsers(TextMessage message) throws IOException { for (WebSocketSession user : users) { if (user.isOpen()) user.sendMessage(message); } } /** * 給某個用戶發送消息 * @param userName * @param message * @throws IOException */ public void sendMessageToUser(String userName, TextMessage message) throws IOException { for (WebSocketSession user : users) { if (user.getAttributes().get(Constants.WEBSOCKET_USERNAME).equals(userName)) { if (user.isOpen()) { user.sendMessage(message); } } } } }
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>websocket</title> <script src="jquery-1.10.2.js"></script> <script src="sockjs-0.3.min.js"></script> <script> $(function(){ var webSocket = newWebSocket(); sendMessage(webSocket); }); /** * 建立webSocket */ function newWebSocket(){ var webSocket; if ('WebSocket' in window) webSocket = new WebSocket("ws://localhost:8080/websocket/webSocketServer?user=123"); else if ('MozWebSocket' in window) webSocket = new MozWebSocket("ws://localhost:8080/websocket/webSocketServer"); else webSocket = new SockJS("http://localhost:8080/websocket/sockjs/webSocketServer"); //打開webSocket鏈接 webSocket.onopen = function (evnt) { }; //接收信息 webSocket.onmessage = function (evnt) { $("#console").append("(<font color='red'>"+evnt.data+"</font>)</br>") }; //錯誤處理 webSocket.onerror = function (evnt) { }; //關閉webSocket webSocket.onclose = function (evnt) { } return webSocket; } /** * 發送信息 */ function sendMessage(webSocket){ $("#send").click(function(){ webSocket.send($("#message").val()); }); } </script> </head> <body> <div> <textarea id="message" style="width: 350px">send message!</textarea> </div> </br> <div> <button id="send">send</button> </div> <div id="console"></div> </body> </html>
<?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-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"> <context:annotation-config /> </beans>
<?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:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd"> <mvc:annotation-driven/> <context:component-scan base-package="demo*"/> <!-- 靜態資源解析 包括 :js、css、img、.. location: 資源所在的本地路徑,建議不要放在webInf下 mapping :url的訪問路徑, **表明包含resource/路徑後的全部子目錄 --> <mvc:resources location="/" mapping="/**"/> </beans>
<?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"> <display-name>websocketDemo</display-name> <!-- 加載spring容器 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/spring/spring.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- springmvc前端控制器,rest配置 --> <servlet> <servlet-name>springmvc_rest</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocation配置springmvc加載的配置文件(配置處理器映射器、適配器等等) 若是不配置contextConfigLocation,默認加載的是/WEB-INF/servlet名稱-serlvet.xml(springmvc-servlet.xml) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring/springmvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc_rest</servlet-name> <!-- 第一種:*.action,訪問以.action結尾 由DispatcherServlet進行解析 第二種:/,因此訪問的地址都由DispatcherServlet進行解析, 使用此種方式能夠實現 RESTful風格的url(對於靜態文件的解析須要配置不讓DispatcherServlet進行解析) 第三種:/*,這樣配置不對,使用這種配置,最終要轉發到一個jsp頁面時, 仍然會由DispatcherServlet解析jsp地址,不能根據jsp頁面找到handler,會報錯。 --> <url-pattern>/</url-pattern> </servlet-mapping> <!-- post亂碼過慮器 --> <!-- 除了加過濾器,因爲tomcat默認編碼ISO-8859-1,還須要修改 %tomcat%/conf/server.xml Connector 標籤加屬性 URIEncoding="UTF-8" --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
打開多個窗口,分別輸入http://localhost:8080/websocket/index.jsp, 而後在某一窗口發送消息的時候,其餘窗口都能接收到:web