
前言
再次重申,本项目非原创,视频来源于:
Springboot项目实战 easypan 仿百度网盘 计算机毕业设计 简历项目 项目经验(后端)
再次重申:本人不分享项目源码,支持项目付费!!
回顾
昨天学习了获取图片验证码和发送邮箱验证码的实现过程,但在发送邮箱验证码时,
可以发现这里我们还缺少了一个步骤,在发送前,还需要判断传递的参数 email,checkCode,type 是否为空以及是否合理。在不合理的情况下需对参数进行拦截。
通常思维是添加 if 语句一个参数一个参数地判断,但这样可以发现比较麻烦,后续其他业务也需要进行参数判断时,还要进行相似的判断过程。。。
所以我们要使用 AOP 来实现参数拦截
AOP 实现切面管理
1. 定义注解
定义一个用于方法层面的拦截的 GlobalInterceptor 注解,允许在方法上标记该注解:
- @Target({ElementType.METHOD}):Target定义了这个注解可以应用于哪些 Java 元素,ElementType.METHOD 指明 GlobalInterceptor 注解只能用在方法上。
- 它提供了一个选项 checkParams,用于控制是否对方法参数进行校验,默认情况下不进行校验
再定义一个用于参数验证的 VerifyParam 注解:
- @Target({ElementType.PARAMETER,ElementType.FIELD}):ElementType.PARAMETER,ElementType.FIELD 指明 VerifyParam 注解可以应用于方法参数(PARAMETER)和类字段(FIELD)两种类型元素。
- 校验的内容包括参数的最小长度,最大长度,是否必传,以及正则表达式参数验证。
2. 定义枚举类型
定义一个用于存储常用的正则表达式以及对应的描述信息的枚举类型VerifyRegexEnum。定义了几种常见的正则表达式(如邮箱和密码)的常量及其说明,用于验证对应的数据。
这段代码比较常见,我直接粘贴在下面,方便我后面使用:
public enum VerifyRegexEnum {
NO("", "不校验"),
EMAIL("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$", "邮箱"),
PASSWORD("^(?=.*\\d)(?=.*[a-zA-Z])[\\da-zA-Z~!@#$%^&*_]{8,}$", "只能是数字、字母、特殊字符,长度8-18位");
//IP("([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}", "IP地址"),
//POSITIVE_INTEGER("^[0-9]*[1-9][0-9]*$", "正整数"),
//NUMBER_LETTER_UNDER_LINE("^\\w+$", "由数字、26个英文字母或者下划线组成的字符串"),
//PHONE("(1[0-9])\\d{9}$", "手机号码"),
//COMMON("^[a-zA-Z0-9_\\u4e00-\\u9fa5]+$", "数字、字母、中文、下划线"),
//ACCOUNT("^[0-9a-zA-Z_]{1,}$", "字母开头,由数字、英文字母或者下划线组成"),
//MONEY("^[0-9]+(.[0-9]{1,2})?$", "金额");
private String regex; // 存储正则表达式的字符串
private String desc; // 存储正则表达式的描述信息
VerifyRegexEnum(String regex, String desc) {
this.regex = regex;
this.desc = desc;
}
public String getRegex() {
return regex;
}
public String getDesc() {
return desc;
}
}
3. AOP切面
编写 GlobalOperationAspect 类,实现面向切面编程,用于在调用标记为 @GlobalInterceptor 注解的方法之前,自动执行一些参数校验和处理逻辑。
- @Pointcut 注解定义了切入点,
后面的@annotation(com.easypan.annotation.GlobalInterceptor)表示:某个目标方法上加上 @GlobalInterceptor 注解时,requestInterceptor() 方法定义的切入点就会被触发。 - requestInterceptor 是切入点的名称,方法体为空。这是因为切入点本身不需要具体的实现逻辑,定义切入点只是为了描述哪些方法需要被拦截。
- @Before 注解定义通知的类型,说明 interceptorDo 方法将在匹配 requestInterceptor 切入点的任何方法之前执行
- JoinPoint 用于提供关于正在执行的连接点(即被拦截的方法)的各种信息,比如方法的名称、参数和目标对象。
interceptorDo 方法获取被拦截的方法的各种信息,用于进行参数校验。这段代码很长,就不粘贴了。
Controller层添加注解:
这里可以仔细看看interceptorDo 方法获取被拦截的方法的各种信息的代码,这里比较难理解。我通过 Debug 方式来看看这些信息:
这里一开始不太理解 methodName 和 method 有什么区别,后来知道:
- methodName 是一个字符串,表示当前方法的名称。它仅包含方法的名称,没有关于方法参数类型或方法对象的其他信息。
- method 是一个 Method 类型的对象,表示当前目标对象上具体的方法。它不仅包含方法的名称,还包括方法的参数类型、返回类型、修饰符等信息,是反射中用于获取和操作类方法的关键对象。
总结
使用了 AOP 切面来实现参数拦截,总的来说就是定义一个切面类,在切面类中定义切点,指定哪些方法需要被拦截,在切面类中编写通知方法,使用 @Before、@After 或 @Around 注解来定义通知的类型,这个通知方法将会在切点匹配到的方法被调用时被触发。通过 ProceedingJoinPoint(在 @Around 通知中)或 JoinPoint(在 @Before 和 @After 通知中)来获取方法参数,再对参数进行处理。