spring请求参数校验
大纲:
- 参数校验
- ConstraintValidator自定义验证
一、参数验证
@NotNull 就是参数必传
javax.validation.constraints下面有许多注解不一一赘述、字面意思也很清晰。
import lombok.Data; import javax.validation.constraints.NotNull; /** * Created by lby on 2019/6/21. */ @Data public class Person { private String name; @NotNull private String age; }
1.1注解验证
@Validated注解加到需要验证的请求对象上
@RequestMapping("/hello") public String hello(@RequestBody @Validated Person person, BindingResult result){ if(result.hasErrors()){ List<FieldError> fieldErrors = result.getFieldErrors(); fieldErrors.forEach(item->{ System.out.println(item.getDefaultMessage()); }); } return person.getName()+person.getAge(); }
未通过的验证信息会存放到BindingResult对象中。
1.2获取SmartValidator进行验证
SmartValidator在spring初始化完成的时候已经在ioc容器里了
@Autowired SmartValidator validator; @RequestMapping("/hello") public String hello(@RequestBody Person person){ BindingResult result = new BeanPropertyBindingResult(person,person.getClass().getSimpleName()); validator.validate(person,result); if(result.hasErrors()){ result.getAllErrors().forEach(item->{ System.out.println(item.getDefaultMessage()); }); } return person.getName()+person.getAge(); }
1.3分组校验
定义分组:定义两个内部接口A和B就是2个组别。
校验分组:修改一下Person对象上的校验注解加上groups,groups里面的内容就是需要校验的组。
例:下例中需中如果校验A组则name、age都要NotNull,如果校验B则只要nameNotNull
@Data public class Person { @NotNull(groups = {A.class,B.class}) private String name; @NotNull(groups = {A.class}) private String age; public interface A{} public interface B{} }
注解校验:
@RequestBody @Validated(value = { Person.A.class}) Person person,
与之前的区别就是在@Validated中填入了需要校验的组(参数为一个数组),上例中校验A组。
smartValidatior校验:
validator.validate(person,result,Person.A.class);
与之前的区别就是validate方法传入了第三个参数来标识需要验证的组(参数为一个数组)上例中校验A组。
二、ConstraintValidator自定义验证
定义一个验证类实现ConstraintValidator接口
public class EnumValidImpl implements ConstraintValidator<EnumValid,String> { private String[] values; private String message; @Override public void initialize(EnumValid constraintAnnotation) { //拿待验证字段注解上的信息 values = constraintAnnotation.value(); message = constraintAnnotation.message(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { //value就是需要校验的值 //验证 boolean exist = false; for (String evalue : values) { if(value.equals(evalue)){ exist = true; break; } } //报错信息 if (StringUtils.isBlank(message)) { StringBuilder sb = new StringBuilder(); for (String s : values) { sb.append(s).append(";"); } String msg = sb.toString(); msg = msg.substring(0,msg.length()-1); //替换原来的报错信息 context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate("value must in:"+msg).addConstraintViolation(); } return exist; } }
自定义注解用于待校验的属性上
@Constraint(validatedBy = {EnumValidImpl.class })//指定这个校验注解的实现类 @Target({ ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface EnumValid { String[] value(); String message() default "默认报错消息"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
用法:
@Data public class Person { @EnumValid({"aa","bb"}) private String name; private String age; }
我自定义的注解意思:name只能为aa,bb