Echarts+vue电商平台数据可视化——webSocket改造项目

news2025/1/2 12:20:45

websocket的基本使用,用于测试前端能否正常获取到后台数据

后台代码编写:

const path = require("path");
const fileUtils = require("../utils/file_utils");
const WebSocket = require("ws");
// 创建WebSocket服务端的对象,绑定的端口号是9998
const wss = new WebSocket.Server({
  port: 9998,
});
// 服务端开启了监听
// 导出一个函数listen
module.exports.listen = () => {
  // 对客户端的连接事件进行监听
  // client: 代表的是客户端的连接socket对象
  wss.on("connection", (client) => {
    console.log("有客户端连接成功了...");
    // 对客户端的连接对象进行message事件的监听
    // msg:由客户端发给服务器的数据
    client.on("message", async (msg) => {
      console.log("客户端发送数据给服务器:" + msg);
      let payload = JSON.parse(msg);
      const action = payload.action;
      if (action === "getData") {
        let filePath = "../data/" + payload.chartName + ".json";
        // payload.charName; // trend seller map rank hot stock
        filePath = path.join(__dirname, filePath);
        const ret = await fileUtils.getFileJsonData(filePath);
        // 需要再服务器获取到数据的基础上,增加一个data的字段
        // data对应的值,就是某个json文件的内容
        payload.data = ret;
        client.send(JSON.stringify(payload));
      } else {
        // 原封不动的将所有收到的数据转发给每一个处于连接状态的客户端
        // wss.clients //所有客户端的连接
        wss.clients.forEach((client) => {
          client.send(JSON.stringify(payload));
        });
      }
      // 由服务端往客户端发送数据
      // client.send("hello socket from backend");
    });
  });
};

调用的获取文件路径的方法(getFileJsonData):

// 读取文件的工具方法
const fs = require("fs");
module.exports.getFileJsonData = (filePath) => {
  // 根据文件的路径,读取文件的内容
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, "utf-8", (error, data) => {
      if (error) {
        // 读取文件失败
        reject(error);
      } else {
        // 读取文件成功
        // return data; // 这里的return返回的是这个函数的调用者,而不是getFileJsonData这个函数的调用者
        // 读取文件是一个异步任务,对于一个异步任务,我们也不能通过return的方式来将数据返回给调用者
        resolve(data);
      }
    });
  });
};

前端使用:

    <button id="connect">连接</button>
    <button id="send" disabled="true">发送数据</button>
    <br />从服务端接收的数据如下: <br />
    <span id="recv"></span>
    <script>
      var connect = document.querySelector("#connect");
      var send = document.querySelector("#send");
      var recv = document.querySelector("#recv");
      let ws = null;
      connect.onclick = function () {
        ws = new WebSocket("ws://localhost:9998");
        ws.onopen = () => {
          console.log("连接服务端成功了...");
          send.disabled = false;
        };
        ws.onclose = () => {
          console.log("连接服务器失败或关闭");
          send.disabled = true;
        };
        ws.onmessage = (msg) => {
          console.log("接收从服务器发送过来的数据了");
          console.log(msg);
          recv.innerHTML = msg.data;
        };
      };
      send.onclick = function () {
        ws.send(
          JSON.stringify({
            action: "getData",
            socketType: "trendData",
            chartName: "trend",
            value: "",
          })
        );
        ws.send(
          JSON.stringify({
            action: "fullScreen",
            socketType: "fullScreen",
            chartName: "trend",
            value: true | false,
          })
        );
        ws.send(
          JSON.stringify({
            action: "themeScreen",
            socketType: "themeScreen",
            chartName: "",
            value: "",
          })
        );
      };
    </script>

 websocket用来改造电商平台项目思维导图:

坐标轴的方向是一个从左往右的方向,朝那个方向就选取x1,y1,x2,y2就选取那几个值

横向:0,0,1,0

竖向:0,0,0,1

报错信息:

js:31[Vue warn]:挂接钩子时出错:“InvalidStateError:在WebSocket上执行send失败:仍处于连接状态。”

代码中的注释解释:

// 有一种报错情况,在组件还没有进行连接成功之前,连接需要一点时间,这个组件就已经进行了加载,就会调用mounted当中指明的send的方法,而send方法是socket_service.js当中定义的一个方法,就会往ws来进行一个send方法的调用,而此时此刻,还没有连接成功

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
// 引入字体的文件
import "./assets/font/iconfont.css";
// 引入全局的样式文件
import "./assets/css/global.less";
import axios from "axios";
import SocketService from "@/utils/socket_service";
// 对服务端的数据进行连接
// SocketService.Instance().connect(); //这样写会报错,报错说明是Instance是不需要就加上小括号的
// 有一种报错情况,在组件还没有进行连接成功之前,连接需要一点时间,这个组件就已经进行了加载,就会调用mounted当中指明的send的方法,而send方法是socket_service.js当中定义的一个方法,就会往ws来进行一个send方法的调用,而此时此刻,还没有连接成功
SocketService.Instance.connect();
// 其他的组件调用websocket的方式  this.$socket
Vue.prototype.$socket = SocketService.Instance;
// 请求的基准路径的配置
axios.defaults.baseURL = "http://127.0.0.1:8888/api/";
// 将axios挂载到Vue的原型对象上
// 在别的组件中 this.$http
Vue.prototype.$http = axios;

// 将全局的echarts对象挂载到Vue的原型对象中
// 别的组件中this.$echarts
Vue.prototype.$echarts = window.echarts;

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: (h) => h(App),
}).$mount("#app");

解决方法,添加一个连接标识,判断websocket连接成功还是失败,true连接成功,false连接失败

项目改造后的后台编写:

export default class SocketService {
  // 单例
  static instance = null;
  static get Instance() {
    if (!this.instance) {
      this.instance = new SocketService();
    }
    return this.instance;
  }

  // 和服务器连接的socket对象
  ws = null;

  // 怎么在得到数据之后,将每个图表数据传递给每个图表组件,让图表数据可以得到更新
  // 先将每一个图表组件的某一个方法先存储在我们当前的这个模块中,比如一个实例属性中,一旦得到有服务端给我们的数据之后,在调用我们之前所存储起来的那个方法,就可以将数据传递给每个图表组件
  // 存储回调函数
  callBackMapping = {};

  // 标识是否连接成功
  connected = false;
  // 记录重试的次数
  sendRetryCount = 0;
  // 重新连接尝试的次数
  connectRetryCount = 0;

  // 定义连接服务器的方法
  connect() {
    // 连接服务器
    if (!window.WebSocket) {
      return console.log("您的浏览器不支持WebSocket");
    }
    this.ws = new WebSocket("ws://localhost:9998");
    // 连接成功的事件
    this.ws.onopen = () => {
      console.log("连接服务器成功了");
      this.connected = true;
      // 重置重新连接的次数
      this.connectRetryCount = 0;
    };
    // 1.连接服务器失败
    // 2.当连接成功之后,服务器关闭的情况
    this.ws.onclose = () => {
      console.log("连接服务器失败");
      // 标识是否连接成功,没有连接成功
      this.connected = false;
      this.connectRetryCount++;
      // 这个时候应该进行重新连接的尝试,但是每一次连接失败,下一次的连接都是500毫秒 不太合适,因为尝试的越多,可能服务器已经坏了,或者已经关闭了,就没有必要那么频繁的次数来进行重新连接的尝试
      setTimeout(() => {
        this.connect();
      }, 500 * this.connectRetryCount);
    };
    this.ws.onmessage = (msg) => {
      console.log("从服务器获取了数据");
      // 真正服务端发送过来的原始数据时在msg中的data字段
      // 如果在的得到数据之后把数据传递给每个图表组件会好一些,因为只有图表组件需要数据
      console.log(msg.data, msg, "--\\\\");
      const recvData = JSON.parse(msg.data);
      const socketType = recvData.socketType;
      // 判断回调函数是否存在
      if (this.callBackMapping[socketType]) {
        const action = recvData.action;
        if (action === "getData") {
          const realData = JSON.parse(recvData.data);
          this.callBackMapping[socketType].call(this, realData);
        } else if (action === "fullScreen") {
          this.callBackMapping[socketType].call(this, recvData);
        } else if (action === "themeScreen") {
          this.callBackMapping[socketType].call(this, recvData);
        }
      }
    };
  }

  // 下面的这个三个方法需要通过组件来调用
  // 回调函数的注册
  // socketType  这个函数的唯一标识,callBack这个函数的回调函数
  registerCallBack(socketType, callBack) {
    this.callBackMapping[socketType] = callBack;
  }
  // 取消某一个回调函数
  // socketType 这个函数的唯一标识
  unRegisterCallBack(socketType) {
    this.callBackMapping[socketType] = null;
  }
  // 发送数据的方法
  send(data) {
    // 判断此时此刻有没有连接成功
    if (this.connected) {
      this.sendRetryCount = 0;
      this.ws.send(JSON.stringify(data));
    } else {
      this.sendRetryCount++;
      setTimeout(() => {
        this.send(data);
      }, this.sendRetryCount * 500);
    }
    // this.ws.send(JSON.stringify(data));
  }
}

新旧setOption是一个相互整合,相互覆盖的过程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2267831.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

神经网络-Inception

Inception网络是由Google开发的一种深度卷积神经网络架构&#xff0c;旨在解决计算机视觉领域中的图像分类和物体识别任务。 Inception网络最初在2014年被提出&#xff0c;并在ImageNet图像分类挑战赛上取得了很好的结果。其设计灵感来自于模块化的思想&#xff0c;将不同尺度…

js给dom分页

减少js操作dom js引擎与渲染引擎相互独立, js操作dom过程开销大操作到了dom层面会触发渲染树的变化,触发回流与重绘开销大 让js给dom分压 js处理完操作后,最后给dom 缓存变量 let container document.getElementById(container) let content for(let count0;count<…

深度学习——神经网络中前向传播、反向传播与梯度计算原理

一、前向传播 1.1 概念 神经网络的前向传播&#xff08;Forward Propagation&#xff09;就像是一个数据处理的流水线。从输入层开始&#xff0c;按照网络的层次结构&#xff0c;每一层的神经元接收上一层神经元的输出作为自己的输入&#xff0c;经过线性变换&#xff08;加权…

秒鲨后端之MyBatis【2】默认的类型别名、MyBatis的增删改查、idea中设置文件的配置模板、MyBatis获取参数值的两种方式、特殊SQL的执行

别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! 下篇更新&#xff1a; 秒鲨后端之MyBatis【3】自定义映射resultMap、动态SQL、MyBatis的缓存、MyBatis的逆向工程、分页插件。 默认的类型别名 MyBatis的增删改查 添加 <!--int insertUs…

瑞芯微全新芯片平台RK3506优势详解,高集成低功耗,为工业而生 触觉智能测评

RK3506是瑞芯微Rockchip在2024年第四季度全新推出的Arm嵌入式芯片平台&#xff0c;三核Cortex-A7单核Cortex-M0多核异构设计&#xff0c;CPU频率达1.5Ghz, M0 MCU为200Mhz。 而RK3506芯片平台下的工业级芯片型号RK3506J&#xff0c;具备-40-85℃的工业宽温性能、发热量小&#…

AIOps平台的功能对比:如何选择适合的解决方案?

定义与概念 AIOps&#xff0c;即人工智能运维&#xff08;Artificial Intelligence for IT Operations&#xff09;&#xff0c;是将人工智能技术应用于 IT 运维领域&#xff0c;以实现自动化、智能化的运维管理。它通过整合大数据、机器学习等先进技术&#xff0c;对海量运维数…

Python + 深度学习从 0 到 1(03 / 99)

希望对你有帮助呀&#xff01;&#xff01;&#x1f49c;&#x1f49c; 如有更好理解的思路&#xff0c;欢迎大家留言补充 ~ 一起加油叭 &#x1f4a6; 欢迎关注、订阅专栏 【深度学习从 0 到 1】谢谢你的支持&#xff01; ⭐ 神经网络的数据表示 – 张量 你可能对矩阵很熟悉&a…

Lumos学习王佩丰Excel第二十三讲:饼图美化与PPT图表

一、双坐标柱形图的补充知识 1、主次坐标设置 2、主次坐标柱形避让&#xff08;通过增加两个系列&#xff0c;挤压使得两个柱形挨在一起&#xff09; 增加两个系列 将一个系列设置成主坐标轴&#xff0c;另一个设成次坐标轴 调整系列位置 二、饼图美化 1、饼图美化常见设置 …

基于Vue+SSM+SpringCloudAlibaba书籍管理系统

功能要求 一、登录功能&#xff08;http://localhost:8080/#/login&#xff09; 输入账号和密码(admin/admin)进行登录&#xff1a; 如果密码错误&#xff0c;给出提示信息 如果密码正确&#xff0c;跳转到主页 账号或密码错误&#xff1a; 账号密码正确&#xff1a;跳转到…

【优先算法】滑动窗口 --(结合例题讲解解题思路)(C++)

目录 ​编辑 1.什么是滑动窗口&#xff1f; 2. 滑动窗口例题 2.1 例题1&#xff1a;长度最小的子数组 2.1.1 解题思路 2.1.2 方法一&#xff1a;暴力枚举出所有的子数组的和 2.1.3 方法二&#xff1a;使用 “同向双指针” 也就是滑动窗口来进行优化 2.2 例题2&#xff1a;无重…

VS Code 从命令行启动

在 VS Code 中&#xff0c;code 命令允许你在命令行中快速打开文件、文件夹或新窗口。 安装 原本地址&#xff1a;https://code.visualstudio.com/docs/setup/mac 使用 使用 code 命令 打开文件&#xff1a;你可以通过在命令行输入 code 文件名 来直接打开一个文件。 打开文…

微服务-配置管理

文章目录 1.什么是配置管理2.配置共享添加共享配置拉取共享配置 3.配置热更新添加配置到Nacos配置热更新 4.动态路由监听Nacos配置变更 1.什么是配置管理 到目前为止我们已经解决了微服务相关的几个问题&#xff1a; 微服务远程调用微服务注册、发现微服务请求路由、负载均衡…

ArrayList 和LinkedList的区别比较

前言 ‌ArrayList和LinkedList的主要区别在于它们的底层数据结构、性能特点以及适用场景。‌ArrayList和LinkedList从名字分析&#xff0c;他们一个是Array&#xff08;动态数组&#xff09;的数据结构&#xff0c;一个是Linked&#xff08;链表&#xff09;的数据结构&#x…

MySQL--》如何在SQL中巧妙运用函数与约束,优化数据处理与验证?

目录 函数使用 字符串函数 数值函数 日期函数 流程函数 约束 外键约束 约束规则 函数使用 函数是指一段可以直接被另一段程序调用的程序或代码&#xff0c;在mysql当中有许多常见的内置函数&#xff0c;接下来开始对这些内置函数及其作用进行简单的讲解和使用&#xf…

一文大白话讲清楚CSS盒子模型和块级格式化上下文(BFC)

一文大白话讲清楚CSS盒子模型和块级格式化上下文&#xff08;BFC&#xff09; 1.啥是个CSS盒子 鞋盒你家总有吧&#xff0c;方方正正&#xff0c;有长度有高度。css盒子跟这个八九不离十当我们编写html页面时&#xff0c;写了很多的元素&#xff0c;比如"div",&quo…

Docker 快速搭建 GBase 8s数据库服务

1.查看Gbase 8s镜像版本 可以去到docker hub网站搜索&#xff1a;gbase8s liaosnet/gbase8s如果无法访问到该网站&#xff0c;可以通过docker search搜索 docker search gbase8s2.拉取Gbase 8s镜像 以下演示的版本是目前官网最新版本Gbase8sV8.8_3.5.1 docker pull liaosn…

密钥登录服务器

1. 生成 SSH 密钥对 如果您还没有生成密钥对&#xff0c;可以使用以下命令生成&#xff1a; ssh-keygen 在 root 用户的家目录中生成了一个 .ssh 的隐藏目录&#xff0c;内含两个密钥文件&#xff1a;id_rsa 为私钥&#xff0c;id_rsa.pub 为公钥。 在提示时&#xff0c;您可…

王佩丰24节Excel学习笔记——第二十讲:图表基础

【以 Excel2010 系列学习&#xff0c;用 Office LTSC 专业增强版 2021 实践】 【本章技巧】 课件图片有问题&#xff0c;不能随隐藏熟悉各个图表小部件的功能&#xff0c;需要修改都是选中右键进行更改。 一、认识图表中的元素 图表标题&#xff1a;主坐标&#xff08;横坐标&…

华为交换机配置本地端口流量镜像

端口镜像&#xff08;Port Mirroring&#xff09;是网络监控的一种重要技术&#xff0c;通过复制流经特定端口的报文&#xff0c;并将其传送到指定的观察端口&#xff0c;以便对网络流量进行分析和监控。下面将详细介绍如何在华为交换机上配置本地端口镜像&#xff0c;以N:1镜像…

IDEA设置作者信息 日期等

file -> setting 或 ctrl alt s找到如下 然后添加注释即可 可以直接编辑5处的文字&#xff0c;在 author 后放自己的名字即可 /*** author 你的名字* date ${DATE} ${TIME})*/当然 整体不止这些 &#xff0c;看下面的描述中&#xff0c;还有很多其他选项 也可以 4 这…