BindingResult是用来校验参数的可用参数如下所示: @Null 只能是null @NotNull 不能为null
注意用在基本类型上无效,基本类型有默认初始值 @AssertFalse 必须为false @AssertTrue 必须是true字符串/数组/集合检查:(字符串本身就是个数组) @Pattern(regexp="reg") 验证字符串满足正则 @Size(max,
min) 验证字符串、数组、集合长度范围 @NotEmpty 验证字符串不为空或者null @NotBlank
验证字符串不为null或者trim()后不为空数值检查:同时能验证一个字符串是否是满足限制的数字的字符串 @Max 规定值得上限int @Min 规定值得下限
@DecimalMax("10.8") 以传入字符串构建一个BigDecimal,规定值要小于这个值 @DecimalMin
可以用来限制浮点数大小 @Digits(int1, int2) 限制一个小数,整数精度小于int1;小数部分精度小于int2 @Digits
无参数,验证字符串是否合法 @Range(min=long1,max=long2) 检查数字是否在范围之间 这些都包括边界值日期检查:Date/Calendar @Post 限定一个日期,日期必须是过去的日期 @Future 限定一个日期,日期必须是未来的日期
其他验证: @Vaild 递归验证,用于对象、数组和集合,会对对象的元素、数组的元素进行一一校验 @Email
用于验证一个字符串是否是一个合法的右键地址,空字符串或null算验证通过
@URL(protocol=,host=,port=,regexp=,flags=) 用于校验一个字符串是否是合法UR
那么我们可以简化,使用自己写的一个注解注入到服务层,让其自己完成必须参数的校验功能
maven项目引入
public class Parameter {
@NotEmpty(message="姓名不能为空")
private String name;
@Min(value = 18, message = "年龄必须大于18岁")
private int age;
@NotEmpty(message="hobbies不能为空")
private List<String> hobbies;
}
建一个实体类对象
/**检查方法实体类是否符合规则
* @author qilong
*/
//在自定义注解的时候可以使用@Documented来进行标注,如果使用@Documented标注了,在生成javadoc的时候就会把@Documented注解给显示出来。
@Documented
//@Retention可以用来修饰注解,是注解的注解,称为元注解。RetentionPolicy.RUNTIME运行时注解,注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;
@Retention(RetentionPolicy.RUNTIME)
//注解的作用目标METHOD——方法,TYPE——接口、类、枚举、注解
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface EntityCheck {
/**
* 是否打印输出拦截日志
* @return
*/
boolean debug() default false;
}
新建一个自定义注解接口
/**实体类检查切面
* @author qilong
*/
@Aspect
@Component
@Slf4j
public class EntityCheckAspect {
//之前注解接口的路径
@Pointcut("@annotation(zx.cloud.commons.utils.entityCheck.EntityCheck)")
public void pointEntityCheck() {
}
/**
* 环绕切入点
* 匹配指定包包下所有使用@Service注解的类
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around(value = "pointEntityCheck()")
private Object entityCheck(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 获取切入的方法对象
// 这个m是代理对象的,没有包含注解
Method m = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();
// this()返回代理对象,target()返回目标对象,目标对象反射获取的method对象才包含注解
Method methodWithAnnotations = proceedingJoinPoint.getTarget().getClass().getDeclaredMethod(
proceedingJoinPoint.getSignature().getName(), m.getParameterTypes());
EntityCheck annotation = methodWithAnnotations.getAnnotation(EntityCheck.class);
if (annotation.debug()) {
log.info("实体类验证:拦截到包:{} 方法:{}", proceedingJoinPoint.getTarget().getClass().getName(), proceedingJoinPoint.getSignature().getName());
}
//获取所有参数
Object[] args = proceedingJoinPoint.getArgs();
for (Object o: args) {
if (o instanceof BindingResult){
//校验不通过如果有错误 不执行方法直接返回出去
String re = getError((BindingResult)o);
if (null != re) {
//NormalResponse 是我自己的返回的格式,你可以自定义,例如返回一个map,String 都可以
return new NormalResponse(Code.FAIL, re);
}
}
}
//参数校验没有错误继续执行方法
return proceedingJoinPoint.proceed(args);
}
//自定义错误返回, 当实体类校验不通过,这里会直接返回给前端
public static String getError(BindingResult result) {
StringBuffer errorInfo = new StringBuffer();
if (result.hasErrors()) {
List<FieldError> fieldErrors = result.getFieldErrors();
for (FieldError error : fieldErrors) {
errorInfo.append(String.format("参数 %s错误: %s ", error.getField(), error.getDefaultMessage()));
}
return errorInfo.toString();
} else {
return null;
}
}
}
新建一个类用以实现AOP
@Slf4j
@Service
public class TestServiceImpl implements TestService {
//加上我们自定义的注解
@EntityCheck
@Override
public NormalResponse createAutoProvisioningGroup(Parameter entity, BindingResult result) {
log.info("没有遇到参数错误我已被运行!");
}
}
服务层
@Slf4j
@Service
public class TestServiceImpl implements TestService {
//加上我们自定义的注解
@EntityCheck
@Override
public NormalResponse createAutoProvisioningGroup(Parameter entity, BindingResult result) {
log.info("没有遇到参数错误我已被运行!");
}
}
访问你的接口,如果有参数不对,就不会执行服务层,被@EntityCheck注解检查后拦截返回,至此自定义参数校验注解完成!