Spring Boot :使用 validation 验证参数
一、简介
1、添加包
hibernate-validator
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.2.Final</version>
</dependency>
或者添加spring-boot-starter-validation
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
或者添加spring-boot-starter-web
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2、注解说明JSR提供的校验注解:
注解 作用
@Null 被注释的元素_值必须为 null
@NotNull 被注释的元素_值必须不为 null
@Pattern(regex=) 被注释的元素字符串_必须符合指定的正则表达式
@Size(max=, min=) 集合元素数量必须在min和max范围内
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Range(min,max) 数字必须在min和max范围内
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Email 字符串必须是Email地址
@SafeHtml 字符串必须是安全的html
@URL 字符串必须是合法的URL
@CreditCardNumber(ignoreNonDigitCharacters=) 字符串必须是信用卡号,按照美国的标准验证
@Size(max,min) 限制字符长度必须在min到max之间
Hibernate Validator提供的校验注解:
注解 作用
@NotBlank(message =) 验证字符串非null,且trim后长度必须大于0
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
@AssertFalse 校验false
@AssertTrue 校验true
@DecimalMax(value=,inclusive=) 小于等于value,
inclusive=true 是小于等于
@DecimalMin(value=,inclusive=) 与上类似
@Max(value=) 小于等于value
@Min(value=) 大于等于value
@NotNull 检查Null
@Past 检查日期
@Pattern(regex=,flag=) 正则
@Size(min=, max=) 字符串,集合,map限制大小
@Valid 对po实体类进行校验
三、代码示例一
1、Controller添加@Valid或者@Validated都可以
@RestController
@RequestMapping("/")
public class UserController {
@RequestMapping("testValidation")
public String testValidation(@Valid @RequestBody UserRequest userRequest) {
return "success";
}
}
2、实体类添加校验注解
import java.io.Serializable;
import javax.validation.constraints.Max;
import javax.validation.constraints.Pattern;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;
import lombok.Data;
@Data
public class UserRequest implements Serializable{
private static final long serialVersionUID = 1L;
@NotEmpty(message="用户id不能为空")
private String userId;
@Email(message="非法邮件地址")
private String email;
@Pattern(regexp="^(\\d{6})(\\d{4})(\\d{2})(\\d{2})(\\d{3})([0-9]|X)$",message="身份证号不合规")
private String cardNo;
@Length(min=1,max=10,message="昵称长度必须在1~10")
private String nickName;
@Range(min=0,max=2,message="非法性别")
private String sex;
@Max(value=100,message="非法年龄")
private int age;
}
3、添加全局异常拦截
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {undefined
/**
* 参数合法性校验异常
* @param exception
* @return
*/
@ResponseBody
@ExceptionHandler(MethodArgumentNotValidException.class)
public String validationBodyException(MethodArgumentNotValidException exception){
StringBuffer buffer = new StringBuffer();
BindingResult result = exception.getBindingResult();
if (result.hasErrors()) {
List<ObjectError> errors = result.getAllErrors();
errors.forEach(p ->{
FieldError fieldError = (FieldError) p;
log.error("Data check failure : object{"+fieldError.getObjectName()+"},field{"+fieldError.getField()+
"},errorMessage{"+fieldError.getDefaultMessage()+"}");
buffer.append(fieldError.getDefaultMessage()).append(",");
});
}
BaseResponse response = new BaseResponse(BusinessCodeEnum.INVALID_PARAM);
response.setRespMsg(buffer.toString().substring(0, buffer.toString().length()-1));
return JSONObject.toJSONString(response);
}}
四、代码示例二
1、校验bean
public class Book{
private Integer id;
@NotBlank(message = '不能为空')
private String bookName;
@NotBlank(message = '不能为空')
private String bookAuthor;
}
2、自定义异常
Spring Boot的Controller方法中可以传一个BindingResult或者Errors类型的参数
@RestController
public class BookController {
@PostMapping("/book")
public Book getBook(@Valid Book book, BindingResult result, HttpServletResponse response) {
if (result.hasErrors()) {
result.getAllErrors().forEach((error) -> {
FieldError fieldError = (FieldError) error;
// 属性
String field = fieldError.getField();
// 错误信息
String message = fieldError.getDefaultMessage();
System.out.println(field + ":" + message);
});
}
// ...
return book;
}
}
Spring Boot的异常处理+Bean Validation
Spring Boot 中有一个专门处理错误信息的一个类叫做ResponseEntityExceptionHandler。其中有很多关于400的错误处理,也就是参数错误的处理,其中就有一个专门用来处理没有通过校验的参数的方法。我们重写这个类的这个方法即可。
@ControllerAdvice // Spring 的异常处理的注解
public class BadRequestExceptionHandler extends ResponseEntityExceptionHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
Map<String, String> messages = new HashMap<>();
BindingResult result = ex.getBindingResult();
if (result.hasErrors()) {
List<ObjectError> errors = result.getAllErrors();
for (ObjectError error : errors) {
FieldError fieldError = (FieldError) error;
messages.put(fieldError.getField(), fieldError.getDefaultMessage());
}
logger.error(messages.toString());
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(messages);
}
}
@AssertFalse
Boolean,boolean
验证注解的元素值是false
@AssertTrue
Boolean,boolean
验证注解的元素值是true
@NotNull
任意类型
验证注解的元素值不是null
@Null
任意类型
验证注解的元素值是null
@Min(value=值)
BigDecimal,BigInteger, byte,short, int, long,等任何Number或CharSequence(存储的是数字)子类型
验证注解的元素值大于等于@Min指定的value值
@Max(value=值)
和@Min要求一样
验证注解的元素值小于等于@Max指定的value值
@DecimalMin(value=值)
和@Min要求一样
验证注解的元素值大于等于@ DecimalMin指定的value值
@DecimalMax(value=值)
和@Min要求一样
验证注解的元素值小于等于@ DecimalMax指定的value值
@Digits(integer=整数位数, fraction=小数位数)
和@Min要求一样
验证注解的元素值的整数位数和小数位数上限
@Size(min=下限, max=上限)
字符串、Collection、Map、数组等
验证注解的元素值的在min和max(包含)指定区间之内,如字符长度、集合大小
@Past
java.util.Date,java.util.Calendar;Joda Time类库的日期类型
验证注解的元素值(日期类型)比当前时间早
@Future
与@Past要求一样
验证注解的元素值(日期类型)比当前时间晚
@NotBlank
CharSequence子类型
验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的首位空格
@Length(min=下限, max=上限)
CharSequence子类型
验证注解的元素值长度在min和max区间内
@NotEmpty
CharSequence子类型、Collection、Map、数组
验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@Range(min=最小值, max=最大值)
BigDecimal,BigInteger,CharSequence, byte, short, int, long等原子类型和包装类型
验证注解的元素值在最小值和最大值之间
@Email(regexp=正则表达式,flag=标志的模式)
CharSequence子类型(如String)
验证注解的元素值是Email,也可以通过regexp和flag指定自定义的email格式
@Pattern(regexp=正则表达式,flag=标志的模式)
String,任何CharSequence的子类型
验证注解的元素值与指定的正则表达式匹配
@Valid
任何非原子类型
指定递归验证关联的对象如用户对象中有个地址对象属性,如果想在验证用户对象时一起验证地址对象的话,在地址对象上加@Valid注解即可级联验证