electron-vue 台称串口对接 SerialPort

大致流程

1.首先找一个串口工具(sscom5.12.1)试试读取串口是否成功连上;

2.创建electron-vue的项目;

3.安装依赖,调整版本,启动项目;(在electron中使用串口_electron 串口_Jack_Kee的博客-CSDN博客)

4.学习SerialPort Usage | Node SerialPort工具;

5.开发入口文件,测试是否成功获取串口信息

6.成功获取串口后,接收台称数据

7.根据台称说明书与协议,解析台称数据(数值,单位,正负,精度...)

8.完成称重需求

9.完成打印需求

10.完成自动更新

串口工具大概样子

通过切换端口号和波特率,可以查看哪个是台称串口及波特率,我本机的端口号COM3 波特率9600是台秤的串口信息。

创建electron项目(起步 · electron-vue)

跟着官方步骤 创建electron-vue项目,成功启动项目(启动,打包)

 "electron": "^17.4.11",

引入serialport

npm install serialport --save

然后,安装electron-rebuild(用来重新编译serialport包):

npm install --save-dev electron-rebuild

重新编译serialport包

.\node_modules\.bin\electron-rebuild.cmd
 

提示Rebuild Complete,表示编译完成

按照该文章,实现最终效果注意安装依赖版本,

此注明我项目使用的各个版本

"dependencies": {
		"@serialport/parser-byte-length": "^11.0.0",
		"axios": "^0.18.0",
		"electron-updater": "^5.3.0",
		"element-ui": "^2.8.2",
		"lodash": "^4.17.21",
		"multispinner": "^0.2.1",
		"qrcodejs2": "^0.0.2",
		"serialport": "^11.0.0",
		"vue": "^2.5.16",
		"vue-electron": "^1.0.6",
		"vue-router": "^3.0.1",
		"vuex": "^3.0.1",
		"vuex-electron": "^1.0.0",
		"vuex-persistedstate": "^4.1.0"
	},
	"devDependencies": {
		"ajv": "^6.5.0",
		"babel-core": "^6.26.3",
		"babel-loader": "^7.1.4",
		"babel-minify-webpack-plugin": "^0.3.1",
		"babel-plugin-component": "^1.1.1",
		"babel-plugin-transform-runtime": "^6.23.0",
		"babel-preset-env": "^1.7.0",
		"babel-preset-stage-0": "^6.24.1",
		"babel-register": "^6.26.0",
		"cfonts": "^2.1.2",
		"chalk": "^2.4.1",
		"copy-webpack-plugin": "^4.5.1",
		"cross-env": "^5.1.6",
		"css-loader": "^0.28.11",
		"del": "^3.0.0",
		"devtron": "^1.4.0",
		"electron": "^17.4.11",
		"electron-builder": "^23.6.0",
		"electron-debug": "^1.5.0",
		"electron-devtools-installer": "^2.2.4",
		"electron-rebuild": "^3.2.9",
		"file-loader": "^1.1.11",
		"html-webpack-plugin": "^3.2.0",
		"listr": "^0.14.3",
		"mini-css-extract-plugin": "0.4.0",
		"node-loader": "^0.6.0",
		"node-sass": "^4.9.2",
		"sass-loader": "^7.0.3",
		"style-loader": "^0.21.0",
		"url-loader": "^1.0.1",
		"vue-html-loader": "^1.2.4",
		"vue-loader": "^15.2.4",
		"vue-style-loader": "^4.1.0",
		"vue-template-compiler": "^2.5.16",
		"webpack": "^4.15.1",
		"webpack-cli": "^3.0.8",
		"webpack-dev-server": "^3.1.4",
		"webpack-hot-middleware": "^2.22.2",
		"webpack-merge": "^4.1.3"
	}
 

 SerialPort (注意不同版本使用方式不同)

serialport:10.x.x

import { SerialPort } from 'serialport'

serialport:7.x.x

const SerialPort = require('serialport')

项目操作案例:

const { ByteLengthParser } = require("@serialport/parser-byte-length");
let ports = []; // 串口list
let mainWindow = null;  // electron 窗口

function registerIpcEvent() {
  // 发送可选串口
  SerialPort.list().then((ports) => {
    setTimeout(() => {
      mainWindow.webContents.send("send-port-info", ports);
    }, 1000);
  });
  //  关闭窗口
  app.on("window-all-closed", function () {
    if (process.platform !== "darwin") {
      ports.forEach((e) => {
        e && e.close();
      });
      app.quit();
    }
  });
  ipcMain.on("closeApp", () => {
    ports.forEach((e) => {
      e && e.close();
    });
    app.quit();
  });

  // 重新初始化串口
  ipcMain.on("init-port", (event, args) => {
    initPort(args);
  });
  // 关闭串口
  ipcMain.on("close-serialport", (event, args) => {
    const currentPort = ports.find((i) => i.path === args.name);
    currentPort && currentPort.close();
    if (currentPort && !currentPort.isOpen) {
      event.reply("close-serialport", { name: args.name });
    }
    ports = ports.filter((e) => e !== currentPort);
  });

  // 打开某个串口
  ipcMain.on("open-serialport", (event, args) => {
    const serialport = new SerialPort(
      {
        path: args.name,
        baudRate: +args.baudRate,
      },
      (err) => {
        console.log(err);
        if (err) {
           event.reply("open-serialport", {
             hasError: true,
             ...args,
             message: err,
           });
        } else {
          event.reply("open-serialport", args);
          ports.push(serialport);
        }
      }
    );
    // 根据说明书数据量字节17一次传输 也可以通过其他方式截取
    const parser = serialport.pipe(new ByteLengthParser({ length: 17  }));
    parser.on("data", (data) => {
     // xxxxxxx 
    });
    serialport.on("open", () => {});
  });
}

function initPort(bool) {
  if (bool) {
    SerialPort.list().then((ports) => {
      setTimeout(() => {
        mainWindow.webContents.send("send-port-info", ports);
      }, 1000);
    });
  }
}

还可以通过下面的形式截断串口数据 

正则匹配:parser-regex  

 一种转换流,它使用正则表达式来拆分传入的文本。

要使用Regex解析器,请提供一个正则表达式来拆分传入的文本。数据作为可由编码选项控制的字符串发出(默认为utf8)

const { SerialPort } = require('serialport')
const { ReadlineParser } = require('@serialport/parser-readline')
const port = new SerialPort({ path: '/dev/ROBOT', baudRate: 14400 })

const parser = port.pipe(new ReadlineParser({ delimiter: '\r\n' }))
parser.on('data', console.log)

分隔符截取:parser-readline 

在接收到换行符后发出数据的转换流。若要使用Readline分析器,请提供分隔符(默认为\n)。数据以可由编码选项控制的字符串形式发出(默认为utf8)。

const { SerialPort } = require('serialport')
const { RegexParser } = require('@serialport/parser-regex')
const port = new SerialPort({ path: '/dev/ROBOT', baudRate: 14400 })

const parser = port.pipe(new RegexParser({ regex: /[\r\n]+/ }))
parser.on('data', console.log)

开发入口文件

const { app, BrowserWindow, ipcMain, Menu, dialog } = require("electron");
const { SerialPort } = require("serialport");
const _ = require("lodash");
const { ByteLengthParser } = require("@serialport/parser-byte-length");
import { updateHandle } from "../renderer/utils/update.js";

let ports = [];
const path = require("path");
const fs = require("fs");


//读取本地更新配置json文件 包含是否调试 请求地址 更新地址...
const File_path = path
  .join(path.resolve("./../"), "/config.json")
  .replace(/\\/g, "/");
const config_res = JSON.parse(fs.readFileSync(File_path, "utf-8"));
let mainWindow = null;
const winURL =
  process.env.NODE_ENV === "development"
    ? `http://localhost:9080`
    : `file://${__dirname}/index.html`;


app.whenReady().then(() => {
  createWindow();

  registerIpcEvent();
  // getPrinterList(); 注释打印
  config_res.IS_DEBUG && createMenu();
  app.on("activate", function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    frame: config_res.IS_DEBUG, // 是否有边框窗口
    fullscreen: !config_res.IS_DEBUG, // 全屏
    webPreferences: {
      // preload: path.join(__dirname, "preload.js"),
      nodeIntegration: true,
      contextIsolation: false,
      enableRemoteModule: true,
      webviewTag: true,
      webSecurity: false,
    },
  });
  config_res.IS_DEBUG ? mainWindow.webContents.openDevTools() : ""; // 生产模式调试开关

  setTimeout(() => {
    mainWindow.loadURL(winURL);
  }, 1000);
  // 监听崩溃
  mainWindow.webContents.on("crashed", () => {
    const options = {
      type: "error",
      title: "系统意外终止",
      message: "可点击以下按钮",
      buttons: ["点击重启", "直接退出"],
    };
    dialog.showMessageBox(options, (index) => {
      if (index === 0) reloadWindow(mainWindow);
      else app.quit();
    });
  });

}

function createMenu() {
  // main
  const template = [
    {
      label: "调试",
      click: function (item, focusedWindow) {
        if (focusedWindow) {
          config_res.IS_DEBUG && focusedWindow.toggleDevTools();
        }
      },
    },

  ];
  const menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);
}
function initPort(bool) {
  if (bool) {
    SerialPort.list().then((ports) => {
      setTimeout(() => {
        mainWindow.webContents.send("send-port-info", ports);
      }, 1000);
    });
  }
}
 
function registerIpcEvent() {
  // 发送可选串口
  SerialPort.list().then((ports) => {
    setTimeout(() => {
      mainWindow.webContents.send("send-port-info", ports);
    }, 1000);
  });
  //  关闭窗口
  app.on("window-all-closed", function () {
    if (process.platform !== "darwin") {
      ports.forEach((e) => {
        e && e.close();
      });
      app.quit();
    }
  });
  ipcMain.on("closeApp", () => {
    ports.forEach((e) => {
      e && e.close();
    });
    app.quit();
  });

  // 重新初始化串口
  ipcMain.on("init-port", (event, args) => {
    initPort(args);
  });
  // 关闭串口
  ipcMain.on("close-serialport", (event, args) => {
    const currentPort = ports.find((i) => i.path === args.name);
    currentPort && currentPort.close();
    if (currentPort && !currentPort.isOpen) {
      event.reply("close-serialport", { name: args.name });
    }
    ports = ports.filter((e) => e !== currentPort);
  });

  // 打开某个串口
  ipcMain.on("open-serialport", (event, args) => {
    const serialport = new SerialPort(
      {
        path: args.name,
        baudRate: +args.baudRate,
      },
      (err) => {
        console.log(err);
        if (err) {
           event.reply("open-serialport", {
             hasError: true,
             ...args,
             message: err,
           });
        } else {
          event.reply("open-serialport", args);
          ports.push(serialport);
        }
      }
    );
    // 数据量字节截取拉大 获取大区间集合
    const parser = serialport.pipe(new ByteLengthParser({ length: 17 * 10 }));
    parser.on("data", (data) => {
      let dataString = data.toString("hex");
 
      sendData(event, {
       // xxxxx 需要发送给页面的信息
      });
    });
    serialport.on("open", () => {});
  });
}
function sendData(event, value) {
  event.sender.send("send-data", value);
}
 
 

需要展示串口信息的页面

1. 发送init-port 初始化请求

const { ipcRenderer } = require("electron");

ipcRenderer.send("init-port", true);

 2.页面接收解析后的串口信息函数

  data() {
    return {
      portNameList: [], // 多称选择
      openedPort: [], // 已经打开的称信息
      currPortData: 0.0, // 显示重量
      currName: "", // 称名称
      currRate: "9600", // 波特率
      sign: "", //秤 正 负
      rateOption: rateOption,// 波特率选择
    };
  },  
  watch: {
    currName(val, oldval) {
      if (val !== "" && oldval !== "") {
        this.openOrclose("open", oldval);
      }
    },
  },  
 methods: {
  listSerialPorts() {
      ipcRenderer.on("open-serialport", (event, args) => {
        console.log("open-serialport", args);
        if (args.hasError) {
          alert(args.message);
        } else {
          this.openedPort.push(args.name);
          console.log("open", this.openedPort);
        }
      });

      ipcRenderer.on("close-serialport", (event, args) => {
        const index = this.openedPort.findIndex((i) => i === args.name);
        this.openedPort.splice(index, 1);
        console.log("close", this.openedPort);
      });

      ipcRenderer.on("send-port-info", (event, args) => {
        for (let port of args) {
          this.portNameList.push({
            portName: `称台${this.portNameList.length + 1}`,
            name: port.path,
            path: port.path,
          });
        }

        this.currName = this.portNameList && this.portNameList[0].name;
        console.log("send-port-info获取的串口", this.portNameList);
        this.openOrclose("open");
      });

      ipcRenderer.on("send-data", (event, args) => {
        console.log("send-data", args, this.resData);
        this.currPortData = args.value; // 接收传入的信息 用于展示
       });
    },

    openOrclose(type, oldname = "") {
      if (this.portNameList.length <= 0) {
        this.$message.error("台称读取失败,请重新进入页面或重新进入系统!");
        return;
      }
      const name = this.currName;
      const baudRate = this.currRate;
      if (oldname !== "" && this.openedPort.includes(oldname)) {
        this.sendMessageToMain("close-serialport", { name: oldname });
      }
      if (type === "close") {
        if (this.openedPort.includes(name)) {
          this.sendMessageToMain("close-serialport", { name });
        }
      } else {
        this.sendMessageToMain("open-serialport", {
          name: this.currName,
          baudRate: this.currRate,
        });
      }
    },
}

根据台称说明书与协议,解析台称数据(数值,单位,正负,精度...)

先看说明书梅特勒托利多METTLER TOLEDO

  

 1.从说明书的是数据含有17/18字节 我通过走数据查到是17个字节

 

 const bufferArray = dataString.split("0d")[1]; 
// 02 34 30 20 20 20 20 32 30 34 20 20 20 30 30 30 0d

 2.连续输出格式 5-10字节代表的称指示重量,11-16字节表示皮重重量

 

3.数据是没有小数点的要通过解析算出小数点的位置和正负号

4.状态A,状态B,状态C 需要解析分别表示一些内容

 状态A说明,main.js里面具体操作

      let dataString = data.toString("hex");
      const bufferArray = dataString.split("0d")[1]; 
      // 02 34 30 20 20 20 20 32 30 34 20 20 20 30 30 30 0d
      const bufferfloat = bufferArray.slice(2, 4); 
      // 小数点位置 截取byte第二位 根据说明书转为二进制查看0,1,2位的值判断小数点位置
      let float = parseInt(bufferfloat, 16).toString(2).substr(-3); 
      //16进制转为2进制 截取后三位;

      let de = 1;

      if (float === "100") {
        de = 100;
      } else if (float === "101") {
        de = 1000;
      } else if (float === "110") {
        de = 10000;
      } else if (float === "111") {
        de = 100000;
      }
      
      var value = Number(weight) / de; 

  状态B说明,main.js里面具体操作

 

      let dataString = data.toString("hex");
      const bufferArray = dataString.split("0d")[1]; 
        // 02 34 30 20 20 20 20 32 30 34 20 20 20 30 30 30 0d
      const buffersign = bufferArray.slice(4, 6); 
        // 单位值位置 截取byte第2位 共2位
      let signCode = parseInt(buffersign, 16).toString(2).substr(-2, 1); 
        //16进制转为2进制 截取倒数第2位; 从倒数第2位开始截取1个长度的字符
        // signCode 0=正1=负

   状态C说明,main.js里面具体操作

 


      let dataString = data.toString("hex");
      const bufferArray = dataString.split("0d")[1]; 
        // 02 34 30 20 /20 20 20 32 30 34/ 20 20 20 30 30 30 0d
      const bufferunit = bufferArray.slice(6, 8); // 单位值位置 截取byte第3位 共2位
      let unitCode = parseInt(bufferunit, 16).toString(2).substr(-3);
      let unit = null;
      
if (unitCode === "000") {
        unit = "kg";
      } else {
        unit = "g";
      }

 

main.js 文件处理

  // 打开某个串口
  ipcMain.on("open-serialport", (event, args) => {
    const serialport = new SerialPort(
      {
        path: args.name,
        baudRate: +args.baudRate,
      },
      (err) => {
        console.log(err);
        if (err) {
           event.reply("open-serialport", {
             hasError: true,
             ...args,
             message: err,
           });
        } else {
          event.reply("open-serialport", args);
          ports.push(serialport);
        }
      }
    );
    // 数据量字节17为一组 但发送太过频繁 所以增大10倍 减少页面渲染压力
    const parser = serialport.pipe(new ByteLengthParser({ length: 17 * 10 }));
    parser.on("data", (data) => {
      let dataString = data.toString("hex");
      const bufferArray = dataString.split("0d")[1]; 
        // 02 34 30 20 /20 20 20 32 30 34/ 20 20 20 30 30 30 0d
      const bufferfloat = bufferArray.slice(2, 4); 
        // 小数点位置 截取byte第二位 根据说明书转为二进制查看0,1,2位的值判断小数点位置
      const buffersign = bufferArray.slice(4, 6); 
        // 正负号位置 截取byte第2位 共2位
      const bufferunit = bufferArray.slice(6, 8); 
        // 单位值位置 截取byte第3位 共2位
      const bufferweight = bufferArray.slice(8, 20);
         // 重量值位置 截取byte第5-10位 共6位
      const bufferpeel = bufferArray.slice(20, 32); 
        // 皮重值位置 截取byte第11-16位 共6位

      let float = parseInt(bufferfloat, 16).toString(2).substr(-3); 
        //16进制转为2进制 截取后三位;
      let signCode = parseInt(buffersign, 16).toString(2).substr(-2, 1); 
        //16进制转为2进制 截取倒数第2位; 从倒数第2位开始截取1个长度的字符。
      let unitCode = parseInt(bufferunit, 16).toString(2).substr(-3);

      let weight = hexToString(bufferweight.toString("hex"));
      let peel = hexToString(bufferpeel.toString("hex"));

      let de = 1;
      let unit = null;
      let sign =  signCode;  // sign 0=正1=负
      if (float === "100") {
        de = 100;
      } else if (float === "101") {
        de = 1000;
      } else if (float === "110") {
        de = 10000;
      } else if (float === "111") {
        de = 100000;
      }
      
      if (unitCode === "000") {
        unit = "kg";
      } else {
        unit = "g";
      }
      var value = Number(weight) / de;
      console.log("weights",value,float,weight,unit,peel,bufferArray,dataString,sign);
      sendData(event, {
        value,
        float,
        weight,
        unit,
        de,
        peel,
        bufferArray,
        dataString,
        sign
      });
    });
    serialport.on("open", () => {});
  });

function sendData(event, value) {
  event.sender.send("send-data", value);
}

/**
 * 将16进制字符串进行分组,每两个一组
 * @param  {[String]} str [16进制字符串]
 * @return {[Array]}     [16进制数组]
 */
//处理中文乱码问题
function utf8to16(str) {
  var out, i, len, c;
  var char2, char3;
  out = "";
  len = str.length;
  i = 0;
  while (i < len) {
    c = str.charCodeAt(i++);
    switch (c >> 4) {
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
        out += str.charAt(i - 1);
        break;
      case 12:
      case 13:
        char2 = str.charCodeAt(i++);
        out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f));
        break;
      case 14:
        char2 = str.charCodeAt(i++);
        char3 = str.charCodeAt(i++);
        out += String.fromCharCode(
          ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0)
        );
        break;
    }
  }
  return out;
}

function hexToString(str) {
  // 30 空格 0d跨行
  var val = "",
    len = str.length / 2;
  for (var i = 0; i < len; i++) {
    val += String.fromCharCode(parseInt(str.substr(i * 2, 2), 16));
  }
  return utf8to16(val);
}

detail.vue 页面组装秤重量

console.log("weights",value,float,weight,unit,peel,bufferArray,dataString,sign);
      // 接收到数据 处理数据展示样子 带上小数点,正负号,显示称设置的皮重
      ipcRenderer.on("send-data", (event, args) => {
        if (
          this.resData &&
          ["kg", "千克", "公斤"].includes(this.resData.unit)
        ) {
          if (args.unit === "kg") {
            this.currPortData = args.value;
          } else {
            this.currPortData = args.value / 1000;
          }
        } else if (
          ["g", "克", "斤", "ml", "毫升"].includes(this.resData.unit)
        ) {
          if (args.unit === "g") {
            this.currPortData = args.value;
          } else {
            this.currPortData = args.value * 1000;
          }
        }
        if (args.sign !== "") {
          this.sign = args.sign === "0" ? "" : "-";
        }
      });

9.完成打印需求

待更新..

10.完成自动更新

待更新..

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

macOS Sonoma 14beta 3(23A5286g)发布(附黑/白苹果镜像地址)

系统镜像下载&#xff1a;百度&#xff1a;黑果魏叔 系统介绍 黑果魏叔 7 月 6 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 14 开发者预览版 Beta 3 更新&#xff08;内部版本号&#xff1a;23A5286g&#xff09;&#xff0c;本次更新距离上次发布隔了 14 天。 小…

ELK日志记录——Kibana组件——grok 正则捕获插件

grok 正则捕获插件 grok 使用文本片段切分的方式来切分日志事件 内置正则表达式调用 %{SYNTAX:SEMANTIC} ●SYNTAX代表匹配值的类型&#xff0c;例如&#xff0c;0.11可以NUMBER类型所匹配&#xff0c;10.222.22.25可以使用IP匹配。 ●SEMANTIC表示存储该值的一个变量声明&…

springboot 日志配置(logback)

概述 Java 中的日志框架主要分为两大类&#xff1a;日志门面和日志实现。 Java 中的日志体系&#xff1a; 日志门面 日志门面定义了一组日志的接口规范&#xff0c;它并不提供底层具体的实现逻辑。Apache Commons Logging 和 Slf4j&#xff08;Simple Logging Facade for Jav…

五、卷积神经网络

文章目录 前言一、图像卷积1.1 不变性1.2 互相关运算1.3 卷积层1.4 互相关和卷积1.5 特征映射和感受野 二、填充和步幅2.1 填充2.2 步幅 三、多输入多输出通道3.1 多输入通道3.2 多输出通道3.3 11卷积层 四、汇聚层/池化层4.1 最大汇聚层与平均汇聚层4.2 填充和步幅4.3 多个通道…

2023-7-11-第十六式职责链模式

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

使用大型语言模(LLM)构建系统(七):评估1

今天我学习了DeepLearning.AI的 Building Systems with LLM 的在线课程&#xff0c;我想和大家一起分享一下该门课程的一些主要内容。之前我们已经学习了下面这些知识&#xff1a; 使用大型语言模(LLM)构建系统(一)&#xff1a;分类使用大型语言模(LLM)构建系统(二):内容审核、…

CE-Net

一、贡献 (1)提出DAC模块和RMP模块&#xff0c;以捕获更多高级特征并保留更多空间信息 (2)将所提出的DAC模块和RMP模块与编码器-解码器结构集成在一起&#xff0c;用于医学图像分割 二、方法 (b)部分是shortcut mechanism 空洞卷积 公式化为&#xff1a; 空洞率r对应于对输…

Django_测试模块(六)

目录 开始写我们的第一个测试 首先得有个 Bug 创建一个测试来暴露这个 bug 运行测试 修复这个 bug 更全面的测试 测试视图 针对视图的测试 Django 测试工具之 Client 改善视图代码 测试新视图 测试 DetailView 集中管理用例文件 使用Django测试运行器 源码等资料…

【IDEA】IDEA 版 Postman 新版发布,功能强大!

介绍 Restful Fast Request 是 IDEA 版 Postman&#xff0c;它是一个强大的 restful api 工具包插件&#xff0c;可以根据已有的方法帮助您快速生成 url 和 params。Restful Fast Request API 调试工具 API 管理工具 API 搜索工具。它有一个漂亮的界面来完成请求、检查服务…

力扣竞赛勋章 | 排名分数计算脚本

文章目录 力扣竞赛勋章介绍竞赛评分算法脚本&#xff08;本文的重点内容&#xff09;运行结果 代码修改自&#xff1a;https://leetcode.cn/circle/discuss/6gnvEj/ 原帖子的代码无法正常运行。 力扣竞赛勋章介绍 https://leetcode.cn/circle/discuss/0fKGDu/ 如果你想知道自…

宝塔 安装/使用/备份数据 Jenkins-图文小白教程

一、Jenkins包下载 大家可以从Jenkins官网&#xff08;https://www.jenkins.io/&#xff09;根据自己的需要下载最新的版本。 但Jenkins官网下载较慢&#xff0c;容易造成下载失败。可以去国内的开源镜像网站下载Jenkins最新版本。目前博主使用的是清华大学的开源镜像网站&…

【youcans动手学模型】SENet 模型及 PyTorch 实现

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【youcans动手学模型】SENet 模型 【经典模型】SENet 模型-Cifar10图像分类1. SENet 卷积神经网络模型1.1 模型简介1.2 论文介绍1.3 分析与讨论 2. 在 PyTorch 中定义 SENet 模型类2.1 定义 SE Block…

【ElasticSearch】JavaRestClient实现索引库和文档的增删改查

文章目录 一、RestClient1、什么是RestClient2、导入demo工程3、数据结构分析与索引库创建4、初始化JavaRestClient 二、RestClient操作索引库1、创建索引库2、删除索引库3、判断索引库是否存在 三、RestClient操作文档1、新增文档2、查询文档3、修改文档4、删除文档5、批量导入…

Linux之CentOS_7.9卸载MySQL_5.7全过程实操手册

前言&#xff1a;接以上&#xff0c;前面记录了Windows和Linux环境的MySQL部署&#xff0c;那我们既然都部署完成验证测试那就来个卸载记录吧&#xff0c;便于闭环收尾。 环境&#xff1a; 1、CentOS-7.9-x86_64-DVD-2009.iso 2、MySQL-5.7.42-linux-glibc2.12-x86_641、关闭…

langchain系列1- langchain-ChatGLM

源码阅读 1 服务启动 (demo.queue(concurrency_count3).launch(server_name0.0.0.0,server_port7860,show_apiFalse,shareFalse,inbrowserFalse))这部分代码使用了 Gradio 库提供的两个函数&#xff1a;queue 和 launch。 在这里&#xff0c;demo 是一个 Interface 类的实例…

计算机网络 day3 广播风暴 - VLAN - Trunk

目录 广播风暴&#xff1a; 1.什么是广播风暴&#xff1f; 2.危害&#xff1a; 3.防范 STP生成树协议&#xff1a;(72条消息) 生成树协议 — STP_生成树协议步骤_一下子就醒了的博客-CSDN博客 VLAN&#xff1a; VLAN是什么&#xff1f; VLAN起到的作用&#xff1a; 广…

ChatGPT落地场景探索-数据库与大模型

目录 openGauss介绍 openGauss介绍 数据库与大模型 openGauss介绍 大模型与数据库 大模型为数据库带来的机遇 大模型解决数据库问题的挑战 数据库为大模型带来的价值 大模型大模型的发展趋势 趋势产品&#xff1a;Chat2DB 简介 特性 生产应用&#xff1a;基…

SpringBoot项目模块间通信的两种方式

说明&#xff1a;在微服务架构开发中&#xff0c;一个请求是通过模块之间的互相通信来完成的&#xff0c;如下面这个场景&#xff1a; 创建两个子模块&#xff1a;订单模块&#xff08;端口8081&#xff09;、用户模块&#xff08;端口8082&#xff09;&#xff0c;两个模块之…

设计模式--------行为型模式

行为型模式 行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象行为模式&#xff0c;前者采用继承机制来在类间…

VSCODE VUE3 element-ui plaus 环境搭建

目录 一、VUE 1、安装VUE 2、创建项目 二、Element Plus 1、在项目目录中安装 Element Plus&#xff0c;执行 2、引入element 三、vscode 中运行 1、打开项目文件夹 2、点击debug&#xff0c;运行 1&#xff09;、首次lanch chrome时 2&#xff09;、lanch node.js …