spirng項目中集成webSocket踩到的坑

 

 

花費了將近一週的時間終於將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>

這樣就能夠了。在此作一個記錄。

相關文章
相關標籤/搜索