• Springboot集成websocket实现消息推送和在线用户统计


    一.HTTP


    说到websocket首先要说Http,Http大家都知道是一个网络通信协议,每当客户端浏览器需要访问后台时都会发一个请求,服务器给出响应后该连接就会关闭,请求只能有客户端发起,服务端是没办法主动发起请求的,对于消息推送的需求Http也可以满足要求,就是前端采用定时任务的方式去请求接口,这种轮询的方式是非常损耗服务器性能的,要尽量避免。基于此产生了全双工的网络协议-websocket。

    二.WebSocket


    所谓全双工指的是通信可以由任意一方发起,可以在两个方向上传输信息,采用websocket可以很好的实现消息推送的功能,从而避免了轮询的方式导致资源浪费的问题。

    三.实现方式


    这里采用springboot集成websocket,在springboot中使用websocket非常的方便。
    首先导入websocket依赖

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

    在启动类上添加一个bean

    @SpringBootApplication
    public class CommonCodeApplication {
    
        @Bean
        public ServerEndpointExporter serverEndpointExporter(){
            return new ServerEndpointExporter();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(CommonCodeApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    核心代码

    @Component
    @ServerEndpoint("/websocket2/{username}")
    @Slf4j
    public class WebSocketDemo2 {
    
        private static Map<String, WebSocketDemo2> webSocketMap = new HashMap<>();
    
        private static Integer onlineUserCount = 0;
    
        private Session session;
    
        private String username;
    
        /**
         * 建立连接
         * @param username
         * @param session
         */
        @OnOpen
        public void onOpen(@PathParam("username") String username, Session session){
            this.username = username;
            this.session = session;
            webSocketMap.put(username, this);
            int count = addOnlineUser();
            log.info("当前在线用户:{}", count);
        }
    
        /**
         * 关闭连接
         * @param username
         */
        @OnClose
        public void onClose(@PathParam("username") String username){
            webSocketMap.remove(username);
            int count = reduceOnlineUser();
            log.info("当前在线用户:{}", count);
        }
    
        @OnMessage
        public void onMessage(String message) throws IOException {
            JSONObject jsonObject = JSONUtil.parseObj(message);
            String target = jsonObject.getStr("target");
            String msg = jsonObject.getStr("msg");
            if (target.equals("all")){
                sendMessageAll(msg);
            }
        }
    
        /**
         * 给特定的人发消息,用于业务中调用
         * @param usernames
         * @param message
         * @throws IOException
         */
        public void sendMessageSpecial(List<String> usernames, String message) throws IOException {
            for (String username : webSocketMap.keySet()) {
                for (String target : usernames) {
                    if (username.equals(target)){
                        webSocketMap.get(username).session.getBasicRemote().sendText(message);
                    }
                }
            }
        }
    
        /**
         * 给所有人发消息
         * @param message
         * @throws IOException
         */
        public void sendMessageAll(String message) throws IOException {
            for (WebSocketDemo2 item : webSocketMap.values()) {
                System.out.println("消息发送");
                item.session.getBasicRemote().sendText(message);
            }
        }
    
    
    
        public void sendMessage(String message) throws IOException {
            session.getBasicRemote().sendText(message);
        }
    
        /**
         * 用户离线
         * @return
         */
        public int reduceOnlineUser(){
           return  -- onlineUserCount;
        }
    
        /**
         * 累加在线用户
         * @return
         */
        public int addOnlineUser(){
            return ++ onlineUserCount;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99

    实现消息推送只要在业务代码中调用sendMessageSpecial()方法即可。

    @RestController
    @RequestMapping("/websocket")
    public class WebSocketController {
    
        @Autowired
        private WebSocketDemo2 webSocketDemo2;
    
        @GetMapping("/t1")
        public String test1() throws IOException {
    
            System.out.println("这是业务代码...");
            
            String message = "消息被督办了!";
            List<String> usernames = new ArrayList<>();
            usernames.add("张三");
            usernames.add("李四");
            usernames.add("王五");
            webSocketDemo2.sendMessageSpecial(usernames, message);
            
            return "ok";
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    四.测试


    这里不用写前端去测试,大家可以使用这个网站进行测试
    websocket测试
    这里开了三个窗口进行测试,三个人的姓名分别是:张三、李四、王五
    在这里插入图片描述

    然后调用刚才的业务接口测试:http://localhost:8080/websocket/t1
    调用成功后可以看到三个窗口中都收到了消息
    在这里插入图片描述

  • 相关阅读:
    【java】【重构二】分模块开发版本锁定以及耦合(打包)实战
    Linux设置禁止SSH空密码登录
    关于浏览器Devtools的open,close监听
    自定义终结符:EOF
    布隆过滤器--你可以永远相信布隆
    【DevOps】Git 图文详解(二):Git 安装及配置
    ECCV 2022 | 视频插帧中的实时中间流估计
    Mybaits-Executor
    redis 集群搭建的三种方式
    彻底搞懂原生事件流和 React 事件流
  • 原文地址:https://blog.csdn.net/weixin_43266529/article/details/127734306