1. 程式人生 > >整合WebSocket+SpringMVC+dubbo的過程中遇到的問題

整合WebSocket+SpringMVC+dubbo的過程中遇到的問題

整合WebSocket的過程中遇到的問題

專案中使用到了dubbo和SpringMVC,並且使用SpringSession管理session,但在整合WebSocket時遇到了一些問題:
1、無法獲取到登入使用者
2、無法獲取到dubbo的提供者
下面是解決這兩個問題的思路,並在文章最後附上最終程式碼

無法獲取到登入使用者的問題

解決方法

  1. 寫一個類GetHttpSessionConfigurator繼承ServerEndpointConfig.Configurator
    重寫modifyHandshake方法。
    可以在modifyHandshake方法中獲取到登入使用者,然後放入ServerEndpointConfig中。

//import com.test.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

/**
 * 配置類將登入使用者傳入WebSocket中
 *
 * @author frank
 * @date 2018/11/14 12:36
 */
public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator { protected final Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { String userId =
""; try{ // TODO 這裡自己獲取session中的userId, // userId = WebUtil.getCurrentUser(); logger.info("GetHttpSessionConfigurator:userId"+userId); }catch (Exception e){ logger.warn("沒有許可權"); return ; } config.getUserProperties().put("userId", userId); } }
  1. 在@ServerEndpoint中配置configurator = GetHttpSessionConfigurator.class
@Controller
@ServerEndpoint(value="/web-socket/get-message-count", configurator = GetHttpSessionConfigurator.class)
  1. 在WebSocketServer的@OnOpen增加中 EndpointConfig config,使用 config.getUserProperties().get() 獲取config中的登入使用者資訊
@OnOpen
    public void onOpen(Session session, EndpointConfig config) throws IOException {
        System.out.println("onOpen======================");
        this.currentSession = session;
        // TODO 獲取config中的資訊 獲取userId 
        String userId = (String) config.getUserProperties().get("userId");
        System.out.println("userId======================"+userId);
        //建立連結時,快取物件
        serverMap.put(userId, this);
        Map<String,Object> map = new HashMap<>();
        map.put("count",countUnreadMessageByUserId(userId));
        session.getBasicRemote().sendText(JSON.toJSONString(map));
    }

無法獲取到dubbo的提供者

經過上面的配置後,發現WebSocketServer類中無法注入dubbo的Provider,
參考一些其他部落格,發現configurator = SpringConfigurator.class時能夠正常注入provider

魚和熊掌不可兼得?去SpringConfigurator一看,SpringConfigurator繼承的也是ServerEndpointConfig.Configurator。

public class SpringConfigurator extends Configurator {
	...
	...
}

這下好了,我們將GetHttpSessionConfigurator繼承SpringConfigurator就可以了
解決方法

public class GetHttpSessionConfigurator extends SpringConfigurator {
	...
	...
}

最終程式碼

最終程式碼如下
GetHttpSessionConfigurator.java


//import com.test.WebUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.server.standard.SpringConfigurator;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

/**
 * 配置類將登入使用者傳入WebSocket中
 *
 * @author frank
 * @date 2018/11/14 12:36
 */
public class GetHttpSessionConfigurator extends SpringConfigurator {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Override
    public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) {
        String userId = "";
        try{
            // TODO 這裡自己獲取session中的userId,
            // userId = WebUtil.getCurrentUser();
            logger.info("GetHttpSessionConfigurator:userId"+userId);
        }catch (Exception e){
            logger.warn("沒有許可權");
            return ;
        }
        config.getUserProperties().put("userId", userId);
    }
}

WebSocketServer.java


import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.test.GetHttpSessionConfigurator;
import com.test.ISysProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
 * WebSocket服務
 *
 * @author frank
 * @date 2018/8/6 18:18
 */
@Controller
@ServerEndpoint(value="/web-socket/get-message-count", configurator = GetHttpSessionConfigurator.class)
public class WebSocketServer  {

    // dubbo的Provider
    @Autowired
    @Qualifier("sysProvider")
    public ISysProvider sysProvider;

    private static final Logger logger = LoggerFactory.getLogger(WebSocketServer.class);
    /**已經建立連結的物件快取起來*/
    private static ConcurrentMap<String, WebSocketServer> serverMap = new ConcurrentHashMap<>();
    /**當前session*/
    private Session currentSession;

    @OnOpen
    public void onOpen(Session session, EndpointConfig config) throws IOException {
        System.out.println("onOpen======================");
        this.currentSession = session;
        String userId = (String) config.getUserProperties().get("userId");
        // 能夠獲取到userId
        System.out.println("userId======================"+userId);
        //建立連結時,快取物件
        serverMap.put(userId, this);
        Map<String,Object> map = new HashMap<>();
        map.put("count",countUnreadMessageByUserId(userId));
        session.getBasicRemote().sendText(JSON.toJSONString(map));
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println("onClose======================");
        // 通過getLoginUserId()獲取userId
        System.out.println("userId======================"+getLoginUserId());
        String userId = getLoginUserId();
        serverMap.remove(userId, this);
        this.currentSession = null;
        try {
            session.close();
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
    }

    @OnMessage()
    public void onMessage(Session session,String msg) throws IOException {
        System.out.println("onMessage======================"+msg);
        // 可以獲取到sysProvider和userId
        System.out.println("sysProvider======================"+(null == sysProvider));
        System.out.println("userId======================"+getLoginUserId());
        Map<String,Object> map = new HashMap<>();
        map.put("count",countUnreadMessageByUserId(getLoginUserId()));
        this.currentSession.getBasicRemote().sendText(JSON.toJSONString(map));
    }
    @OnError
    public void onError(Throwable t) {
        logger.error(t.getMessage());
    }

    /**
     * 根據傳入的userId得到最新的未讀訊息數量
     * @param userId
     * @author frank
     */
    public void sendUnreadMessageCountByUserId(String userId){
        try {
            //如果連線開啟,則傳送最新資料
            if ( serverMap.containsKey(userId) && serverMap.get(userId).currentSession.isOpen() ) {
                Map<String,Object> map = new HashMap<>();
                map.put("count",countUnreadMessageByUserId(userId));
                serverMap.get(userId).currentSession.getBasicRemote().sendText(JSON.toJSONString(map));
            }
        } catch (IOException e) {
            logger.error(e.getMessage());
        }
    }

    /**
     * 根據websocket的session獲取userId
     * @author frank
     * @param
     * @date 2018/11/14 14:01
     * @return java.lang.String
     */
    private String getLoginUserId(){
        if (serverMap.containsValue(this)) {
            Iterator<String> keys = serverMap.keySet().iterator();
            String userId = "";
            while(keys.hasNext()) {
                userId = keys.next();
                if (serverMap.get(userId) == this) {
                    return userId;
                }
            }
        }
        return null;
    }

    /**
     * 根據使用者id統計未讀訊息數量
     * @author frank
     * @param userId
     * @date 2018/8/6 21:40
     * @return int
     */
    public int countUnreadMessageByUserId(String userId){
    	/*
    	 * TODO 獲取最新的資料
    	 */
        return RandomUtils.nextInt()/100000000;
    }


}