Spring boot JSR-303参数校验器
1. 运用场景
规定前端传入的内容,否者返回对应的题提示,进一步减少脏数据的出现。不用我们自己判断数据是否合法,拿到我们想要的数据。
2. 进入maven依赖
此实例为Spring boot 2.4.5
1 2 3 4 | < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-validation</ artifactId > </ dependency > |
3. 工具类
返回值对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | import lombok.Data; import java.util.HashMap; import java.util.Map; /** * @Description 统一返回值对象 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ @Data public class R { private String msg; private Integer code; private Boolean success; private Map<String, Object> data; public static R ok(){ R r = new R(); r.setMsg( "OK" ); r.setSuccess( true ); r.setCode( 0 ); r.setData( new HashMap<String, Object>()); return r; } public static R error(){ R r = new R(); r.setMsg( "error" ); r.setSuccess( false ); r.setCode(- 1 ); return r; } public R code(Integer code){ this .code = code; return this ; } public R msg(String msg){ this .msg = msg; return this ; } public R success(Boolean success){ this .success = success; return this ; } public R data(Map map){ this .data = map; return this ; } public R data(String key,Object val){ if ( this .data== null ) this .data = new HashMap<String, Object>(); this .data.put(key,val); return this ; } } |
统一异常处理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | import com.zkq.utils.R; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.BindException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; /** * @Description 异常信息处理器 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ @RestControllerAdvice @Slf4j public class ExceptionHandle { // 固定处理JSR-303 抛出的异常 @ExceptionHandler (BindException. class ) public R validException(BindException e){ Map<String,String> map = new HashMap<String, String>(); e.getBindingResult().getFieldErrors().forEach((fieldError) -> { map.put(fieldError.getField(),fieldError.getDefaultMessage()); }); return R.ok().msg( "参数错误!" ).data(map); } // 统一处理不是上面JSR-303 的错误,当然也可以细分,我在此就部分了,统一处理。 @ExceptionHandler public R error(Throwable t){ // 记录响应的错误信息 // log.error("",t.getMessage()); return R.error().msg( "系统错误!" ); } } |
4. 代码实例
4.1 普通校验 @Valid
验证对象User
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; /** * @Description 普通校验 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ @Data public class User { @NotNull (message = "id不能为空" ) private Long id; @NotBlank (message = "姓名不能为空" ) private String name; @NotNull (message = "年龄不能为空" ) private Integer age; } |
测试接口
1 2 3 4 5 6 7 8 9 10 11 | import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; @RestController public class ZkqController{ // 测试 @Valid @GetMapping ( "/zkq" ) public R zkq( @Valid User user){ return R.ok().msg( "标准校验" ).data( "user" ,user); } } |
测试结果:
不符合规范
符合规范
4.2 分组校验 @Validated
这里我就分一组演示
创建校验器分组类
1 2 3 4 5 6 7 8 | /** * @Description 校验器分组,GetGroup这个不固定可随意写 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ public interface GetGroup { } |
创建校验对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | import lombok.Data; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; /** * @Description 分组校验 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ @Data public class User2 { // groups = {GetGroup.class,User.class} 可分多组这里我就分了一组,根据需求自行分组 @NotNull (message = "id不能为空" ,groups = GetGroup. class ) private Long id; @NotBlank (message = "姓名不能为空" ,groups = GetGroup. class ) private String name; @NotNull (message = "年龄不能为空" ,groups = GetGroup. class ) private Integer age; } |
测试接口
1 2 3 4 5 6 7 8 9 10 11 | import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ZkqController{ // 测试 @Validated @GetMapping ( "/zkq2" ) public R zkq2( @Validated (GetGroup. class ) User2 user){ return R.ok().msg( "分组校验" ).data( "user" ,user); } } |
校验结果
不符合规范
符合校验
4.3 自定义校验器校验 @Valid
创建检验器注解@ZkqNumRange
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; /** * @Description 自定义校验器注解 (message和groups,payload 是必须的) * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ @Documented // 支持校验的类型 Long ,Float ,Integer 暂时这三种类型,有需要可以自己扩展 @Constraint (validatedBy = {ZkqNumRangeConstraintValidatorLong. class , ZkqNumRangeConstraintValidatorFloat. class , ZkqNumRangeConstraintValidatorInteger. class }) @Target ({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) @Retention (RetentionPolicy.RUNTIME) public @interface ZkqNumRange { // 必须的不符合的的提示语,也可以象注解一样写{javax.validation.constraints.ZkqNumRange .message} // 但是要在 resources 创建对应的文件 ValidationMessages.properties String message() default "参数不符!" ; // 必须的适用于分组校验 Class<?>[] groups() default {}; // 必须的 Class<? extends Payload>[] payload() default {}; // 这个是我们自己定义是否为必须的参数,默认为不必须 boolean required() default false ; // 这个是我们自己定义的最小值,默认为 0 int min() default 0 ; // 这个是我们自己定义的最大值,默认为 2147483647 Integer.MAX_VALUE = 2147483647 Integer.MIN_VALUE = -2147483648 int max() default Integer.MAX_VALUE; } |
定义校验器支持的类型 这里我们就写三种类型Long ,Float ,Integer 。需要其他的自己扩展
Float 校验器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * @Description 参数校验器 Float 类型 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ public class ZkqNumRangeConstraintValidatorFloat implements ConstraintValidator<ZkqNumRange, Float> { private Integer max; private Integer min; private boolean required; @Override public void initialize(ZkqNumRange constraintAnnotation) { max = constraintAnnotation.max(); min = constraintAnnotation.min(); required = constraintAnnotation.required(); } @Override public boolean isValid(Float value, ConstraintValidatorContext context) { if (required || value!= null ) { if (value== null ) return false ; if ((min <= value) && (value<= max)) { return true ; } return false ; } return true ; } } |
Integer 校验器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * @Description 参数校验器 Integer 类型 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ public class ZkqNumRangeConstraintValidatorInteger implements ConstraintValidator<ZkqNumRange, Integer> { private Integer max; private Integer min; private boolean required; @Override public void initialize(ZkqNumRange constraintAnnotation) { max = constraintAnnotation.max(); min = constraintAnnotation.min(); required = constraintAnnotation.required(); } @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { if (required || value!= null ) { if (value== null ) return false ; if ((min <= value) && (value<= max)) { return true ; } return false ; } return true ; } } |
Long 校验器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * @Description 参数校验器 Long 类型 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ public class ZkqNumRangeConstraintValidatorLong implements ConstraintValidator<ZkqNumRange, Long> { private Integer max; private Integer min; private boolean required; @Override public void initialize(ZkqNumRange constraintAnnotation) { max = constraintAnnotation.max(); min = constraintAnnotation.min(); required = constraintAnnotation.required(); } @Override public boolean isValid(Long value, ConstraintValidatorContext context) { if (required || value!= null ) { if (value== null ) return false ; if ((min <= value) && (value<= max)) { return true ; } return false ; } return true ; } } |
测试对象User3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import lombok.Data; /** * @Description 自定义校验器 校验 * @Author 张凯强 * @Date Created in 2021/5/20 * @E-mail 862166318@qq.com */ @Data public class User3 { // required 默认为不必须 @ZkqNumRange (message = "id不正确!" ) private Long id; @ZkqNumRange (message = "钱数不正确!" , required = true ) private Float money; // 最大值为150 @ZkqNumRange (max = 150 , message = "年龄不正确!" , required = true ) private Integer age; } |
测试接口
1 2 3 4 5 6 7 8 9 10 11 12 | import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; @RestController public class ZkqController{ // 测试 自定义校验器 @ZkqNumRange @GetMapping ( "/zkq3" ) public R zkq2( @Valid User3 user){ return R.ok().msg( "自定义校验器校验" ).data( "user" ,user); } } |
不符合规范
符合校验
4. 自带校验注解
我把截图放这,想看的自行研究。
也可以自行阅读校验器源码,例如 @NotNull 和 @NotBlank 区别了
@NotBlank 做了toString(),然后去空格后的长度大于0。
@NotNull 就做了 object != null
有问题质询QQ:248048521,欢迎技术交流
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器