springBoot集成websocket实时消息推送

简介: 本文介绍了如何在Spring Boot项目中集成WebSocket实现实时消息推送。首先,通过引入`spring-boot-starter-websocket`依赖,配置`WebSocketConfig`类来启用WebSocket支持。接着,创建`WebSocketTest`服务器类,处理连接、消息收发及错误等事件,并使用`ConcurrentHashMap`管理用户连接。最后,前端通过JavaScript建立WebSocket连接,监听消息并进行相应处理。此方案适用于需要实时通信的应用场景,如聊天室、通知系统等。

springBoot集成websocket实时消息推送

WebSocket是一种在Web应用程序中实现双向通信的协议。它允许在客户端和服务器之间建立持久性的连接,并支持双向数据传输,实现了实时、低延迟的通信。

📍常见的消息推送方法

  1. WebSocket:通过使用WebSocket协议,可以在Java后端实现双向通信,从而实现消息的实时推送。你可以使用Java中的WebSocket API或者使用开源库如Tomcat的WebSocket支持、Spring WebSocket等来实现。
  2. Server-Sent Events (SSE):SSE是一种基于HTTP的轻量级服务器推送技术,它允许服务器向客户端单向推送消息。在Java后端,你可以使用Servlet或者基于框架的实现来支持SSE。
  3. 消息队列:通过使用消息队列如RabbitMQ、ActiveMQ或者Kafka等,Java后端可以将消息发布到消息队列中,然后客户端通过订阅消息队列来获取实时消息推送。
  4. 短轮询(Long Polling):即浏览器定时向服务器发送请求,以此来更新数据的方法。如下图所示,原理就是客户端不断地向服务端发请求,如果服务端数据有更新,服务端就把数据发送回来,客户端就能接收到新数据了
  5. 长轮询(Long Polling):虽然不同于实时推送,但长轮询是一种模拟实时推送的技术。在Java后端,你可以实现长轮询机制来达到类似实时推送的效果。 以上是一些常见的Java后端实现消息实时推送提醒的方法。每种方法都有其适用的场景和特点

📍引入依赖

xml

代码解读

复制代码

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

📍WebSocketConfig配置类

java

代码解读

复制代码

package com.yxsd.cnooc.data.wb;
 
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 
@Component
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}

📍WebSocketServer服务器类

java

代码解读

复制代码

package com.yxsd.cnooc.data.service;
 
import org.springframework.stereotype.Component;
 
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
 
/**
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,
 * 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@Component
@ServerEndpoint("/websocket/{userId}")
public class WebSocketTest {
 
    private static ConcurrentHashMap<String, CopyOnWriteArraySet<WebSocketTest>> userwebSocketMap = new ConcurrentHashMap<String, CopyOnWriteArraySet<WebSocketTest>>();
 
    private static ConcurrentHashMap<String, Integer> count = new ConcurrentHashMap<String, Integer>();
 
    private String userId;
 
 
    /*
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;
 
    /**
     * 连接建立成功调用的方法
     *
     * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") final String userId) {
        this.session = session;
        this.userId = userId;
        System.out.println("session:"+session);
        System.out.println("userId:"+userId);
        if (!exitUser(userId)) {
            initUserInfo(userId);
        } else {
            CopyOnWriteArraySet<WebSocketTest> webSocketTestSet = getUserSocketSet(userId);
            webSocketTestSet.add(this);
            userCountIncrease(userId);
        }
        System.out.println("有" + userId + "新连接加入!当前在线人数为" + getCurrUserCount(userId));
    }
 
 
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        CopyOnWriteArraySet<WebSocketTest> webSocketTestSet = userwebSocketMap.get(userId);
        //从set中删除
        webSocketTestSet.remove(this);
        //在线数减1
        userCountDecrement(userId);
        System.out.println("有一连接关闭!当前在线人数为" + getCurrUserCount(userId));
    }
 
    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     * @param session 可选的参数
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        CopyOnWriteArraySet<WebSocketTest> webSocketSet = userwebSocketMap.get(userId);
       /* System.out.println("来自客户端" + userId + "的消息:" + message);
        //群发消息
        for (WebSocketTest item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }*/
    }
 
 
    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }
 
 
 
    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。
     *
     * @param message
     * @throws IOException
     */
 
    public void sendMessage(String message) throws IOException {
        System.out.println("服务端推送" + userId + "的消息:" + message);
        this.session.getAsyncRemote().sendText(message);
    }
 
 
    /**
     * 这个方法与上面几个方法不一样。没有用注解,是根据自己需要添加的方法。   我是在有代办消息时 调用此接口 向指定用户发送消息 
     *
     * @param message
     * @throws IOException
     */
 
    public void sendMessage(String userId,String message) throws IOException {
        System.out.println("服务端推送" + userId + "的消息:" + message);
        CopyOnWriteArraySet<WebSocketTest> webSocketSet = userwebSocketMap.get(userId);
        //群发消息
        for (WebSocketTest item : webSocketSet) {
            try {
                item.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }
 
 
    public boolean exitUser(String userId) {
        return userwebSocketMap.containsKey(userId);
    }
 
    public CopyOnWriteArraySet<WebSocketTest> getUserSocketSet(String userId) {
        return userwebSocketMap.get(userId);
    }
 
    public void userCountIncrease(String userId) {
        if (count.containsKey(userId)) {
            count.put(userId, count.get(userId) + 1);
        }
    }
 
 
    public void userCountDecrement(String userId) {
        if (count.containsKey(userId)) {
            count.put(userId, count.get(userId) - 1);
        }
    }
 
    public void removeUserConunt(String userId) {
        count.remove(userId);
    }
 
    public Integer getCurrUserCount(String userId) {
        return count.get(userId);
    }
 
    private void initUserInfo(String userId) {
        CopyOnWriteArraySet<WebSocketTest> webSocketTestSet = new CopyOnWriteArraySet<WebSocketTest>();
        webSocketTestSet.add(this);
        userwebSocketMap.put(userId, webSocketTestSet);
        count.put(userId, 1);
    }
 
}

📍前端实现代码

  • 方法一:使用在线websocket客户端
    客户端页面使用 www.jsons.cn/websocket/ 与项目建立连接,充当web客户端
  • 方法二:自己编写客户端

html

代码解读

复制代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 
</body>
<script>
    let webSocket = null;   // 创建一个变量
    if ('WebSocket' in window){  // 判断当前的浏览器是否支持WebSocket
        // 如果支持则创建一个WebSocket赋值给刚才创建的变量
        // 后面的路径实际上就是一次请求,但是这里用的是WebSocket协议
        // 记住这个地方后面详细讲到怎么写
        webSocket = new WebSocket('ws://localhost:8080/webSocket');
    }else{  // 如果不兼容则弹框,该浏览器不支持
        alert('该浏览器不支持')
    }
 
    /** 
     * 当WebSocket创建连接(初始化)会触发该方法
     */
    webSocket.onopen = function (event){
        console.log('建立连接') // 这个代表在浏览器打印日志,跟Java的System.out.println()意思一致
    }
 
    /** 
     * 当WebSocket关闭时候会触发该方法
     */
    webSocket.onclose = function (event){
        console.log('关闭连接') // 同上
    }
    
     /** 
     * 当WebSocket接受消息会触发该方法
     */
    webSocket.onmessage = function (event){
        console.log('收到消息:'+event.data)
    }
 
    /** 
     * 当WebSocket连接出错触发该方法
     */
    webSocket.onerror = function (event){
        console.log('websocket发生错误');
    }
    
    /** 
     * 页面关闭,WebSocket关闭
     */
    window.onbeforeunload = function (){
        webSocket.close();
    }
</script>
</html>


转载来源:https://juejin.cn/post/7300876243952631859

目录
打赏
0
2
2
1
173
分享
相关文章
|
1月前
|
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
80 0
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
本文介绍在 Spring Boot 中集成 Redis 的方法。Redis 是一种支持多种数据结构的非关系型数据库(NoSQL),具备高并发、高性能和灵活扩展的特点,适用于缓存、实时数据分析等场景。其数据以键值对形式存储,支持字符串、哈希、列表、集合等类型。通过将 Redis 与 Mysql 集群结合使用,可实现数据同步,提升系统稳定性。例如,在网站架构中优先从 Redis 获取数据,故障时回退至 Mysql,确保服务不中断。
107 0
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
|
1月前
|
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的使用
本文详细介绍了Swagger2的使用方法,包括在Spring Boot项目中的配置与应用。重点讲解了Swagger2中常用的注解,如实体类上的`@ApiModel`和`@ApiModelProperty`,Controller类上的`@Api`、`@ApiOperation`以及参数上的`@ApiParam`等。通过示例代码展示了如何为实体类和接口添加注解,并在页面上生成在线接口文档,实现接口测试。最后总结了Swagger的优势及其在项目开发中的重要性,提供了课程源代码下载链接供学习参考。
72 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的使用
|
1月前
|
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
本文介绍了在Spring Boot中配置Swagger2的方法。通过创建一个配置类,添加`@Configuration`和`@EnableSwagger2`注解,使用Docket对象定义API文档的详细信息,包括标题、描述、版本和包路径等。配置完成后,访问`localhost:8080/swagger-ui.html`即可查看接口文档。文中还提示了可能因浏览器缓存导致的问题及解决方法。
78 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
85 0
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
63 0
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
64 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的 maven 依赖
在项目中使用Swagger2工具时,需导入Maven依赖。尽管官方最高版本为2.8.0,但其展示效果不够理想且稳定性欠佳。实际开发中常用2.2.2版本,因其稳定且界面友好。以下是围绕2.2.2版本的Maven依赖配置,包括`springfox-swagger2`和`springfox-swagger-ui`两个模块。
43 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档—— Swagger 简介
第6课介绍了在Spring Boot中集成Swagger2以展示在线接口文档的方法。随着前后端分离架构的发展,API文档成为连接前端与后端开发的重要纽带。然而,代码更新频繁导致文档难以同步维护,Swagger2解决了这一问题。通过Swagger,在线API文档不仅方便了接口调用方查看和测试,还支持开发者实时测试接口数据。本文使用Swagger 2.2.2版本,讲解如何在Spring Boot项目中导入并配置Swagger2工具,从而高效管理接口文档。
103 0
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装
本教程介绍ActiveMQ的安装与基本使用。首先从官网下载apache-activemq-5.15.3版本,解压后即可完成安装,非常便捷。启动时进入解压目录下的bin文件夹,根据系统选择win32或win64,运行activemq.bat启动服务。通过浏览器访问`http://127.0.0.1:8161/admin/`可进入管理界面,默认用户名密码为admin/admin。ActiveMQ支持两种消息模式:点对点(Queue)和发布/订阅(Topic)。前者确保每条消息仅被一个消费者消费,后者允许多个消费者同时接收相同消息。
67 0
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装

热门文章

最新文章