spring boot 2.x + spring websocket + thymeleaf + echarts 实现实时更新进度条

文章目录

      • 需求大致如下:
      • 代码部分如下:
        • 后端代码如下:
      • 前端代码如下:
      • 最终效果如下
    • 总结

过程比较曲折,在网上查了不少的案例,但是大多数实际用起来并不太符合所想的要求。

需求大致如下:

1.后端实时推送数据到前端,前端实时更新数据

要满足后端实时推送数据这个要求,就不能使用http方式,因为在http方式下需要浏览器向服务端主动发起请求,然后建立连接,服务端返回数据给浏览器。于是便准备使用websocket方式建立一个接口,浏览器和服务端建立连接后,通过请求这个接口便可以不断的活动服务器推送的数据。

websocket简介
WebSocket是双向通信协议,模拟Socket协议,可以双向发送或接受信息

理解STOMP
https://blog.csdn.net/javazhudong/article/details/120594063
面向消息的简单文本协议。websocket定义了两种传输信息类型: 文本信息和二进制信息。类型虽然被确定,但是他们的传输体是没有规定的。所以,需要用一种简单的文本传输类型来规定传输内容,它可以作为通讯中的文本传输协议,即交互中的高级协议来定义交互信息。 STOMP本身可以支持流类型的网络传输协议: websocket协议和tcp协议。 Stomp还提供了一个stomp.js,用于浏览器客户端使用STOMP消息协议传输的js库。

消息协议则是指用于实现消息队列功能时所涉及的协议,支持STOMP协议的消息队列有Apache ActiveMQ、RabbitMQ等很多

2.图表的展示考虑用echarts进行,开箱即用。

代码部分如下:

因为也是第一次用spring websocket,所以后端部分基本上是参照这篇文章https://www.jianshu.com/p/969da26d5bea进行的,前端展示部分可以看下echarts的官方文档https://echarts.apache.org/handbook/zh/basics/import

后端代码如下:

1.创建websocket配置类

ps:
AbstractWebSocketMessageBrokerConfigurer 类已经过时,目前的实现方式是 通过implements WebSocketMessageBrokerConfigurer来进行

注解说明:
@Configuration :将配置类添加的spring bean容器中,使配置生效
@EnableWebSocketMessageBroker:开启WebSocket对高级通信协议的支持,例如支持基于代理的STOMP协议

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

/**
 * ClassName WebSocketStompConfig
 * Author tutu
 * Date 2022-05-26 11:36:37
 * Version 1.0
 * Description TODO
 **/
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {

    // 设置socket连接
    @Override
    public void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
        stompEndpointRegistry
                // websocket的服务端地址,后面前端通过这个地址和服务端建立连接,http://localhost:8089/testSocket
                .addEndpoint("/testSocket")
                //.setAllowedOrigins("*")
                //解决跨域问题
                .setAllowedOriginPatterns("*")
                //开启sockJS模式支持
                .withSockJS();
                //.setAllowedOrigins("*")
                //解决跨域问题
                .setAllowedOriginPatterns("*")
                //开启sockJS模式支持
                .withSockJS();
    }

    // 设置发布订阅的主题
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic", "/top");
    }
}

2.Controller
关于ModelAndView注解的介绍
https://blog.csdn.net/qq_36306340/article/details/78542918

import com.delta.boot.pojo.ProgressEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * ClassName WebsocketController
 * Author tutu
 * Date 2022-05-26 11:37:34
 * Version 1.0
 * Description TODO
 **/
@Controller
public class WebsocketController {

    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;

    /**
     * 服务端向客户端发送消息
     */
    @RequestMapping("/send01")
    @ResponseBody
    public ModelAndView send2() throws InterruptedException {
        // 订阅主题,只有订阅了这个主题的连接才会接收消息
        String topic = "/topic/businessUserId/162";
        // 消息内容
        // 模拟实时向前端发送数据
        for (int i = 0; i < 101; i++) {
            Thread.sleep(1000);
            String message = String.valueOf(i);
            simpMessagingTemplate.convertAndSend(topic, message);
        }
        // 返回原页面
        return new ModelAndView("socket");;
    }

    /**
     * 客户端向客户端发送消息
     */
    @MessageMapping("/test")
    @SendTo("/topic/businessUserId/162")
    @ResponseBody
    public String call(String msg) {
        System.out.println(msg);
        return msg;
    }

    @RequestMapping("/socketPage")
    public String socketPage() {
        return "socket";
    }

}

前端代码如下:

socket.html

前端通过var socket = new SockJS(“http://localhost:8089/testSocket”);来创建websocket连接,用的js包为sockjs.min.js、stomp.js

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webSockettitle>
head>
<body>
<div>
    <h2>Socket 网络实时交互测试h2>
    <div>
        <button id="connect" onclick="connect();">建立连接button>
        <button id="disconnect" disabled="disabled" onclick="disconnect();">断开连接button>
    div>
    <div id="conversationDiv">
        <label>What is your name?label>
        <input type="text" id="name" />
        <button id="sendName" onclick="sendName();">Sendbutton>
        <p id="response">p>
    div>

    <form action="/send01" method="get">
        <input type="submit" value="查看进度">
    form>

    <div id="main" style="width: 400px;height:50px;">div>

div>

body>

<script src="http://cdn.bootcss.com/sockjs-client/1.1.1/sockjs.min.js">script>
<script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.js">script>
<script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js">script>
<script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js">script>
<script type="text/javascript">
    var stompClient = null;

    var processBar= $("#progressBar");

    var myChart = echarts.init(document.getElementById('main'));

    $(function(){
        connect();
    });

    function setConnected(connected) {
        $("#connect").attr("disabled", connected);
        $("#disconnect").attr("disabled", !connected);
        if (connected) {
            $("#conversationDiv").show();
        }else{
            $("#conversationDiv").hide();
        }
        $("#response").html("");
    }

    //this line.
    function connect() {
        var socket = new SockJS("http://localhost:8089/testSocket");
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
            setConnected(true);
            // console.log('Connected: ' + frame);
            // stompClient.subscribe('/top/test', function(frame){
            stompClient.subscribe('/topic/businessUserId/162', function(frame){
                //showGreeting(JSON.parse(greeting.body).content);
                console.info(frame);
                // showGreeting(frame.body);
                option = {
                    xAxis: {
                        // 隐藏x轴
                        show:false,
                        // data: []
                        min:0,
                        max:100
                    },
                    yAxis: {
                        //隐藏y轴
                        show:false,
                        // 均分
                        type: "category",
                    },
                    series: [
                        {
                            type: 'bar',
                            data: [frame.body],
                            color:"cyan",
                            barWidth:10
                        }
                    ],
                    label: {
                        show: true,
                        position: 'right'
                    }
                };

                // 使用刚指定的配置项和数据显示图表。
                myChart.setOption(option);
            });
        });
    }

    function sendName() {
        var name = $("#name").val();
        stompClient.send("/test", {}, name);
    }

    function disconnect() {
        if (stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log("Disconnected");
    }

    function showGreeting(message) {
        $("#response").append("" + message + "");
    }

    function returnMessage(message){
        var completePercent = Math.round(message / 100 * 100);
            // + '%';
        return completePercent
    }
script>
html>

最终效果如下

http://localhost:8089/socketPage
spring boot 2.x + spring websocket + thymeleaf + echarts 实现实时更新进度条_第1张图片
spring boot 2.x + spring websocket + thymeleaf + echarts 实现实时更新进度条_第2张图片
spring boot 2.x + spring websocket + thymeleaf + echarts 实现实时更新进度条_第3张图片
spring boot 2.x + spring websocket + thymeleaf + echarts 实现实时更新进度条_第4张图片

总结

算是走通了一个demo,后面要真正漂亮的用起来还需要调整不少地方。

前端要想灵活的用起来是真的不容易

websocket确实是一个很强大的利器

https://www.ucloud.cn/yun/99576.html
WebSocket、SockJs、STOMP三者关系
简而言之,WebSocket 是底层协议,SockJS 是WebSocket 的备选方案,也是底层协议,而 STOMP 是基于 WebSocket(SockJS)的上层协议。
1、HTTP协议解决了 web 浏览器发起请求以及 web 服务器响应请求的细节,假设 HTTP 协议 并不存在,只能使用 TCP 套接字来 编写 web 应用。
2、直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用,因为没有高层协议,就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义;
3、同HTTP在TCP 套接字上添加请求-响应模型层一样,STOMP在WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;

你可能感兴趣的:(Java,websocket,spring,spring,boot)