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

Java—注解

1.注解介绍

Annotation (注解) 是 Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或者变量,提供某些信息供程序在编译或者运行时使用。

注解本质是一个继承了Annotation 的特殊接口:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {}public interface Override extends Annotation{}

注解只有被解析之后才会生效,常见的解析方法有两种:

  • 编译期直接扫描:编译器在编译 Java 代码的时候扫描对应的注解并处理,比如某个方法使用@Override 注解,编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。
  • 运行期通过反射处理:像框架中自带的注解(比如 Spring 框架的 @Value@Component)都是通过反射来进行处理的。

2. 自定义注解实现数据加密

2.1 创建自定义注解,自定义注解的创建需要使用 @interface 关键字

@Target({ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EncryptMethod  {String[] fields() default ""; // 用于指定需要加密的字段名称
}
  • @Target:定义注解可以应用的目标元素类型。

  • @Retention:定义注解的保留策略(源码、编译时、运行时)。

  • @Documented:标记注解类型,使其在 JavaDoc 文档中可见。

2.2 解析自定义注解

@Aspect
@Component
public class EncryptAspect {@PostConstructpublic void init() {System.out.println("EncryptAspect initialized.");}/* ---------- 切点 ---------- */@Pointcut("@annotation(encryptMethod)")public void encryptPointcut(EncryptMethod encryptMethod) {}/* ---------- 环绕通知 ---------- */@Around("encryptPointcut(encryptMethod)")public Object encryptFields(ProceedingJoinPoint jp, EncryptMethod encryptMethod) throws Throwable {System.out.println("EncryptAspect invoked for: " + jp.getSignature());// 1. 处理入参Object[] args = jp.getArgs();if (args != null) {for (Object arg : args) {if (arg == null) continue;for (String fieldName : encryptMethod.fields()) {encryptField(arg, fieldName);}}}// 2. 执行原方法Object result = jp.proceed();// 3. 处理返回值if (result != null) {// 情况1:直接返回 Listif (result instanceof Collection<?>) {for (Object item : (Collection<?>) result) {for (String field : encryptMethod.fields()) {encryptField(item, field);}}}// 情况2:返回 TableDataInfoelse if (result instanceof TableDataInfo) {TableDataInfo table = (TableDataInfo) result;List<?> rows = table.getRows();if (rows != null) {for (Object row : rows) {for (String field : encryptMethod.fields()) {encryptField(row, field);}}}}// 情况3:单个对象else {for (String field : encryptMethod.fields()) {encryptField(result, field);}}}return result;}/* ---------- 反射加密指定字段 ---------- */private void encryptField(Object target, String fieldName) {try {Field field = findField(target.getClass(), fieldName);if (field == null) return;field.setAccessible(true);Object value = field.get(target);if (value instanceof String) {String cipher = encrypt((String) value);field.set(target, cipher);}} catch (Exception e) {// 记录日志即可,不要阻断业务e.printStackTrace();}}/* ---------- 递归找字段(支持父类) ---------- */private Field findField(Class<?> clazz, String fieldName) {for (; clazz != Object.class; clazz = clazz.getSuperclass()) {try {return clazz.getDeclaredField(fieldName);} catch (NoSuchFieldException ignored) {}}return null;}/* ---------- AES 加密 ---------- */private String encrypt(String plain) {try {String key = "XnUFyFy+9G0JWc9LwaYAWw==";byte[] cipherBytes = AES.encrypt(plain.getBytes(StandardCharsets.UTF_8),key.getBytes(), AES.ALGORITHM_AEPP);return Base64.getUrlEncoder().withoutPadding().encodeToString(cipherBytes);} catch (Exception e) {e.printStackTrace();return plain;}}
}

切面:EncryptAspect

  • @Aspect:标记该类为一个切面类。

切点:

@Pointcut("@annotation(encryptMethod)")
  • @Pointcut:定义一个切点,指定哪些方法会被拦截。

  • @annotation(encryptMethod):匹配所有被 @EncryptMethod 注解标记的方法。

连接点:

public Object encryptFields(ProceedingJoinPoint jp, EncryptMethod encryptMethod) throws Throwable {

ProceedingJoinPoint:提供对目标方法的访问,可以通过 proceed() 方法执行目标方法

通知:

@Around("encryptPointcut(encryptMethod)")
  • @Around:定义一个环绕通知,用于在方法执行前后执行自定义逻辑。

总结执行逻辑:

  1. 定义切点:匹配被 @EncryptMethod 注解标记的方法。

  2. 环绕通知:在方法执行前后执行自定义逻辑。

  3. 处理入参:对方法的参数中的指定字段进行加密。

  4. 执行原方法:调用目标方法。

  5. 处理返回值:对返回值中的指定字段进行加密。

  6. 反射加密:通过反射机制访问和修改字段值。

  7. AES 加密:使用 AES 算法对字段值进行加密。

这种实现方式可以灵活地对方法的参数和返回值进行加密处理,适用于需要对敏感数据进行加密的场景。

http://www.dtcms.com/a/332722.html

相关文章:

  • mysql-条件查询案例
  • zabbix部署问题后常见问题
  • Codeforces 无路可走
  • 分布式系统设计的容错机制
  • AI优质信息源汇总:含X账号,Newsletter,播客,App
  • 如何在 FastAPI 中玩转 APScheduler,让任务定时自动执行?
  • 上下文块嵌入(contextualized-chunk-embeddings)
  • collections:容器数据类型
  • C语言——深入理解指针(四)
  • 完整技术栈分享:基于Hadoop+Spark的在线教育投融资大数据可视化分析系统
  • 使用XXL-SSO实现登录认证以及权限管控
  • 解决 MySQL 查询速度缓慢的问题
  • Filebeat 轻量级日志采集实践:安装、配置、多行合并、JSON 解析与字段处理
  • Java集合Map与Stream流:Map实现类特点、遍历方式、Stream流操作及Collections工具类方法
  • 【软件设计模式】前置知识类图、七大原则(精简笔记版)
  • C++ 调试报错 常量中有换行符
  • 基于桥梁三维模型的无人机检测路径规划系统设计与实现
  • Cursor 分析 bug 记录
  • 3D视觉与空间智能
  • imx6ull-驱动开发篇25——Linux 中断上半部/下半部
  • 智谱开源了最新多模态模型,GLM-4.5V
  • 关系型数据库从入门到精通:MySQL 核心知识全解析
  • 高并发系统性能优化实战:实现5万并发与毫秒级响应
  • Kafka生产者——提高生产者吞吐量
  • LeetCode 面试经典 150_数组/字符串_最长公共前缀(20_14_C++_简单)(暴力破解)(求交集)
  • 简单使用 TypeScript 或 JavaScript 创建并发布 npm 插件
  • 从零到一:发布你的第一个 npm 开源库(2025 终极指南)
  • IT资讯 | VMware ESXi高危漏洞影响国内服务器
  • Day62--图论--97. 小明逛公园(卡码网),127. 骑士的攻击(卡码网)
  • 嵌入式 C 语言编程规范个人学习笔记,参考华为《C 语言编程规范》