第一步: 添加Spring WebSocket的依賴jar包javascript
(注:這裏使用maven方式添加 手動添加的同窗請自行下載相應jar包放到lib目錄)css
<!-- 使用spring websocket依賴的jar包 --> <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>
第二步:創建一個類實現WebSocketConfigurer接口html
package com.quicksand.push; 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.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; import org.springframework.web.socket.handler.TextWebSocketHandler; @Configuration @EnableWebMvc @EnableWebSocket public class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer { public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(webSocketHandler(),"/websocket/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor()); registry.addHandler(webSocketHandler(), "/sockjs/socketServer.do").addInterceptors(new SpringWebSocketHandlerInterceptor()).withSockJS(); } @Bean public TextWebSocketHandler webSocketHandler(){ return new SpringWebSocketHandler(); } }
第三步:繼承WebSocketHandler對象。該對象提供了客戶端鏈接,關閉,錯誤,發送等方法,重寫這幾個方法便可實現自定義業務邏輯java
package com.quicksand.push; import java.io.IOException; import java.util.ArrayList; import org.apache.log4j.Logger; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; public class SpringWebSocketHandler extends TextWebSocketHandler { private static final ArrayList<WebSocketSession> users;//這個會出現性能問題,最好用Map來存儲,key用userid private static Logger logger = Logger.getLogger(SpringWebSocketHandler.class); static { users = new ArrayList<WebSocketSession>(); } public SpringWebSocketHandler() { // TODO Auto-generated constructor stub } /** * 鏈接成功時候,會觸發頁面上onopen方法 */ public void afterConnectionEstablished(WebSocketSession session) throws Exception { // TODO Auto-generated method stub System.out.println("connect to the websocket success......當前數量:"+users.size()); users.add(session); //這塊會實現本身業務,好比,當用戶登陸後,會把離線消息推送給用戶 //TextMessage returnMessage = new TextMessage("你將收到的離線"); //session.sendMessage(returnMessage); } /** * 關閉鏈接時觸發 */ public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { logger.debug("websocket connection closed......"); String username= (String) session.getAttributes().get("WEBSOCKET_USERNAME"); System.out.println("用戶"+username+"已退出!"); users.remove(session); System.out.println("剩餘在線用戶"+users.size()); } /** * js調用websocket.send時候,會調用該方法 */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super.handleTextMessage(session, message); } public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { if(session.isOpen()){session.close();} logger.debug("websocket connection closed......"); users.remove(session); } public boolean supportsPartialMessages() { return false; } /** * 給某個用戶發送消息 * * @param userName * @param message */ public void sendMessageToUser(String userName, TextMessage message) { for (WebSocketSession user : users) { if (user.getAttributes().get("WEBSOCKET_USERNAME").equals(userName)) { try { if (user.isOpen()) { user.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } break; } } } /** * 給全部在線用戶發送消息 * * @param message */ public void sendMessageToUsers(TextMessage message) { for (WebSocketSession user : users) { try { if (user.isOpen()) { user.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } } } }
第四步:繼承HttpSessionHandshakeInterceptor對象。該對象做爲頁面鏈接websocket服務的攔截器,代碼以下:jquery
package com.quicksand.push; 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.support.HttpSessionHandshakeInterceptor; /** * WebSocket攔截器 * @author WANG * */ public class SpringWebSocketHandlerInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { // TODO Auto-generated method stub System.out.println("Before Handshake"); if (request instanceof ServletServerHttpRequest) { ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request; HttpSession session = servletRequest.getServletRequest().getSession(false); if (session != null) { //使用userName區分WebSocketHandler,以便定向發送消息 String userName = (String) session.getAttribute("SESSION_USERNAME"); if (userName==null) { userName="default-system"; } attributes.put("WEBSOCKET_USERNAME",userName); } } return super.beforeHandshake(request, response, wsHandler, attributes); } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { // TODO Auto-generated method stub super.afterHandshake(request, response, wsHandler, ex); } }
第5步 讓SpringWebSocketConfig配置類隨spring容器啓動 spring文件中加入以下代碼:web
<!-- websocket相關掃描,主要掃描:WebSocketConfig 若是前面配置能掃描到此類則能夠不加 --> <context:component-scan base-package="com.quicksand.push"/>
-------------------------------------------------------------------------到這裏就算完成啦 下面準備測試-------------------------------------------------------------spring
1.定義一個控制器用來作鏈接標識和發送消息apache
package com.quicksand.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.socket.TextMessage; import com.quicksand.push.SpringWebSocketHandler; @Controller public class WebsocketController { @Bean//這個註解會從Spring容器拿出Bean public SpringWebSocketHandler infoHandler() { return new SpringWebSocketHandler(); } @RequestMapping("/websocket/login") public ModelAndView login(HttpServletRequest request, HttpServletResponse response) throws Exception { String username = request.getParameter("username"); System.out.println(username+"登陸"); HttpSession session = request.getSession(false); session.setAttribute("SESSION_USERNAME", username); //response.sendRedirect("/quicksand/jsp/websocket.jsp"); return new ModelAndView("websocket"); } @RequestMapping("/websocket/send") @ResponseBody public String send(HttpServletRequest request) { String username = request.getParameter("username"); infoHandler().sendMessageToUser(username, new TextMessage("你好,測試!!!!")); return null; } }
2.創建登陸頁面websocket
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <body> <h2>Hello World!</h2> <body> <!-- ship是個人項目名--> <form action="websocket/login.do"> 登陸名:<input type="text" name="username"/> <input type="submit" value="登陸"/> </form> </body> </body> </html>
3.創建發消息頁面session
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Insert title here</title> </head> <body> <script type="text/javascript" src="http://cdn.bootcss.com/jquery/3.1.0/jquery.min.js"></script> <script type="text/javascript" src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.js"></script> <script type="text/javascript"> var websocket = null; if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/quicksand/websocket/socketServer.do"); } else if ('MozWebSocket' in window) { websocket = new MozWebSocket("ws://localhost:8080/quicksand/websocket/socketServer.do"); } else { websocket = new SockJS("http://localhost:8080/quicksand/sockjs/socketServer.do"); } websocket.onopen = onOpen; websocket.onmessage = onMessage; websocket.onerror = onError; websocket.onclose = onClose; function onOpen(openEvt) { //alert(openEvt.Data); } function onMessage(evt) { alert(evt.data); } function onError() {} function onClose() {} function doSend() { if (websocket.readyState == websocket.OPEN) { var msg = document.getElementById("inputMsg").value; websocket.send(msg);//調用後臺handleTextMessage方法 alert("發送成功!"); } else { alert("鏈接失敗!"); } }
window.close=function()
{
websocket.onclose();
}
</script> 請輸入:<textarea rows="5" cols="10" id="inputMsg" name="inputMsg"></textarea> <button onclick="doSend();">發送</button> </body> </html>
測試結果以下圖: