坚持年年写博客,不能断了,所以粘贴平时写的一份笔记吧
一、简介
校验参数在以前基本都是使用大量的if/else
,稍微方便一点的可以使用反射+自定义注解
的形式,但是复用性不是很好,并且每个人对于的自定义注解有着自己的使用习惯,不过好在spring开发了validated框架用于注解校验,可以节省很多的校验ifelse
代码。
@PostMapping("/save")public Object save(@RequestBody User user) {String mobile = userVO.getMobile();//手动逐个 参数校验~ 写法if (StringUtils.isBlank(mobile)) {return R.bulid(ResultEnum.PARAM_FAIL_CODE,"mobile:手机号码不能为空");} else if (!Pattern.matches("^[1][3,4,5,6,7,8,9][0-9]{9}$", mobile)) {return R.bulid(ResultEnum.PARAM_FAIL_CODE,"mobile:手机号码格式不对");}//抛出自定义异常等~写法if (StringUtils.isBlank(userVO.getUsername())) {throw new ParamException(ResultEnum.PARAM_FAIL_CODE, "用户名不能为空");}// 比如写一个map返回if (StringUtils.isBlank(userVO.getSex())) {Map<String, Object> result = new HashMap<>(5);result.put("code", Constant.PARAM_FAIL_CODE);result.put("msg", "性别不能为空");return result;}//.........各种写法 ...userService.save(user);return R.success();}
二、Spring Validation
spring Validation
是一种参数检验工具,集成在spring-context包中, 常用于spring mvc
中Controller
的参数处理,主要针对整个实体类的多个可选域进行判定,对于不合格的数据信息springMVC会把它保存在错误对象中,这些错误信息我们也可以通过SpringMVC
提供的标签或者前端的脚本等在前端页面上进行展示。
1、实现方式
实现方式和使用方式:一般使用较多的是两个注解:@Validated
、@Valid
@Valid和@Validated 两种注释都会导致应用标准Bean验证。
如果验证不通过会抛出BindException
异常,并变成400(BAD_REQUEST)响应;
或者可以通过Errors或BindingResult参数在控制器内本地处理验证错误。
如果参数前有@RequestBody注解,验证错误会抛出MethodArgumentNotValidException
异常。
2、Java Bean Validation
JSR是Java Specification Requests的缩写,意思是Java 规范提案。关于数据校验这块,最新的是JSR380,也就是我们常说的Bean Validation 2.0。
Bean Validation 2.0 是JSR第380号标准。该标准连接如下:The Java Community Process(SM) Program - Community Update - View Community Update Information for JSR# 380
Bean Validation的主页:Jakarta Bean Validation - Home
Bean Validation的参考实现:/hibernate/hibernate-validator
Bean Validation是一个通过配置注解来验证参数的框架,它包含两部分Bean Validation API(规范)和Hibernate Validator(实现)。
Bean Validation是Java定义的一套基于注解/xml的数据校验规范,目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于.08),已经经历了三个版本
3、@Valid
和@Validated
区别
可以理解成@Validated是@Valid升级版
Spring最终是调用Hibernate Validator执行校验,Spring Validation只是做了一层封装。
通过源码分析:
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Valid {}@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Validated {Class<?>[] value() default {};}
@Valid:没有分组的功能。
@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
关于分组功能,此处我们不涉及,有兴趣的同学可以自己研究一下
3、常用注解
validator-api-2.0的约束注解有22个,具体我们看下面表格
空与非空检查
@NotNull:适用于基本数据类型(Integer,Long,Double等等),当 @NotNull 注解被使用在 String 类型的数据上,则表示该数据不能为 Null(但是可以为 Empty,即双引号空) @NotBlank:适用于 String 类型的数据上,加了@NotBlank 注解的参数不能为 Null 且 trim() 之后 size > 0 @NotEmpty:适用于 String、Collection集合、Map、数组等等,加了@NotEmpty 注解的参数不能为 Null 或者 长度为 0
Boolean值检查
日期检查
数值检查
其他
hibernate-validator扩展约束(部分)
综合在一起,对于不同的api版本可能出现部分注解过时等情况,注意!
三、通过BindingResult处理错误信息
使用
Validator
,利用BindingResult
获取Errors信息
1、pom引入依赖
只需要spring-boot-starter-validation和web即可
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- validation --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency>
2、修改实体类User
package com.woniuxy.ssm.entity;import java.io.Serializable;import java.util.Date;import com.fasterxml.jackson.annotation.JsonFormat;import lombok.Data;import org.hibernate.validator.constraints.Length;import org.hibernate.validator.constraints.Range;import org.springframework.format.annotation.DateTimeFormat;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;import javax.validation.constraints.Pattern;import javax.validation.constraints.Size;/*** * @TableName user*/@Datapublic class User implements Serializable {/*** */private Integer id;/*** 用户名*/@NotBlank(message = "用户名不能为空")@Length(message = "用户名长度不能超过{max}个字符",max = 10)private String userName;/*** 电话*/@Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手机号码有误!")private String tel;/*** 密码*/@NotBlank(message = "密码不能为空")@Size(message = "密码不小于{min}位", min= 8)private String password;/*** 年龄*/@NotNull(message = "请输入年龄")@Range(message = "年龄范围为 {min} 到 {max} 之间", min = 1, max = 100)private Integer age;/*** */@DateTimeFormat(pattern = "yyyy-MM-dd")@JsonFormat(pattern = "yyyy-MM-dd" ,timezone = "GMT+8")private Date createDate;/*** */private String headImg;/*** */private Integer deptId;private static final long serialVersionUID = 1L;}
3、修改UserController中的add方法
得到所有错误中的第一个返回给用户显示,第一个并不一定是固定的,如果密码长度和年龄同时不满足,多次查询返回的结果并不是固定的,且不会超过这两个错误信息
/*** @Description TODO* @Valid 表示对这个对象校验* @param user* @param bindingResult 获取的是校验的结果,这个对象有许多方法获取校验信息,可以自定义返回信息* @Return com.woniuxy.ssm.util.Result* @Author fengSir* @Date Create by -06-12 14:58*/@PostMapping("addDo")public Result add(@Valid @RequestBody User user, BindingResult bindingResult){if(bindingResult.hasErrors()){return Result.error(bindingResult.getFieldError().getDefaultMessage());}int result = userService.insertSelective(user);return Result.ok();}
我们也可以@Valid换成@Validated,两者效果相同
4、通过测试工具类测试
三、使用全局异常处理错误信息
虽然使用bindingResult可以解决校验问题,但代码侵入性太强。此时我们可以考虑采用全局异常来解决
1、改造UserController中的add方法
@PostMapping("addDo")public Result add(@Validated @RequestBody User user){int result = userService.insertSelective(user);return Result.ok();}
2、通过测试工具测试
由于参数里有@RequestBody注解,验证错误会抛出
MethodArgumentNotValidException
异常
3、自定义全局异常
package com.woniuxy.ssm.exception;import org.springframework.validation.BindException;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.RestControllerAdvice;/*** @author :fengSir* @date :Created By -06-12 16:12* @description :TODO*/@RestControllerAdvicepublic class ValidExceptionHandler {@ExceptionHandler(BindException.class)public Result validExceptionHandler(BindException exception) {return Result.error(exception.getBindingResult().getFieldError().getDefaultMessage());}}
4、再次测试
得到和以前一样的测试结果
四、@Valid 和 @Validated 比较
对 @Valid 和 @Validated 两个注解进行总结下:
@Valid 和 @Validated 两者都可以对数据进行校验,待校验字段上打的规则注解(@NotNull, @NotEmpty等)都可以对 @Valid 和 @Validated 生效;
@Valid 进行校验的时候,需要用 BindingResult 来做一个校验结果接收。当校验不通过的时候,如果手动不 return ,则并不会阻止程序的执行;
@Validated 进行校验的时候,也可以用 BindingResult 来做一个校验结果接收。当校验不通过的时候,程序会抛出400异常,阻止方法中的代码执行,这时需要再写一个全局校验异常捕获处理类,然后返回校验提示。
总体来说,@Validated 使用起来要比 @Valid 方便一些,它可以帮我们节省一定的代码,并且使得方法看上去更加的简洁。
如果觉得《Springbootg整合validation整合》对你有帮助,请点赞、收藏,并留下你的观点哦!