Vue、uniApp、微信小程序、Html5等实现数缓存
此文章带你实现前端缓存,利用时间戳封装一个类似于Redis可以添加过期时间的缓存工具
不仅可以实现对缓存数据设置过期时间,还可以自定义是否需要对缓存数据进行加密处理
工具介绍说明
对缓存数据进行非对称加密处理

对必要数据进行缓存,并设置过期时间,并设置是否需要对缓存数据进行加密处理

其他工具

1、
过期时间:封装好的工具,可以添加数据的缓存时长(过期时间)
2、是否加密:可以根据需求,是否需要对缓存的数据进行加密处理
3、加密解密:只需要简单配置,就可以实现缓存数据的加密解密功能
4、长期有效:对于不需要过期的数据,只要不手动清理可以长期有效
5、扩展性强:可以根据自己的需求直接进行代码的调整,简单易懂易扩展
本地缓存
1、
Vue、Html5的数据缓存可以存放到localStorage、cookie或者sessionStorage中
2、uniApp、和微信小程序的数据缓存可以使用自带的APIuni.setStorageSync
缓存的缺点
1、无论
localStorage、cookie、sessionStorage还是uni.setStorageSync都没有过期时间的限制
2、不能对数据进行实时的加解密处理,或者加解密扩展性差
3、对于大量旧的缓存数据还要手动处理,不能实时的去除旧数据
简单封装
代码以
uniApp为例,先实现可以添加过期时间的功能
缓存工具类:cacheUtil.js
const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './utils.js';/*** 添加缓存* @param {String} key 缓存的key* @param {Object} val 缓存的val* @param {Number} expire 过期时间(单位:秒)* @returns {Boolean} 成功 | 失败*/
export const setCache = (key, val, expire) => {if (isEmpty(key)) return false;expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));let param = JSON.stringify({data: val, // 缓存的数据expire: expire // 过期时间});key = keyPrefix + key; // 缓存的keyuni.setStorageSync(key, param); // 同步缓存return true;
}/*** 获取缓存的数据* @param {String} key 缓存key* @returns {Object}*/
export const getCache = (key) => {if (isEmpty(key)) return {};key = keyPrefix + key;let value = uni.getStorageSync(key) || '';if (value.includes('data') && value.includes('expire')) {value = JSON.parse(value) || {};let expire = value.expire || '';if (isEmpty(expire) || !isNumberStr(expire)) {return value.data || '';}expire = Number(expire) || 0;if (expire < Date.now()) {removeKeys(key);return {};}}return value.data;
}/*** 获取缓存有效时长,单位:秒* @param {String} key 缓存的key* @param {Number} unit 0:毫秒,1:秒,2:分钟,默认毫秒值* @returns {Number} 有效时长*/
export const getExpire = (key, unit) => {if (isEmpty(key)) return 0;key = keyPrefix + key;let value = uni.getStorageSync(key) || '';if (value.includes('data') && value.includes('expire')) {value = JSON.parse(value) || {};let expire = Number(value.expire || 0);if (unit === 1) return expire / 1000;if (unit === 2) return expire / 1000 / 60;return expire;}return 0;
}/*** 给缓存设置过期时间* @param {String} key 缓存数据的key* @param {Number} expire 过期时长(单位:秒)*/
export const setExpire = (key, expire) => {let value = getCache(key) || {};setCache(key, value, expire);
}/*** 删除缓存数据* @param keys 删除缓存,多个key之间使用,隔开* @returns {Number} 删除条数*/
export const removeKeys = (...keys) => {if (isEmpty(keys)) return 0;keys.forEach((key, index) => {key = keyPrefix + key;uni.removeStorageSync(key); // 同步删除});return keys.length;
}/*** 清空所有缓存*/
export const clearAll = () => {uni.clearStorageSync(); // 同步清除
}
数据加解密
我这里使用的使用非对称加密,根据个人项目需求可进行调整
加解密工具类:jsencryptUtil.js
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
const encryptor = new JSEncrypt();
const publicKey = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALg
CXvS1JPTluyIqr3eie4mqkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQ==
-----END PUBLIC KEY-----`;
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALgCXvS1JPTluyIqr3eie4m
qkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQJABNYdbvX2nbC8vxoYBLal
wO9kTFfhLH++O9k6Hiop2k5wjbl7FlOBUr7iEeFxdYeuT0JcNyLVeGphKZAS9HlR
0QIhALWpLQaV/UFD/E3lTtkCd890Hn6noLKCOxMRcwtx22oxAiEA2ublehWoGwA5
F+GL9s7B9AgMOwzX0Z43F4fzCfAwCF8CIGYhR6QVPT2tKDLvAWY14f/q654PReQ2
HVo6DDDaAR5xAiEAgyFMGD0+7aXNjcO8D4Y944yqnvkLk/N+NydmbO6oJ2sCIAzn
bQCPl4yK81yVTdUA0fMKWRZn3vJ2C11AaemSs42C
-----END RSA PRIVATE KEY-----`;/*** 使用公钥进行加密处理* @param {string} txt 明文字符串*/
export function encrypt(txt) {// 设置公钥encryptor.setPublicKey(publicKey); // 对数据进行加密return encryptor.encrypt(txt);
}/*** 使用私钥进行解密处理* @param {string} enc 密文字符串*/
export function decrypt(enc) {// 设置私钥encryptor.setPrivateKey(privateKey);// 对数据进行解密return encryptor.decrypt(enc);
}
完善缓存工具
const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './utils.js';
import { encrypt, decrypt } from './jsencryptUtil.js';/*** 添加缓存* @param {String} key 缓存的key* @param {Object} val 缓存的val* @param {Number} expire 过期时间(单位:秒)* @param {Boolean} enc 是否需要加密处理:true | false* @returns {Boolean} 成功 | 失败*/
export const setCache = (key, val, expire, enc) => {if (isEmpty(key)) return false;expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));let param = JSON.stringify({data: val, // 缓存的数据expire: expire // 过期时间});if (enc === true) param = encrypt(param );key = keyPrefix + key; // 缓存的keyuni.setStorageSync(key, param); // 同步缓存return true;
}/*** 获取缓存的数据* @param {String} key 缓存key* @param {Boolean} dec 是否需要解密处理:true | false* @returns {Object}*/
export const getCache = (key, dec) => {if (isEmpty(key)) return {};key = keyPrefix + key;let value = uni.getStorageSync(key) || '';if (dec === true) value = decrypt(value);if (value.includes('data') && value.includes('expire')) {value = JSON.parse(value) || {};let expire = value.expire || '';if (isEmpty(expire) || !isNumberStr(expire)) {return value.data || '';}expire = Number(expire) || 0;if (expire < Date.now()) {removeKeys(key);return {};}}return value.data;
}/*** 删除缓存数据* @param keys 删除缓存,多个key之间使用,隔开* @returns {Number} 删除条数*/
export const removeKeys = (...keys) => {if (isEmpty(keys)) return 0;keys.forEach((key, index) => {key = keyPrefix + key;uni.removeStorageSync(key); // 同步删除});return keys.length;
}/*** 清空所有缓存*/
export const clearAll = () => {uni.clearStorageSync(); // 同步清除
}
这样就可以对缓存的数据进行加密处理了
每次都要传入一个参数来确定是否需要加密或者解密处理,太繁琐了
能不能不需要我来传是否需要解密呢?根据加密参数进行判断?答案时可以的
接下来,我们先处理一下加解密工具,对于很长很长的明文数据进行加密时,加密工具会报错
下面对加密工具进行改造,改造完成之后,再来进一步完善缓存工具,不用每次都传入解密标志
加密太长报错
使用
JSEncrypt加密数据时,对于比较长的字符串,加密时会出现异常报错,并提示数据太大
解决方法:需要对加密工具进行一次改造处理
修改加密工具
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
const encryptor = new JSEncrypt();
const publicKey = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALg
CXvS1JPTluyIqr3eie4mqkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQ==
-----END PUBLIC KEY-----`;
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALgCXvS1JPTluyIqr3eie4m
qkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQJABNYdbvX2nbC8vxoYBLal
wO9kTFfhLH++O9k6Hiop2k5wjbl7FlOBUr7iEeFxdYeuT0JcNyLVeGphKZAS9HlR
0QIhALWpLQaV/UFD/E3lTtkCd890Hn6noLKCOxMRcwtx22oxAiEA2ublehWoGwA5
F+GL9s7B9AgMOwzX0Z43F4fzCfAwCF8CIGYhR6QVPT2tKDLvAWY14f/q654PReQ2
HVo6DDDaAR5xAiEAgyFMGD0+7aXNjcO8D4Y944yqnvkLk/N+NydmbO6oJ2sCIAzn
bQCPl4yK81yVTdUA0fMKWRZn3vJ2C11AaemSs42C
-----END RSA PRIVATE KEY-----`;/*** 使用公钥进行加密处理* @param {string} txt 明文字符串*/
export function encrypt(txt) {encryptor.setPublicKey(publicKey); // 设置公钥if (txt.length > 100) {let result = "";while (txt && txt.length > 0) {let dl = txt.slice(0, 100);txt = txt.slice(100);if (!result) {result = result + encryptor.encrypt(dl);} else {result = result + "~" + encryptor.encrypt(dl);}}return result;}return encryptor.encrypt(txt); // 对数据进行加密
}/*** 使用私钥进行解密处理* @param {string} enc 密文字符串*/
export function decrypt(enc) {// 设置私钥encryptor.setPrivateKey(privateKey);if (enc.includes("~")) {let result = "";let arr = enc.split("~");for (let i = 0; i < arr.length; i++) {if (arr[i] && arr[i].length > 0) {result = result + encryptor.decrypt(arr[i]);}}return result;}return encryptor.decrypt(enc);
}
改造缓存工具
const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './util.js';
import { encrypt, decrypt } from './jsencryptUtil.js';/*** 添加缓存* @param {String} key 缓存的key* @param {Object} val 缓存的val* @param {Number} expire 过期时间(单位:秒)* @param {Boolean} enc 是否需要加密处理:true | false* @returns {Boolean} 成功 | 失败*/
export const setCache = (key, val, expire, enc) => {if (isEmpty(key)) return false;expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));enc = enc === true;let param = JSON.stringify({data: (enc ? encrypt(val) : val), // 缓存的数据encrypt: enc, // 数据加密标志expire: expire // 过期时间});key = keyPrefix + key; // 缓存的keyuni.setStorageSync(key, param); // 同步缓存return true;
}/*** 获取缓存的数据* @param {String} key 缓存key* @returns {Object}*/
export const getCache = (key) => {if (isEmpty(key)) return {};key = keyPrefix + key;let value = uni.getStorageSync(key) || '';if (value.includes('data') && value.includes('expire')) {value = JSON.parse(value) || {};let expire = value.expire || '';let dec = value.encrypt == true;if (dec) value.data = decrypt(value.data);if (isEmpty(expire) || !isNumberStr(expire)) {return value.data || '';}expire = Number(expire) || 0;if (expire < Date.now()) {removeKeys(key);return {};}}return value;
}/*** 删除缓存数据* @param keys 删除缓存,多个key之间使用,隔开* @returns {Number} 删除条数*/
export const removeKeys = (...keys) => {if (isEmpty(keys)) return 0;keys.forEach((key, index) => {key = keyPrefix + key;uni.removeStorageSync(key); // 同步删除});return keys.length;
}/*** 清空所有缓存*/
export const clearAll = () => {uni.clearStorageSync(); // 同步清除
}
到此,缓存工具就完成了,只要在缓存时传入是否需要加密的参数就可以了,解密时只需要传入key就可以了,不需要再额外传入解密参数
最终完整代码
util工具
util.js
/*** 判断数据是否为空* @param {*} input 原数据* @return {Boolean}*/
export const isEmpty = (input) => {if (Object.prototype.toString.call(input) === '[object Object]') {let vals = Object.values(input) || [];let num = 0;for (let val of vals) {val = (!val ? '' : JSON.stringify(val)).trim().replace(/\s*/g, "");num = !val ? num + 1 : num;}return vals.length === num;}if (typeof input !== 'string') input = (!input ? '' : JSON.stringify(input)).trim().replace(/\s*/g, "");return !input || input.length === 0 || (['[]', '{}', 'NaN', 'null', 'undefined'].includes(input));
}/*** 去除特殊字符,包括但不限于空格、制表符\t、换行符\r、回车符\n* @param {string} input 原数据* @return {string}*/
export const trimAllBlank = (input) => {input = typeof input === 'string' ? input.trim() : JSON.stringify(input);return (input || '').replace(/\s*/g, "");
}/*** 是否数字* @param {string} str 字符串* @returns {boolean}*/
export const isNumberStr = (str) => {str = isEmpty(str) ? '' : str;return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str);
}
加密工具
jsencryptUtil.js
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min';
const publicKey = `-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALg
CXvS1JPTluyIqr3eie4mqkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQ==
-----END PUBLIC KEY-----`;
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAJtV6S0G6O9LpOVx/riiZzNk1gAl1ALgCXvS1JPTluyIqr3eie4m
qkVdFROjNpCxvtXkRtisB9PlmU9YOPTt8C8CAwEAAQJABNYdbvX2nbC8vxoYBLal
wO9kTFfhLH++O9k6Hiop2k5wjbl7FlOBUr7iEeFxdYeuT0JcNyLVeGphKZAS9HlR
0QIhALWpLQaV/UFD/E3lTtkCd890Hn6noLKCOxMRcwtx22oxAiEA2ublehWoGwA5
F+GL9s7B9AgMOwzX0Z43F4fzCfAwCF8CIGYhR6QVPT2tKDLvAWY14f/q654PReQ2
HVo6DDDaAR5xAiEAgyFMGD0+7aXNjcO8D4Y944yqnvkLk/N+NydmbO6oJ2sCIAzn
bQCPl4yK81yVTdUA0fMKWRZn3vJ2C11AaemSs42C
-----END RSA PRIVATE KEY-----`;/*** 使用公钥进行加密处理* @param {string} txt 明文字符串*/
export function encrypt(txt) {const encryptor = new JSEncrypt();encryptor.setPublicKey(publicKey); // 设置公钥if (txt.length > 100) {let result = "";while (txt && txt.length > 0) {let dl = txt.slice(0, 100);txt = txt.slice(100);if (!result) {result = result + encryptor.encrypt(dl);} else {result = result + "~" + encryptor.encrypt(dl);}}return result;}return encryptor.encrypt(txt); // 对数据进行加密
}/*** 使用私钥进行解密处理* @param {string} enc 密文字符串*/
export function decrypt(enc) {const encryptor = new JSEncrypt();encryptor.setPrivateKey(privateKey);if (enc.includes("~")) {let result = "";let arr = enc.split("~");for (let i = 0; i < arr.length; i++) {if (arr[i] && arr[i].length > 0) {result = result + encryptor.decrypt(arr[i]);}}return result;}return encryptor.decrypt(enc);
}
缓存工具
cacheUtil.js
const expiration = 1000 * 60 * 60 * 24 * 7; // 默认有效期7天
const keyPrefix = 'KEY_'; // 缓存key的统一前缀
import { isEmpty, isNumberStr, trimAllBlank } from './util.js';
import { encrypt, decrypt } from './jsencryptUtil.js';/*** 添加缓存* @param {String} key 缓存的key* @param {Object} val 缓存的val* @param {Number} expire 过期时间(单位:秒)* @param {Boolean} enc 是否需要加密处理:true | false* @returns {Boolean} 成功 | 失败*/
export const setCache = (key, val, expire, enc) => {if (isEmpty(key)) return false;expire = expire && isNumberStr(expire) ? Number(trimAllBlank(expire)) : 0;expire = Date.now() + (expire <= 0 ? expiration : (expire * 1000));enc = enc === true;let param = JSON.stringify({data: (enc ? encrypt(val) : val), // 缓存的数据encrypt: enc, // 数据加密标志expire: expire // 过期时间});key = keyPrefix + key; // 缓存的keyuni.setStorageSync(key, param); // 同步缓存return true;
}/*** 获取缓存的数据* @param {String} key 缓存key* @returns {Object}*/
export const getCache = (key) => {if (isEmpty(key)) return {};key = keyPrefix + key;let value = uni.getStorageSync(key) || '';if (value.includes('data') && value.includes('expire')) {value = JSON.parse(value) || {};let expire = value.expire || '';let dec = value.encrypt == true;if (dec) value.data = decrypt(value.data);if (isEmpty(expire) || !isNumberStr(expire)) {return value.data || '';}expire = Number(expire) || 0;if (expire < Date.now()) {removeKeys(key);return {};}}return value;
}/*** 获取缓存有效时长,单位:秒* @param {String} key 缓存的key* @param {Number} unit ms:毫秒,s:秒,m:分钟,默认毫秒值* @returns {Number} 有效时长*/
export const getExpire = (key, unit) => {if (isEmpty(key)) return 0;key = keyPrefix + key;let value = uni.getStorageSync(key) || '';if (value.includes('data') && value.includes('expire')) {value = JSON.parse(value) || {};let expire = Number(value.expire || 0);unit = unit.toLowerCase();if (unit === "s") return expire / 1000;if (unit === "m") return expire / 1000 / 60;return expire;}return 0;
}/*** 给缓存设置过期时间* @param {String} key 缓存数据的key* @param {Number} expire 过期时长(单位:秒)*/
export const setExpire = (key, expire) => {let value = getCache(key) || {};setCache(key, value, expire);
}/*** 删除缓存数据* @param keys 删除缓存,多个key之间使用,隔开* @returns {Number} 删除条数*/
export const removeKeys = (...keys) => {if (isEmpty(keys)) return 0;keys.forEach((key, index) => {key = keyPrefix + key;uni.removeStorageSync(key); // 同步删除});return keys.length;
}/*** 清空所有缓存*/
export const clearAll = () => {uni.clearStorageSync(); // 同步清除
}
其他语言改造
vue:vue中使用时,需要将uni.xxxStorage(...)替换为localStorage或者sessionStorage
html5:和vue一样,需要将uni.xxxStorage(...)替换为localStorage或者sessionStorage
微信小程序:需要将uni.xxxStorage(...)替换为wx.xxxStorage(...)
localStorage和sessionStorage的区别:
sessionStorage:只在本次会话有效,关闭浏览器数据将被删除
localStorage:如果不手动删除,则长期有效,关闭浏览器数据也不会被清除
相关文章:
Vue、uniApp、微信小程序、Html5等实现数缓存
此文章带你实现前端缓存,利用时间戳封装一个类似于Redis可以添加过期时间的缓存工具 不仅可以实现对缓存数据设置过期时间,还可以自定义是否需要对缓存数据进行加密处理 工具介绍说明 对缓存数据进行非对称加密处理 对必要数据进行缓存,并…...
如何将ArcGIS工程文件迁移到ArcGIS Pro内
当你刚接触ArcGIS Pro的时候,尝试新建一个工程文件会发现工程文件的后缀已经改变,那么以前在ArcGIS内辛苦制作的工程文件是否就不能在ArcGIS Pro内使用了,答案是否定的,对此Esri也给出了解决方案,这里为大家介绍一下迁…...
Jenkins基础篇--添加用户和用户权限设置
添加用户 点击系统管理,点击管理用户,然后点击创建用户(Create User) 用户权限管理 点击系统管理,点击全局安全配置,找到授权策略,选择安全矩阵,配置好用户权限后,点击…...
C语言基础内容(七)——第08章_C语言常用函数
文章目录 第08章_C语言常用函数本章专题脉络1、字符串相关函数1.1 字符串的表示方式1.2 两种方式的区别1.2 字符串常用函数strlen()strcpy()strncpy()strcat()strncat()strcmp()strlwr()/strupr()1.3 基本数据类型和字符串的转换基本数据类型 -> 字符串字符串 -> 基本数据…...
CRM系统针对销售管理有哪些功能?如何帮助销售效率增长?
从长远来看,有效的CRM管理系统可以帮助您的企业达到甚至超过收入目标。现代大多数企业都依靠CRM系统来管理其销售周期并增加收入。但是,当大多数人提到CRM时,他们指的是使能够改善业务关系并轻松管理不断团队的软件或工具。合格的CRM系统能够…...
基于Pixhawk和ROS搭建自主无人车(一):底盘控制篇
参考 ArduPilot Development超维空间科技乐迪MiniPix车船使用说明书 1. 硬件篇 1.1 底盘构成一览 1.2 底盘接线示意 2. 软件篇 2.1 APM 固件下载 pixhawk 是硬件平台,PX4 是 pixhawk 的原生固件,APM(Ardupilot Mega)是硬件平台…...
部署 Spring Boot 应用中文文档
本文为官方文档直译版本。原文链接 部署 Spring Boot 应用中文文档 引言部署到云Cloud Foundry与服务绑定 KubernetesKubernetes 容器生命周期 HerokuOpenShift亚马逊网络服务(AWS)AWS Elastic Beanstalk使用 Tomcat 平台使用 Java SE 平台 总结 CloudCa…...
【数据库原理】(23)实际应用中的查询优化方法
一.基于索引的优化 索引是数据库查询优化的关键工具之一。合理地使用索引可以显著提高查询速度,降低全表扫描的成本。以下是建立和使用索引的一些基本原则和最佳实践。 索引的建立与使用原则 数据量规模与查询频率: 值得建立索引的表通常具有较多的记录࿰…...
MySQL中datetime和timestamp的区别
datetime和timestamp的区别 相同点: 存储格式相同 datetime和timestamp两者的时间格式都是YYYY-MM-DD HH:MM:SS 不同点: 存储范围不同. datetime的范围是1000-01-01到9999-12-31. 而timestamp是从1970-01-01到2038-01-19, 即后者的时间范围很小. 与时区关系. datetime是存储…...
2024年如何使用WordPress构建克隆Udemy市场
您想创建像 Udemy 这样的学习管理 (LMS) 网站吗?最好的学习管理系统工具LifterLMS将帮助您制作像Udemy市场这样的 LMS 网站。 目录 Udemy市场是什么? 创建 Udemy 克隆所需的几项强制性技术: 步骤 1) 注册您的域名 步骤 2) 获取虚拟主…...
(leetcode)Z字形变换 -- 模拟算法
个人主页:Lei宝啊 愿所有美好如期而遇 题目链接 . - 力扣(LeetCode) 输入描述 string convert(string s, int numRows),输入一个字符串s,以及一个行数numRows,将字符串按照这个行数进行Z字形排列&…...
STM32--基于STM32F103的MAX30102心率血氧测量
本文介绍基于STM32F103ZET6MAX30102心率血氧测量0.96寸OLED(7针)显示(完整程序代码见文末链接) 一、简介 MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块。它集成了一个红光LED和一个红外光LED、光电检测器、光器…...
Qt/C++音视频开发63-设置视频旋转角度/支持0-90-180-270度旋转/自定义旋转角度
一、前言 设置旋转角度,相对来说是一个比较小众的需求,如果视频本身带了旋转角度,则解码播放的时候本身就会旋转到对应的角度显示,比如手机上拍摄的视频一般是旋转了90度的,如果该视频文件放到电脑上打开,一些早期的播放器可能播放的时候是躺着的,因为早期播放器设计的…...
Python电能质量扰动信号分类(五)基于CNN-Transformer的一维信号分类模型
目录 往期精彩内容: 引言 1 数据集制作与加载 1.1 导入数据 1.2 制作数据集 2 CNN-Transformer分类模型和超参数选取 2.1定义CNN-Transformer分类模型 2.2 设置参数,训练模型 3 模型评估 3.1 准确率、精确率、召回率、F1 Score 3.2 十分类混淆…...
基于Vue组合式API的实用工具集
简介 今天,给大家分享一个很实用的工具库 VueUse,它是基于 Vue Composition Api,也就是组合式API。支持在Vue2和Vue3项目中进行使用,据说是目前世界上Star最高的同类型库之一。 图片 官方地址:https://vueuse.org/ 中文地址:https://www.vueusejs.com/ github:https…...
065:vue中将一维对象数组转换为二维对象数组
第065个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下,本专栏提供行之有效的源代码示例和信息点介绍,做到灵活运用。 (1)提供vue2的一些基本操作:安装、引用,模板使…...
mysql 字符串分割
目录 前言substring_indexsubstring_index 特性字符串分割 前言 略 substring_index 正向截取字符串 mysql> select substring_index(www.baidu.com,.,1); ---------------------------------------- | substring_index(www.baidu.com,.,1) | -------------------------…...
解决Windows11 “我们无法设置移动热点”
目录 问题复现解决办法①启动网络适配器②打开移动热点③共享网络连接④连接移动热点总结 问题复现 因为交换机上网口限制,开发环境暂时没有WIFI设备,只有一根网线和一台笔记本电脑。于是开启笔记本电脑的WiFi共享服务。结果提示 “我们无法设置移动热点…...
python tcp socket中实现SSL/TLS认证
SSL/TLS介绍 官话说SSL是安全套接层(secure sockets layer),TLS是SSL的继任者,叫传输层安全(transport layer security)。 说白点,就是在明文的上层和TCP层之间加上一层加密,这样就保证上层信息传输的安全。如HTTP协议是明文传输…...
SQL-修改表操作
🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页:小小恶斯法克的博客 🎈该系列文章专栏:重拾MySQL 🍹文章作者技术和水平很有限,如果文中出现错误&am…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
