当前位置: 首页 > news >正文

Vue、uniApp、微信小程序、Html5等实现数缓存

此文章带你实现前端缓存,利用时间戳封装一个类似于Redis可以添加过期时间的缓存工具
不仅可以实现对缓存数据设置过期时间,还可以自定义是否需要对缓存数据进行加密处理

工具介绍说明

对缓存数据进行非对称加密处理
在这里插入图片描述
对必要数据进行缓存,并设置过期时间,并设置是否需要对缓存数据进行加密处理
在这里插入图片描述
其他工具
在这里插入图片描述

1、过期时间:封装好的工具,可以添加数据的缓存时长(过期时间)
2、是否加密:可以根据需求,是否需要对缓存的数据进行加密处理
3、加密解密:只需要简单配置,就可以实现缓存数据的加密解密功能
4、长期有效:对于不需要过期的数据,只要不手动清理可以长期有效
5、扩展性强:可以根据自己的需求直接进行代码的调整,简单易懂易扩展

本地缓存

1、VueHtml5 的数据缓存可以存放到localStoragecookie 或者 sessionStorage
2、uniApp、和 微信小程序 的数据缓存可以使用自带的API uni.setStorageSync

缓存的缺点

1、无论localStoragecookiesessionStorage 还是 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等实现数缓存

此文章带你实现前端缓存&#xff0c;利用时间戳封装一个类似于Redis可以添加过期时间的缓存工具 不仅可以实现对缓存数据设置过期时间&#xff0c;还可以自定义是否需要对缓存数据进行加密处理 工具介绍说明 对缓存数据进行非对称加密处理 对必要数据进行缓存&#xff0c;并…...

如何将ArcGIS工程文件迁移到ArcGIS Pro内

当你刚接触ArcGIS Pro的时候&#xff0c;尝试新建一个工程文件会发现工程文件的后缀已经改变&#xff0c;那么以前在ArcGIS内辛苦制作的工程文件是否就不能在ArcGIS Pro内使用了&#xff0c;答案是否定的&#xff0c;对此Esri也给出了解决方案&#xff0c;这里为大家介绍一下迁…...

Jenkins基础篇--添加用户和用户权限设置

添加用户 点击系统管理&#xff0c;点击管理用户&#xff0c;然后点击创建用户&#xff08;Create User&#xff09; 用户权限管理 点击系统管理&#xff0c;点击全局安全配置&#xff0c;找到授权策略&#xff0c;选择安全矩阵&#xff0c;配置好用户权限后&#xff0c;点击…...

C语言基础内容(七)——第08章_C语言常用函数

文章目录 第08章_C语言常用函数本章专题脉络1、字符串相关函数1.1 字符串的表示方式1.2 两种方式的区别1.2 字符串常用函数strlen()strcpy()strncpy()strcat()strncat()strcmp()strlwr()/strupr()1.3 基本数据类型和字符串的转换基本数据类型 -> 字符串字符串 -> 基本数据…...

CRM系统针对销售管理有哪些功能?如何帮助销售效率增长?

从长远来看&#xff0c;有效的CRM管理系统可以帮助您的企业达到甚至超过收入目标。现代大多数企业都依靠CRM系统来管理其销售周期并增加收入。但是&#xff0c;当大多数人提到CRM时&#xff0c;他们指的是使能够改善业务关系并轻松管理不断团队的软件或工具。合格的CRM系统能够…...

基于Pixhawk和ROS搭建自主无人车(一):底盘控制篇

参考 ArduPilot Development超维空间科技乐迪MiniPix车船使用说明书 1. 硬件篇 1.1 底盘构成一览 1.2 底盘接线示意 2. 软件篇 2.1 APM 固件下载 pixhawk 是硬件平台&#xff0c;PX4 是 pixhawk 的原生固件&#xff0c;APM&#xff08;Ardupilot Mega&#xff09;是硬件平台…...

部署 Spring Boot 应用中文文档

本文为官方文档直译版本。原文链接 部署 Spring Boot 应用中文文档 引言部署到云Cloud Foundry与服务绑定 KubernetesKubernetes 容器生命周期 HerokuOpenShift亚马逊网络服务&#xff08;AWS&#xff09;AWS Elastic Beanstalk使用 Tomcat 平台使用 Java SE 平台 总结 CloudCa…...

【数据库原理】(23)实际应用中的查询优化方法

一.基于索引的优化 索引是数据库查询优化的关键工具之一。合理地使用索引可以显著提高查询速度&#xff0c;降低全表扫描的成本。以下是建立和使用索引的一些基本原则和最佳实践。 索引的建立与使用原则 数据量规模与查询频率: 值得建立索引的表通常具有较多的记录&#xff0…...

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) 网站吗&#xff1f;最好的学习管理系统工具LifterLMS将帮助您制作像Udemy市场这样的 LMS 网站。 目录 Udemy市场是什么&#xff1f; 创建 Udemy 克隆所需的几项强制性技术&#xff1a; 步骤 1) 注册您的域名 步骤 2) 获取虚拟主…...

(leetcode)Z字形变换 -- 模拟算法

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 题目链接 . - 力扣&#xff08;LeetCode&#xff09; 输入描述 string convert(string s, int numRows)&#xff0c;输入一个字符串s&#xff0c;以及一个行数numRows&#xff0c;将字符串按照这个行数进行Z字形排列&…...

STM32--基于STM32F103的MAX30102心率血氧测量

本文介绍基于STM32F103ZET6MAX30102心率血氧测量0.96寸OLED&#xff08;7针&#xff09;显示&#xff08;完整程序代码见文末链接&#xff09; 一、简介 MAX30102是一个集成的脉搏血氧仪和心率监测仪生物传感器的模块。它集成了一个红光LED和一个红外光LED、光电检测器、光器…...

Qt/C++音视频开发63-设置视频旋转角度/支持0-90-180-270度旋转/自定义旋转角度

一、前言 设置旋转角度,相对来说是一个比较小众的需求,如果视频本身带了旋转角度,则解码播放的时候本身就会旋转到对应的角度显示,比如手机上拍摄的视频一般是旋转了90度的,如果该视频文件放到电脑上打开,一些早期的播放器可能播放的时候是躺着的,因为早期播放器设计的…...

Python电能质量扰动信号分类(五)基于CNN-Transformer的一维信号分类模型

目录 往期精彩内容&#xff1a; 引言 1 数据集制作与加载 1.1 导入数据 1.2 制作数据集 2 CNN-Transformer分类模型和超参数选取 2.1定义CNN-Transformer分类模型 2.2 设置参数&#xff0c;训练模型 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联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…...

mysql 字符串分割

目录 前言substring_indexsubstring_index 特性字符串分割 前言 略 substring_index 正向截取字符串 mysql> select substring_index(www.baidu.com,.,1); ---------------------------------------- | substring_index(www.baidu.com,.,1) | -------------------------…...

解决Windows11 “我们无法设置移动热点”

目录 问题复现解决办法①启动网络适配器②打开移动热点③共享网络连接④连接移动热点总结 问题复现 因为交换机上网口限制&#xff0c;开发环境暂时没有WIFI设备&#xff0c;只有一根网线和一台笔记本电脑。于是开启笔记本电脑的WiFi共享服务。结果提示 “我们无法设置移动热点…...

python tcp socket中实现SSL/TLS认证

SSL/TLS介绍 官话说SSL是安全套接层(secure sockets layer)&#xff0c;TLS是SSL的继任者&#xff0c;叫传输层安全(transport layer security)。 说白点&#xff0c;就是在明文的上层和TCP层之间加上一层加密&#xff0c;这样就保证上层信息传输的安全。如HTTP协议是明文传输…...

SQL-修改表操作

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

从零实现STL哈希容器:unordered_map/unordered_set封装详解

本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说&#xff0c;直接开始吧&#xff01; 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)

本文把滑坡位移序列拆开、筛优质因子&#xff0c;再用 CNN-BiLSTM-Attention 来动态预测每个子序列&#xff0c;最后重构出总位移&#xff0c;预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵&#xff08;S…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

免费数学几何作图web平台

光锐软件免费数学工具&#xff0c;maths,数学制图&#xff0c;数学作图&#xff0c;几何作图&#xff0c;几何&#xff0c;AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...