欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

SpringBoot2.0整合WebSocket,实现后端数据实时推送!

程序员文章站 2022-04-14 20:05:58
之前公司的某个系统为了实现推送技术,所用的技术都是Ajax轮询,这种方式浏览器需要不断的向服务器发出请求,显然这样会浪费很多的带宽等资源,所以研究了下WebSocket,本文将详细介绍下。 一、什么是WebSocket? WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的 ......

之前公司的某个系统为了实现推送技术,所用的技术都是ajax轮询,这种方式浏览器需要不断的向服务器发出请求,显然这样会浪费很多的带宽等资源,所以研究了下websocket,本文将详细介绍下。

一、什么是websocket?

websocket是html5开始提供的一种在单个tcp连接上进行全双工通讯的协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

websocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据,在websocket api中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

二、springboot整合websocket

新建一个spring boot项目spring-boot-websocket,按照下面步骤操作。

  1. pom.xml引入jar包
<dependency>
    <groupid>org.springframework.boot</groupid>
    <artifactid>spring-boot-starter-websocket</artifactid>
</dependency>
  1. 新建websocket的配置类

这个配置类检测带注解@serverendpoint的bean并注册它们,配置类代码如下:

@configuration
public class websocketconfig {
    /**
     * 给spring容器注入这个serverendpointexporter对象
     * 相当于xml:
     * <beans>
     * <bean id="serverendpointexporter" class="org.springframework.web.socket.server.standard.serverendpointexporter"/>
     * </beans>
     * <p>
     * 检测所有带有@serverendpoint注解的bean并注册他们。
     *
     * @return
     */
    @bean
    public serverendpointexporter serverendpointexporter() {
        system.out.println("我被注入了");
        return new serverendpointexporter();
    }
}
  1. 新建websocket的处理类

这个处理类需要使用@serverendpoint,这个类里监听连接的建立关闭、消息的接收等,具体代码如下:

@serverendpoint(value = "/ws/asset")
@component
public class websocketserver {

    @postconstruct
    public void init() {
        system.out.println("websocket 加载");
    }
    private static logger log = loggerfactory.getlogger(websocketserver.class);
    private static final atomicinteger onlinecount = new atomicinteger(0);
    // concurrent包的线程安全set,用来存放每个客户端对应的session对象。
    private static copyonwritearrayset<session> sessionset = new copyonwritearrayset<session>();


    /**
     * 连接建立成功调用的方法
     */
    @onopen
    public void onopen(session session) {
        sessionset.add(session);
        int cnt = onlinecount.incrementandget(); // 在线数加1
        log.info("有连接加入,当前连接数为:{}", cnt);
        sendmessage(session, "连接成功");
    }

    /**
     * 连接关闭调用的方法
     */
    @onclose
    public void onclose(session session) {
        sessionset.remove(session);
        int cnt = onlinecount.decrementandget();
        log.info("有连接关闭,当前连接数为:{}", cnt);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     *            客户端发送过来的消息
     */
    @onmessage
    public void onmessage(string message, session session) {
        log.info("来自客户端的消息:{}",message);
        sendmessage(session, "收到消息,消息内容:"+message);

    }

    /**
     * 出现错误
     * @param session
     * @param error
     */
    @onerror
    public void onerror(session session, throwable error) {
        log.error("发生错误:{},session id: {}",error.getmessage(),session.getid());
        error.printstacktrace();
    }

    /**
     * 发送消息,实践表明,每次浏览器刷新,session会发生变化。
     * @param session
     * @param message
     */
    public static void sendmessage(session session, string message) {
        try {
//            session.getbasicremote().sendtext(string.format("%s (from server,session id=%s)",message,session.getid()));
            session.getbasicremote().sendtext(message);
        } catch (ioexception e) {
            log.error("发送消息出错:{}", e.getmessage());
            e.printstacktrace();
        }
    }

    /**
     * 群发消息
     * @param message
     * @throws ioexception
     */
    public static void broadcastinfo(string message) throws ioexception {
        for (session session : sessionset) {
            if(session.isopen()){
                sendmessage(session, message);
            }
        }
    }

    /**
     * 指定session发送消息
     * @param sessionid
     * @param message
     * @throws ioexception
     */
    public static void sendmessage(string message,string sessionid) throws ioexception {
        session session = null;
        for (session s : sessionset) {
            if(s.getid().equals(sessionid)){
                session = s;
                break;
            }
        }
        if(session!=null){
            sendmessage(session, message);
        }
        else{
            log.warn("没有找到你指定id的会话:{}",sessionid);
        }
    }
}
  1. 新建一个html

目前大部分浏览器支持websocket,比如chrome, mozilla,opera和safari,在html页面进行websocket的连接建立、收消息的监听,页面代码如下:

<html>
<head>
    <meta charset="utf-8">
    <title>websocket测试</title>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <style type="text/css">
        h3,h4{
            text-align:center;
        }
    </style>
</head>
<body>

<h3>websocket测试,客户端接收到的消息如下:</h3>

<textarea id = "messageid" readonly="readonly" cols="150" rows="30" >

</textarea>


<script type="text/javascript">
    var socket;
    if (typeof (websocket) == "undefined") {
        console.log("遗憾:您的浏览器不支持websocket");
    } else {
        console.log("恭喜:您的浏览器支持websocket");
        //实现化websocket对象
        //指定要连接的服务器地址与端口建立连接
        //注意ws、wss使用不同的端口。我使用自签名的证书测试,
        //无法使用wss,浏览器打开websocket时报错
        //ws对应http、wss对应https。
        socket = new websocket("ws://localhost:8080/ws/asset");
        //连接打开事件
        socket.onopen = function() {
            console.log("socket 已打开");
            socket.send("消息发送测试(from client)");
        };
        //收到消息事件
        socket.onmessage = function(msg) {
            $("#messageid").append(msg.data+ "\n");
            console.log(msg.data  );
        };
        //连接关闭事件
        socket.onclose = function() {
            console.log("socket已关闭");
        };
        //发生了错误事件
        socket.onerror = function() {
            alert("socket发生了错误");
        }
        //窗口关闭时,关闭连接
        window.unload=function() {
            socket.close();
        };
    }
</script>

</body>
</html>

三、查看运行效果

启动springboot项目

  1. 打开首页

本地浏览器打开首页http://localhost:8080/,出现websocket测试页面,同时后台打印连接的日志。

有连接加入,当前连接数为:1,sessionid=0
  1. 往客户端发送消息

通过上面日志可以看到客户端连接连接的sessionid,我测试时候sessionid是0,然后浏览器访问下面接口即可往客户端发送消息。

//参数说明: id:sessionid 
//参数说明: message:消息内容
http://localhost:8080/api/ws/sendone?id=0&message=你好java碎碎念

SpringBoot2.0整合WebSocket,实现后端数据实时推送!

到此springboot整合websocket的功能已经全部实现,有问题欢迎留言沟通哦!

完整源码地址:

推荐阅读

1.一分钟带你了解下mybatis的动态sql!

2.一分钟带你了解下spring security!

3.一分钟带你学会利用mybatis-generator自动生成代码!

4.手把手带你实战下spring的七种事务传播行为

5.springboot系列-整合mybatis(注解方式)


如果觉得文章不错,希望可以随手转发或者”在看“哦,非常感谢哈!

关注下方公众号后回复「1024」,有惊喜哦!

SpringBoot2.0整合WebSocket,实现后端数据实时推送!

本文由博客一文多发平台 openwrite 发布!