当前位置: 首页 > 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…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录

ASP.NET Core 是一个跨平台的开源框架&#xff0c;用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录&#xff0c;以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

P3 QT项目----记事本(3.8)

3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...

[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...