springboot vue webSocket 整合
阿新 • • 發佈:2021-06-10
vue 前端
import {websocket_path,S_200,E_700} from '@/utils/constants'; import {getToken} from '@/utils/oauth'; import { Notification } from 'element-ui'; import store from '@/store'; import {genUUID} from '@/utils/stringUtils' let socket; const socketUrl = "/ws/msgWebSocket" function initWebSocket(){ if(typeof(WebSocket) === "undefined"){ Notification({ title: '系統資訊', message: "您的瀏覽器不支援socket,請聯絡管理員", type: 'error' }) console.error("您的瀏覽器不支援socket,請聯絡管理員") return null; }else{ // 例項化socket socket = new WebSocket(websocket_path+socketUrl+"?token="+getToken()); // 監聽socket連線 socket.onopen = handlerOpen; // 監聽socket錯誤資訊 socket.onerror = handlerError; // 監聽socket訊息 socket.onmessage = getMessage; return socket; } } let handlerOpen = function(){ } let handlerError = function(err){ console.error("websocket 連線錯誤",err); } /*接收訊息*/ let getMessage = function(msg){ let msgObj = JSON.parse(msg.data); if(msgObj.code == E_700){ //token校驗失敗 socket.close(); console.error(msgObj) Notification({ title: '系統資訊', message: "token驗證失敗,socket無法連線", type: 'error' }) return; } if(msgObj.code == S_200){ //socket連線成功 console.log("websocket 連線成功",msgObj) //判斷是否是伺服器推送的訊息 if(JSON.stringify(msgObj.info) != "{}" ){ Notification({ title: '新訊息', message: `<span>傳送人: ${msgObj.info.senderUser.name_}</span><br/> <span>標題: ${msgObj.info.title_}</span><br/>`, type: 'success', dangerouslyUseHTMLString:true }) //觸發訊息標記 store.commit('commonData/SET_MSGUPDATEFLAG',genUUID()); } } return msg; } /*傳送訊息*/ let send = function(msg){ socket.send(msg) } /*關閉連線*/ let close = function () { socket.close(); } export default initWebSocket;
後臺配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
import java.io.IOException; import java.util.Date; import java.util.List; import java.util.concurrent.CopyOnWriteArraySet;import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSONObject; import com.sun.star.uno.RuntimeException; import com.ylkj.common.constants.ErrorEnum; import com.ylkj.common.constants.SuccessEnum; import com.ylkj.common.oauth.jwt.JwtUtils; import com.ylkj.common.utils.DateUtils; import com.ylkj.common.utils.Result; import com.ylkj.common.utils.StringUtils; @Component @ServerEndpoint(value = "/ws/msgWebSocket") public class WebSocketServer { private static Logger log = LoggerFactory.getLogger(WebSocketServer.class); //用來存放每個客戶端對應的WebSocketServer物件。 private static CopyOnWriteArraySet<WebSocketServer> WebSocketServers = new CopyOnWriteArraySet<WebSocketServer>(); //與某個客戶端的連線會話,需要通過它來給客戶端傳送資料 private Session session; //每個連線客戶的賬號 private String account; @OnOpen public void onOpen(Session session) { this.session = session; WebSocketServers.add(this); String token= session.getQueryString().substring(session.getQueryString().indexOf("=")+1); //token為空 if(StringUtils.isEmpty(token)){ JSONObject param = new JSONObject(); param.put("msg", "對於半開放資源和受限資源,token不可為空"); try { this.session.getBasicRemote().sendText(Result.error(ErrorEnum.E_700,param).toJSONString()); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } finally{ WebSocketServers.remove(this); } return; } //token校驗失敗 if(StringUtils.isEmpty(JwtUtils.getAccount(token))){ JSONObject param = new JSONObject(); param.put("msg", "token校驗失敗,已過期或偽造"); try { this.session.getBasicRemote().sendText(Result.error(ErrorEnum.E_700,param).toJSONString()); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } finally{ WebSocketServers.remove(this); } return; } this.account = JwtUtils.getAccount(token); log.info("使用者連線成功("+DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss")+"):"+JwtUtils.getAccount(token)); try { this.session.getBasicRemote().sendText(Result.success(SuccessEnum.S_200).toJSONString()); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } /** * @Title: onClose * @Description: 當客戶端退出時觸發,當服務端關閉時觸發 * 客戶端退出: 客戶端遊覽器直接關閉,前端呼叫socket方法關閉 * @param session * void * @throws */ @OnClose public void onClose(Session session) { WebSocketServers.remove(this); log.info("使用者斷開連線("+DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss")+"):"+account); } @OnError public void onError(Session session, Throwable error) { log.info("連線錯誤"); } /** * @Title: onMessage * @Description: 接收客戶端的訊息 * @param message * void * @throws */ @OnMessage public void onMessage(String message) { log.info("["+this.account+"]發來訊息("+DateUtils.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss")+"):"+message); } /** * @Title: sendMessageAll * @Description: 伺服器主動推送(所有線上使用者都將收到) * @param msg * void * @throws */ public static synchronized void sendMessageAll(JSONObject msg) { for (WebSocketServer webSocketServer : WebSocketServers) { try { webSocketServer.session.getBasicRemote().sendText(Result.success(SuccessEnum.S_200, msg).toJSONString()); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } } /** * @Title: sendMessage * @Description: 伺服器主動推送(指定賬號可以收到) * @param msg * @param accounts * void * @throws */ public static synchronized void sendMessage(JSONObject msg,List<String> accounts) { //遍歷所有使用者 for (String account : accounts) { //遍歷每一個當前session集合 for (WebSocketServer webSocketServer : WebSocketServers) { if(account.equals(webSocketServer.account)){ try { webSocketServer.session.getBasicRemote().sendText(Result.success(SuccessEnum.S_200, msg).toJSONString()); } catch (IOException e) { throw new RuntimeException(e.getMessage()); } } } } } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configuration public class WebSocketConfig { /** * ServerEndpointExporter 作用 * * 這個Bean會自動註冊使用@ServerEndpoint註解宣告的websocket endpoint * * @return */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } @Bean public MySpringConfigurator mySpringConfigurator() { return new MySpringConfigurator(); } }
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import javax.websocket.server.ServerEndpointConfig; public class MySpringConfigurator extends ServerEndpointConfig.Configurator implements ApplicationContextAware { private static volatile BeanFactory context; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { MySpringConfigurator.context = applicationContext; } @Override public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException { return context.getBean(clazz); } }