全方面使用参数校验工具
//被注释的元素,值必须是一个字符串,不能为null,且调用trim()后,长度必须大于0
@NotBlank(message = "")
//被注释的元素,值不能为null,但可以为"空",用于基本数据类型的非空校验上,而且被其标注的字段可以使用 @size、@Max、@Min 等对字段数值进行大小的控制
@NotNull(message = "")
//被注释的的元素,值不能为null,且长度必须大于0,一般用在集合类上面
@NotEmpty(message = "")
//被注释的元素必须符合指定的正则表达式。
@Pattern(regexp = "", message = "")
//被注释的元素的大小必须在指定的范围内。
@Size(min =, max =)
//被注释的元素,值必须是一个数字,且值必须大于等于指定的最小值
@Min(value = long以内的值, message = "")
//被注释的元素,值必须是一个数字,且值必须小于等于指定的最大值
@Max(value = long以内的值, message = "")
//被注释的元素,值必须是一个数字,其值必须大于等于指定的最小值
@DecimalMin(value = 可以是小数, message = "")
//被注释的元素,值必须是一个数字,其值必须小于等于指定的最大值
@DecimalMax(value = 可以是小数, message = "")
//被注释的元素,值必须为null
@Null(message = "")
//被注释的元素必须是一个数字,其值必须在可接受的范围内
@Digits(integer =, fraction =)
//被注释的元素,值必须为true
@AssertTrue(message = "")
//被注释的元素,值必须为false
@AssertFalse(message = "")
//被注释的元素必须是一个过去的日期
@Past(message = "")
//被注释的元素必须是一个将来的日期
@Future(message = "")
//被注释的元素必须是电子邮件地址
@Email(regexp = "", message = "")
//被注释的元素必须在合适的范围内
@Range(min =, max =, message = "")
//被注释的字符串的大小必须在指定的范围内
@Length(min =, max =, message = "")
代码实现
如果项目的框架是 spring boot 的话,在 spring-boot-starter-web 中已经包含了 Hibernate-validator 的依赖(版本必须是2.3之前)。2.3
以后的版本 spring-boot-starter-web
已经去除了这个依赖,需要手动引入 Hibernate-validator
依赖,详细内容见官网描述
org.springframework.boot
spring-boot-starter-validation
非springboot
项目的话直接引入
org.hibernate
hibernate-validator
6.0.17.Final
@Data
public class UserForNormal {
String id;
@NotNull
@Length(min=3,max=8)
String name;
@NotNull
@Email
String email;
@Min(value = 18,message = "未满18哟")
@Max(value = 24,message = "超过24咯")
Integer age;
}
@Validated
@RestController
@RequestMapping("/v")
public class ValidationController {
//推荐将一个个参数平铺到方法入参中。
// 在这种情况下,必须在 Controller 类上标注 @Validated 注解,
// 并在入参上声明约束注解 (如 @Min 等)。
// 如果校验失败,会抛出 ConstraintViolationException 异常。
@GetMapping("/1")
public Object get1(@Length(min=6,max = 10)@NotNull String str,
@NotNull String a){
return str;
}
@PostMapping("/2")
public Object save(@Validated @RequestBody UserForNormal user){
return "2";
}
}
@Data
public class UserForGroup {
@Min(value = 10, groups = Update.class)
String id;
@NotNull(groups = {Save.class, Update.class})
@Length(min = 2, max = 10, groups = {Save.class, Update.class})
String name;
@NotNull(groups = {Save.class})
String email;
public interface Save {
}
public interface Update {
}
}
/*
@Validated 注解上指定校验分组
* */
@PostMapping("/save")
public Object saveUser(@RequestBody @Validated(UserForGroup.Save.class) UserForGroup user) {
// 校验通过,才会执行业务逻辑处理
return "save";
}
@PostMapping("/update")
public Object updateUser(@RequestBody @Validated(UserForGroup.Update.class) UserForGroup user) {
// 校验通过,才会执行业务逻辑处理
return "update";
}
//实际场景中,有可能某个字段也是一个对象,这种情况先,可以使用嵌套校验。
//必须标记 @Valid 注解
@Data
public class UserForObject {
@Length(min = 2, max = 10)
private String userName;
@NotNull
@Valid
private Job job;
@Data
public static class Job {
@Length(min = 2, max = 10)
private String jobName;
}
}
/* 嵌套校验
前面的示例中,DTO 类里面的字段都是基本数据类型和 String 类型。
但是实际场景中,有可能某个字段也是一个对象,这种情况先,可以使用嵌套校验。*/
@PostMapping("/qiantao")
public Object customValidator(@RequestBody @Validated UserForObject user) {
// 校验通过,才会执行业务逻辑处理
/* {
"userName":"22",
"job":
{
"jobName":"3"
}
}*/
return "qiantao";
}
当当前校验字段有误,直接返回错误信息,不会校验后面的字段。默认关闭此功能
@Configuration
public class FailFastConfig {
/* 快速失败 (Fail Fast)
Spring Validation 默认会校验完所有字段,然后才抛出异常。
可以通过一些简单的配置,开启 Fali Fast 模式,一旦校验失败就立即返回。*/
@Bean
public Validator validator(){
ValidatorFactory validatorFactory= Validation.byProvider(HibernateValidator.class)
.configure()
//快速失败模式
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
}
/*
* 编程式校验
上面的示例都是基于注解来实现自动校验的,
在某些情况下,我们可能希望以编程方式调用验证。
这个时候可以注入 javax.validation.Validator 对象,
然后再调用其 api。
*
* */
@Autowired
private javax.validation.Validator globalValidator;
// 编程式校验
@PostMapping("/saveWithCodingValidate")
public Object saveWithCodingValidate(@RequestBody UserForGroup userDTO) {
Set> validate = globalValidator.validate(userDTO, UserForGroup.Save.class);
// 如果校验通过,validate为空;否则,validate包含未校验通过项
if (validate.isEmpty()) {
// 校验通过,才会执行业务逻辑处理
} else {
for (ConstraintViolation userDTOConstraintViolation : validate) {
// 校验失败,做其它逻辑
System.out.println(userDTOConstraintViolation);
}
}
return "编程方式调用验证";
}
自定义注解标注需校验参数字段,进行自定义方法校验参数值
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {IsUniqueIdValidator.class})
public @interface IsUniqueId {
//默认错误信息提示
String message() default "非独特id";
//分组
Class>[] groups() default {};
//负载
Class extends Payload>[] payload() default {};
}
public class IsUniqueIdValidator implements ConstraintValidator
{
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if(value!=null){
return true;
}
return false;
}
}
@Data
public class UserForCustAnnotation {
@IsUniqueId
String id;
}
@PostMapping("/custom/val")
public Object customValidator(@RequestBody @Validated UserForCustAnnotation user) {
// 校验通过,才会执行业务逻辑处理
return "custom/annotation";
}
@RestControllerAdvice
public class CommonExceptionHandler {
@ExceptionHandler({MethodArgumentNotValidException.class})
@ResponseStatus(HttpStatus.OK)
public Map handleMethodArgumentNotValidException(MethodArgumentNotValidException ex){
Map map=new HashMap();
BindingResult bindingResult = ex.getBindingResult();
StringBuilder sb = new StringBuilder("校验失败:");
for (FieldError fieldError : bindingResult.getFieldErrors()) {
sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
}
String msg = sb.toString();
map.put("code",5001);
map.put("msg",msg);
return map;
}
@ExceptionHandler({ConstraintViolationException.class})
@ResponseStatus(HttpStatus.OK)
public Map handleConstraintViolationException(ConstraintViolationException ex) {
Map map=new HashMap();
Set> violations = ex.getConstraintViolations();
Iterator> iterator = violations.iterator();
StringBuilder sb = new StringBuilder("校验失败:");
while (iterator.hasNext()){
ConstraintViolation> next = iterator.next();
sb.append(next.getPropertyPath().toString().split("\\.")[1]).append(":").append(next.getMessage()).append(", ");
}
map.put("code",5001);
map.put("msg",sb.toString());
return map;
}
}
区别 | @Valid | @Validated |
提供者 | JSR-303规范 | Spring |
是否支持分组 | 不支持 | 支持 |
标注位置 | Method,filed,constructor,parameter,type_use | type,method,parameter |
嵌套校验 | 支持 | 不支持 |