0


Springboot3.X集成WebSocket完整流程

WebSocket介绍

WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455,后由 RFC 7936 补充规范。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocketAPI 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输

环境介绍

springboot

  1. pom文件

  1. <!--spring 版本--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.0.5</version></parent>
  1. websocket依赖
  1. <!--websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

Vue

  1. "vue":"3.2.45","websocket":"^1.0.34"

后端代码示例

目录结构

在这里插入图片描述

配置类

  1. packagegzsf.epg.sever.webSocket.config;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.socket.server.standard.ServerEndpointExporter;/**
  2. * webSocket的配置类
  3. * @author
  4. * @date 2023/10/7
  5. */@ConfigurationpublicclassWebSocketConfig{@BeanpublicServerEndpointExporterserverEndpointExporter(){returnnewServerEndpointExporter();}}
  1. packagegzsf.epg.sever.webSocket.websocket;importjakarta.websocket.Session;/**
  2. * @author
  3. * @date 2023/10/7
  4. */publicclassWebSocketClient{// 与某个客户端的连接会话,需要通过它来给客户端发送数据privateSession session;//连接的uriprivateString uri;publicSessiongetSession(){return session;}publicvoidsetSession(Session session){this.session = session;}publicStringgetUri(){return uri;}publicvoidsetUri(String uri){this.uri = uri;}}

如下是后端发送消息的配置,如需发送文本类的数据需要配置这个

  1. packagegzsf.epg.sever.webSocket.util;importcom.fasterxml.jackson.core.JsonProcessingException;importcom.fasterxml.jackson.databind.json.JsonMapper;importgzsf.epg.sever.datacheck.vo.ExportVo;importjakarta.websocket.EncodeException;importjakarta.websocket.Encoder;importjakarta.websocket.EndpointConfig;publicclassServerEncoderimplementsEncoder.Text<ExportVo>{@Overridepublicvoiddestroy(){// TODO Auto-generated method stub// 这里不重要}@Overridepublicvoidinit(EndpointConfig arg0){// TODO Auto-generated method stub// 这里也不重要}/*
  2. * encode()方法里的参数和Text<T>里的T一致,如果你是Student,这里就是encodeStudent student
  3. */@OverridepublicStringencode(ExportVo responseMessage)throwsEncodeException{try{JsonMapper jsonMapper =newJsonMapper();return jsonMapper.writeValueAsString(responseMessage);}catch(JsonProcessingException e){
  4. e.printStackTrace();returnnull;}}}

服务类

  1. packagegzsf.epg.sever.webSocket.service;importgzsf.epg.sever.datacheck.vo.ExportVo;importgzsf.epg.sever.webSocket.util.ServerEncoder;importgzsf.epg.sever.webSocket.websocket.WebSocketClient;importjakarta.websocket.*;importjakarta.websocket.server.PathParam;importjakarta.websocket.server.ServerEndpoint;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.context.ApplicationContext;importorg.springframework.stereotype.Component;importjava.io.IOException;importjava.util.concurrent.ConcurrentHashMap;/**
  2. * @author
  3. * @date 2023/10/7
  4. */@ServerEndpoint(value ="/websocket/{userName}", encoders ={ServerEncoder.class})@ComponentpublicclassWebSocketService{privatestaticfinalLogger log =LoggerFactory.getLogger(WebSocketService.class);privatestaticApplicationContext applicationContext;publicstaticvoidsetApplicationContext(ApplicationContext context){
  5. applicationContext = context;}privatestaticConcurrentHashMap<String,WebSocketClient> webSocketMap =newConcurrentHashMap<>();/**
  6. * 与某个客户端的连接会话,需要通过它来给客户端发送数据
  7. */privateSession session;/**
  8. * 接收userName
  9. */privateString userName;/**
  10. * 客户端与服务端连接成功
  11. *
  12. * @param session
  13. */@OnOpenpublicvoidonOpen(Session session,@PathParam("userName")String userName){this.session = session;//根据token获取用户名this.userName = userName;WebSocketClient client =newWebSocketClient();
  14. client.setSession(session);
  15. client.setUri(session.getRequestURI().toString());
  16. webSocketMap.put(userName, client);
  17. log.info("连接成功!"+session.getRequestURI().toString());
  18. log.info("连接成功!"+session);}/**
  19. * 客户端与服务端连接关闭
  20. */@OnClosepublicvoidonClose(){
  21. log.info("连接关闭!");}/**
  22. * 客户端与服务端连接异常
  23. *
  24. * @param error
  25. * @param session
  26. */@OnErrorpublicvoidonError(Throwable error,Session session){}/**
  27. * 客户端向服务端发送消息
  28. *
  29. * @param message
  30. * @throws IOException
  31. */@OnMessagepublicvoidonMsg(Session session,String message)throwsIOException{
  32. log.info("消息测试!");}publicstaticvoidsendVo(String userName,ExportVo vo){try{WebSocketClient webSocketClient = webSocketMap.get(userName);if(webSocketClient !=null){
  33. webSocketClient.getSession().getBasicRemote().sendObject(vo);}}catch(IOException e){
  34. e.printStackTrace();thrownewRuntimeException(e.getMessage());}catch(EncodeException e){thrownewRuntimeException(e.getMessage());}}/**
  35. * 向指定客户端发送消息
  36. *
  37. * @param message
  38. */publicstaticvoidsendMessage(String userName,String message){try{
  39. log.info("准备发消息!"+userName);WebSocketClient webSocketClient = webSocketMap.get(userName);
  40. log.info("连接成功》》》》》》》》》"+webSocketMap);if(webSocketClient !=null){
  41. log.info("发送的消息是!"+message);
  42. webSocketClient.getSession().getBasicRemote().sendText(message);}}catch(IOException e){
  43. e.printStackTrace();
  44. log.info("失败");thrownewRuntimeException(e.getMessage());}}}

需要注意

修改启动类如下,服务类就能注入,否则在调用service的时候会空指针异常,具体原因可以去了解下 spring 默认管理

  1. packagegzsf.epg.sever;importgzsf.epg.common.core.utils.SpringContextUtils;importgzsf.epg.common.security.annotation.EnableCustomConfiguration;importgzsf.epg.common.security.annotation.EnableFeignBeanClients;importgzsf.epg.sever.webSocket.service.WebSocketService;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.ConfigurableApplicationContext;importorg.springframework.context.annotation.Import;/**
  2. * @author
  3. * @date 2023/10/19
  4. */@EnableCustomConfiguration@EnableFeignBeanClients@SpringBootApplication@Import(SpringContextUtils.class)publicclassServiceApplication{privatestaticfinalLogger logger =LoggerFactory.getLogger(ServiceApplication.class);publicstaticvoidmain(String[] args){ConfigurableApplicationContext run =SpringApplication.run(ServiceApplication.class, args);//解决WebSocket不能注入的问题WebSocketService.setApplicationContext(run);}}

前端代码示例

连接地址里

  1. admin

为用户名,因为websocket是单独为每个用户创建长连接,发送的消息也是一对一发送,当然也可以改为一对多,全权在业务怎么用。前端可获取用户名传到后端,如下代码示例是写死的
注意:前端也需下载依赖
下面展示一些

  1. 内联代码片

  1. npm install vue-native-websocket
  1. /**
  2. * 创建webSocket连接
  3. */functioncreateWS(){
  4. webSocket.value =newWebSocket("ws://127.0.0.1:8080/server/websocket/admin");//onopen事件监听
  5. webSocket.value.addEventListener('open',e=>{
  6. console.log('与服务端连接打开->', e)},false)//onclose事件监听
  7. webSocket.value.addEventListener('close',e=>{
  8. console.log('与服务端连接关闭->', e)},false)//onmessage事件监听
  9. webSocket.value.addEventListener('message',e=>{
  10. console.log('接收到服务端的消息->', e)},false)//onerror事件监听
  11. webSocket.value.addEventListener('error',e=>{},false)}

只需在需要开启长连接的时候调用

  1. createWS();

即可;

简单说明一下执行流程

前端

在需要开启长连接处调用

  1. createWS();

开启长连接即可,需注意用户名(该用户名就是唯一标识)传递。

后端

前端发起建立长连接请求后,执行WebSocketService类中的onOpen方法,创建client并存放在map集合中以便执行完业务后发送反馈消息。

  1. /**
  2. * 客户端与服务端连接成功
  3. *
  4. * @param session
  5. */@OnOpenpublicvoidonOpen(Session session,@PathParam("userName")String userName){this.session = session;//根据token获取用户名this.userName = userName;WebSocketClient client =newWebSocketClient();
  6. client.setSession(session);
  7. client.setUri(session.getRequestURI().toString());
  8. webSocketMap.put(userName, client);
  9. log.info("连接成功!"+session);}

如何调用

后端接收到前端请求后可新建线程执行业务流程,先返回执行中状态给前端,防止前后端连接超时的报错。

  1. @PostMapping("/importDx")publicAjaxResultimportDx(@RequestParam("xlsxFile")MultipartFile file){this.onCallback(file);returnAjaxResult.success();}publicvoidonCallback(MultipartFile file){ExecutorService executor =Executors.newCachedThreadPool();
  2. executor.execute(()->{try{//服务类代码}catch(IOException e){thrownewRuntimeException(e);}});
  3. executor.shutdown();}

业务执行完成后可调用,username为创建websocket的唯一标识。

  1. /**
  2. * 调用sendMessage方法使用
  3. */WebSocketService.sendMessage(username,"执行成功");

只要是在长连接里面,想做什么全看业务,

  1. 简单来说干什么都行!至此WebSocket使用结束

本文转载自: https://blog.csdn.net/qq_43437208/article/details/136647914
版权归原作者 你看我每天都很忙 所有, 如有侵权,请联系我们删除。

“Springboot3.X集成WebSocket完整流程”的评论:

还没有评论