花費了將近一週的時間終於將webSocket 集成到了原來的springmvc+spring +mybatis 項目中了,一路心酸一路的淚水啊,網上的技術文檔都沒有解決個人問題,(不少文章都是你抄個人我抄你的)。前端
先來講一下個人環境:java
windows 10, myeclipse 2014,orcale11 ,jdk 1.7.0.79 ,spring 4.3.8 springmvc 4.2.4.RELEASE web
websocket jarspring
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>4.2.4.RELEASE</version> </dependency>
下面就記錄一下本身遇到的問題,以及如何解決的問題數據庫
想貼上本身的代碼json
SpringWebSocketConfig.java 文件windows
/** * * * @Description: TODO <p>SpringWebSocketConfig.java</p> * @做者: 王彥寶 * @時間: 2018年10月24日下午3:52:57 * @version V1.0 * @see java.lang.Class * @since JDK{jdk1.7} */ //@EnableWebMvc//測試這個註解能夠不要 @Configuration @EnableWebSocket public class SpringWebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer{ @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(webSocketHandler(),"/webSocketIMServer.json").addInterceptors(myInterceptor()).setAllowedOrigins("*"); registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer.json").withSockJS(); } @Bean public SpringWebSocketHandler webSocketHandler(){ return new SpringWebSocketHandler(); } @Bean public SpringWebSocketHandlerInterceptor myInterceptor(){ return new SpringWebSocketHandlerInterceptor(); } }
SpringWebSocketHandler.java 文件api
import java.io.IOException; import java.util.ArrayList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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; /** * * * @Description: TODO <p>SpringWebSocketHandler.java</p> * @做者: 王彥寶 * @時間: 2018年10月24日下午3:55:49 * @version V1.0 * @see java.lang.Class * @since JDK{jdk1.7} */ public class SpringWebSocketHandler extends TextWebSocketHandler{ private static final Logger LOGGER = LoggerFactory.getLogger(SpringWebSocketHandler.class); private static final ArrayList<WebSocketSession> users;//這個會出現性能問題,最好用Map來存儲,key用userid static { users = new ArrayList<WebSocketSession>(); } public SpringWebSocketHandler() { // TODO Auto-generated constructor stub } /** * 鏈接成功時候,會觸發頁面上onopen方法 */ public void afterConnectionEstablished(WebSocketSession session) throws Exception { LOGGER.info("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 { String username= (String) session.getAttributes().get("WEBSOCKET_EDU_SESSION_USERID"); LOGGER.info("用戶"+username+"已退出!"); users.remove(session); LOGGER.info("剩餘在線用戶"+users.size()); } /** * 給某個用戶發送消息 * @param userAndHosId * @param message * @做者: 王彥寶 * @時間: 2018年11月30日下午1:51:32 * @返回 void */ public void sendMessageToUser(String username, TextMessage message) { LOGGER.info("發送消息:"+message); for (WebSocketSession user : users) { if (user.getAttributes().get("WEBSOCKET_SESSION_USERID").equals(username)) { try { if (user.isOpen()) { LOGGER.info("發送消息:"+message); user.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } break; } } } /** * 羣發全部在線用戶消息 * * @param userName * @param message */ public void sendMessage(TextMessage message) { LOGGER.info("發送消息:"+message); for (WebSocketSession user : users) { try { if (user.isOpen()) { LOGGER.info("發送消息:"+message); user.sendMessage(message); } } catch (IOException e) { e.printStackTrace(); } } } /** * js調用websocket.send時候,會調用該方法 */ @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super.handleTextMessage(session, message); /** * 收到消息,自定義處理機制,實現業務 */ System.out.println("服務器收到消息:"+message); if(message.getPayload().startsWith("#anyone#")){ //單發某人 sendMessageToUser((String)session.getAttributes().get("WEBSOCKET_SESSION_USERID"), new TextMessage("服務器單發:" +message.getPayload())) ; }else if(message.getPayload().startsWith("#everyone#")){ sendMessage(new TextMessage("服務器羣發:" +message.getPayload())); }else{ } } }
SpringWebSocketHandlerInterceptor.java 文件tomcat
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攔截器 * @Description: TODO <p>SpringWebSocketHandlerInterceptor.java</p> * @做者: 王彥寶 * @時間: 2018年10月24日下午3:58:34 * @version V1.0 * @see java.lang.Class * @since JDK{jdk1.7} */ 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_USERID"); if (username==null) { username="default-system"; } attributes.put("WEBSOCKET_SESSION_USERID",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); } }
這就是核心的代碼了。在spring 的配置文件中加入 SpringWebSocketConfig 文件的掃描路徑,而後啓動項目在前端進行訪問服務器
ws://localhost:8081/XXXXX/webSocketIMServer.json"); 這樣訪問就OK 了。
遇到的問題我總結一下:
一、404問題:
在第一次訪問的時候報出了404 的錯誤,找不到路徑,最後發現問題在這裏
registry.addHandler(webSocketHandler(),"/webSocketIMServer.json").addInterceptors(myInterceptor()).setAllowedOrigins("*");
registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer.json").withSockJS();
前端訪問的方法必須和後臺寫的這個方法名一致(包括後綴名,若是後臺代碼沒有後綴,前端訪問時候就不要加後綴,否則就是訪問不到)"/webSocketIMServer.json"。
二、403問題:
上面解決了404 的問題就又報出了403 的問題,而後我就在網上各類搜索,有各類各樣的方案,都試過了,沒有解決問題,而後搜到了這個
博客:https://blog.csdn.net/goxidono/article/details/53414897
和個人問題如出一轍,說的挺詳細,spring-webSocket.jar 裏面自動實現了HandshakeInterceptor 接口
public class OriginHandshakeInterceptor implements HandshakeInterceptor {
而後再執行到這個方法的時候,this.interceptors 就會又兩個 interceptors, 第一個是咱們本身實現的SpringWebSocketHandlerInterceptor 這個接口實現類,第二個就是 spring-webSocket 自動幫你實現的 OriginHandshakeInterceptor 這個接口實現類,
public boolean applyBeforeHandshake(ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> attributes) throws Exception { for (int i = 0; i < this.interceptors.size(); i++) { HandshakeInterceptor interceptor = this.interceptors.get(i); if (!interceptor.beforeHandshake(request, response, this.wsHandler, attributes)) { if (logger.isDebugEnabled()) { logger.debug(interceptor + " returns false from beforeHandshake - precluding handshake"); } applyAfterHandshake(request, response, null); return false; } this.interceptorIndex = i; } return true; }
就在這個方法中會被攔截,而後我就改變了寫法,
下面是我剛開始的寫法:
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //WebIM WebSocket通道 registry.addHandler(webSocketHandler(),"/webSocketIMServer").addInterceptors(myInterceptor()); registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer").addInterceptors(myInterceptor()).withSockJS(); }
改變後的寫法:
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { //WebIM WebSocket通道 registry.addHandler(webSocketHandler(),"/webSocketIMServer.json").addInterceptors(myInterceptor()).setAllowedOrigins("*"); registry.addHandler(webSocketHandler(), "/sockjs/webSocketIMServer.json").withSockJS(); }
而後繼續測試,發現仍是不行,緣由在執行到 applyBeforeHandshake 方法時有兩個攔截器,按照上面的寫法咱們本身實現的攔截器時經過了,可是spring-webSocket 實現的攔截器沒有經過,而後又被攔截了報403 ,可是仍是沒有解決個人問題。文章裏用的jdk 8 ,tomcat 8 ,和個人問題類似可是環境不一樣,用不了他的寫法,測試到這裏的時候我用的spirng 的版本 時4.2.4 ,而後我就想一想換一個高點的spring 的版本試試看,以後就換了Spirng 4.3.8 的版本,啓動測試,竟然OK了。好吧原來時版本的問題 最後的的環境是:
windows 10, myeclipse 2014,orcale11 ,jdk 1.7.0.79 ,spring 4.3.8 springmvc 4.2.4.RELEASE
websocket jar
<dependency> <groupId>javax.websocket</groupId> <artifactId>javax.websocket-api</artifactId> <version>1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>4.2.4.RELEASE</version> </dependency>
這樣就能夠了。在此作一個記錄。