• Springboot 集成 WebSocket


    WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

    1.添加依赖包

    1. <!--webSocket-->
    2. <dependency>
    3. <groupId>org.springframework.boot</groupId>
    4. <artifactId>spring-boot-starter-websocket</artifactId>
    5. </dependency>

    2.添加WebSocket配置

    1. import org.springframework.context.annotation.Bean;
    2. import org.springframework.context.annotation.Configuration;
    3. import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    4. @Configuration
    5. public class WebSocketConfig {
    6. @Bean
    7. public ServerEndpointExporter serverEndpointExporter() {
    8. return new ServerEndpointExporter();
    9. }
    10. }

    3.编写web服务端

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.stereotype.Component;
    3. import javax.websocket.*;
    4. import javax.websocket.server.PathParam;
    5. import javax.websocket.server.ServerEndpoint;
    6. import java.util.concurrent.ConcurrentHashMap;
    7. import java.util.concurrent.CopyOnWriteArraySet;
    8. @Component
    9. @ServerEndpoint("/websocket/{clientId}")
    10. @Slf4j
    11. public class WebSocketServer {
    12. /**
    13. * 客户端的连接会话,需要通过它来给客户端发送数据
    14. */
    15. private Session session;
    16. /**
    17. * 客户端id
    18. */
    19. private String clientId;
    20. /**
    21. * 用来存放每个客户端对应的MyWebSocket对象
    22. */
    23. private static CopyOnWriteArraySet webSockets = new CopyOnWriteArraySet<>();
    24. /**
    25. * 用来存在线连接用户信息
    26. */
    27. private static ConcurrentHashMap sessionPool = new ConcurrentHashMap();
    28. /**
    29. * 链接成功调用的方法
    30. */
    31. @OnOpen
    32. public void onOpen(Session session, @PathParam(value = "clientId") String clientId) {
    33. try {
    34. this.session = session;
    35. this.clientId = clientId;
    36. webSockets.add(this);
    37. sessionPool.put(clientId, session);
    38. log.info("【websocket消息】有新的连接 clientId:{},总数为:{}", clientId, webSockets.size());
    39. } catch (Exception e) {
    40. log.info("【websocket消息】有新的连接构建失败 clientId:{},总数为:{},error:", clientId, webSockets.size(), e);
    41. }
    42. }
    43. /**
    44. * 链接关闭调用的方法
    45. */
    46. @OnClose
    47. public void onClose() {
    48. try {
    49. webSockets.remove(this);
    50. sessionPool.remove(this.clientId);
    51. log.info("【websocket消息】连接断开 clientId:{},总数为:{}", this.clientId, webSockets.size());
    52. } catch (Exception e) {
    53. log.info("【websocket消息】连接断开失败 clientId:{},总数为:{},error:", clientId, webSockets.size(), e);
    54. }
    55. }
    56. /**
    57. * 收到客户端消息后调用的方法
    58. */
    59. @OnMessage
    60. public void onMessage(String message) {
    61. log.info("【websocket消息】收到客户端消息:{}", message);
    62. }
    63. /**
    64. * 发送错误时的处理
    65. *
    66. * @param session
    67. * @param error
    68. */
    69. @OnError
    70. public void onError(Session session, Throwable error) {
    71. log.error("【websocket消息】发生错误,原因:", error);
    72. }
    73. /**
    74. * 此为广播消息
    75. */
    76. public void sendBroadcastMessage(String message) {
    77. log.info("【websocket消息】广播消息:{}", message);
    78. for (WebSocketServer webSocket : webSockets) {
    79. try {
    80. if (webSocket.session.isOpen()) {
    81. webSocket.session.getAsyncRemote().sendText(message);
    82. }
    83. } catch (Exception e) {
    84. log.error("【websocket消息】广播消息异常,消息:{},error:", message, e);
    85. }
    86. }
    87. }
    88. /**
    89. * 此为单点消息
    90. */
    91. public void sendSinglePointMessage(String targetId, String message) {
    92. Session session = sessionPool.get(targetId);
    93. if (session != null && session.isOpen()) {
    94. try {
    95. session.getAsyncRemote().sendText(message);
    96. log.info("【websocket消息】单点消息,targetId:{},消息:{}", targetId, message);
    97. } catch (Exception e) {
    98. log.error("【websocket消息】单点消息异常,targetId:{},消息:{},error:", targetId, message, e);
    99. }
    100. }
    101. }
    102. }

    4.html测试页面

    1. html>
    2. <html>
    3. <head>
    4. <meta charset="utf-8">
    5. <title>Websocket客户端title>
    6. head>
    7. <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js">script>
    8. <script>
    9. var socket;
    10. function openSocket() {
    11. const socketUrl = "ws://localhost:8081/websocket/" + $("#clientId").val();
    12. console.log(socketUrl);
    13. if (socket != null) {
    14. socket.close();
    15. socket = null;
    16. }
    17. socket = new WebSocket(socketUrl);
    18. // 开启WebSocket连接
    19. socket.onopen = function () {
    20. console.log("websocket已开启");
    21. };
    22. // 获得消息事件
    23. socket.onmessage = function (msg) {
    24. console.log(msg.data);
    25. };
    26. // 关闭事件
    27. socket.onclose = function () {
    28. console.log("websocket已关闭");
    29. };
    30. // 发生了错误事件
    31. socket.onerror = function () {
    32. console.log("websocket发生了错误");
    33. }
    34. }
    35. function sendMessage() {
    36. socket.send('{"targetId":"' + $("#targetId").val() + '","contentText":"' + $("#contentText").val() + '"}');
    37. console.log('{"targetId":"' + $("#targetId").val() + '","contentText":"' + $("#contentText").val() + '"}');
    38. }
    39. script>
    40. <body>
    41. <div>
    42. 客户端身份标识ID
    43. <input id="clientId" type="text" value="10">
    44. <button style="color: cornflowerblue"><a onclick="openSocket()">开启WebSocket连接a>button>
    45. div>
    46. <br><br>
    47. <div>
    48. 客户端向服务器发送的内容
    49. <input id="targetId" type="text" value="20">
    50. <input id="contentText" type="text" value="hello WebSocket">
    51. <button style="color: cornflowerblue"><a onclick="sendMessage()">发送消息a>button>
    52. div>
    53. body>
    54. html>

    5.模拟服务端发送消息

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.stereotype.Component;
    3. import javax.websocket.*;
    4. import javax.websocket.server.PathParam;
    5. import javax.websocket.server.ServerEndpoint;
    6. import java.util.concurrent.ConcurrentHashMap;
    7. import java.util.concurrent.CopyOnWriteArraySet;
    8. @Component
    9. @ServerEndpoint("/websocket/{clientId}")
    10. @Slf4j
    11. public class WebSocketServer {
    12. /**
    13. * 客户端的连接会话,需要通过它来给客户端发送数据
    14. */
    15. private Session session;
    16. /**
    17. * 客户端id
    18. */
    19. private String clientId;
    20. /**
    21. * 用来存放每个客户端对应的MyWebSocket对象
    22. */
    23. private static CopyOnWriteArraySet webSockets = new CopyOnWriteArraySet<>();
    24. /**
    25. * 用来存在线连接用户信息
    26. */
    27. private static ConcurrentHashMap sessionPool = new ConcurrentHashMap();
    28. /**
    29. * 链接成功调用的方法
    30. */
    31. @OnOpen
    32. public void onOpen(Session session, @PathParam(value = "clientId") String clientId) {
    33. try {
    34. this.session = session;
    35. this.clientId = clientId;
    36. webSockets.add(this);
    37. sessionPool.put(clientId, session);
    38. log.info("【websocket消息】有新的连接 clientId:{},总数为:{}", clientId, webSockets.size());
    39. } catch (Exception e) {
    40. log.info("【websocket消息】有新的连接构建失败 clientId:{},总数为:{},error:", clientId, webSockets.size(), e);
    41. }
    42. }
    43. /**
    44. * 链接关闭调用的方法
    45. */
    46. @OnClose
    47. public void onClose() {
    48. try {
    49. webSockets.remove(this);
    50. sessionPool.remove(this.clientId);
    51. log.info("【websocket消息】连接断开 clientId:{},总数为:{}", this.clientId, webSockets.size());
    52. } catch (Exception e) {
    53. log.info("【websocket消息】连接断开失败 clientId:{},总数为:{},error:", clientId, webSockets.size(), e);
    54. }
    55. }
    56. /**
    57. * 收到客户端消息后调用的方法
    58. */
    59. @OnMessage
    60. public void onMessage(String message) {
    61. log.info("【websocket消息】收到客户端消息:{}", message);
    62. }
    63. /**
    64. * 发送错误时的处理
    65. *
    66. * @param session
    67. * @param error
    68. */
    69. @OnError
    70. public void onError(Session session, Throwable error) {
    71. log.error("【websocket消息】发生错误,原因:", error);
    72. }
    73. /**
    74. * 此为广播消息
    75. */
    76. public void sendBroadcastMessage(String message) {
    77. log.info("【websocket消息】广播消息:{}", message);
    78. for (WebSocketServer webSocket : webSockets) {
    79. try {
    80. if (webSocket.session.isOpen()) {
    81. webSocket.session.getAsyncRemote().sendText(message);
    82. }
    83. } catch (Exception e) {
    84. log.error("【websocket消息】广播消息异常,消息:{},error:", message, e);
    85. }
    86. }
    87. }
    88. /**
    89. * 此为单点消息
    90. */
    91. public void sendSinglePointMessage(String targetId, String message) {
    92. Session session = sessionPool.get(targetId);
    93. if (session != null && session.isOpen()) {
    94. try {
    95. session.getAsyncRemote().sendText(message);
    96. log.info("【websocket消息】单点消息,targetId:{},消息:{}", targetId, message);
    97. } catch (Exception e) {
    98. log.error("【websocket消息】单点消息异常,targetId:{},消息:{},error:", targetId, message, e);
    99. }
    100. }
    101. }
    102. }

    发送广播消息:http://localhost:8081/api//websocket/sendBroadcastMessage?message=hello

    发送点对点消息:http://localhost:8081/api//websocket/sendSinglePointMessage?message=hello&targetId=10

  • 相关阅读:
    JAVA毕业设计河南口腔医疗机构线上服务系统计算机源码+lw文档+系统+调试部署+数据库
    机器人过程自动化(RPA)入门 4. 数据处理
    Android音视频开发:MediaCodec解码视频,得到YUV值,一帧一帧加载到SD卡中保存
    系统介绍浏览器缓存机制及前端优化方案
    (附源码)计算机毕业设计SSM教师教学质量评价系统
    VS2019 Qt源码编译
    力扣题解7.27
    【论文阅读】 Dimensionality reduction for large-scale neural recordings
    docker概念
    Vue里面怎么使用站点地图Sitemap做SEO
  • 原文地址:https://blog.csdn.net/qq_34253002/article/details/133807170