整合WebSocket+SpringMVC+dubbo的過程中遇到的問題
阿新 • • 發佈:2018-11-17
整合WebSocket的過程中遇到的問題
專案中使用到了dubbo和SpringMVC,並且使用SpringSession管理session,但在整合WebSocket時遇到了一些問題:
1、無法獲取到登入使用者
2、無法獲取到dubbo的提供者
下面是解決這兩個問題的思路,並在文章最後附上最終程式碼
無法獲取到登入使用者的問題
解決方法
- 寫一個類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);
}
}
- 在@ServerEndpoint中配置configurator = GetHttpSessionConfigurator.class
@Controller
@ServerEndpoint(value="/web-socket/get-message-count", configurator = GetHttpSessionConfigurator.class)
- 在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;
}
}