Spring定时任务+webSocket实现定时给指定用户发送消息

这篇具有很好参考价值的文章主要介绍了Spring定时任务+webSocket实现定时给指定用户发送消息。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

生命无罪,健康万岁,我是laity。

我曾七次鄙视自己的灵魂:

第一次,当它本可进取时,却故作谦卑;

第二次,当它在空虚时,用爱欲来填充;

第三次,在困难和容易之间,它选择了容易;

第四次,它犯了错,却借由别人也会犯错来宽慰自己;

第五次,它自由软弱,却把它认为是生命的坚韧;

第六次,当它鄙夷一张丑恶的嘴脸时,却不知那正是自己面具中的一副;

第七次,它侧身于生活的污泥中,虽不甘心,却又畏首畏尾。

Spring定时任务 + webSocket实现定时给指定用户发送消息:类似于消息中心;
相信有需求的小伙伴读此文章可以有一定的帮助或者思路

逻辑思路

在做这个业务的时候也遇到了很多的坑,但是现在我帮你踩完了。

  • 使用Spring定时任务框架(@Scheduled)和websocket网络通信协议框架来进行定时向指定用户的客户端推送消息;
  • 编写并设置webSocketConfig配置文件(百度上的常规配置即可);
  • 基于@ServerEndpoint(value = “/websocket/{userId}”)注解标记路径并让前端进行连接服务器端
  • SocketServer中都是使用ConcurrentHashMap集合来进行接收和存储
    • 它是Java 5中引入了ConcurrentHashMap这个并发集合类
    • ConcurrentHashMap通过将一个大的数据结构分解为多个小的数据结构,然后对每个小的数据结构加锁来实现线程安全。这种方式称为分段锁。分段锁我记得是有问题的:性能不好(什么原因导致的有时间去查:查询热点数据),在JDK8时弃用后采用CAS和synchronized组合的方式来保证并发安全。
    • Java 8中的ConcurrentHashMap在内部实现上采用了数组+链表+红黑树的数据结构,也使得其具有较好的查找和遍历性能
    • 有兴趣的小伙伴可以去阅读下:一文看懂 jdk8 中的 ConcurrentHashMap,个人感觉写的很不错。
  • 集合clients用于记录连接的客户端(session)、key为生成的uuid;集合conn用于存放clients数据,key为用户唯一标识(id)。同时也充分使用了websocket的生命周期进行资源释放等操作。
  • 自定义方法sendMessageByUserId(Integer userId, String message),基于userId获取conn中的set集合,基于iterator进行集合迭代,使用hasNext()返回的Boolean进行判断是否继续进行循环遍历,.next()获取其中uuid数据(指针移动),通过uuid取出存在clients集合中的session进行发送数据
  • ===========================================以上是WebSocket实现思路
  • 基于@EnableScheduling注解开启定时任务,基于@Scheduled(cron = “……”)注解和cron表达式进行任务执行。
  • 业务逻辑:因不同的人业务不同,所以这里我省略掉了我的业务逻辑,有需求的小伙伴可以私信我进一步沟通;
  • 调用websocket的sendMessageUserById()方法来进行返回数据;

代码实现

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.7.0</version>
</dependency>

webSocketServer.java

/**
 * @Project: JavaLaity
 * @Description: 服务端
 */
@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{userId}")
public class WebSocketServer {

    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象,若要实现服务器端与单一客户端通信的话,可以使用Map来存放,其中key可以为用户标识
     */
    private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

    // public static ThreadLocal<SysUser> clientUser = new ThreadLocal<>();
    /**
     * 用于记录连接的客户端 (sid,session)
     */
    public static Map<String, Session> clients = new ConcurrentHashMap<>();
    /**
     * 基于userId关联sid(用于解决同一用户id,在多个web端连接的问题)
     */
    public static Map<Integer, Set<String>> conn = new ConcurrentHashMap<>();

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    private String sid = null;


    // 当WebSocket连接建立时,会调用标注有@OnOpen的方法
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") Integer userId) {
        System.out.println("WebSocket opened: " + session.getId());
        this.session = session;
        this.sid = UUID.randomUUID().toString();
        clients.put(this.sid, session);

        Set<String> clientSet = conn.get(userId);
        if (clientSet == null) {
            clientSet = new HashSet<>();
            conn.put(userId, clientSet);
        }
        clientSet.add(this.sid);
        // 加入set中
        webSocketSet.add(this);
    }

    // 给所有当前连接的用户发送消息
    public void sendMessageAll(String message) {
        try {
            if (webSocketSet.size() != 0) {
                for (WebSocketServer item : webSocketSet) {
                    if (item != null) {
                        // 同步锁,解决多线程下发送消息异常关闭
                        // 避免高并发下多处频繁调用sendMessage()方法发送消息而导致的webSocket挂掉,我们在sendMessage这个方法里面加入同步锁,
                        // 锁住session,这样就能保障webSocket有条不絮的向前端推送消息
                        synchronized (item.session) {
                            item.session.getBasicRemote().sendText(message);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据用户ID发送给某一个用户
     */
    public void sendMessageByUserId(Integer userId, String message) {
        if (userId != null) {
            Set<String> clientSet = conn.get(userId);
            if (clientSet != null) {
                Iterator<String> iterator = clientSet.iterator();
                while (iterator.hasNext()) {
                    String sid = iterator.next();
                    Session session = clients.get(sid);
                    if (session != null) {
                        try {
                            session.getBasicRemote().sendText(message);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    // TODO 当浏览器关闭触发该事件
    @OnClose
    public void OnClose(Session session) {
        log.info(this.sid + "断开连接");
        clients.remove(this.sid);
        webSocketSet.remove(this);
    }

    // 当收到客户端(前端)发送的消息时,会调用@OnMessage方法
    @OnMessage
    public void OnMessage(String message, Session session) {
        System.out.println("Received message:" + message);
    }

    // TODO 发生错误时调用
    @OnError
    public void OnError(Session session, Throwable error) {
        System.out.println("发生错误!");
        error.printStackTrace();
    }
}

AideScheduleTask.java

/**
 * @Project: JavaLaity
 * @Description: 实现业务逻辑的位置
 */
@Configuration
public class AideScheduleTask {

    @Autowired
    WebSocketServer webSocketServer;

    @Autowired
    RedisCache redisCache;

    // 测试
    @Scheduled(cron = "0/20 * * * * ?")
    private void testTask() throws Exception {
        // 使用ThreadLocal - 哈哈哈,弃用了,行不通!。
        // TODO: 你需要的业务逻辑
        SysUser sysUser = new SysUser().setId(1)
        if (sysUser.getId() != null) {
            webSocketServer.sendMessageByUserId(sysUser.getId(), "这个是老大可以发:role = ");
        }
    }
}

注意问题

  • 在写Corn表达式时需要注意的点:

    • 外国对于周几的定义和中国是不一样的,中国1-7对应周一到周日,外国的1-7对应的是周日到周六
    • 国内:1-7 MON,TUE,WED,THU,FRI,SAT,SUN
    • 国外:1-7 SUN,MON,TUE,WED,THU,FRI,SAT √
  • 个人认为有性能问题以及数据库压力的大问题,这里本人就只是简单的分享下设计思路,不同业务需求,实现策略不同。也有肯定公司不在乎这种性能问题。

愿每个人都能遵循自己的时钟,做不后悔的选择。我是Laity,正在前行的Laity。文章来源地址https://www.toymoban.com/news/detail-733488.html

到了这里,关于Spring定时任务+webSocket实现定时给指定用户发送消息的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot实现WebSocket发送接收消息 + Vue实现SocketJs接收发送消息

    1、https://www.mchweb.net/index.php/dev/887.html 2、https://itonline.blog.csdn.net/article/details/81221103?spm=1001.2101.3001.6661.1utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-81221103-blog-121078449.pc_relevant_aadepth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-81221103-blog-12107

    2024年02月05日
    浏览(46)
  • Java 实现使用 Websocket 发送消息

    需求背景:之前做了个楼栋房间数量出租了多少,需要在数据大屏上实时展示 解决方案:以切面拦截出租接口,当有房间出租时重新查询相关数据,封装好用websocket实时传送前端展示 提示:以下是本篇文章正文内容,下面案例可供参考 WebSocket 是一种在单个TCP连接上进行全双

    2024年03月27日
    浏览(42)
  • Python如何实现定时发送qq消息

    因为生活中老是忘记各种事情,刚好又在学python,便突发奇想通过python实现提醒任务的功能(尽管TIM有定时功能),也可定时给好友、群、讨论组发送qq消息。其工作流程是:访问数据库提取最近计划——根据数据内容(提醒时间、提醒对象、提醒内容)设置定时任务——给

    2024年02月19日
    浏览(38)
  • qt websocket 通讯实现消息发送接收

    websocket 是基于 TCP socket 之上的应用层, 解决 HTML 轮询连接的问题,实现客户端与服务端长连接, 实现消息互相发送,全双工。 服务端, 使用 QT 教程demo chatserver.h chatserver.cpp main.cpp 客户端 clientwidget.h clientwidget.cpp websocketclient.h websocketclient.cpp

    2024年02月15日
    浏览(45)
  • 如何实现企微群机器人定时发送消息提醒?

    一、首先添加群机器人 二、创建完成的机器人是这样的,会有一个唯一标识:Webhook地址 三、设置 机器人发消息文本 以下是用curl工具往群组推送文本消息的示例(注意要将url替换成你的机器人webhook地址,content必须是utf8编码): 具体可以详见 机器人配置说明 机器人搞定了

    2024年02月09日
    浏览(50)
  • 支付超时取消订单实现方案 - 定时任务、延迟队列、消息队列等

    在实际业务场景中,我们经常会碰到类似一下场景: 淘宝等购物平台在订单支付时,如果30分钟内未支付自动取消。 腾讯会议预约会议后,在会议开始前15分钟提醒。 未使用的优惠券有效期结束后,自动将优惠券状态更新为已过期。 等等。。。 像这种支付超时取消的场景需

    2024年04月22日
    浏览(42)
  • 如何在前端实现WebSocket发送和接收TCP消息(多线程模式)

    当在前端实现WebSocket发送和接收TCP消息时,可以使用以下步骤来实现多线程模式。本文将详细介绍如何在前端实现WebSocket发送和接收TCP消息,并解释使用到的相关函数及原理。 在前端实现WebSocket发送和接收TCP消息的第一步是创建一个WebSocket连接。我们可以使用浏览器提供的

    2024年02月12日
    浏览(41)
  • 如何在前端实现WebSocket发送和接收UDP消息(多线程模式)

    本文将继续介绍如何在前端应用中利用WebSocket技术发送和接收UDP消息,并引入多线程模式来提高发送效率和性能。我们将使用JavaScript语言来编写代码,并结合WebSocket API、UDP数据包、Web Workers和UDP消息监听器来实现这一功能。 首先,我们需要在前端应用中建立一个WebSocket连接

    2024年02月12日
    浏览(43)
  • Python实现飞书机器人定时发送文本、图片等群消息

    工作中会经常遇到监控告警相关问题,监控和告警的目的是要在事中及时发现问题并定位系统问题,那么当系统或平台出现问题了,如何及时暴露这些问题给对应的项目开发人员呢? 本文记录了在Python项目中利用飞书的自定义机器人webhook向飞书群推送文本及图片消息~ 飞书群

    2024年01月25日
    浏览(50)
  • SSE与WebSocket分别实现服务器发送消息通知(Golang、Gin)

    服务端推送,也称为消息推送或通知推送,是一种允许应用服务器主动将信息发送到客户端的能力,为客户端提供了实时的信息更新和通知,增强了用户体验。 服务端推送的背景与需求主要基于以下几个诉求: 实时通知:在很多情况下,用户期望实时接收到应用的通知,如

    2024年02月03日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包