SpringBoot+Mybatis通过自定义注解实现字段加密存储
目录
- 前言
- 实现
- 自定义注解
- AES对称加密工具类
- 创建拦截器
- 加密拦截器
- 解密拦截器
- 验证
- 创建实体类
- 数据写入与查询
- 加密字段参与查询
- 不生效情况
前言
通过Mybatis提供的拦截器,在新增、修改时对特定的敏感字段进行加密存储,查询时自动进行解密操作,减少业务层面的代码逻辑;
加密存储意义:
- 防止数据泄露:即使数据库被非法访问或泄露,加密数据也无法被直接利用
- 保护个人隐私:如身份证号、手机号、住址等PII(个人身份信息)数据
- 保障财务安全:加密银行卡号、支付密码等金融信息
核心逻辑:
- 自定义注解,对需要进行加密存储的使用注解进行标注;
- 构建AES对称加密工具类;
- 实现Mybatis拦截器,通过反射获取当前实体类的字段是否需要进行加解密;
实现
自定义注解
通过自定义@EncryptDBBean
与@EncryptDBColumn
标识某个DO实体类的某些字段需要进行加解密处理;
- EncryptDBBean:作用在类上
- EncryptDBColumn:作用在字段上
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface EncryptDBBean {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface EncryptDBColumn {
}
AES对称加密工具类
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;public class DBAESUtils {/*** 设置为CBC加密模式,默认情况下ECB比CBC更高效*/private final static String CBC = "/CBC/PKCS5Padding";private final static String ALGORITHM = "AES";/*** 定义密钥Key,AES加密算法,key的大小必须是16个字节*/private final static String KEY = "1234567812345678";/*** 设置偏移量,IV值任意16个字节*/private final static String IV = "1122334455667788";/*** 对称加密数据** @return : 密文* @throws Exception*/public static String encryptBySymmetry(String input) {try {// CBC模式String transformation = ALGORITHM + CBC;// 获取加密对象Cipher cipher = Cipher.getInstance(transformation);// 创建加密规则// 第一个参数key的字节// 第二个参数表示加密算法SecretKeySpec sks = new SecretKeySpec(KEY.getBytes(), ALGORITHM);// ENCRYPT_MODE:加密模式// DECRYPT_MODE: 解密模式// 使用CBC模式IvParameterSpec iv = new IvParameterSpec(IV.getBytes());cipher.init(Cipher.ENCRYPT_MODE, sks, iv);// 加密byte[] bytes = cipher.doFinal(input.getBytes());// 输出加密后的数据return Base64.getEncoder().encodeToString(bytes);} catch (Exception e) {throw new RuntimeException("加密失败!", e);}}/*** 对称解密** @param input : 密文* @throws Exception* @return: 原文*/public static String decryptBySymmetry(String input) {try {// CBC模式String transformation = ALGORITHM + CBC;// 1,获取Cipher对象Cipher cipher = Cipher.getInstance(transformation);// 指定密钥规则SecretKeySpec sks = new SecretKeySpec(KEY.getBytes(), ALGORITHM);// 使用CBC模式IvParameterSpec iv = new IvParameterSpec(IV.getBytes());cipher.init(Cipher.DECRYPT_MODE, sks, iv);// 3. 解密,上面使用的base64编码,下面直接用密文byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(input));// 因为是明文,所以直接返回return new String(bytes);} catch (Exception e) {throw new RuntimeException("解密失败!", e);}}
}
创建拦截器
- 加密拦截器:EncryptInterceptor
- 解密拦截器:DecryptInterceptor
加密拦截器
在新增或者更新时,通过拦截对被注解标识的字段进行加密存储处理;
import com.lhz.demo.annotation.EncryptDBBean;
import com.lhz.demo.annotation.EncryptDBColumn;
import com.lhz.demo.utils.DBAESUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.*;@Slf4j
@Component
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = {PreparedStatement.class}),
})
public class EncryptInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {try {ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");parameterField.setAccessible(true);Object parameterObject = parameterField.get(parameterHandler);if (parameterObject != null) {Set<Object> objectList = new HashSet<>();if (parameterObject instanceof Map<?, ?>) {Collection<?> values = ((Map<?, ?>) parameterObject).values();objectList.addAll(values);} else {objectList.add(parameterObject);}for (Object o1 : objectList) {Class<?> o1Class = o1.getClass();// 实体类是否存在 加密注解boolean encryptDBBean = o1Class.isAnnotationPresent(EncryptDBBean.class);if (encryptDBBean) {//取出当前当前类所有字段,传入加密方法Field[] declaredFields = o1Class.getDeclaredFields();// 便利字段,是否存在加密注解,并且进行加密处理for (Field field : declaredFields) {//取出所有被EncryptDecryptField注解的字段boolean annotationPresent = field.isAnnotationPresent(EncryptDBColumn.class);if (annotationPresent) {field.setAccessible(true);Object object = field.get(o1);if (object != null) {String value = object.toString();//加密 这里我使用自定义的AES加密工具field.set(o1, DBAESUtils.encryptBySymmetry(value));}}}}}}return invocation.proceed();} catch (Exception e) {throw new RuntimeException("字段加密失败!", e);}}/*** 默认配置,否则当前拦截器不会加入拦截器链*/@Overridepublic Object plugin(Object o) {return Plugin.wrap(o, this);}}
解密拦截器
将查询的数据,返回为DO实体类时,对被注解标识的字段进行解密处理
import com.lhz.demo.annotation.EncryptDBBean;
import com.lhz.demo.annotation.EncryptDBColumn;
import com.lhz.demo.utils.DBAESUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.lang.reflect.Field;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;@Intercepts({@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
@Slf4j
@Component
public class DecryptInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object resultObject = invocation.proceed();try {if (Objects.isNull(resultObject)) {return null;}// 查询列表数据if (resultObject instanceof ArrayList) {List list = (ArrayList) resultObject;if (!CollectionUtils.isEmpty(list)) {for (Object result : list) {Class<?> objectClass = result.getClass();boolean encryptDBBean = objectClass.isAnnotationPresent(EncryptDBBean.class);if (encryptDBBean) {// 解密处理decrypt(result);}}}} else {// 查询单个数据Class<?> objectClass = resultObject.getClass();boolean encryptDBBean = objectClass.isAnnotationPresent(EncryptDBBean.class);if (encryptDBBean) {// 解密处理decrypt(resultObject);}}return resultObject;} catch (Exception e) {throw new RuntimeException("字段解密失败!", e);}}@Overridepublic Object plugin(Object o) {return Plugin.wrap(o, this);}public <T> void decrypt(T result) throws Exception {//取出resultType的类Class<?> resultClass = result.getClass();Field[] declaredFields = resultClass.getDeclaredFields();for (Field field : declaredFields) {boolean annotationPresent = field.isAnnotationPresent(EncryptDBColumn.class);if (annotationPresent) {field.setAccessible(true);Object object = field.get(result);if (object != null) {String value = object.toString();//对注解的字段进行逐一解密field.set(result, DBAESUtils.decryptBySymmetry(value));}}}}
}
验证
创建实体类
创建实体类,并且使用加密注解@EncryptDBBean
、@EncryptDBColumn
进行标注,此处以手机号
为例;
@Data
@TableName("sys_user_info")
@EncryptDBBean
public class TestEntity {/*** 用户id*/@TableId("id")private Long id;/*** 用户名称*/private String name;/*** 手机号*/@EncryptDBColumnprivate String mobile;
}
数据写入与查询
对数据的操作使用伪代码进行表示
TestEntity entity = new TestEntity();
entity.setId(1L);
entity.setName("测试");
entity.setMobile("166xxxx8888");
// 插入数据
entityService.insert(entity);
// 更新数据
entity.setMobile("166xxxx7777");
entityService.updateById(entity);// 列表查询
List<TestEntity> list = testService.list();
效果:
- insert和update后的数据,在数据库是加密字符串存储的形式;
- list方法查询的数据,将明文进行显示;
加密字段参与查询
如果是加密字段进行条件查询时,需要自行将查询参数进行加密处理,因为数据库是存储的密文,所以查询时也需要使用密文进行匹配,比如:要查询mobile=111
的数据
// 伪代码
// 获取前端传入的查询条件
String mobile = "111"
// 手动加密
mobile = DBAESUtils.decryptBySymmetry(mobile );
testService.selectByMobile(mobile);
不生效情况
1、在通过LambdaQueryWrapper
获取QueryWrapper
方式查询时,拦截器无法获取自定义注解对象,需要手动对查询的字段进行加密,比如:
如果是 通过自定义的xml查询,如果入参有加密注解,那么会自动对字段进行加密处理 testMapper.listTest(testEntity)
LambdaQueryWrapper<TestEntity> wrapper = new LambdaQueryWrapper<>();
String mobile = test.getMobile();
if (mobile != null) {// mobile在数据库中加密储存,此处需要手动进行加密mobile = DBAESUtils.encryptBySymmetry(mobile);
}
wrapper.eq(StringUtils.isNotBlank(test.getMobile()), TestEntity::getMobile, mobile);
List<TestEntity> testEntities = testMapper.selectList(wrapper);
2、使用Mybatis提供的selectOne或者getOne方法查询时,无法对响应的数据进行解密,需要手动进行处理,比如:
如果是 通过自定义的xml查询,无论多少条数据都会对数据进行解密,testMapper.selectXmlById(Long id)
TestEntity one = testService.getOne(new QueryWrapper<>(), false);
// mobile在数据库中加密储存,此处需要手动进行解密
one.setMobile(DBAESUtils.decryptBySymmetry(one.getMobile()));
相关文章:
SpringBoot+Mybatis通过自定义注解实现字段加密存储
😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: SpringBootMybatis实现字段加密 ⏱️ 创作时间: 2025年04月…...
Vue3调度器错误解析,完美解决Unhandled error during execution of scheduler flush.
目录 Vue3调度器错误解析,完美解决Unhandled error during execution of scheduler flush. 一、问题现象与本质 二、七大高频错误场景与解决方案 1、Setup初始化陷阱 2、模板中的"幽灵属性" 3、异步操作的"定时炸弹" 4、组件嵌套黑洞 5…...
第35周Zookkeeper+Dubbo Zookkeeper
第35周ZooKeeperDubbo ZooKeeper 一、周介绍 本周主要内容包括ZooKeeper、Dubbo以及面试三部分。 1.1 ZooKeeper 节点介绍 ZooKeeper的数据结构核心是每个node节点。节点具有属性、特点和功能,其数据结构为树形结构,类似于多叉树,分隔符是…...
基于tabula对pdf中多个excel进行识别并转换成word中的优化(四)
对上一节进行优化: 1、识别多个excel 2、将表格中的nan替换成空字符串 一、示例中的pdf内容 二、完整代码参考: import tabula import numpy as np from docx import Document from docx.oxml.ns import qn from docx.oxml import OxmlElementdef get_t…...
Electron-vite中ELECTRON_RENDERER_URL环境变量如何被设置的
近期我专注于前端技术栈 Electron 与 Vue3 的学习实践,依照教程网站 快速开始 | electron-vite 的快速入门指引,搭建了一个示例项目。成功完成项目下载,并通过 npm run dev 命令启动项目后,在研读项目 main 目录下的 index.ts 文件…...
Electron Forge【实战】桌面应用 —— 将项目配置保存到本地
最终效果 定义默认配置 src/initData.ts export const DEFAULT_CONFIG: AppConfig {language: "zh",fontSize: 14,providerConfigs: {}, };src/types.ts export interface AppConfig {language: zh | enfontSize: numberproviderConfigs: Record<string, Recor…...
gem5-gpu 安装过程碰到的问题记录 关于使用 Ruby + Garnet
如何使用Garnet? 这并不像一组命令行参数那么简单。要使用gem5-gpu+garnet,您可能需要修改python配置脚本。 问题是配置文件gem5-gpu/configs/gpu_protocol/VI_hammer_fusion.py指定了链接的intBW和extBW。 看来Garnet不支持这一点。然而,似乎所有的链路都是相同的带宽,所…...
全平台开源即时通讯IM框架MobileIMSDK:7端+TCP/UDP/WebSocket协议,鸿蒙NEXT端已发布,5.7K Stars
一、基本介绍 MobileIMSDK是一套全平台原创开源IM通信层框架: 超轻量级、高度提炼,lib包50KB以内;精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);客户端支持iOS…...
《阿里Qwen3开源:AI新纪元的破晓之光》
《阿里Qwen3开源:AI新纪元的破晓之光》 惊爆!阿里释放 Qwen3 “大杀器” 在人工智能的星辰大海中,每一次新模型的诞生都如同点亮一颗新星,而阿里巴巴此次发布并开源 Qwen3,无疑是投下了一枚震撼弹,瞬间吸引了全球 AI 领域的目光。这不仅是阿里在 AI 征程上的一座重要里程…...
前端防护利器:disable-devtool 使用指南 - 保护你的Web应用安全
文章目录 前端防护利器:disable-devtool 使用指南 - 保护你的Web应用安全为什么需要禁用开发者工具?什么是 disable-devtool?安装与引入通过npm/yarn安装通过CDN引入ES6模块引入配置选项详解完整使用示例检测模式说明最佳实践在线考试系统防护敏感数据保护注意事项更多资源前…...
万物皆可执行:多功能机器人正在定义新生产力法则
引言 当波士顿动力的Atlas完成高难度体操动作,当特斯拉Optimus在工厂精准分拣零件,当小鹏Iron机器人以拟态双手递上咖啡——这些场景不再只是科幻电影的桥段,而是多功能机器人(Polyfunctional Robots)带来的真实变革…...
从车道检测项目入门open cv
从车道检测项目入门open cv 前提声明:非常感谢b站up主 嘉然今天吃带变,感谢其视频的帮助。同时希望各位大佬积积极提出宝贵的意见。😊😊😊(❁◡❁)(●’◡’●)╰(▽)╯ github地址:https://github.com/liz…...
Vue3取消网络请求的方法(AbortController)
在 Vue3 中,已经发出的请求是否可以被取消,取决于你使用的 HTTP 客户端库。Vue3 本身不直接处理 HTTP 请求,但通常搭配 Axios 或原生 fetch 使用。以下是两种主流方案的取消方法: 1. 使用 Axios CancelToken Axios 提供了 Cance…...
深度解析Qwen3:性能实测对标Gemini 2.5 Pro?开源大模型新标杆的部署挑战与机遇
大语言模型(LLM)的浪潮持续席卷技术圈,性能天花板不断被刷新。以 Gemini 2.5 Pro 为代表的闭源模型展现了惊人的能力,但其高昂的成本和有限的可访问性也让许多开发者望而却步。与此同时,开源力量正以前所未有的速度崛起…...
AI遇见端动态神经网络:Cephalon(联邦学习+多模态编码)认知框架构建
前引: 在数字化浪潮席卷全球的今天,数据爆炸与算力需求的指数级增长正推动着云计算向更智能、更高效的方向演进。面对海量终端设备的实时响应需求、复杂AI模型的分布式训练挑战,以及多场景数据的协同处理难题,传统云架构逐渐显露出…...
机器学习之五:基于解释的学习
正如人们有各种各样的学习方法一样,机器学习也有多种学习方法。若按学习时所用的方法进行分类,则机器学习可分为机械式学习、指导式学习、示例学习、类比学习、解释学习等。这是温斯顿在1977年提出的一种分类方法。 有关机器学习的基本概念,…...
高翔视觉slam中常见的OpenCV和Eigen的几种数据类型的内存布局及分配方式详解
vector<Eigen::Vector2d, Eigen::aligned_allocator<Eigen::Vector2d>> 内存布局及分配方式详解 1. 内存对齐的必要性 Eigen 的固定大小类型(如 Eigen::Vector2d、Eigen::Matrix4d 等)需要 16 字节内存对齐,以支持 SIMD 指令(如 SSE/AVX)的并行计算。若未对…...
电子电器架构 --- 人工智能、固态电池和先进自动驾驶功能等新兴技术的影响
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…...
【C++11】类的新功能
前言 上文我们学习了包装器:function和bind。function可以包装一切可调用对象,并用统一的调用方式调用不同的可调用对象。bind则可以控制函数参数个数【C11】包装器:function与bind-CSDN博客 本文我们来学习C11的类中新增的一些功能 默认的移…...
1.6 点云数据获取方式——单目相机多视图几何
图1-6-1多视图几何重建 单目相机的多视图几何研究具有重要的理论与实际意义。在理...
马井堂-区块链技术:架构创新、产业变革与治理挑战(马井堂)
区块链技术:架构创新、产业变革与治理挑战 摘要 区块链技术作为分布式账本技术的革命性突破,正在重构数字时代的信任机制。本文系统梳理区块链技术的核心技术架构,分析其在金融、供应链、政务等领域的实践应用,探讨共识算法优化、…...
MicroBlaze软核的开发使用
一、MicroBlaze 介绍 MicroBlaze 是由 Xilinx 开发的一种可配置的 32 位 RISC 软处理器内核。它作为 FPGA 设计中的 IP 核,通过 Vivado 工具进行配置和集成。MicroBlaze 提供了高度的灵活性,允许开发人员根据应用需求调整处理器的功能、性能和资源占用。…...
是从原始数据到价值挖掘的完整流程解析,涵盖数据采集、清洗、存储、处理、建模、可视化等核心环节,并附上完整代码示例(含详细注释)及技术选型建议表
以下是从原始数据到价值挖掘的完整流程解析,涵盖数据采集、清洗、存储、处理、建模、可视化等核心环节,并附上完整代码示例(含详细注释)及技术选型建议表。 一、全流程技术栈概览 阶段核心任务关键技术/工具数据采集获取原始数据…...
【爬虫】案例-获取cbh电影
以cupfox.in为例子: 观察ts文件和m3u8文件,可以知道一个完整的视频是由多个ts文件组合,而m3u8则是记录所有ts文件信息的文本 思路 1.先爬一个ts,测试能否观看 2.爬m3u8文件,通过正则分析出变化的部分 3.完整的把每个…...
分治而不割裂—分治协同式敏捷工作模式
分治而不割裂:解密敏捷协同工作模式如何驱动大企业持续领跑 在数字化浪潮中,亚马逊仅用11天完成Prime Day全球技术架构升级,华为5G基站项目组创造过单周迭代47个功能模块的纪录,这些商业奇迹的背后,都隐藏着一个共性秘…...
【MySQL】聚合查询 和 分组查询
个人主页:♡喜欢做梦 欢迎 👍点赞 ➕关注 ❤️收藏 💬评论 目录 🌴 一、聚合查询 🌲1.概念 🌲2.聚合查询函数 COUNT() SUM() AVG(&…...
Weka通过10天的内存指标数据计算内存指标动态阈值
在数据处理和监控系统中,动态阈值的计算是一种常见的方法,用以根据数据的实际分布和变化来调整阈值,从而更有效地监控和预警。在Weka中,虽然它主要是用于机器学习和数据挖掘的工具,但你可以通过一些间接的方法来实现…...
iOS签名的包支持推送功能吗?
推送失败的可能原因: 1. 生产包没有上报token ,所以无法推送成功,需要检查是否在企业包签名后导致无法完成apns的注册,无法从Apple取到token 2. 问题可能出在证书上,因为iOS推送有一个开发证书和一个生产证书ÿ…...
JavaWeb:后端web基础(TomcatServletHTTP)
一、今日内容 二、Tomcat 介绍与使用 介绍 基本使用 小结 配置 配置 查找进程 三、Servlet 什么是Servlet 快速入门 需求 步骤 1.新建工程-模块(Maven) 2.修改打包方式-war 3.编写代码 /*** 可以选择继承HttpServlet*/ WebServlet("/hello&q…...
关于浏览器对于HTML实体编码,urlencode,Unicode解析
目录 HTML实体编码 URL编码 Unicode编码 解析层次逻辑 为什么<script></script>不可以编码符号 为什么不能编码JavaScript:协议 为什么RCDATA标签中的都会被解析成文本 为什么HTML编码了<>无法执行 HTML实体编码 通过特殊语法(<、>…...
C++智能指针滥用带来的性能与内存问题有哪些
在现代C编程中,智能指针(Smart Pointers)已经成为开发者工具箱中不可或缺的一部分。它们作为一种对传统裸指针(Raw Pointers)的替代方案,旨在解决长期困扰C开发者的内存管理难题。C作为一门高性能的系统编程…...
C++算法(17):reverse函数用法详解,头文件<algorithm>与实战示例
在C中,std::reverse 函数用于反转容器或数组中元素的顺序,需包含头文件 <algorithm>。以下是其用法详解: 基本用法 函数原型: template <class BidirIt> void reverse(BidirIt first, BidirIt last); 参数…...
【滑动窗口】最大连续1的个数|将x减到0的最小操作数
文章目录 1.最大连续1的个数2.将x减到0的最小操作数 1.最大连续1的个数 解法: 1.暴力解法给定一个left指针固定左端点元素,再给定一个right指针从左端点元素开始遍历。 当遇到1时,让一个计数器cnt1,当遇到0时,让统计0…...
MySQL 在 CentOS 7 环境下的安装教程
🌟 各位看官好,我是maomi_9526! 🌍 种一棵树最好是十年前,其次是现在! 🚀 今天来学习C语言的相关知识。 👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更…...
嵌入式复习第一章
1. 嵌入式系统概念、应用与特点 2. 嵌入式系统的硬件( CPU 、外设) 3. 主要嵌入式软件系统(应用及 OS ) 4. 嵌入式系统的发展趋势 嵌入式系统定义 “以 应用为中心 ,以计算机技术为基础,并且软硬件…...
【C#】.net core6.0无法访问到控制器方法,直接404。由于自己的不仔细,出现个低级错误,这让DeepSeek看出来了,是什么错误呢,来瞧瞧
🌹欢迎来到《小5讲堂》🌹 🌹这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解。🌹 🌹温馨提示:博主能力有限,理解水平有限,若有不对之处望指正!&#…...
Tailwind CSS 实战:基于 Kooboo 构建企业官网页面(三)
基于前两篇内容,继续完善企业官网页面: Tailwind CSS 实战:基于 Kooboo 构建企业官网页面(一)-CSDN博客 Tailwind CSS 实战:基于 Kooboo 构建企业官网页面(二)-CSDN博客 3.5 联系方…...
Opencv中图像深度(Depth)和通道数(Channels)区别
在OpenCV中,图像深度(Depth)和通道数(Channels)是两个完全不同的概念,需严格区分。以下是详细解析: 图像深度(Depth) 定义:指图像中每个像素通道的位数&#…...
【网络原理】从零开始深入理解HTTP的报文格式(一)
本篇博客给大家带来的是网络HTTP协议的知识点, 重点介绍HTTP的报文格式. 🐎文章专栏: JavaEE初阶 🚀若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅Ὠ…...
Go语言之路————接口、泛型
Go语言之路————接口 前言接口定义实操,接口的定义和实现接口的继承空接口和Any 泛型类型集 结语 前言 我是一名多年Java开发人员,因为工作需要现在要学习go语言,Go语言之路是一个系列,记录着我从0开始接触Go,到后…...
Go语言中的 `time.Tick` 函数详解
time.Tick 是 Go 标准库中用于创建周期性定时器的简便函数。 函数签名 func Tick(d Duration) <-chan Time核心功能 创建一个周期性的定时器通道当 d < 0 时返回 nil返回一个只读的时间通道,定期发送当前时间 与 NewTicker 的关系 time.Tick 是 time.New…...
打印及判断回文数组、打印N阶数组、蛇形矩阵
打印回文数组 1 1 1 1 1 1 2 2 2 1 1 2 3 2 1 1 2 2 2 1 1 1 1 1 1方法1: 对角线对称 左上和右下是对称的。 所以先考虑左上打印, m i n ( i 1 , j 1 ) \text min(i1,j1) min(i1,j1),打印出来: 1 1 1 1 1 2 2 2 1 2 3 3 1 2 …...
【图像融合】基于非负矩阵分解分解 CNMF的高光谱和多光谱数据融合附MATLAB代码
基于CNMF的高光谱与多光谱数据融合技术详解 一、非负矩阵分解(NMF)与约束非负矩阵分解(CNMF)的核心原理 NMF的基本概念 非负矩阵分解(NMF)是一种通过将非负矩阵分解为两个非负矩阵乘积的降维方法。给定非负…...
HarmonyOS NEXT 诗词元服务项目开发上架全流程实战(一、项目介绍及实现效果)
在当今数字化时代,如何让传统文化与现代科技相结合,成为了一个值得思考的问题。诗词作为中国传统文化的重要组成部分,承载着丰富的历史信息和文化内涵。为了让更多人了解和欣赏诗词的魅力,我们决定开发一款基于HarmonyOS NEXT的诗…...
线性代数与数据学习
The Functions of Deep Learning (essay from SIAM News, December 2018) Deep Learning and Neural Nets...
Linux中的计划任务
一次性任务 功能介绍: 如果我们希望在将来的某个时间点去执行某件事件,这个事件执行完后任务就结束,那么我们 就可以使用一性计划任务。而要实现这种功能,我们需要任务 atd 服务。我们先查询一下系 统是否存在这个服务。 查看是…...
【C++】线程池
C 线程池介绍 什么是线程池? 线程池(Thread Pool) 是一种并发编程模型,用于管理和复用多个线程,避免频繁创建/销毁线程的开销。它通过预创建一组线程,并将任务提交到队列中,由空闲线程自动执行…...
美团社招一面
美团社招一面 做题 1、面试题 <style> .outer{width: 100px;background: red;height: 100px; }.inner {width: 50px;height: 50px;background: green; }</style> <div class"outer"><div class"inner"></div> </div>…...
C++:BST、AVL、红黑树
C:BST、AVL、红黑树 二叉搜索树(BST)二叉平衡搜索树(AVL)红黑树(RBT)三者对比什么情况下使用?C 标准库中的使用总结 二叉搜索树(BST) 二叉搜索树(Binary Sea…...
算法笔记.染色法判断二分图
题目:(来自AcWing) 给定一个 n 个点 m 条边的无向图,图中可能存在重边和自环。 请你判断这个图是否是二分图。 输入格式 第一行包含两个整数 n 和 m。 接下来 m 行,每行包含两个整数 u 和 v,表示点 u …...