当前位置: 移动技术网 > IT编程>开发语言>Java > SpringBoot2.0整合WebSocket,实现后端数据实时推送!

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

2019年11月26日  | 移动技术网IT编程  | 我要评论

之前公司的某个系统为了实现推送技术,所用的技术都是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://www.lhsxpumps.com/_localhost:8080/,出现websocket测试页面,同时后台打印连接的日志。

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

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

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

发送消息动图

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

完整源码地址:

推荐阅读

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

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

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

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

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


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

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

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网