• springboot实现websocket


    一、maven依赖

    1. <dependency>
    2. <groupId>org.springframework.bootgroupId>
    3. <artifactId>spring-boot-starter-websocketartifactId>
    4. dependency>

    二、websocket配置类

    1. @ServerEndpoint("/websocket/{userId}")
    2. @Component
    3. public class WebSocketServer {
    4. static Log log = LogFactory.get(WebSocketServer.class);
    5. /**
    6. * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    7. */
    8. private static int onlineCount = 0;
    9. /**
    10. * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    11. */
    12. private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>();
    13. /**
    14. * 与某个客户端的连接会话,需要通过它来给客户端发送数据
    15. */
    16. private Session session;
    17. /**
    18. * 接收userId
    19. */
    20. private String userId = "";
    21. /**
    22. * 连接建立成功调用的方法
    23. */
    24. @OnOpen
    25. public void onOpen(Session session, @PathParam("userId") String userId) {
    26. this.session = session;
    27. this.userId = userId;
    28. if (webSocketMap.containsKey(userId)) {
    29. webSocketMap.remove(userId);
    30. webSocketMap.put(userId, this);
    31. //加入set中
    32. } else {
    33. webSocketMap.put(userId, this);
    34. //加入set中
    35. addOnlineCount();
    36. //在线数加1
    37. }
    38. log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
    39. try {
    40. sendMessage("连接成功");
    41. } catch (IOException e) {
    42. log.error("用户:" + userId + ",网络异常!!!!!!");
    43. }
    44. }
    45. /**
    46. * 连接关闭调用的方法
    47. */
    48. @OnClose
    49. public void onClose() {
    50. if (webSocketMap.containsKey(userId)) {
    51. webSocketMap.remove(userId);
    52. //从set中删除
    53. subOnlineCount();
    54. }
    55. log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
    56. }
    57. /**
    58. * 收到客户端消息后调用的方法
    59. *
    60. * @param message 客户端发送过来的消息
    61. */
    62. @OnMessage
    63. public void onMessage(String message, Session session) {
    64. log.info("用户消息:" + userId + ",报文:" + message);
    65. //可以群发消息
    66. //消息保存到数据库、redis
    67. if (StringUtils.isNotBlank(message)) {
    68. try {
    69. //解析发送的报文
    70. JSONObject jsonObject = JSON.parseObject(message);
    71. //追加发送人(防止串改)
    72. jsonObject.put("fromUserId", this.userId);
    73. String toUserId = jsonObject.getString("toUserId");
    74. //传送给对应toUserId用户的websocket
    75. if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
    76. log.info("请求的userId:" + toUserId + "在该服务器上");
    77. webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
    78. } else {
    79. log.error("请求的userId:" + toUserId + "不在该服务器上");
    80. //否则不在这个服务器上,发送到mysql或者redis
    81. }
    82. } catch (Exception e) {
    83. e.printStackTrace();
    84. }
    85. }
    86. }
    87. /**
    88. * @param session
    89. * @param error
    90. */
    91. @OnError
    92. public void onError(Session session, Throwable error) {
    93. log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
    94. error.printStackTrace();
    95. }
    96. /**
    97. * 实现服务器主动推送
    98. */
    99. public void sendMessage(String message) throws IOException {
    100. this.session.getBasicRemote().sendText(message);
    101. }
    102. /**
    103. * 发送自定义消息
    104. */
    105. public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
    106. log.info("发送消息到:" + userId + ",报文:" + message);
    107. if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
    108. webSocketMap.get(userId).sendMessage(message);
    109. } else {
    110. log.error("用户" + userId + ",不在线!");
    111. }
    112. }
    113. public static synchronized int getOnlineCount() {
    114. return onlineCount;
    115. }
    116. public static synchronized void addOnlineCount() {
    117. WebSocketServer.onlineCount++;
    118. }
    119. public static synchronized void subOnlineCount() {
    120. WebSocketServer.onlineCount--;
    121. }
    122. }
    1. /**
    2. * 开启WebSocket支持
    3. * @author
    4. */
    5. @Configuration
    6. public class WebSocketConfig {
    7. @Bean
    8. public ServerEndpointExporter serverEndpointExporter() {
    9. return new ServerEndpointExporter();
    10. }
    11. }

    三、controller

    1. @RestController
    2. public class DemoController {
    3. @GetMapping("index")
    4. public ResponseEntity index() {
    5. return ResponseEntity.ok("请求成功");
    6. }
    7. @GetMapping("page")
    8. public ModelAndView page() {
    9. return new ModelAndView("websocket");
    10. }
    11. @RequestMapping("/push/{toUserId}")
    12. public ResponseEntity pushToWeb(String message, @PathVariable String toUserId) throws IOException {
    13. WebSocketServer.sendInfo(message, toUserId);
    14. return ResponseEntity.ok("MSG SEND SUCCESS");
    15. }
    16. }

    以上代码完成了websocket的接入,可以用在线的websocket测试网站测试

    四、在线websocket测试网站

     websocket在线测试

     1、下面是测试连接的页面

     本地调试的话,用ws://ip:port/websocket/{{userId}} 连接

    2、发送消息

     发送内容{"toUserId":"1111","body":"测试消息"},服务器受到消息后,会带上fromUserId返回

    五、 nginx配置

    如果使用了nginx,需要进行配置实现websocket协议的转发

    1. location /websocket/ {
    2. proxy_pass http://127.0.0.1:7017/websocket/;
    3. proxy_http_version 1.1;
    4. proxy_set_header Upgrade $http_upgrade;
    5. proxy_set_header Connection "upgrade";
    6. }

    上面的配置放在 server配置里

    六、遇到的问题

    本地启动项目可以正常测试,但是准备打个jar包扔到服务器的时候,使用maven install出现问题,解决方案:删除   spring-boot-starter-test 依赖和 test测试类代码,或者install时忽略test文件夹。

  • 相关阅读:
    visionpro学习课程-CogPMAlignTool大总结
    2021.03青少年软件编程(Python)等级考试试卷(三级)
    windows系统安装php,运行php
    基于内存的分布式NoSQL数据库Redis(六)AOF设计
    22/5/21
    Apache 网站服务基础
    认知战壳吉桔:认知战战略不是从思潮开始,而在策划!
    Camunda 使用restapi
    springboot2 shardingjdbc4.x 分表
    SQL Server高级编程
  • 原文地址:https://blog.csdn.net/xrq1995/article/details/126581698