场景
SpringBoot+Vue整合WebSocket实现前后端消息推送:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/114392573
若依微服务版手把手教你本地搭建环境并运行前后端项目:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/109363303
在上面介绍了在SpringBoot+Vue的基础上使用WebSocket的过程以及使用SpringCloud(若依微服务版)搭建项目的基础上,如果在SpringCloud中使用WebSocket的过程。
实现
首先在需用集成WebSocket的服务下面添加WebSocket的依赖
<!-- WebSocket--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
这里是放在定时任务服务下面
然后在项目包路径下新建config目录,在此目录下新建WebSocketConfig配置类
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Configurationpublic class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); }}
然后在包下新建websocket目录,在此目录下新建WebSocketClient客户端实体类用来存储连接的会话个uri
import javax.websocket.Session; public class WebSocketClient { // 与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; //连接的uri private String uri; public Session getSession() { return session; } public void setSession(Session session) { this.session = session; } public String getUri() { return uri; } public void setUri(String uri) { this.uri = uri; }}
然后还在此目录下新建WebSocketService服务类
import org.apache.commons.lang.StringUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component; import javax.websocket.*;import javax.websocket.server.PathParam;import javax.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.concurrent.ConcurrentHashMap; @ServerEndpoint(value = "/websocket/{userName}")@Componentpublic class WebSocketService { private static final Logger log = LoggerFactory.getLogger(WebSocketService.class); //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的WebSocketServer对象。 private static ConcurrentHashMap<String, WebSocketClient> webSocketMap = new ConcurrentHashMap<>(); /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/ private Session session; /**接收userName*/ private String userName=""; /** * 连接建立成功调用的方法*/ @OnOpen public void onOpen(Session session, @PathParam("userName") String userName) { if(!webSocketMap.containsKey(userName)) { addOnlineCount(); // 在线数 +1 } this.session = session; this.userName= userName; WebSocketClient client = new WebSocketClient(); client.setSession(session); client.setUri(session.getRequestURI().toString()); webSocketMap.put(userName, client); log.info("----------------------------------------------------------------------------"); log.info("用户连接:"+userName+",当前在线人数为:" + getOnlineCount()); try { sendMessage("来自后台的反馈:连接成功"); } catch (IOException e) { log.error("用户:"+userName+",网络异常!!!!!!"); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { if(webSocketMap.containsKey(userName)){ webSocketMap.remove(userName); if(webSocketMap.size()>0) { //从set中删除 subOnlineCount(); } } log.info("----------------------------------------------------------------------------"); log.info(userName+"用户退出,当前在线人数为:" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息*/ @OnMessage public void onMessage(String message, Session session) { log.info("收到用户消息:"+userName+",报文:"+message); //可以群发消息 //消息保存到数据库、redis if(StringUtils.isNotBlank(message)){ } } /** * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { log.error("用户错误:"+this.userName+",原因:"+error.getMessage()); error.printStackTrace(); } /** * 连接服务器成功后主动推送 */ public void sendMessage(String message) throws IOException { synchronized (session){ this.session.getBasicRemote().sendText(message); } } /** * 向指定客户端发送消息 * @param userName * @param message */ public static void sendMessage(String userName,String message){ try { WebSocketClient webSocketClient = webSocketMap.get(userName); if(webSocketClient!=null){ webSocketClient.getSession().getBasicRemote().sendText(message); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e.getMessage()); } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketService.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketService.onlineCount--; } public static void setOnlineCount(int onlineCount) { WebSocketService.onlineCount = onlineCount; } public static ConcurrentHashMap<String, WebSocketClient> getWebSocketMap() { return webSocketMap; } public static void setWebSocketMap(ConcurrentHashMap<String, WebSocketClient> webSocketMap) { WebSocketService.webSocketMap = webSocketMap; } public Session getSession() { return session; } public void setSession(Session session) { this.session = session; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
注意这里引入的WebSocketClient是上面新建的
找到网关的配置文件,这里是使用Nacos作为配置中心。将websocket的路径放开权限认证
这里是在ruoyi-gateway-dev.xml最后面的ignore-whites下面添加
- /schedule/websocket/**
这里是将websocket放在定时任务这个服务下面,这个服务的路由也在网关的配置文件中
然后为了简单化以及演示,这里直接在使用websocket的连接时直接不走网关,直接调用定时任务服务下的端口的服务
为了进行推送的测试,需要使用websocket客户端的测试工具,具体可自行解决,或者使用下面的工具
https://download.csdn.net/download/BADAO_LIUMANG_QIZHI/15630118
这里直接使用9203是具体定时任务服务的地址,而不是网关的端口,然后连接的地址为
ws://localhost:9203/websocket/badao
其中badao是传递的UserName参数,输入地址后点击连接,可以看到连接成功
并且点击发送数据
后台也会收到。
然后在后台新建一个测试的接口
@RestController@RequestMapping("/schedule/websocket")public class WebSocketTestController { @GetMapping("/push") public void push(SysJobLog sysJobLog) { WebSocketService.sendMessage("badao","badao"); }}
调用此接口后,客户端也会收到发送的数据
这里是使用客户端工具来测试websocket,然后前端Vue集成websocket和上面的博客的集成流程一样。
不_言 1 年前