• springboot1.5.9整合websocket实现实时显示的小demo


    最近由于项目需要实时显示数据库更新的数据变化情况,一开始想过在前端使用ajax异步轮询方法实现,但后面考虑到性能和流量等要求,就放弃该方法而选择使用websocket(毕竟现在springboot整合websocket的技术算是比较成熟了,哈哈),现在此小小记录下。

    首先,在springboot项目创建并配置成功的基础上对websocket进行整合。

    1、在pom文件中添加对websocket的依赖

    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.stereotype.Component;
      2 
      3 import javax.websocket.*;
      4 import javax.websocket.server.ServerEndpoint;
      5 import java.io.IOException;
      6 import java.util.concurrent.CopyOnWriteArraySet;
      7 
      8 /**
      9 * @Name:WebSocket
     10 * @Description:WebSocket配置
     11 * @Version:V1.0.0
     12 * @Author:mYunYu
     13 * @Create Date:2018/11/15 14:45
     14 */
     15 @Component
     16 @ServerEndpoint(value = "/ws/webSocket" , encoders = {EncoderClassVo.class})
     17 public class WebSocket {
     18     //每个客户端都会有相应的session,服务端可以发送相关消息
     19     private Session session;
     20 
     21     //J.U.C包下线程安全的类,主要用来存放每个客户端对应的webSocket连接
     22     private static CopyOnWriteArraySet<WebSocket> copyOnWriteArraySet = new CopyOnWriteArraySet<WebSocket>();
     23 
     24    /**
     25    * @Name:onOpen
     26    * @Description:打开连接。进入页面后会自动发请求到此进行连接
     27    * @Author:mYunYu
     28    * @Create Date:14:46 2018/11/15
     29    * @Parameters:
     30    * @Return:
     31    */
     32     @OnOpen
     33     public void onOpen(Session session) {
     34         this.session = session;
     35         copyOnWriteArraySet.add(this);
     36         System.out.println("websocket有新的连接, 总数:"+ copyOnWriteArraySet.size());
     37 
     38     }
     39 
     40    /**
     41    * @Name:onClose
     42    * @Description:用户关闭页面,即关闭连接
     43    * @Author:mYunYu
     44    * @Create Date:14:46 2018/11/15
     45    * @Parameters:
     46    * @Return:
     47    */
     48     @OnClose
     49     public void onClose() {
     50         copyOnWriteArraySet.remove(this);
     51         System.out.println("websocket连接断开, 总数:"+ copyOnWriteArraySet.size());
     52     }
     53 
     54     /**
     55     * @Name:onMessage
     56     * @Description:测试客户端发送消息,测试是否联通
     57     * @Author:mYunYu
     58     * @Create Date:14:46 2018/11/15
     59     * @Parameters:
     60     * @Return:
     61     */
     62     @OnMessage
     63     public void onMessage(String message) {
     64         System.out.println("websocket收到客户端发来的消息:"+message);
     65     }
     66 
     67     /**
     68     * @Name:onError
     69     * @Description:出现错误
     70     * @Author:mYunYu
     71     * @Create Date:14:46 2018/11/15
     72     * @Parameters:
     73     * @Return:
     74     */
     75     @OnError
     76     public void onError(Session session, Throwable error) {
     77         System.out.println("发生错误:" + error.getMessage() + "; sessionId:" + session.getId());
     78         error.printStackTrace();
     79     }
     80 
     81     public void sendMessage(Object object){
     82         //遍历客户端
     83         for (WebSocket webSocket : copyOnWriteArraySet) {
     84             System.out.println("websocket广播消息:" + object.toString());
     85             try {
     86                 //服务器主动推送
     87                 webSocket.session.getBasicRemote().sendObject(object) ;
     88             } catch (Exception e) {
     89                 e.printStackTrace();
     90             }
     91         }
     92     }
     93 
     94     /**
     95     * @Name:sendMessage
     96     * @Description:用于发送给客户端消息(群发)
     97     * @Author:mYunYu
     98     * @Create Date:14:46 2018/11/15
     99     * @Parameters:
    100     * @Return:
    101     */
    102     public void sendMessage(String message) {
    103         //遍历客户端
    104         for (WebSocket webSocket : copyOnWriteArraySet) {
    105             System.out.println("websocket广播消息:" + message);
    106             try {
    107                 //服务器主动推送
    108                 webSocket.session.getBasicRemote().sendText(message);
    109             } catch (Exception e) {
    110                 e.printStackTrace();
    111             }
    112         }
    113     }
    114 
    115     /**
    116     * @Name:sendMessage
    117     * @Description:用于发送给指定客户端消息
    118     * @Author:mYunYu
    119     * @Create Date:14:47 2018/11/15
    120     * @Parameters:
    121     * @Return:
    122     */
    123     public void sendMessage(String sessionId, String message) throws IOException {
    124         Session session = null;
    125         WebSocket tempWebSocket = null;
    126         for (WebSocket webSocket : copyOnWriteArraySet) {
    127             if (webSocket.session.getId().equals(sessionId)) {
    128                 tempWebSocket = webSocket;
    129                 session = webSocket.session;
    130                 break;
    131             }
    132         }
    133         if (session != null) {
    134             tempWebSocket.session.getBasicRemote().sendText(message);
    135         } else {
    136             System.out.println("没有找到你指定ID的会话:{}"+ "; sessionId:" + sessionId);
    137         }
    138     }
    139 
    140     /**
    141      * 如果使用springboot内置tomcat,需要配置,否则不需要
    142      *
    143      * @return
    144      */
    145 //    @Bean
    146 //    public ServerEndpointExporter serverEndpointExporter() {
    147 //        return new ServerEndpointExporter();
    148 //    }
    149 
    150 
    151 }

    上面类中的红色注释的代码是只有当springboot项目使用内置tomcat时需要配置(即打成jar包),如果使用外置tomcat则不需要配置(即打成war包)

    3、配置编码器,主要是需要后端向前端发送对象数据,如果只是发送普通的字符串数据的话,就不需要

     1 import com.alibaba.fastjson.JSON;
     2 import com.xxx.utils.MsgUtil;
     3 
     4 import javax.websocket.EncodeException;
     5 import javax.websocket.Encoder;
     6 import javax.websocket.EndpointConfig;
     7 
     8 /**
     9 * @Name:EncoderClassVo
    10 * @Description:编码器,防止发送对象出错
    11 * @Version:V1.0.0
    12 * @Author:mYunYu
    13 * @Create Date:2018/11/15 14:43
    14 */
    15 public class EncoderClassVo implements Encoder.Text<MsgUtil> {
    16 
    17     @Override
    18     public void init(EndpointConfig endpointConfig) {
    19 
    20     }
    21 
    22     @Override
    23     public void destroy() {
    24 
    25     }
    26 
    27     @Override
    28     public String encode(MsgUtil msgUtil) throws EncodeException {
    29         try{
    30             return JSON.toJSONString(msgUtil) ;
    31         }catch (Exception e){
    32             e.printStackTrace() ;
    33             return null;
    34         }
    35     }
    36 }

    4、接下来就是写controller层了,我这边demo只是简单的发送一些随机的数据,具体信息还需要根据各个项目需要来写

     1 import com.xxx.pojo.User;
     2 import com.xxx.utils.MsgUtil;
     3 import com.xxx.webSocket.WebSocket;
     4 import org.springframework.web.bind.annotation.RequestMapping;
     5 import org.springframework.web.bind.annotation.RestController;
     6 
     7 import javax.annotation.Resource;
     8 import java.io.IOException;
     9 
    10 /**
    11 * @Name:SocketController
    12 * @Description:消息发送Controller
    13 * @Version:V1.0.0
    14 * @Author:mYunYu
    15 * @Create Date:2018/11/15 16:44
    16 */
    17 @RestController
    18 public class SocketController {
    19 
    20     @Resource
    21     WebSocket webSocket;
    22 
    23     /**
    24     * @Name:helloManyWebSocket
    25     * @Description:群发消息
    26     * @Author:mYunYu
    27     * @Create Date:16:44 2018/11/15
    28     * @Parameters:
    29     * @Return:
    30     */
    31     @RequestMapping("many")
    32     public String helloManyWebSocket(){
    33 
    34         int i = 1 ;
    35         while(i > 0){
    36             i=1+(int)(Math.random()*600) ;
    37             User user = new User() ;
    38             user.setUserid(i+1) ;
    39             user.setUsername(String.valueOf(i) + String.valueOf(i+i)) ;
    40 
    41             //将对象转为json对象,并发送到前端
    42             MsgUtil msgUtil = MsgUtil.success().addMsg("map", user);
    43             webSocket.sendMessage(msgUtil);
    44 
    45             try{
    46                 Thread.sleep(1000) ;
    47             }catch (Exception e){
    48                 e.printStackTrace() ;
    49             }
    50         }
    51 
    52         return "发送成功";
    53     }
    54 
    55     /**
    56     * @Name:helloOneWebSocket
    57     * @Description:根据session单个发送消息
    58     * @Author:mYunYu
    59     * @Create Date:16:44 2018/11/15
    60     * @Parameters:
    61     * @Return:
    62     */
    63     @RequestMapping("one")
    64     public String helloOneWebSocket(String sessionId) throws IOException {
    65         //向某个人发送消息
    66         webSocket.sendMessage(sessionId,"你好~!,单个用户");
    67 
    68         return "发送成功";
    69     }
    70 
    71 
    72 }

    5、接下来该在前端写配置了,我这里使用的是thymeleaf模板

     1 <!DOCTYPE html >
     2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
     3 <head>
     4     <meta charset="UTF-8"/>
     5     <title>Title</title>
     6 </head>
     7 <body>
     8 
     9 自动连接websocket
    10 <script type="text/javascript">
    11 
    12     var socket;
    13     if (typeof (WebSocket) == "undefined") {
    14         console.log("遗憾:您的浏览器不支持WebSocket");
    15     } else {
    16         console.log("恭喜:您的浏览器支持WebSocket");
    17 
    18         //实现化WebSocket对象
    19         //指定要连接的服务器地址与端口建立连接
    20         //注意ws、wss使用不同的端口。我使用自签名的证书测试,
    21         //无法使用wss,浏览器打开WebSocket时报错
    22         //ws对应http、wss对应https。
    23         socket = new WebSocket("ws://127.0.0.1:端口号/项目名/ws/webSocket");
    24         //连接打开事件
    25         socket.onopen = function() {
    26             console.log("Socket 已打开");
    27             socket.send("消息发送测试(From Client)");
    28         };
    29         //收到消息事件
    30         socket.onmessage = function(msg) {
    31             console.log(msg.data) ;
    32         };
    33         //连接关闭事件
    34         socket.onclose = function() {
    35             console.log("Socket已关闭");
    36         };
    37         //发生了错误事件
    38         socket.onerror = function() {
    39             alert("Socket发生了错误");
    40         }
    41 
    42         //窗口关闭时,关闭连接
    43         window.unload=function() {
    44             socket.close();
    45         };
    46 
    47     }
    48 
    49 </script>
    50 
    51 
    52 </body>
    53 </html>

    6、最后就是测试了,先右击项目,选择Run Mavan-->clear install进行项目打包

    打包成功之后再启动外置tomcat来启动项目

    启动项目成功,在浏览器中访问

    按f12,如果出现”Socket已打开“字样,则表示客户端连接ok,现在需要使用服务端向客户端发送消息

    再打开另一个浏览器,输入http://localhost:端口号/项目名/many进行访问,就可以观察到idea和浏览器中已经打印了发送的消息字样了

    上图是客户端访问的浏览器所显示的消息,下图是服务器端所打印的消息

    好了,实现的很成功,接下来就是对发送的数据进行替换就差不多了,哈哈~

  • 相关阅读:
    6、CC2541修改按键调节广播发送功率例程为持续发送4DB的蓝牙基站
    [nRF51822] 16、nRF51822的随机数生成器,及随机数生成器的一些知识(可以帮您补补随机数发生器的知识)
    [PCB设计] 4、BAT脚本处理AD生成的GERBER文件为生产文件
    [异常解决] 奇巧淫技——VirtualBox中的linux无显示启动,并在win7上远程控制
    [PCB设计] 3、用CAM350修改GERBER文件(删除某些部分)
    [异常解决] Make nRF51 DFU Project Appear "fatal error: uECC.h: No such file or directory"
    [异常解决] How to build a gcc toolchain for nRF51 on linux (very detailed!!!)
    [异常解决] windows用SSH和linux同步文件&linux开启SSH&ssh client 报 algorithm negotiation failed的解决方法之一
    [模拟电路] 2、Passive Band Pass Filter
    Docker常用命令
  • 原文地址:https://www.cnblogs.com/mYunYu/p/9964673.html
Copyright © 2020-2023  润新知