使用AOP切面对返回的数据进行脱敏的问题
1.注解类
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Author: xiaoxin* @Date: 2023/7/21 17:15*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface Encrypt {Type type() default Type.MOBILE_PHONE;enum Type {//用户idUSER_ID,//中文名CHINESE_NAME,//身份证号ID_CARD,//座机号FIXED_PHONE,//手机号MOBILE_PHONE,//地址ADDRESS,//电子邮件EMAIL,//密码PASSWORD,//中国大陆车牌,包含普通车辆、新能源车辆CAR_LICENSE,//银行卡BANK_CARD,//字符串STR}}
2.EncryptUtil工具
import cn.hutool.core.util.DesensitizedUtil;
import io.ctc.commons.tools.utils.StringUtils;import java.lang.reflect.Field;/*** @Author: xiaoxin* @Date: 2023/7/21 17:16*/
public class EncryptUtil {public static void encryptFields(Object obj) {Field[] fields = obj.getClass().getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(Encrypt.class)) {Encrypt encryptAnnotation = field.getAnnotation(Encrypt.class);Encrypt.Type type = encryptAnnotation.type();field.setAccessible(true);try {String value = (String) field.get(obj);String encryptedValue = encryptValue(type, value);field.set(obj, encryptedValue);} catch (IllegalAccessException e) {e.printStackTrace();}}}}/**** 根据类型进行脱敏处理* @param type* @param value* @return*/public static String encryptValue(Encrypt.Type type, String value) {StringBuffer sb = new StringBuffer();switch (type) {case USER_ID:sb.append(DesensitizedUtil.userId());break;case CHINESE_NAME:sb.append(DesensitizedUtil.chineseName(value));break;case ID_CARD:sb.append(DesensitizedUtil.idCardNum(value, 1, 2));break;case FIXED_PHONE:sb.append(DesensitizedUtil.fixedPhone(value));break;case MOBILE_PHONE:sb.append(DesensitizedUtil.mobilePhone(value));break;case ADDRESS:sb.append(DesensitizedUtil.address(value,6));break;case EMAIL:sb.append(DesensitizedUtil.email(value));break;case PASSWORD:sb.append(DesensitizedUtil.password(value));break;case CAR_LICENSE:sb.append(DesensitizedUtil.carLicense(value));break;case BANK_CARD:sb.append(DesensitizedUtil.bankCard(value));break;case STR:if (StringUtils.isNotBlank(encryptionStr(value))){sb.append(encryptionStr(value));}break;}return sb.toString();}/**** 自定义字符串处理* @param str* @return*/public static String encryptionStr(String str) {if (StringUtils.isBlank(str)){return "";}int length = str.length();if (length <= 4){return str;}// 替换的起始位置int startIndex = (length - 3) / 2;// 替换的结束位置int endIndex = startIndex + 3;// 替换为4个*String replacement = "****";StringBuilder sb = new StringBuilder(str);sb.replace(startIndex, endIndex, replacement);return sb.toString();}
}
3.EncryptAspect切面类
import io.ctc.commons.tools.utils.Result;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import java.util.List;
import java.util.Objects;/*** @author xiaoxin*/
@Aspect
@Component
public class EncryptAspect {protected Logger logger = LoggerFactory.getLogger(getClass());@Pointcut("@annotation(io.util.test.Encrypt)")public void encryptDataPointCut() {}/**** 后置增强,返回数据脱敏切面类,页面上有部分数据是不能对外展示的,此方法不支持反脱敏* 示例:原数据19879835555 脱敏后198****5555* @param point* @throws Throwable*/@AfterReturning(value = "encryptDataPointCut()",returning = "returnValue")public void around(JoinPoint point, Object returnValue){logger.info("---------------后置增强~~~~对部分数据脱敏---------------");if (Objects.nonNull(returnValue)){//1.判断object是否可以转换为List<?>类型if (returnValue instanceof List<?>){List list = (List) returnValue;list.stream().forEach(a->{EncryptUtil.encryptFields(a);});}else//2.result对象,属性有code、msg、dataif (returnValue instanceof Result){try{Result result = (Result) returnValue;Object data = result.getData();if (Objects.nonNull(data)){if (data instanceof List<?>){List list = (List) data;list.stream().forEach(a->{EncryptUtil.encryptFields(a);});}else {EncryptUtil.encryptFields(data);}}}catch (ClassCastException e){throw new ClassCastException("数据脱敏转换失败");}}else {EncryptUtil.encryptFields(returnValue);}}}
}
4.User对象(需要脱敏的属性)
import io.util.test.Encrypt;
import lombok.Data;/*** 测试* @Author: xiaoxin* @Date: 2023/7/21 17:16*/
@Data
public class User {@Encrypt(type = Encrypt.Type.USER_ID)private String user_id;@Encrypt(type = Encrypt.Type.CHINESE_NAME)private String chinese_name;@Encrypt(type = Encrypt.Type.ID_CARD)private String id_card;@Encrypt(type = Encrypt.Type.FIXED_PHONE)private String fixed_phone;@Encrypt(type = Encrypt.Type.MOBILE_PHONE)private String mobile_phone;@Encrypt(type = Encrypt.Type.ADDRESS)private String address;@Encrypt(type = Encrypt.Type.EMAIL)private String email;@Encrypt(type = Encrypt.Type.PASSWORD)private String password;@Encrypt(type = Encrypt.Type.CAR_LICENSE)private String car_license;@Encrypt(type = Encrypt.Type.BANK_CARD)private String bank_card;@Encrypt(type = Encrypt.Type.STR)private String str;}
5.下面为测试:
Controller
service
结果:
统一返回结果就上面这样子的,controller上打上注解,实体类上根据类型打上注解就可以了。可以支持返回对象、List集合,分页的谁要的话在切面里写一下就好了,DesensitizedUtil是hutool的。
相关文章:

使用AOP切面对返回的数据进行脱敏的问题
1.注解类 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** Author: xiaoxin* Date: 2023/7/21 17:15*/ Retention(RetentionPolicy.RUNTIME) Targe…...

TDengine时区设置
一般来说,时序数据就是带有时间序列属性的数据。在处理时序数据时,TDengine有着自己独特的方式。但是如果没有正确理解TDengine在写入和查询上的行为,极可能会因为配置了错误的时区(timezone),而导致写入和…...

站外引流效果差?一文带你搞懂解海外主流社交媒体算法!
在流量成本越来越高的当下,无论是平台卖家还是独立站卖家都在努力拓展流量渠道。站外引流是推动业务增长的关键策略,很多卖家会把重点放在内容营销上,但其实除了做好内容之前,了解社交媒体的算法才能让营销效果最大化。 01.Faceb…...

css 动画之旋转视差
序:网上看到的一个例子,做一下 效果图: 代码: <style>.content{width: 300px;height: 300px;margin: 139px auto;display: grid;grid-template-columns: repeat(3,1fr);grid-template-rows: repeat(3,1fr);grid-template:…...

maven项目、springboot项目复制文件进来后没反应、不编译解决方法
问题如下 把文件复制进springboot项目后,没反应,不编译。 解决 在maven工具框中选择compile工具,运行即可。...
android jetpack App Startup 应用启动时初始化组件(java)
有什么用? 应用启动时初始化组件。 怎么用 添加依赖 dependencies {implementation "androidx.startup:startup-runtime:1.1.1" }创建类,继承Initializer。 public class AppInit implements Initializer<String> {NonNullOverride…...
【设计模式|行为型】命令模式(Command Pattern)
说明 命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,以便在不同的请求者和接收者之间进行解耦、参数化和操作的队列化。命令模式允许你将具体的请求封装为对象,这些对象之间彼此独立ÿ…...
SqlServer 批量删除表
SqlServer 批量删除表 直接上SQL脚本吧 SELECT row_number()over(order by Name) as FID,Name into #temp FROM SysObjects Where XTypeU --类型,U为实体表 and name like TMP% --表名过滤(自定义就好) ORDER BY Namedeclare count int 0…...

[Linux]线程基本知识
概念 进程 一个正在执行的程序,它是资源分配的最小单位 进程中的事情需要按照一定的顺序逐个进行 进程出现了很多弊端: 一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程; 二是由于对称多…...

STM32 串口基础知识学习
串行/并行通信 串行通信:数据逐位按顺序依次传输。 并行通信:数据各位通过多条线同时传输。 对比 传输速率:串行通信较低,并行通信较高。抗干扰能力:串行通信较强,并行通信较弱。通信距离:串…...
页面滚动时隐藏element-ui下拉框/时间弹框
场景 在系统中,当(有垂直滚动时)点击下拉框后滚动页面,会发现下拉项会遮盖住页面中的元素,不会隐藏 解决:(以vue为例) 在页面滚动或者缩放时隐藏下拉项即可(借助点击目标元素,下…...
C#中i++和++i的底层原理
一:前言 我们都知道,i是先取值,后计算。i是先计算,后取值。下面说下它的底层原理 二:原理 int i 0; i; Console.WriteLine(i); 结果是1 执行步骤是: 1.将常量0压入栈中 2.从栈中取出元素0,局…...

在win10下安装verilator
主要参考文章 Verilator简介及其下载安装卸载_徐晓康的博客的博客-CSDN博客https://blog.csdn.net/weixin_42837669/article/details/114505364上面的文章可以解决大部分问题,但是可能是方案有些老了,已经安装最新的版本,下面对最新的版本安装提供解决方案 一 预备工作 安…...

java设计模式-建造者(Builder)设计模式
介绍 Java的建造者(Builder)设计模式可以将产品的内部表现和产品的构建过程分离开来,这样使用同一个构建过程来构建不同内部表现的产品。 建造者设计模式涉及如下角色: 产品(Product)角色:被…...

iOS开发-实现获取下载主题配置动态切换主题
iOS开发-实现获取下载主题配置动态切换主题 iOS开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。 比如新年主题风格,常见的背景显示红色氛围图片、tabbar显示新…...
react经验4:动态组件
什么是动态组件? 在页面的一小块区域切换显示不同的组件 实现方法 1.声明示例组件 //写在component1.tsx中 const Component1()>{return (<div>组件1</div>) } //写在component2.tsx中 const Component2()>{return (<div>组件2</div…...

Java maven的下载解压配置(保姆级教学)
mamen基本概念 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以…...

Java课题笔记~数据库连接池
一、数据库连接池 1.1 数据库连接池简介 数据库连接池是个容器,负责分配、管理数据库连接(Connection) 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个; 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数…...
设计模式-单例模式
文章目录 单例模式饿汉式单例懒汉式单例懒汉式加锁单例双重锁校验单例静态内部类单例枚举单例 单例模式 单例模式主要是确保一个类在任何情况下都只有一个实例,并提供一个全局访问的点。 主要有以下几种 饿汉式单例 /*** 饿汉式* 类加载到内存后,就实…...
golang mysql
驱动 "github.com/go-sql-driver/mysql"使用到的方法 func sql.Open(driverName string, dataSourceName string) (*sql.DB, error) func (*sql.DB).Prepare(query string) (*sql.Stmt, error)//使用DB.Prepare预编译并使用参数化查询,对预编译的SQL语句…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

Ubuntu Cursor升级成v1.0
0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开,快捷键也不好用,当看到 Cursor 升级后,还是蛮高兴的 1. 下载 Cursor 下载地址:https://www.cursor.com/cn/downloads 点击下载 Linux (x64) ,…...