1. 程式人生 > 其它 >springboot vue webSocket 整合

springboot vue webSocket 整合

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);
    }
}