RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密
文章归档:https://www.yuque.com/u27599042/coding_star/cl4dl599pdmtllw1
依赖
- import JSEncrypt from ‘jsencrypt’
pnpm i jsencrypt
- import {stringIsNull} from “@/utils/string_utils.js”:https://www.yuque.com/u27599042/coding_star/slncupw7un3ce7cb
- import {isNumber} from “@/utils/number_utils.js”:https://www.yuque.com/u27599042/coding_star/tuwmm3ghf5lgo4bw
导入依赖
import JSEncrypt from 'jsencrypt'
import {stringIsNull} from "@/utils/string_utils.js"
import {isNumber} from "@/utils/number_utils.js"
内部变量
/*** RSA 加密算法获取密钥对中的公钥使用的 key** @type {string}*/
export const PUBLIC_KEY = 'RSAPublicKey'/*** RSA 加密算法获取密钥对中的密钥使用的 key** @type {string}*/
export const PRIVATE_KEY = 'RSAPrivateKey'/*** RSA 密钥对的 bit 数(密钥对的长度)。* 常用 1024、2048,密钥对的 bit 数,越大越安全,但是越大对服务器的消耗越大** @type {number}*/
let keySize = 1024/*** keySize bit 数下的 RSA 密钥对所能够加密的最大明文大小。* RSA 算法一次能加密的明文长度与密钥长度(RSA 密钥对的 bit 数)成正比,* 默认情况下,Padding 方式为 OPENSSL_PKCS1_PADDING,RSA 算法会使* 用 11 字节的长度用于填充,所以默认情况下,RSA 所能够加密的最大明文大* 小为 (keySize / 8 - 11) byte** @type {number}*/
let maxEncryptPlainTextLen = 117/*** keySize bit 数下的 RSA 密钥对所能够解密的最大密文大小。* (keySize / 8) byte** @type {number}*/
let maxDecryptCipherTextLen = 128/*** 密钥长度为 1024 bit 下,通过公钥生成的密文字符串的长度** @type {number}*/
let cipherTextStrLen = 172
设置 RSA 密钥对的 bit 数
/*** 为 RSA 密钥对的 bit 数赋值,同时重新计算 keySize bit 数下的* RSA 密钥对所能够加密的最大明文大小、所能够解密的最大密文大小** @param size RSA 密钥对的 bit 数*/
export function setKeySize(size) {if (!isNumber(size) || size <= 0) {throw new TypeError("参数 {size} 需要是大于 0 的整数")}keySize = sizemaxEncryptPlainTextLen = keySize / 8 - 11maxDecryptCipherTextLen = keySize / 8
}
获取指定字符的 UTF8 字节大小
/*** 获取指定字符的 UTF8 字节大小* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param charCode 字符编码* @return {number} 指定字符的 UTF8 字节大小*/
export function getCharByteSizeUTF8(charCode) {if (!isNumber(charCode) || charCode < 0) {throw new TypeError("参数 {charCode} 需要是大于 0 的整数")}//字符代码在000000 – 00007F之间的,用一个字节编码if (charCode <= 0x007f) {return 1}//000080 – 0007FF之间的字符用两个字节else if (charCode <= 0x07ff) {return 2}//000800 – 00D7FF 和 00E000 – 00FFFF之间的用三个字节,注: Unicode在范围 D800-DFFF 中不存在任何字符else if (charCode <= 0xffff) {return 3}//010000 – 10FFFF之间的用4个字节else {return 4}
}
获取字符串的 UTF8 字节长度
/*** 获取字符串的 UTF8 字节长度* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @returns {number} 字符串的 UTF8 字节长度*/
export function getStrByteLenUTF8(str) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小strByteLen += getCharByteSizeUTF8(charCode)}return strByteLen
}
获取字符串的 UTF8 字节长度, 同时获取按照指定的子字符串字节长度划分的子字符串数组
/*** 获取字符串的 UTF8 字节长度,同时获取按照指定的子字符串字节长度划分的子字符串数组* 代码参考: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @param subStrByteLen 子字符串字节长度* @return {[]} 按照指定的子字符串字节长度划分的子字符串数组*/
export function getStrByteLenUTF8AndSubStrs(str, subStrByteLen) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}if (!isNumber(subStrByteLen) || subStrByteLen <= 0) {throw new TypeError("参数 {subStrByteLen} 需要是大于 0 的整数")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 记录上一次分隔的字符串的位置let preIdx = 0;// 记录当前子字符串的字节大小let subStrByteSize = 0;// 记录子字符串const subStrs = []// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小let charByteSizeUTF8 = getCharByteSizeUTF8(charCode)strByteLen += charByteSizeUTF8// 当前子字符串的字节大小subStrByteSize += charByteSizeUTF8// 子字符串达到切割长度if (subStrByteSize > subStrByteLen) {// 当前子字符串加入返回结果数组中subStrs.push(str.substring(preIdx, i))// 更新数据preIdx = isubStrByteSize = charByteSizeUTF8}}// 如果还有子字符串还为加入返回结果数组中if (subStrByteSize > 0) {subStrs.push(str.substring(preIdx))}return {strByteLen,subStrs}
}
使用公钥对明文进行加密(支持长文本)
/*** 使用公钥对明文进行加密(支持长文本)** @param publicKey 公钥* @param plainText 明文* @returns {string} 明文加密后的密文*/
export function encryptByPublicKey(publicKey, plainText) {if (stringIsNull(publicKey) || stringIsNull(plainText)) {throw new TypeError("参数 {publicKey} {plainText} 需要非空字符串")}// 获取明文字符串的字节大小和根据指定字节大小划分的子字符串数组const { strByteLen: plainTextByteSize, subStrs: plainTextSubStrArr } = getStrByteLenUTF8AndSubStrs(plainText,maxEncryptPlainTextLen)// 明文加密后的完整密文let cipherText = ""// 对明文进行分段加密plainTextSubStrArr.forEach(subStr => {// 获取加密解密器const encryptor = new JSEncrypt()// 设置公钥encryptor.setPublicKey(publicKey)// 加密cipherText += encryptor.encrypt(subStr)})return cipherText
}
使用私钥对密文进行解密(支持长文本)
注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密
/*** 使用私钥对密文进行解密(支持长文本)* 注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密** @param privateKey 密钥* @param cipherText 密文* @return {string} 密文解密后的明文*/
export function decryptByPrivateKey(privateKey, cipherText) {if (stringIsNull(privateKey) || stringIsNull(cipherText)) {throw new TypeError("参数 {privateKey} {cipherText} 需要非空字符串")}// 获取密文的字符长度let cipherTextLen = cipherText.length// 计算分段解密的次数, cipherTextStrLen 每段密文长度let decryptCount = cipherTextLen / cipherTextStrLen// 解密后的完整明文let plainText = ""// 对密文进行分段解密for (let i = 0; i < decryptCount; i++) {// 分段密文距离开始位置的偏移量let offSet = i * cipherTextStrLenlet subCipherText = cipherText.substring(offSet, offSet + cipherTextLen)// 加密解密器const encryptor = new JSEncrypt()// 设置私钥encryptor.setPrivateKey(privateKey)// 解密plainText += encryptor.decrypt(subCipherText)}return plainText
}
与 RSAUtil 搭配的 Java 后端 RSAUtilInteractiveWithFrontEnd
完整源码
import JSEncrypt from 'jsencrypt'
import {stringIsNull} from "@/utils/string_utils.js"
import {isNumber} from "@/utils/number_utils.js"/*** RSA 加密算法获取密钥对中的公钥使用的 key** @type {string}*/
export const PUBLIC_KEY = 'RSAPublicKey'/*** RSA 加密算法获取密钥对中的密钥使用的 key** @type {string}*/
export const PRIVATE_KEY = 'RSAPrivateKey'/*** RSA 密钥对的 bit 数(密钥对的长度)。* 常用 1024、2048,密钥对的 bit 数,越大越安全,但是越大对服务器的消耗越大** @type {number}*/
let keySize = 1024/*** keySize bit 数下的 RSA 密钥对所能够加密的最大明文大小。* RSA 算法一次能加密的明文长度与密钥长度(RSA 密钥对的 bit 数)成正比,* 默认情况下,Padding 方式为 OPENSSL_PKCS1_PADDING,RSA 算法会使* 用 11 字节的长度用于填充,所以默认情况下,RSA 所能够加密的最大明文大* 小为 (keySize / 8 - 11) byte** @type {number}*/
let maxEncryptPlainTextLen = 117/*** keySize bit 数下的 RSA 密钥对所能够解密的最大密文大小。* (keySize / 8) byte** @type {number}*/
let maxDecryptCipherTextLen = 128/*** 密钥长度为 1024 bit 下,通过公钥生成的密文字符串的长度** @type {number}*/
let cipherTextStrLen = 172/*** 为 RSA 密钥对的 bit 数赋值,同时重新计算 keySize bit 数下的* RSA 密钥对所能够加密的最大明文大小、所能够解密的最大密文大小** @param size RSA 密钥对的 bit 数*/
export function setKeySize(size) {if (!isNumber(size) || size <= 0) {throw new TypeError("参数 {size} 需要是大于 0 的整数")}keySize = sizemaxEncryptPlainTextLen = keySize / 8 - 11maxDecryptCipherTextLen = keySize / 8
}/*** 获取指定字符的 UTF8 字节大小* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param charCode 字符编码* @return {number} 指定字符的 UTF8 字节大小*/
export function getCharByteSizeUTF8(charCode) {if (!isNumber(charCode) || charCode < 0) {throw new TypeError("参数 {charCode} 需要是大于 0 的整数")}//字符代码在000000 – 00007F之间的,用一个字节编码if (charCode <= 0x007f) {return 1}//000080 – 0007FF之间的字符用两个字节else if (charCode <= 0x07ff) {return 2}//000800 – 00D7FF 和 00E000 – 00FFFF之间的用三个字节,注: Unicode在范围 D800-DFFF 中不存在任何字符else if (charCode <= 0xffff) {return 3}//010000 – 10FFFF之间的用4个字节else {return 4}
}/*** 获取字符串的 UTF8 字节长度* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @returns {number} 字符串的 UTF8 字节长度*/
export function getStrByteLenUTF8(str) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小strByteLen += getCharByteSizeUTF8(charCode)}return strByteLen
}/*** 获取字符串的 UTF8 字节长度,同时获取按照指定的子字符串字节长度划分的子字符串数组* 代码参考: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @param subStrByteLen 子字符串字节长度* @return {[]} 按照指定的子字符串字节长度划分的子字符串数组*/
export function getStrByteLenUTF8AndSubStrs(str, subStrByteLen) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}if (!isNumber(subStrByteLen) || subStrByteLen <= 0) {throw new TypeError("参数 {subStrByteLen} 需要是大于 0 的整数")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 记录上一次分隔的字符串的位置let preIdx = 0;// 记录当前子字符串的字节大小let subStrByteSize = 0;// 记录子字符串const subStrs = []// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小let charByteSizeUTF8 = getCharByteSizeUTF8(charCode)strByteLen += charByteSizeUTF8// 当前子字符串的字节大小subStrByteSize += charByteSizeUTF8// 子字符串达到切割长度if (subStrByteSize > subStrByteLen) {// 当前子字符串加入返回结果数组中subStrs.push(str.substring(preIdx, i))// 更新数据preIdx = isubStrByteSize = charByteSizeUTF8}}// 如果还有子字符串还为加入返回结果数组中if (subStrByteSize > 0) {subStrs.push(str.substring(preIdx))}return {strByteLen,subStrs}
}/*** 使用公钥对明文进行加密(支持长文本)** @param publicKey 公钥* @param plainText 明文* @returns {string} 明文加密后的密文*/
export function encryptByPublicKey(publicKey, plainText) {if (stringIsNull(publicKey) || stringIsNull(plainText)) {throw new TypeError("参数 {publicKey} {plainText} 需要非空字符串")}// 获取明文字符串的字节大小和根据指定字节大小划分的子字符串数组const { strByteLen: plainTextByteSize, subStrs: plainTextSubStrArr } = getStrByteLenUTF8AndSubStrs(plainText,maxEncryptPlainTextLen)// 明文加密后的完整密文let cipherText = ""// 对明文进行分段加密plainTextSubStrArr.forEach(subStr => {// 获取加密解密器const encryptor = new JSEncrypt()// 设置公钥encryptor.setPublicKey(publicKey)// 加密cipherText += encryptor.encrypt(subStr)})return cipherText
}/*** 使用私钥对密文进行解密(支持长文本)* 注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密** @param privateKey 密钥* @param cipherText 密文* @return {string} 密文解密后的明文*/
export function decryptByPrivateKey(privateKey, cipherText) {if (stringIsNull(privateKey) || stringIsNull(cipherText)) {throw new TypeError("参数 {privateKey} {cipherText} 需要非空字符串")}// 获取密文的字符长度let cipherTextLen = cipherText.length// 计算分段解密的次数, cipherTextStrLen 每段密文长度let decryptCount = cipherTextLen / cipherTextStrLen// 解密后的完整明文let plainText = ""// 对密文进行分段解密for (let i = 0; i < decryptCount; i++) {// 分段密文距离开始位置的偏移量let offSet = i * cipherTextStrLenlet subCipherText = cipherText.substring(offSet, offSet + cipherTextLen)// 加密解密器const encryptor = new JSEncrypt()// 设置私钥encryptor.setPrivateKey(privateKey)// 解密plainText += encryptor.decrypt(subCipherText)}return plainText
}
相关文章:
RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密
文章归档:https://www.yuque.com/u27599042/coding_star/cl4dl599pdmtllw1 依赖 import JSEncrypt from ‘jsencrypt’ pnpm i jsencryptimport {stringIsNull} from “/utils/string_utils.js”:https://www.yuque.com/u27599042/coding_star/slncupw…...
uniapp map polygons 区域填充色(fillColor)在ios显示正常,但在安卓手机显示是黑色的,怎么解决?
uniapp map polygons 区域填充色(fillColor)在ios显示正常,但在安卓手机显示是黑色的,怎么解决? <MapPage :longitude"item.centerCoord[0]" :latitude"item.centerCoord[1]":polygons"[{ points: it…...
OSCAR数据库上锁问题如何排查
关键字 oscar lock 问题描述 oscar 数据库上锁问题如何排查 解决问题思路 准备数据 create table lock_test(name varchar(10),age varchar(10));insert into lock_test values(ff,10); insert into lock_test values(yy,20); insert into lock_test values(ll,30);sessio…...
FPGA与人工智能泛谈-01
文章目录 前言一、FPGA(Field Programmable Gate Array)是什么?二、与GPU的对比1.GPU特点2. FPGA的优势三、人工智能实现的基础架构总结前言 人工智能技术的快速发展正从各个方面改变人类的生活、工作及教育等各个方面,其中人工智能算法的演进又是其中的关键一步,其中会涉及…...
【VASP】POTCAR文件
【VASP】POTCAR文件 POTCAR 文件的介绍qvasp 生成POTCARvaspkit 生成POTCAR再来认识一下各种赝势如何区分US、PAW、LDA、GGA、PW91 前言 一、4个常用的输入文件INCAR、POSCAR、POTCAR、KPOINTS INCAR: 计算任务类型是什么?怎么计算? KPOINTS: 包含了倒易…...
棒球俱乐部青少年成长体系·棒球1号位
棒球俱乐部青少年成长体系介绍 1. 培养理念 简要介绍棒球俱乐部的宗旨和培养青少年的目标 棒球俱乐部是一个致力于培养青少年棒球运动员的体育组织,其宗旨是通过提供专业的棒球训练和比赛机会,帮助青少年提高身体素质、培养团队合作精神和塑造积极向上…...
折叠式菜单怎么做编程,初学编程系统化教程初级1上线
中文编程系统化教程,不需英语基础,学习链接——入门篇课程 https://edu.csdn.net/course/detail/39036中文编程系统化教程,不需英语基础,学习链接—— 初级1课程 https://edu.csdn.net/course/detail/39061 ——————————…...
与AI对话,如何写好prompt?
玩转AIGC,优质的Prompt提示词实在是太重要了!同样的问题,换一个问法,就会得到差别迥异的答案。你是怎样和AI进行对话交流的呢?我来分享几个: 请告诉我…我想知道…对于…你有什么看法?帮我解决…...
基于YOLOv8模型和UA-DETRAC数据集的车辆目标检测系统(PyTorch+Pyside6+YOLOv8模型)
摘要:基于YOLOv8模型和UA-DETRAC数据集的车辆目标检测系统可用于日常生活中检测与定位汽车(car)、公共汽车(bus)、面包车(vans)等目标,利用深度学习算法可实现图片、视频、摄像头等方…...
0037【Edabit ★☆☆☆☆☆】【修改Bug 2】Buggy Code (Part 2)
0037【Edabit ★☆☆☆☆☆】【修改Bug 2】Buggy Code (Part 2) bugs language_fundamentals Instructions Fix the code in the code tab to pass this challenge (only syntax errors). Look at the examples below to get an idea of what the function should do. Exampl…...
【算法中的Java】— 判断语句
📒博客首页:Sonesang的博客 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 ❤️ :热爱Java与算法学习,期待一起交流! 🙏作者水平很有限,如果发现错误…...
【单例模式】饿汉式,懒汉式?JAVA如何实现单例?线程安全吗?
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ 单例设计模式 Java单例设计模式 Java单例设计模…...
Spark_SQL-DataFrame数据写出以及读写数据库(以MySQl为例)
一、数据写出 (1)SparkSQL统一API写出DataFrame数据 二、写出MySQL数据库 一、数据写出 (1)SparkSQL统一API写出DataFrame数据 统一API写法: 常见源写出: # cording:utf8from pyspark.sql import SparkSes…...
Linux进程终止
文章目录 进程退出场景进程退出码strerrorerrno浅谈进程异常exit && _exit 进程退出场景 代码运行完毕,结果正确代码运行完毕,结果不正确代码异常 进程退出码 我们写的C/C的代码,main函数每次都需要返回0,而这个return…...
0036【Edabit ★☆☆☆☆☆】【让我加油】Let‘s Fuel Up!
0036【Edabit ★☆☆☆☆☆】【让我加油 】Let’s Fuel Up! control_flow language_fundamentals numbers Instructions A vehicle needs 10 times the amount of fuel than the distance it travels. However, it must always carry a minimum of 100 fuel before setting o…...
React 中常用的几种路由跳转方式
目录 一、push跳转 1、Link组件: 二、replace跳转 三、goBack跳转(回退) 四、goForward跳转(前进) 五、 go跳转(向前或向后跳转指定步数) 一、push跳转 1、Link组件: 可以在不刷新…...
C++内存管理:其七、标准库中的allocator
首先明确一点,绝大多数情况下,是标准库中的容器使用allocator。因为容器需要频繁的申请和释放内存。 一、容器使用allocator 典型的例子: vector<int , allocator<int>> a;但是为什么我们通常的定义vector变量的方法是&#x…...
【机器学习合集】人脸表情分类任务Pytorch实现TensorBoardX的使用 ->(个人学习记录笔记)
人脸表情分类任务 注意:整个项目来自阿里云天池,下面是开发人员的联系方式,本人仅作为学习记录!!!该文章原因,学习该项目,完善注释内容,针对新版本的Pytorch进行部分代码…...
Maven - 国内 Maven 镜像仓库(加速包,冲冲冲~)
<?xml version"1.0" encoding"UTF-8" ?><!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding…...
【Solidity】智能合约案例——③版权保护合约
目录 一、合约源码分析: 二、合约整体流程: 1.部署合约: 2.添加实体: 3.查询实体 4.审核版权: 5.版权转让 一、合约源码分析: Copyright.sol:主合约,定义了版权局的实体ÿ…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
(二)TensorRT-LLM | 模型导出(v0.20.0rc3)
0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述,后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作,其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
