900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > @Validated注解详解 分组校验 嵌套校验 @Valid和@Validated 区别 Spring Boot @Validated

@Validated注解详解 分组校验 嵌套校验 @Valid和@Validated 区别 Spring Boot @Validated

时间:2019-04-30 22:11:15

相关推荐

@Validated注解详解 分组校验 嵌套校验 @Valid和@Validated 区别 Spring Boot @Validated

技术栈:

spring boot2.3.3.RELEASE

hibernate-validator

文末附项目源代码

目录

简述

项目依赖

全局异常处理类

基础参数校验

实体类

控制类

测试

嵌套参数验证

实体类

控制类

测试

分组参数验证

接口类

实体类

控制类

测试

@Valid和@Validated 区别

简述

@Validation是一套帮助我们继续对传输的参数进行数据校验的注解,通过配置Validation可以很轻松的完成对数据的约束。

@Validated作用在类、方法和参数上

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface Validated {Class<?>[] value() default {};}

错误的状态码

返回的响应码推荐使用400 bad request.

所有参数注解含义

项目依赖

Maven 依赖坐标:

说明:在演示项目中所有实体类均在包entity,控制层均在包controller。

全局异常处理类

说明:若不做异常处理,@Validated注解的默认异常消息如下(示例):

-09-05 21:48:38.106 WARN 9796 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public java.lang.String com.example.validateddemo.controller.DemoController.validatedDemo1(com.example.validateddemo.entity.dto.UseDto): [Field error in object 'useDto' on field 'username': rejected value [null]; codes [NotBlank.useDto.username,NotBlank.username,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [useDto.username,username]; arguments []; default message [username]]; default message [用户名不能为空!]] ]

因此我们在这里做了一个全局的异常处理类,用于处理参数校验失败后抛出的异常,同时进行日志输出。

package com.example.validateddemo.handler;import com.example.validateddemo.base.Result;import com.example.validateddemo.enums.ResultEnum;import com.example.validateddemo.utils.ResultUtil;import lombok.extern.slf4j.Slf4j;import org.springframework.http.HttpStatus;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.validation.ObjectError;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.ResponseStatus;import java.util.List;/*** @author He Changjie on /9/5*/@Slf4j@ControllerAdvicepublic class ValidatedExceptionHandler {/*** 处理@Validated参数校验失败异常* @param exception 异常类* @return 响应*/@ResponseBody@ResponseStatus(HttpStatus.BAD_REQUEST)@ExceptionHandler(MethodArgumentNotValidException.class)public Result exceptionHandler(MethodArgumentNotValidException exception){BindingResult result = exception.getBindingResult();StringBuilder stringBuilder = new StringBuilder();if (result.hasErrors()) {List<ObjectError> errors = result.getAllErrors();if (errors != null) {errors.forEach(p -> {FieldError fieldError = (FieldError) p;log.warn("Bad Request Parameters: dto entity [{}],field [{}],message [{}]",fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage());stringBuilder.append(fieldError.getDefaultMessage());});}}return ResultUtil.validatedException(stringBuilder.toString());}}

基础参数校验

实体类

package com.example.validateddemo.entity.dto;import lombok.Data;import org.springframework.format.annotation.DateTimeFormat;import javax.validation.constraints.*;/*** 用户实体* 数据传输对象* @author He Changjie on /9/5*/@Datapublic class User1Dto {/*** 用户名*/@NotBlank(message = "用户名不能为空!")private String username;/*** 性别*/@NotBlank(message = "性别不能为空!")private String gender;/*** 年龄*/@Min(value = 1, message = "年龄有误!")@Max(value = 120, message = "年龄有误!")private int age;/*** 地址*/@NotBlank(message = "地址不能为空!")private String address;/*** 邮箱*/@Email(message = "邮箱有误!")private String email;/*** 手机号码*/@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 mobile;}

控制类

package com.example.validateddemo.controller;import com.example.validateddemo.entity.dto.Use1Dto;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/*** @author He Changjie on /9/5*/@RestController@RequestMapping("/api/v1")public class Demo1Controller {@PostMapping("/insert")public String validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){System.out.println(use1Dto);return "success";}}

测试

1、参数校验通过:

2、参数校验不通过:

嵌套参数验证

验证实体中的其他需要被验证的对象集合或其他对象

实体类

package com.example.validateddemo.entity.dto;import lombok.Data;import javax.validation.Valid;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;import java.util.List;/*** 队伍实体* 数据传输对象* @author He Changjie on /9/5*/@Datapublic class Team1Dto {/*** 队伍名称*/@NotBlank(message = "队伍名称不能为空!")private String name;/*** 队伍人员*/@NotNull(message = "队伍人员不能为空!")@Validprivate List<User1Dto> userList;/*** 队伍负责人*/@NotNull(message = "队伍负责人不能为空!")@Validprivate User1Dto user;}

控制类

package com.example.validateddemo.controller;import com.example.validateddemo.base.Result;import com.example.validateddemo.entity.dto.Team1Dto;import com.example.validateddemo.entity.dto.Use1Dto;import com.example.validateddemo.utils.ResultUtil;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/*** @author He Changjie on /9/5*/@RestController@RequestMapping("/api/v1")public class Demo1Controller {@PostMapping("/insert")public Result validatedDemo1(@Validated @RequestBody Use1Dto use1Dto){return ResultUtil.success(use1Dto);}@PostMapping("/insert2")public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){return ResultUtil.success(team1Dto);}}

测试

1、参数验证通过:

2、参数验证不通过:

分组参数验证

将不同的校验规则分给不同的组,在使用时,指定不同的校验规则

接口类

package com.example.validateddemo.interfaces;/*** 校验分组1* @author He Changjie on /9/5*/public interface Group1 {}

package com.example.validateddemo.interfaces;/*** 校验分组2* @author He Changjie on /9/5*/public interface Group2 {}

实体类

package com.example.validateddemo.entity.dto;import com.example.validateddemo.interfaces.Group1;import com.example.validateddemo.interfaces.Group2;import lombok.Data;import javax.validation.constraints.*;/*** @author He Changjie on /9/5*/@Datapublic class User2Dto {/*** 用户名*/@NotBlank(message = "用户名不能为空!", groups = {Group1.class})private String username;/*** 性别*/@NotBlank(message = "性别不能为空!")private String gender;/*** 年龄*/@Min(value = 1, message = "年龄有误!", groups = {Group1.class})@Max(value = 120, message = "年龄有误!", groups = {Group2.class})private int age;/*** 地址*/@NotBlank(message = "地址不能为空!")private String address;/*** 邮箱*/@Email(message = "邮箱有误!", groups = {Group2.class})private String email;/*** 手机号码*/@Pattern(regexp = "^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$",message = "手机号码有误!", groups = {Group2.class})private String mobile;}

控制类

package com.example.validateddemo.controller;import com.example.validateddemo.base.Result;import com.example.validateddemo.entity.dto.Team1Dto;import com.example.validateddemo.entity.dto.User1Dto;import com.example.validateddemo.entity.dto.User2Dto;import com.example.validateddemo.interfaces.Group1;import com.example.validateddemo.interfaces.Group2;import com.example.validateddemo.utils.ResultUtil;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;/*** @author He Changjie on /9/5*/@RestController@RequestMapping("/api/v1")public class Demo1Controller {@PostMapping("/insert")public Result validatedDemo1(@Validated @RequestBody User1Dto user1Dto){return ResultUtil.success(user1Dto);}@PostMapping("/insert2")public Result validatedDemo2(@Validated @RequestBody Team1Dto team1Dto){return ResultUtil.success(team1Dto);}@PostMapping("/insert3")public Result validatedDemo3(@Validated @RequestBody User2Dto user2Dto){return ResultUtil.success(user2Dto);}@PostMapping("/insert4")public Result validatedDemo4(@Validated(Group1.class) @RequestBody User2Dto user2Dto){return ResultUtil.success(user2Dto);}@PostMapping("/insert5")public Result validatedDemo5(@Validated(Group2.class) @RequestBody User2Dto user2Dto){return ResultUtil.success(user2Dto);}}

测试

1、未分组校验通过:

2、未分组参数校验不通过:

3、分组1参数校验通过

4、分组1参数校验不通过

5、分组2参数校验通过

6、分组2参数校验不通过

7、使用默认分组,参数校验通过:

说明:将控制层/insert3接口调整如下后测试

@PostMapping("/insert3")public Result validatedDemo3(@Validated(Default.class) @RequestBody User2Dto user2Dto){return ResultUtil.success(user2Dto);}

Default.class为Validated依赖中含有的接口类,非自定义接口类

8、使用默认分组,参数校验不通过:

说明:同第7点相同操作

@Valid和@Validated 区别

通过源码分析:

@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:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上

两者是否能用于成员属性(字段)上直接影响能否提供嵌套验证的功能

码云地址:/jie_harris/validateddemo.git

手编不易,转载请注明来源

谢谢!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。