SpringBoot实现自定义校验demo
一、聊聊为什么要自定义校验(个人理解)。
校验旨在对参数的合理性作出判断,然后进行下一步操作,以往甚至现在仍然有一些公司,后台的校验是在业务层,通过判断进行校验的。这样做实际上没有什么过错,对于一个参数的合理性也能做到判断,那么聊聊现在主流为什么要将校验从业务层面往前剥离了?我认为有以下几个原因:
- 为什么前端做了校验,后台还要做校验?很简单,因为前端做校验一部分程度是因为前端的校验的目的不仅仅是为了提高参数安全性和合理性,同时也是为了提高用户的体验感。后台还要做一层校验是为了更为安全。很简单的一个道理,在前后端分离的时代,难道只有前端能调用你的接口吗,随便一个AapiPost都能调用你的接口,再退一步而言,即使访问你的接口需要上面token认证啊,其他参数协调啊,但是总归还是存在一定的风险的,在项目上线之后,很有可能,因为接口参数的不规范,导致整个系统崩掉,而造成巨大损失。因此后端不做校验的系统,是一个不健壮的系统,既然可以规避这些风险,为什么不做呢?
- 管理将校验从业务中往前剥离。我认为主要是两点:(1):函数职责单一性,我这个接口函数,明明目的性就是为了做一个计算业务逻辑,你还要我做参数的校验工作,明显不合理。(2)解耦:我将参数的校验从业务接口里面剥离出来,如果哪天我参数的校验规则发生了变化,那么我就不需要去动我接口里面的代码,我就往前该校验规则就行了。
(3)方便性:以往我做校验还要各种if语句,有些相同的参数,明明同一规则,却要我在不同的接口里面调用校验两次,我将其剥离出来之后,通过一个注解就可以完成校验,何乐而不为了?
二、自定义注解
- 自定义注解声明
- 自定义注解的实现
由于注解里面可以写内部类,那就直接写在一起了,方便看,关于其他一些常见的注解其大致的实现原理如下(以@NotNull为例)
@NotNull的注解如下:截图
安装截图标注点进去之后
我们直接进去其顶级父接口ConstraintValidator去找对应的实现类
可以发现他的实现类好多好多哈哈
其校验实现逻辑在这
最后我们自己来个自定义校验注解吧,为了好看,我直接将实现类写在注解内部
package com.fcs.pcrm.annotation;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
/**
* 校验list元素的范围是否在[min,max]之内
*/
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidListRange.ListItemRangeImpl.class)
public @interface ValidListRange {
String message() default "ListItem is not right";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int min() default Integer.MIN_VALUE;
int max() default Integer.MAX_VALUE;
class ListItemRangeImpl implements ConstraintValidator<ValidListRange, List<Integer>> {
private long min;
private long max;
@Override
public void initialize(ValidListRange constraintAnnotation) {
this.max = constraintAnnotation.max();
this.min = constraintAnnotation.min();
}
@Override
public boolean isValid(List<Integer> list, ConstraintValidatorContext context) {
for(Integer value : list) {
if(value < min || value > max) {
return false;
}
}
return true;
}
}
}
就这么简单,