springboot+websocket遇见的问题

先说需求

需求很简单,springboot+websocket定时推送前端页面。
因为我之前没有用过websocket,所以在网上找了很多案例,网上给的案例大多都是统计在线人数或者对话框那种,外边的框架差不多,所以我找了一个,这个文章我不贴地址了,直接给的大概是先写一个websocket类,onOpen里面记录数据,然后在写一个controller,用定时器调用onmessage发送数据。

踩坑过程

这个过程代码不难,因为我用的springboot,所以我照猫画虎写了一个@Scheduled,给了一个cron表达式,找了一个网站测试http://www.jsons.cn/websocket/
然后我发现,第一次推送数据的时候好着呢,但是比如我多开页面调接口或者刷新,我刷新几次后台就会给我推几次

原因

后来我发现每一次调用用这个controller的时候都会创造一个定时器,然后一直在定时,所以就会导致这样的情况,你调一次创建一个,这会我脑子里面第一个解决方案就是在onclose销毁的时候把这个定时器干掉
百度了一下,@Scheduled除了该配置文件开关,剩下好像并不是很好干掉,实例化所有bean暴力干掉有点太危险,我想可能是我的代码不对了

最新的解决方案

网上关于websocket的解决方案很多,但是大多都是一个模子,你抄我的我抄你的,后来我就一直在研究这个定时,我想这应该从这里下手,然后我发现每一次刷新都会创建新连接,那我就在这个onopen里面下手,一直到我发现了一个东西,
https://blog.csdn.net/dtlscsl/article/details/94185614
时间轮,具体你们可以看看,然后就开始了我的改造
我直接贴代码,很简单

 package com.sbr.pam.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sbr.pam.mvc.resacc.service.PamResAccService;
import com.sbr.pam.tool.SpringUtils;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.server.ServerEndpointConfig;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @Author:fengqifan
 * @DATE: 2022-08-09 16:22
 * @Use:
 */

@ServerEndpoint(value = "/webSocket", configurator = LargeScreenWebSocket.class)
//主要是将目前的类定义成一个websocket服务器端, 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
@Component
@EnableScheduling
/*@Component
@EnableScheduling// cron定时任务*/
@Data
public class LargeScreenWebSocket extends ServerEndpointConfig.Configurator {
    private static final Logger logger = LoggerFactory.getLogger(LargeScreenWebSocket.class);

    private static int onlineCount = 0;
    private static Map<String, LargeScreenWebSocket> clients = new ConcurrentHashMap<String, LargeScreenWebSocket>();
    private Session session;
    private String sessionId;

    @OnOpen
    public void onOpen(Session session) throws IOException {

        this.sessionId = session.getId();
        this.session = session;
        HashedWheelTimer hashedWheelTimer = SpringUtils.getBean(HashedWheelTimer.class);
        addOnlineCount();
        clients.put(sessionId, this);
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run(Timeout timeout) throws Exception {
                Map<String, Object> resMap = SpringUtils.getBean(PamResAccService.class).getAllInfo();
                System.out.println(resMap);
                if(clients.containsKey(LargeScreenWebSocket.this.sessionId)){
                    onMessage(JSON.toJSONString(resMap));
                    hashedWheelTimer.newTimeout(this, 1, TimeUnit.MINUTES);
                }
            }
        };
        hashedWheelTimer.newTimeout(timerTask, 0, TimeUnit.SECONDS);

    }

    @OnClose
    public void onClose() throws IOException {
        this.sessionId = session.getId();
        clients.remove(sessionId);
        subOnlineCount();
    }

    @OnMessage
    public void onMessage(String message) throws IOException {
        this.session.getAsyncRemote().sendText(message);
    }


    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    public void sendMessageTo(String message, String To) throws IOException {
        /*  ----- 后续如果需要单独对某一个session推送可以修改这个方法调用发送
        this.session.getAsyncRemote().sendText(message);
        // session.getBasicRemote().sendText(message);
        //session.getAsyncRemote().sendText(message);
        for (LargeScreenWebSocket item : clients.values()) {
            if (item.sessionId.equals(To)) {
                item.session.getAsyncRemote().sendText(message);
            }
        }*/
    }

    public void sendMessageAll(String message) throws IOException {
        for (LargeScreenWebSocket item : clients.values()) {
            item.session.getAsyncRemote().sendText(message);
        }
    }


    public static synchronized void addOnlineCount() {
        LargeScreenWebSocket.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        LargeScreenWebSocket.onlineCount--;
    }

    public static synchronized Map<String, LargeScreenWebSocket> getClients() {
        return clients;
    }
}





创建新链接,初始化我直接给0s,onmessone数据,然后改成我需要的时间间隔,最后删掉那个controller,好了,记录一下这个

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冯囧囧

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值