参照:https://www.cnblogs.com/yihuihui/p/11656053.html
一、参数校验依赖的引入
当我们创建了一个springboot项目,引入了 spring-boot-web-starter
依赖之后,我们 就可以使用 参数校验了。
因为 web-starter
中已经默认的引入了 hibernate validator
参数校验功能了。
二、数据校验的使用场景?
场景: 当我们需要校验的参数个数较多时,我们可以把这些参数 封装到一个VO类
中,然后在 对每个属性进行参数校验。
好处 :这样会使得 我们的代码看起来非常简洁,而且搭配 全局异常处理 之后,会有更好的效果。
三、 校验类型都有哪些?
参考:
###空检查###
@Null 参数值必须为null,否则校验失败,抛异常。
@NotNull 参数值必须 不能为null。无法查检长度为0的字符串。
@NotEmpty String的话:值不能为 `null` 和 不能是空字符串 "".
Collection的话:值 不能为null 和 size != 0。
@NotBlank String的话:值不能为 `null` 、 不能空字符串 "" 、不能是空格字符串" "。
【注】:此注解只对字符串有效,并且会自动的去掉字符串的前后空格.
**Booelan检查**
@AssertTrue Boolean值必须为 true
@AssertFalse Boolean值必须为 true false
**长度检查**
@Size(min=, max=, message="元素个数必须在5-20之间")
验证对象(Array,Collection,Map,String)长度 必须在指定的范围之内
@Length(min=5, max=20, message="用户名长度必须在5-20之间")
**日期检查**
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern String值 必须否符合正则表达式的规则
**数值检查,**
建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为String为"",Integer为null
@Min Number 和 String 值不能小于 给定值
@Max Number 和 String 值不能大于 给定值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.
小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.
小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。
@Range(min=, max=) Checks whether the annotated value lies between (inclusive) the specified minimum and maximum.
@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;
**@Valid 递归的对关联对象进行校验**, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
四、如何使用:
1、在实体类中的属性上 添加 需要的校验规则注解:
如:
@Email (message=" ")
,message属性的意思是:数值校验失败时的提示信息。
代码如下:
@Data
public class UserVO {
@NotBlank(message = "not null")
private String name;
@Email(message = "format is not")
private String email;
}
2、然后在 VO使用的地方,使用@Validated
注解,来开启数据格式校验。
如在Controller代码的入参上:
/**
* 使用了@RequestBody 注解接收参数
*
* 校验失败,抛出异常:MethodArgumentNotValidException
*
* @param person
* @return
*/
@RequestMapping("/valid1")
public Object test1(@RequestBody @Validated Person person, BindingResult bindingResult) {
//参数校验
if (bindingResult.hasErrors()) {
// 抛出一个自定义类型的异常,然后用全局处理器 统一补货来处理。
throw new ParamException(bindingResult.getAllErrors().get(0).getDefaultMessage());
}
return person;
}
/**
* 未使用@RequestBody 注解接收参数
*
* 校验失败,抛出异常:BindException BeanPropertyBindingResult
*
* @param person
* @param bindingResult 校验的结果对象
* @return
*/
@RequestMapping("/valid2")
public Object test2(@Validated Person person, BindingResult bindingResult) {
//参数校验
if (bindingResult.hasErrors()) {
// 抛出一个自定义类型的异常,然后用全局处理器 统一补货来处理。
throw new ParamException(bindingResult.getAllErrors().get(0).getDefaultMessage());
}
return person;
}
五、校验失败时的异常 情况分类:
-
当使用
@RequestBody
接收json
格式数据时,数据校验失败时,就会抛出异常:MethodArgumentNotValidException
。 -
若未用
@RequestBody
的形式直接接收参数时,校验失败,则会抛出BindException e
这个类型的异常。
异常的处理:
异常被抛出后,一般是使用 全局异常处理
的方式,来进行统一的异常捕获处理。然后响应给前端 提示信息。
@ControllerAdvice
public class GlobalException {
/**
* MethodArgumentNotValidException 异常处理
* 产生原因:使用@RequestBody 注解的参数校验失败。
*
* @param e MethodArgumentNotValidException
* @return FebsResponse
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public String MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
StringBuilder message = new StringBuilder();
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError error : fieldErrors) {
message.append(error.getField()).append(error.getDefaultMessage()).append(",");
}
message = new StringBuilder(message.substring(0, message.length() - 1));
return "MethodArgumentNotValidException " + message.toString();
}
/**
* BindException 异常处理
* 产生原因:对象类型的参数绑定失败(即:未使用@RequestBody 注解的参数校验)
*
* @param e BindException
* @return FebsResponse
*/
@ExceptionHandler(BindException.class)
@ResponseBody
public String validExceptionHandler(BindException e) {
StringBuilder message = new StringBuilder();
List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
for (FieldError error : fieldErrors) {
message.append(error.getField()).append(error.getDefaultMessage()).append(",");
}
message = new StringBuilder(message.substring(0, message.length() - 1));
return "BindException : " + message.toString();
}
/**
自定义的异常类型ParamException,来捕获以上 两种不同类的参数校验异常类型。
*/
@ExceptionHandler(value = ParamException.class)
@ResponseBody
public void paramException(ParamException ex, WebRequest request, HttpServletResponse response) throws IOException {
//利用HttpServletResponse返回 特定http状态码
RespDataUtil.buildBizError(response, ExceptionCodeEnum.USER_REQUEST_PARAMETER_ERROR.getErrorCode(), ex.getMessage());
logger.error("参数异常信息 ex={}", ex.getMessage(), ex);
return;
}
}