用mui做的网站,网站开发岗位,职业生涯规划书模板,看过的网站做记号欢迎使用Markdown编辑器
你好#xff01; 这片文章将教会你从后端springCloud到前端VueEleementAdmin如何搭建Websocket
前端
1. 创建websocket的配置文件在utils文件夹下websocket.js // 暴露自定义websocket对象
export const socket {// 后台请求路径url: ,websocketCo…欢迎使用Markdown编辑器
你好 这片文章将教会你从后端springCloud到前端VueEleementAdmin如何搭建Websocket
前端
1. 创建websocket的配置文件在utils文件夹下websocket.js // 暴露自定义websocket对象
export const socket {// 后台请求路径url: ,websocketCount: -1,// websocket对象websocket: null,// websocket状态websocketState: false,// 重新连接次数reconnectNum: 0,// 重连锁状态保证重连按顺序执行lockReconnect: false,// 定时器信息timeout: null,clientTimeout: null,serverTimeout: null,// 初始化方法根据url创建websocket对象封装基本连接方法并重置心跳检测initWebSocket(newUrl) {socket.url newUrlsocket.websocket new WebSocket(socket.url)socket.websocket.onopen socket.websocketOnOpensocket.websocket.onerror socket.websocketOnErrorsocket.websocket.onmessage socket.webonmessagesocket.websocket.onclose socket.websocketOnClosethis.resetHeartbeat()},reconnect() {// 判断连接状态console.log(判断连接状态)if (socket.lockReconnect) returnsocket.reconnectNum 1// 重新连接三次还未成功调用连接关闭方法if (socket.reconnectNum 3) {socket.reconnectNum 0socket.websocket.onclose()return}// 等待本次重连完成后再进行下一次socket.lockReconnect true// 5s后进行重新连接socket.timeout setTimeout(() {socket.initWebSocket(socket.url)socket.lockReconnect false}, 5000)},// 重置心跳检测resetHeartbeat() {socket.heartbeat()},// 心跳检测heartbeat() {socket.clientTimeout setTimeout(() {if (socket.websocket) {// 向后台发送消息进行心跳检测socket.websocket.send(JSON.stringify({ type: heartbeat }))socket.websocketState false// 一分钟内服务器不响应则关闭连接socket.serverTimeout setTimeout(() {if (!socket.websocketState) {socket.websocket.onclose()console.log(一分钟内服务器不响应则关闭连接)} else {this.resetHeartbeat()}}, 60 * 1000)}}, 3 * 1000)},// 发送消息sendMsg(message) {socket.websocket.send(message)},websocketOnOpen(event) {// 连接开启后向后台发送消息进行一次心跳检测socket.sendMsg(JSON.stringify({ type: heartbeat }))},// 初始化websocket对象// window.location.host获取ip和端口// process.env.VUE_APP_WEBSOCKET_BASE_API获取请求前缀// 绑定接收消息方法webonmessage(event) {// 初始化界面时主动向后台发送一次消息获取数据this.websocketCount 1if (this.websocketCount 0) {const queryCondition {type: message}socket.sendMsg(JSON.stringify(queryCondition))console.log(初始化界面时主动向后台发送一次消息获取数据)}const info JSON.parse(event.data)switch (info.type) {case heartbeat:socket.websocketState trueconsole.log(JSON.stringify(info))breakcase message:if (info.message 成功) {this.$notify({title: 提示,message: 成功,type: success,duration: 0})} else {this.$notify({title: 提示,message: 上传失败 info.message,type: warning,duration: 0})}breakcase error:console.log(websocketerror)break}},websocketOnError(error) {console.log(error)console.log(websocket报错了 error)socket.reconnect()},websocketOnClose() {console.log(websocke他关闭了)socket.websocket.close()}
}
2. 在main.js中引入配置文件使websocket全局都能使用 3. 设置登陆时开启websocket连接
this. s o c k e t . i n i t W e b S o c k e t ( ‘ w s : socket.initWebSocket( ws: socket.initWebSocket(‘ws:{process.env.VUE_APP_WEBSOCKET_BASE_API}/websocket/ this.loginForm.username ) 这句是开启websocket连接的。
// 登录方法
handleLogin() {this.$refs.loginForm.validate(valid {if (valid) {this.loading truethis.$store.dispatch(user/login, this.loginForm).then(() {this.$router.push({ path: this.redirect || /, query: this.otherQuery })this.$store.dispatch(user/addInfomation, this.infoMation)this.$socket.initWebSocket(ws:${process.env.VUE_APP_WEBSOCKET_BASE_API}/websocket/ this.loginForm.username)this.loading false}).catch(() {this.loading false})} else {console.log(error submit!!)return false}})
},4. 设置退出时关闭websocket连接
this.$socket.websocketOnClose()这句是关闭websocket连接的 logout() {await this.$store.dispatch(user/logout)this.$socket.websocketOnClose()this.$router.push(/login?redirect${this.$route.fullPath})}重点和需要配置的地方都在websocket.js里比如接收消息方法webonmessage
后端
1.引依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId/dependency
2.写配置
package com.szc.material.analysisService.confg.WebSocket;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*/Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}}3.创建Websocket服务类依据自己的业务去改OnMessage方法
package com.szc.material.analysisService.confg.WebSocket;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;import javax.security.auth.message.MessageInfo;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;/*** author zhj* ServerEndpoint将目前的类定义成一个websocket服务器端注解的值将被用于监听用户连接的终端访问URL地址客户端可以通过这个URL来连接到WebSocket服务器端* OnOpen当WebSocket建立连接成功后会触发这个注解修饰的方法。* OnClose当WebSocket建立的连接断开后会触发这个注解修饰的方法。* OnMessage当客户端发送消息到服务端时会触发这个注解修改的方法。* OnError当WebSocket建立连接时出现异常会触发这个注解修饰的方法。* ————————————————* 版权声明本文为CSDN博主「人人都在发奋」的原创文章遵循CC 4.0 BY-SA版权协议转载请附上原文出处链接及本声明。* 原文链接https://blog.csdn.net/qq991658923/article/details/127022522*/
Component
Slf4j
ServerEndpoint(/websocket/{userId})
public class MyWebSocketHandler extends TextWebSocketHandler {/*** 线程安全的无序的集合*/private static final CopyOnWriteArraySetSession SESSIONS new CopyOnWriteArraySet();/*** 存储在线连接数*/private static final MapString, Session SESSION_POOL new HashMap();OnOpenpublic void onOpen(Session session, PathParam(value userId) String userId) {try {SESSIONS.add(session);SESSION_POOL.put(userId, session);log.info(【WebSocket消息】有新的连接总数为 SESSIONS.size());} catch (Exception e) {e.printStackTrace();}}OnClosepublic void onClose(Session session,PathParam(value userId) String userId) {try {SESSIONS.remove(session);SESSION_POOL.remove(userId);log.info(【WebSocket消息】连接断开总数为 SESSION_POOL.size());} catch (Exception e) {e.printStackTrace();}}OnMessagepublic void onMessage(String message, PathParam(value userId) String userId) {JSONObject jsonObject JSON.parseObject(message);if(heartbeat.equals(jsonObject.get(type).toString())){MapString,String messageInfornew HashMap();messageInfor.put(type,heartbeat);messageInfor.put(message,我收到了你的心跳);sendOneMessage( userId,messageInfor);log.info(【WebSocket消息】收到客户端消息 message);}}/*** 此为广播消息** param message 消息*/public void sendAllMessage(String message) {log.info(【WebSocket消息】广播消息 message);for (Session session : SESSIONS) {try {if (session.isOpen()) {session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}/*** 此为单点消息** param userId 用户编号* param message 消息*/public void sendOneMessage(String userId, MapString,String message) {Session session SESSION_POOL.get(userId);if (session ! null session.isOpen()) {try {synchronized (session) {log.info(【WebSocket消息】单点消息 message.get(message));session.getAsyncRemote().sendText(JSON.toJSONString(message));}} catch (Exception e) {e.printStackTrace();}}}/*** 此为单点消息(多人)** param userIds 用户编号列表* param message 消息*/public void sendMoreMessage(String[] userIds, String message) {for (String userId : userIds) {Session session SESSION_POOL.get(userId);if (session ! null session.isOpen()) {try {log.info(【WebSocket消息】单点消息 message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}}
4.在需要的地方进行调用
1先注入websocket服务类 AutowiredMyWebSocketHandler myWebSocketHandler;2在方法中调用给前端发消息的方法
myWebSocketHandler.sendOneMessage(userId,messageInfor);问题
1.如果你在controller层调用了service层中身为异步的方法出现了HttpServeletrequst空指针你需要在controller层调用异步方法前加入下面的代码。
ServletRequestAttributes servletRequestAttributes (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();RequestContextHolder.getRequestAttributes().setAttribute(request, request, RequestAttributes.SCOPE_REQUEST);RequestContextHolder.setRequestAttributes(servletRequestAttributes,true);//设置子线程共享
调用requst中的参数时必须使用下面的方法 HttpServletRequest request2 ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();if( request2.getHeader(UserContext.USER_NAME)!null){return Optional.of(request2.getHeader(UserContext.USER_NAME));}