本文部分内容来自互联网。
在进行REST接口开发的时候,需要对POST/PUT等接口传入的参数进行一些校验的时候,可以通过Hibernate Validator提供的注解进行校验。这些注解放在参数实体定义的属性或者类上面,能够进行默认的校验。
配合@Valid
注解和BindingResult
功能一起使用,则可以在Controller的具体实现逻辑中进行校验后的处理。
1. 常用的校验注解
注解 | 功能 |
---|---|
@NotNull |
值不为空 |
@Null |
值只能为空 |
@Pattern(regex=) |
字符串必须匹配括号内的正则表达式 |
@Size(max=,min=) |
集合的元素数量必须max和min之间的值 |
@CreditCardNumber(ignoreNonDigitCharacters=) |
字符串必须是美国标准的信用卡卡号 |
@Email |
字符串必须是email地址 |
@Length(min=,max=) |
检查字符串的长度 |
@NotBlank |
字符串必须有字符 |
@NotEmpty |
字符串不为null,集合有元素 |
@Range(min=,max=) |
数字必须大于min,小于max |
@SafeHtml |
字符串是安全的html代码 |
@URL |
字符串是合法的url |
@AssertFalse |
值必须是false |
@AssertTrue |
值必须是true |
@DecimalMax(value=,inclusive=) |
值必须小于等于(inclusive=true)/值必须小于(inclusive=false):可以注解在字符串类型上 |
@DecimalMin(value=,inclusive=) |
值必须大于等于(inclusive=true)/值必须大于(inclusive=false):可以注解在字符串类型上 |
@Max(value=) |
值必须小于等于value指定的值,不能注解在字符串类型上 |
@Min(value=) |
值必须大于等于value执行的值,不能注解在字符串类型上 |
@Digits(integer=,fraction=) |
数字格式检查,integer指定整数部分的长度,fraction指定小数部分的长度 |
@Futrue |
值必须是未来的注解 |
@Past |
值只能是过去的时间 |
2. 在服务中使用校验
例如,通过请求添加一个用户信息,
- 那么首先需要在这个用户的定义时确定好要满足哪些信息。比如,用户名不能为空,密码不能为空等。
public class UserInfo {
private int id;
@NotBlank
private String name;
@NotNull
private String passwd;
@Range(min=10, message = "年龄不能小于10")
private int age;
private String mail;
private String phoneNumber;
private String address;
}
- 通过REST的post接口添加用户,则用户信息的body体必须满足这些条件,否则的话controller的服务中,就要校验,并捕获这些异常。
/**
* 添加一个新的用户
*/
@PostMapping(value = "/user")
public UserInfo addOneSpecifiedUser(@Valid UserInfo userInfo, BindingResult errors) {
if(errors.hasErrors()){
errors.getAllErrors().stream().forEach(
error -> logger.error(error.toString())
);
}
logger.info("进入到用户添加的页面");
return userInfo;
}
@Valid
注解的功能是检查REST请求推送来的请求体是否满足预定义的格式,如果不满足,那么这些请求中的错误信息将会被BindingResult绑定的变量errors
所接收,并带着这些异常进入请求响应代码,由请求响应部分去处理这些异常。
- 使用REST工具发送这样的请求后,产生的效果如下:
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController : Field error in object 'userInfo' on field 'age': rejected value [1]; codes [Range.userInfo.age,Range.age,Range.int,Range]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.age,age]; arguments []; default message [age],9223372036854775807,10]; default message [年龄不能小于10]
2018-04-25 10:41:09.303 ERROR 3240 --- [nio-8080-exec-9] o.l.s.controller.UserController : Field error in object 'userInfo' on field 'passwd': rejected value [null]; codes [NotNull.userInfo.passwd,NotNull.passwd,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userInfo.passwd,passwd]; arguments []; default message [passwd]]; default message [不能为null]
3. 自定义校验
要实现类似于本文中提供那些常用校验方式同样的便利,需要自定义我们自己的校验规则注解。
自定义注解进行校验的步骤:
- 写一个校验注解,在注解中指定校验器类,校验注解与校验器一般一一对应。
- 写一个校验器类并在校验器类中写校验逻辑,校验器必须实现ConstraintValidator<?, ?>接口,第一个参数是对应的注解,第二个参数是要校验的属性的类型。
代码实例
S1: 自定义校验注解
package com.kunlun.validation.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import com.kunlun.validation.validator.KlPatternValidator;
/**
* 自定义的校验注解
* 规则:
* 1.如果字符串为空串或者为null,则不进行正则校验
* 2.如果字符串不为空串,则必须进行正则校验
* @author xc
* @date 2018年1月19日上午11:38:02
*/
@Documented
// 指定该注解可以使用的地方
@Target(value= {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
// 指定实际进行校验的校验器,该校验器是自己写的且必须实现ConstraintValidator接口
@Constraint(validatedBy=KlPatternValidator.class)
public @interface KlPattern {
/*
* 用于验证的注解下列这三个方法必须要,这是Hibernate Validation框架要求的,否则程序再在调用的时候会报错
* default用于对属性给定默认值
* 如果不给定默认值,则在使用注解的时候必须给属性指定属性值,否则报错
* 给定默认值时,在使用注解的时候可以不用指定属性值
*/
String message() default "不符合正则!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
// 没加default给定默认值,使用注解的时候该属性必须赋值,否则报错
String regex();
// value属性,加上了default "mercy" 使得该属性在使用注解的时候可以不用输入也不会报错
String value() default "mercy";
}
S2: 与上面校验注解对应的校验器类
package com.kunlun.validation.validator;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import com.kunlun.validation.annotation.KlPattern;
/**
* KlPatternValidator是KlPattern注解实际调用的验证器
* 在KlPatternValidator中完成校验逻辑
*
* @author xc
* @date 2018年1月19日上午11:44:38
*/
public class KlPatternValidator implements ConstraintValidator<KlPattern, String> {
private String regex;
/**
* 通过initialize()可以获取注解里的属性值
*/
@Override
public void initialize(KlPattern constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
regex = constraintAnnotation.regex();
}
/**
* 实际验证逻辑
* 返回值为true表示验证通过,
* 返回值为false表示验证未通过
*/
@Override
public boolean isValid(String s, ConstraintValidatorContext ctx) {
// 当前前端传过来的请求参数是空串,或者没传的时候,不进行后续正则校验
if ("".equals(s) || s == null) {
return true;
}
// 进行正则校验
if(s.matches(regex)) {
return true;
}
return false;
}
}