背景:當(dāng)用戶登錄的時候,建立websocket連接,默認(rèn)使用websocket連接,如果瀏覽器不支持(安卓需要4.4以上)則使用sockjs模擬連接;服務(wù)器返回對應(yīng)的用戶沒有讀取的消息;服務(wù)端不定時的向某個用戶或者某些用戶或者全部用戶推送消息
分析:需要三個類,第一個實(shí)現(xiàn)配置類:繼承WebMvcConfigureAdapter實(shí)現(xiàn)類WebSocketConfigure用于注冊訪問的地址,(應(yīng)該)屬于第一次握手;第二個連接和消息處理類:實(shí)現(xiàn)WebSocketHandler類,對socket的連接、建立、關(guān)閉、消息處理等方法重寫;第三個攔截器類:實(shí)現(xiàn)HandslerShakerInterceptor類,重寫兩個方法,攔截和重定向;一個配置文件;
解決方案:
1、首先實(shí)現(xiàn)WebSocketHandler類
public class SystemWebSocketHandler implements WebSocketHandler{
//幾個方法
?private static final Logger logger = Logger.getLogger(WebSocketHander.class);??
? private static final ArrayListusers = new ArrayList();? ?
?//初次鏈接成功執(zhí)行? ?
?@Override? ? public void afterConnectionEstablished(WebSocketSession session) throws Exception { ? ? ? ? ? ?users.add(session);? ?
?}? ?
?//接受消息、處理消息??
? @Override? ? public void handleMessage(WebSocketSession webSocketSession, WebSocketMessage <?>webSocketMessage) throws Exception {? ? ?
?? String userName = (String) webSocketSession.getAttributes().get("WEBSOCKET_USERNAME");? ?
?String to_user = (String) webSocketSession.getAttributes().get("WEBSOCKET_TOUSER");? ?
?if(to_user.equals("all")){? ??
sendMessageToUsers(new TextMessage(webSocketMessage.getPayload() + ""));??
? }else if(!to_user.equals("")){? ?
?sendMessageToUser(to_user,new TextMessage(webSocketMessage.getPayload() + ""));?
?? }??
? }? ?
//如果連接拋出異常
?@Override? ? public void handleTransportError(WebSocketSession webSocketSession, Throwable throwable) throws Exception {? ? ??
? if(webSocketSession.isOpen()){? ?
?? ? ? ? webSocketSession.close();? ? ? ?
?}? ??
? ? logger.debug("鏈接出錯,關(guān)閉鏈接......");? ? ? ?
?users.remove(webSocketSession);? ?
?}? ?
//連接關(guān)閉后
?@Override? ? public void afterConnectionClosed(WebSocketSession webSocketSession, CloseStatus closeStatus) throws Exception {? ? ?
?? logger.debug("鏈接關(guān)閉......" + closeStatus.toString());? ? ??
? users.remove(webSocketSession);? ?
?}? ?
?@Override? ? public boolean supportsPartialMessages() {? ? ? ?
?return false;? ?
?}? ?
/*******************************自定義方法*********************************************/
?/**? ? * 給所有在線用戶發(fā)送消息? ? *? ? * @param message? ? */??
? public void sendMessageToUsers(TextMessage message) {
//遍歷消息
? for (WebSocketSession user : users) {? ? ? ? ??
? try {? ? ? ? ? ??
? ? if (user.isOpen()) { ? ?
?? ? ? ? ? ? ? user.sendMessage(message);? ? ? ? ? ?
?? ? }? ? ? ? ?
?? } catch (IOException e) {? ? ? ? ??
? ? ? e.printStackTrace();? ? ? ? ?
?? }? ??
? ? }??
? }? ?
?/**? ? * 給某個用戶發(fā)送消息? ? *? ? * @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;? ? ? ? ?
?? }? ? ? ?
?}? ?
?} ? ? ??
}
2、實(shí)現(xiàn)WebSocketConfigure類
//springmvc的注解,三個
@Configuration
@EnableWebMvc
@EnableWebSocket//開啟websocket
public class WebSocketConfig extends WebMvcConfigurerAdapter implements WebSocketConfigurer {
public WebSocketConfig() {
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
//WebSocketHandler 和 HandshakeInterceptor都是自定義的類
registry.addHandler( systemWebSocketHandler(),"/echo").addInterceptors(new HandshakeInterceptor()).setAllowedOrigins("*"); //支持websocket 的訪問鏈接
registry.addHandler( systemWebSocketHandler(),"/sockjs/echo").addInterceptors(new HandshakeInterceptor()).withSockJS(); //不支持websocket的訪問鏈接
}
public WebSocketHandler systemWebSocketHandler() {
return new WebSocketHandler();
}
}
3、實(shí)現(xiàn)HandlerShakeInterceptor類
public class HandshakeInterceptor implements org.springframework.web.socket.server.HandshakeInterceptor {??
? //進(jìn)入hander之前的攔截??
? @Override? ? public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler,? ? Mapmap) throws Exception {
if (request instanceof ServletServerHttpRequest) {
//? ? ? ? ? ? ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
//? ? ? ? ? ? request.getURI();
String parameter=request.getURI().getQuery();
String openid="";
String to_user="";
if(request.getHeaders().containsKey("Sec-WebSocket-Extensions")) {
request.getHeaders().set("Sec-WebSocket-Extensions", "permessage-deflate");
}
if(parameter!=null){
if(parameter.indexOf("&")>0){ // 發(fā)送信息鏈接
String part[]=parameter.split("&");
String user[]=part[0].split("=");
openid=user[1];
String touser[];
if(part.length==2){
touser=part[1].split("=");
to_user=touser[1];
}
}else{ //會員登錄鏈接
String user[]=parameter.split("=");
if (user.length>1){
openid=user[1];
}else{
openid="guest";
}
}
//使用userName區(qū)分WebSocketHandler,以便定向發(fā)送消息
map.put("WEBSOCKET_USERNAME",openid);
map.put("WEBSOCKET_TOUSER", to_user);
}
}
return true;
}
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
}
}
4、配置文件
web-app version="3.0"http://此處,之前version=“1.0”,最近后臺報錯,參考其他作者的資料意思要大于3.0才行

5.再客戶端引入sockjs.js
6.在需要推送消息的頁面添加代碼
var socket_url='ws://*****************/echo?openid='+openid;
$(function(){
var websocket;
websocket= new WebSocket(socket_url);
websocket.onopen = function (evnt) {
console.log("鏈接服務(wù)器成功");
};
//接收消息
websocket.onmessage = function (evnt) {
//
***************************
};
websocket.onerror = function (evnt) {
};
websocket.onclose = function (evnt) {
//? ? ? ? ? ? ? alert("與服務(wù)器斷開了鏈接!");
websocket= new WebSocket(socket_url);
}
function send(){
if (websocket != null) {
websocket.send(message);
} else {
//? ? ? ? ? ? ? ? ? alert('未與服務(wù)器鏈接.');
}
}
});
參考文檔https://my.oschina.net/ldl123292/blog/304360?p=2&temp=1484634049679#blog-comments-list