当你的接口需要参数校验的时候,尤其是判空操作的时候,是不是还在用validated和notNull组合标签呢,其实这个spring提供的组合技没啥打问题,最大的问题我觉得就是太繁琐了,而且有时候我们开发功能的时候,业务需求可能不仅仅是判空,有些还带有业务特性上的校验,反正业务是永远在变化的,需求是无穷的,所以,有没有办法搞一个满足所有需求的参数校验的类似notNull的注解呢,答案当然是有了。
好了,我们今天的主角还是AOP,aop我想都很熟悉了,切面嘛,可以把一些特有的逻辑从一个切入点插入到我们的业务系统中,从而更优雅的实现业务功能,今天我们的参数校验功能也是一样的,最关键的是如何找到这个切入点。
作为接口参数校验,一般想的都是既然是接口,那切入点自然就是collection嘛,我们可以把所有collection所在的包路劲作为切入点,这个想法是可以的,但是我们可以更精确一点,参照notNull的思路,它是检测每一个被打上validated的接口方法,那么我们作为接口参数的校验,每个接口是不是都需要实现GetMapping和PostMapping,不然的话都这个接口都无法被外部访问到了,所以,我们的切入点可以是GetMapping和PostMapping这两个注解,这里我们插一段面经哈,如果你面试的时候面试官问你为什么你们公司所有的接口都只用postMapping,以后,除了post请求和get请求的不同之处外,你还可以告诉他,因为我们公司使用postMapping注解自主实现了参数校验,技术统一,约定大于配置嘛哈哈
好了,我们的aop切入点找到了,接下来就是代码实现了,代码很简单,定义我们的切入点PostMapping
@Aspect
public class EnvNotNullAspect {
@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void EnvNotNull() {
}
}
切入点有了,下一步我们应该实现自己的参数注解了,就是为你需要校验的参数打上的注解,自定义注解嘛,老朋友了,首先分析注解需要的属性,第一个错误提示肯定是必须的,然后就是基于业务规划我们可以定义某些像httpStatus的状态码,所以我们需要一个code,初步的就是这样了
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EnvNotNull {
/**
* 报错code
* @return
*/
String Code() default "400";
/**
* 报错消息
* @return
*/
String Msg() default "不能为空";
}
这里,我们就以判空操作为例子来讲解了,自定义注解有了,最后一步就是实现我们判空的逻辑了,作为参数判空,肯定是请求进入之前做判断了,废话不多说,直接上代码
@Aspect
public class EnvNotNullAspect {
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")
public void EnvNotNull() {
}
@Before("EnvNotNull()")
public void before(JoinPoint joinPoint) throws IllegalAccessException {
Object[] args = joinPoint.getArgs();
if (args.length == 0) return;
Field[] fields = args[0].getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
Object value = field.get(args[0]);
EnvNotNull annotation = field.getAnnotation(EnvNotNull.class);
if (annotation != null) {
if (value == null || StringUtils.isEmpty(value)) {
throw new NotNullException(annotation.Code(), annotation.Msg());
}
}
}
}
}
这里稍微解释下吧,首先我们通过切入点拿到参数,这里要注意的是要设置accessible为true,不然后面获取属性值的时候会报错,拿到我们打上自定义注解的属性以及它的值之后,剩下的就是基于我们的业务逻辑处理,因为这里我们只是判空,所以就是拿到值判断是否为空即可,如果你想扩展如加上手机号判断以及邮箱或者业务规则也是同样的道理
我们的自定义参数校验功能初步实现了,看起来很简单,其实也并没有多么困难对吧哈哈
最后,还是要送上一位名人曾说的一句话:手上没有剑和有剑不用是两回事!