Vue2+Echarts+SpringBoot+Websocket+Scheduled实现大屏图表数据实时展示

这篇具有很好参考价值的文章主要介绍了Vue2+Echarts+SpringBoot+Websocket+Scheduled实现大屏图表数据实时展示。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.简介

近期在学习websocket的相关技术,用于做前后端的数据实时交互,结合网上资料和个人理解,整理了一个小白入门案例,不喜勿喷!!!!!

1.1 webSocket

  • WebSocket是HTML5下一种新的协议(websocket协议本质上是一个基于tcp的协议)
  • 它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯的目的
  • Websocket是一个持久化的协议vue大屏展示定时任务,Java知识日常分享,echarts,前端,javascript,java,spring boot,websocket

WebSocket有以下特点:

  • 是真正的全双工方式,建立连接后客户端与服务器端是完全平等的,可以互相主动请求。而HTTP长连接基于HTTP,是传统的客户端对服务器发起请求的模式。
  • HTTP长连接中,每次数据交换除了真正的数据部分外,服务器和客户端还要大量交换HTTP header,信息交换效率很低。Websocket协议通过第一个request建立了TCP连接之后,之后交换的数据都不需要发送 HTTP header就能交换数据,这显然和原有的HTTP协议有区别所以它需要对服务器和客户端都进行升级才能实现(主流浏览器都已支持HTML5)

2.效果图展示

vue大屏展示定时任务,Java知识日常分享,echarts,前端,javascript,java,spring boot,websocket

图 1 初始状态

vue大屏展示定时任务,Java知识日常分享,echarts,前端,javascript,java,spring boot,websocket

图 2 推送一段时间之后的状态 

socket演示

demo中以饼图和柱形图为例,结合websocket,对后端数据进行实时推送

3.代码实现

3.1 前端代码

该项目为前后端分离项目,前端主要使用Vue2+原生websocket进行页面搭建和服务端数据交互

  • 主要代码实现部分
<template>
  <div class="hello">
   <!-- 柱形图渲染 -->
   <div id="chart">

   </div>
   <!-- 饼图渲染 -->
   <div id="pie">

  </div>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data(){
    return {
      ws: null,
      url:"ws://127.0.0.1:8080/websocket/",
      barChart: null,
      pieChart: null,
      userId: null
    }
  },
  mounted(){
    //挂载的时候进行初始化
    this.init()
  },
  created(){
  
  },
  methods:{
    initChart(data){
      if(!this.barChart){
        this.barChart= this.$echarts.init(document.getElementById('chart'))
      }
      let chart = this.barChart
      const option = {
        title: {
          text: 'websocket测试',
          textStyle:{
            color: "white"
          }
        },
        tooltip: {
          trigger: 'axis'
        },
        legend: {
          data: ['日销量'],
          textStyle:{
            color: "white"
          }
        },
        xAxis: {
          name: "日期",
          type: 'category',
          data: data.xAxisData,
          axisLabel:{
            color: "white"
          },
          nameTextStyle:{
            color: "white"
          }
        },
        yAxis: {
          type: 'value',
          name:"销量",
          axisLabel:{
            color: "white"
          },
          nameTextStyle:{
            color: "white"
          }
        },
        series: [
          {
            name: '日销量',
            type: 'bar',
            data: data.yAxisData
          }
        ]
      } 
      chart.setOption(option)  
    },
    init(){
      let obj = this.getUrlParams2(window.location.href)
      this.ws = new WebSocket(this.url+obj.userid)
      this.ws.onopen = this.websocketOnOpen;
      this.ws.onmessage = this.websocketOnMessage;
    },
    websocketOnOpen(){
      console.log("连接成功")
    },
    websocketOnMessage(datas){
      console.log(datas)
      if(datas.data !== "连接成功"){
        let res = JSON.parse(datas.data)
        if(res.type == 1){
            this.$message({
              type: "warning",
              message: res.msg
            })
        }else{
          this.initChart(JSON.parse(datas.data).server)
          this.initPie(JSON.parse(datas.data).pie)
        }
        
      }
    },
    getUrlParams2(url){
      let urlStr = url.split('?')[1]
      const urlSearchParams = new URLSearchParams(urlStr)
      const result = Object.fromEntries(urlSearchParams.entries())
      return result
    },
    initPie(pies){
      if(!this.pieChart){
        this.pieChart= this.$echarts.init(document.getElementById('pie'))
      }
      let chart = this.pieChart
      const option = {
          // legend 图例组件配置项 (图例,其实就是颜色指示器)
          legend: {
            top: "bottom", // 图例组件离容器上侧的距离。
          },
          // 工具栏组件
          toolbox: {
            show: true, // 是否显示工具栏组件
            feature: {
              mark: { show: false },
              dataView: { show: true, readOnly: false }, // 数据视图工具
              restore: { show: true },  // 配置项还原
              saveAsImage: { show: true }, // 保存图片
            },
          },
          series: [
            {
              name: "Nightingale Chart", // 名称
              type: "pie",  // 类型 饼图
              radius: [50, 150], // 饼图的半径 `50, 250 => 内半径 外半径`
              center: ["50%", "50%"], // 饼图的中心(圆心)坐标,数组的第一项是横坐标,第二项是纵坐标。
              roseType: "area", // 是否展示成南丁格尔图,通过半径区分数据大小
              // 图形的颜色
              itemStyle: {
                borderRadius: 8,
              },
              // 图表的数据
              data: pies.pie,
            },
          ],
        };
        // 3.5 将配置参数和图表关联
        chart.setOption(option);
    }
  }
}
</script>

<style scoped lang="less">
  .hello{
    display: flex;
    #chart,#pie{
      width: 600px;
      height: 400px;
      background-color: black;
    }
    #pie{
      margin-left: 20px;
    }
  }
</style>

3.2 后端代码

后端我是用的是Java语言,主要使用SpringBoot生态进行服务端的搭建

3.2.1 项目目录结构

vue大屏展示定时任务,Java知识日常分享,echarts,前端,javascript,java,spring boot,websocket 3.2.2 导入相关依赖

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!--   spring-web依赖    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--   websocket相关依赖     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <!--   lombok     -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--EntityUtils工具类包-->
        <dependency>
            <groupId>xin.altitude.cms</groupId>
            <artifactId>ucode-cms-common</artifactId>
            <version>1.5.8</version>
        </dependency>
        <!--    hutool工具类    -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.18</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
    </dependencies>

 3.3.3 WebSocket配置文件

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

@Configuration
public class WebSocketConfig {
    /**
     * 	注入ServerEndpointExporter,
     * 	这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
    
}

3.3.4 WebSocket服务类

@ServerEndpoint("/websocket/{userId}")
@Component
public class WebSocketServer {
    static Log log= LogFactory.get(WebSocketServer.class);
    /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static int onlineCount = 0;
    /**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
    private Session session;
    /**接收userId*/
    private String userId="";
    @Autowired
    private ItemService itemService;

    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId=userId;
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            webSocketMap.put(userId,this);
            //加入set中
        }else{
            webSocketMap.put(userId,this);
            //加入set中
            addOnlineCount();
            //在线数加1
        }

        log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());

        try {
            Map<String,Object> map = new HashMap<>();
            map.put("server",itemService.getData());
            map.put("pie", itemService.getPieData());
            JSONObject jsonObject =  new JSONObject(map);
            sendMessage(jsonObject.toString());
        } catch (Exception e) {
            log.error("用户:"+userId+",网络异常!!!!!!");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:"+userId+",报文:"+message);
        //可以群发消息
        //消息保存到数据库、redis
        if(StringUtils.isNotBlank(message)){
            try {
                //解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:"+this.userId+",原因:"+error.getMessage());
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }
    /**
     * 消息单发
     */
    public static void sendOneMessage(String userId,String message) throws IOException {
        WebSocketServer webSocketServer = webSocketMap.get(userId);
        webSocketServer.session.getBasicRemote().sendText(message);
    }


    /**
     * 实现服务器主动推送
     */
    public static void sendAllMessage(String message) throws IOException {
        ConcurrentHashMap.KeySetView<String, WebSocketServer> userIds = webSocketMap.keySet();
        for (String userId : userIds) {
            WebSocketServer webSocketServer = webSocketMap.get(userId);
            webSocketServer.session.getBasicRemote().sendText(message);
            System.out.println("webSocket实现服务器主动推送成功userIds===="+userIds);
        }
    }

    /**
     * 发送自定义消息
     * */
    public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
        log.info("发送消息到:"+userId+",报文:"+message);
        if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
            webSocketMap.get(userId).sendMessage(message);
        }else{
            log.error("用户"+userId+",不在线!");
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
}

以上便完成了websocket服务的搭建,上述中设置了单发和群发两种通信方式

3.3.5 测试实体类

 分别创建柱形图(Bar)和饼图(Pie)的实体类

@AllArgsConstructor
@NoArgsConstructor
@Data
public class Bar {
    private String name;
    private int data;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Pie {
    private String name;
    private int value;
}

3.3.6 编写Service从数据库获取实时数据

此处为服务端从数据库中获取最新数据的过程,demo中,并没有进行查库操作,而是写了一个模拟数据进行测试,使用static静态变量对数据进行静态初始化,如需操作数据库可以进行数据库连接即可,持久层可使用mybatis或者JPA对数据库进行操作

 初始化完成后,分别获取饼图和柱形图的相关数据,通过Math.random()方法对初始数据进行加工,使得每次获取到的数据都是不一样的,从而模拟数据的变化更新

@Service
public class ItemService {
    private static final List<Bar> items = new ArrayList<>();
    private static final List<Pie> pie = new ArrayList<>();
    static {
        items.add(new Bar("周一",12));
        items.add(new Bar("周二",20));
        items.add(new Bar("周三",15));
        items.add(new Bar("周四",8));
        items.add(new Bar("周五",7));
        items.add(new Bar("周六",11));
        items.add(new Bar("周日",13));
        pie.add(new Pie("rose1",38));
        pie.add(new Pie("rose2",46));
        pie.add(new Pie("rose3",12));
        pie.add(new Pie("rose4",30));
        pie.add(new Pie("rose5",54));
        pie.add(new Pie("rose6",36));
    }
    //获取柱形图数据
    public Map<String,?> getData(){
        //模拟数据更新
        items.forEach(e -> e.setData(e.getData()+(int)(Math.random() * 5 + 1)));
        HashMap<String,Object> map = new HashMap<>();
        map.put("xAxisData", EntityUtils.toList(items,Bar::getName));
        map.put("yAxisData", EntityUtils.toList(items,Bar::getData));
        return map;
    }
    //获取饼图数据
    public Map<String,?> getPieData(){
        //模拟数据更新
        pie.forEach(e -> e.setValue(e.getValue()+(int)(Math.random() * 5 + 1)));
        HashMap<String,Object> map = new HashMap<>();
        map.put("pie",pie);
        return map;
    }
}

3.3.7 编写测试接口

@RestController
@RequestMapping("/news")
@Slf4j
public class TestApi {
    @Autowired
    private ItemService itemService;
    /**
     * 3秒执行一次
     * @return
     * @throws Exception
     */
    @Scheduled(fixedRate = 3 * 1000)
    @GetMapping("/send")
    public String send() throws Exception {
        Map<String,Object> map = new HashMap<>();
        map.put("server",itemService.getData());
        map.put("pie",itemService.getPieData());
        JSONObject jsonObject =  new JSONObject(map);
        WebSocketServer.sendAllMessage(jsonObject.toString());
        return jsonObject.toString();
    }
}

以上接口编写完成之后,使用SpringBoot自带的定时任务Scheduled类对接口进行设置,我这里是设置3秒执行一次,即@Scheduled(fixedRate = 3 * 1000),同时将每次获取到的最新数据通过websocket向客户端进行消息推送

至此 ,完成整个项目的搭建,本人也不太会,都是慢慢摸索的,有啥讲的不对的地方,欢迎大家批评指正!!!!如果觉得对您有帮助的话,请不要吝啬您的点赞+关注+评论哟!!!!文章来源地址https://www.toymoban.com/news/detail-828914.html

到了这里,关于Vue2+Echarts+SpringBoot+Websocket+Scheduled实现大屏图表数据实时展示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Springboot+Flask+Neo4j+Vue2+Vuex+Uniapp+Mybatis+Echarts+Swagger综合项目学习笔记

    项目访问入口 Neo4j高性能图数据库从入门到实战 教程博客:Neo4j 开启命令 医学知识图谱问答系统 neo4j知识图谱 Vue+flask 中药中医方剂大数据可视化系统 ECharts数据可视化项目、 D3js: 数据可视化入门D3.js 展示地址:数据可视化 子绝父相 立即执行函数(function(){})(); ECharts官网:

    2024年02月16日
    浏览(34)
  • websocket实现聊天室(vue2 + node)

    需求分析如图: 搭建的项目结构如图: 前端步骤: vue create socket_demo (创建项目) views下面建立Home , Login组件 路由里面配置路径 Home组件内部开启websocket连接 前端相关组件代码: Login组件 Home组件 router/index.js 后端步骤: 在项目外层创建server文件夹(src目录同级) npm init -y创建

    2024年01月22日
    浏览(31)
  • springboot+echarts+mysql制作数据可视化大屏(滑动大屏)

     作者水平低,如有错误,恳请指正!谢谢!!!!! 项目简单,适合大学生参考 分类专栏还有其它的可视化博客哦! 专栏地址:https://blog.csdn.net/qq_55906442/category_11906804.html?spm=1001.2014.3001.5482 目录  一、数据源 二、所需工具 三、项目框架搭建 四、代码编写 温度堆叠折线图

    2024年02月11日
    浏览(32)
  • vue项目业务实现,视频监控-文件流,大屏适配方案(v-scale-screen),websocket前端

    最近把以前的业务场景及解决方案整理了一下,具体实现的工具如下: 监控-视频文件流==video.js + videojs-contrib-hls 大屏适配方案== v-scale-screen websocket==sockjs-client+ webstomp-client 下载video插件, 使用方法 (1)导入 (2)模板中写入标签 (3)页面渲染时调用函数,渲染视频 option

    2024年02月16日
    浏览(33)
  • Springboot+Flask+Neo4j+Vue2+Vuex+Uniapp+Mybatis+Echarts+Swagger+JWT+Nginx+VueRouter综合项目学习笔记【包括项目部署】

    项目访问入口 Neo4j高性能图数据库从入门到实战 教程博客:Neo4j 开启命令 医学知识图谱问答系统 neo4j知识图谱 Vue+flask 中药中医方剂大数据可视化系统 ECharts数据可视化项目、 D3js: 数据可视化入门D3.js 展示地址:数据可视化 子绝父相 立即执行函数(function(){})(); ECharts官网:

    2024年02月03日
    浏览(30)
  • springboot+echarts +mysql制作数据可视化大屏(四图)

    作者水平低,如有错误,恳请指正!谢谢!!!!! 项目简单,适合大学生参考 分类专栏还有其它的可视化博客哦! 专栏地址:https://blog.csdn.net/qq_55906442/category_11906804.html?spm=1001.2014.3001.5482 成果展示: 1)可以使用自己的MySQL数据库; 2)使用我提供的数据。(要数据私信

    2024年02月13日
    浏览(32)
  • springboot+mybatis+echarts +mysql制作数据可视化大屏

    作者水平低,如有错误,恳请指正!谢谢!!!!! 目录 一、数据源 二、所需工具 三、项目框架搭建 3.1新建springboot项目 3.1.1进入官网 3.1.2创建项目 四、后端代码编写 4.1根据需求修改pom.xml 4.2配置数据源 4.3创建目录结构 4.4后端编写代码 4.4.1entity类 4.4.2dao 4.4.3service 4.4.4co

    2024年02月03日
    浏览(32)
  • 大屏可视化(VUE2 + DataV)

    dataV地址:DataV

    2024年02月14日
    浏览(33)
  • 基于Echarts+Vue3的低代码可视化数据大屏拖拽设计器 vue拖拽设计大屏

    本产品是一款基于Vue3开发的可视化数据大屏拖拽设计器。提供一种简单易用的拖拽式数据可视化大屏设计方案,可帮助用户快速创建和定制自己的数据大屏,通过拖拽组件、调整布局和设置属性,实现数据展示的自由组合和个性化定制。 可视化编辑:通过拖拽组件、调整布

    2024年02月03日
    浏览(40)
  • Vue2 Echarts 3D饼图

    2024年01月19日
    浏览(33)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包