springboot 关于controller层传递单个参数的校验

SpringBoot参数校验
本文介绍如何在SpringBoot项目中实现控制器层的参数校验,包括引入依赖、配置验证器、异常处理等内容。
关于springboot项目中,controller层对传递对象的校验,可以参照该文进行查看, 点击打开链接http://www.cnblogs.com/myinspire/articles/7649027.html

本文主要针对controller层中,对于单个参数的校验:

1、引入依赖

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.3.1.Final</version>
</dependency>

2、首先,需要我们声明一个Bean,注入校验器到Spring Boot的运行环境,负责不能生效对应的@Range@Min@Maxvalidator包里面提供的注解

@Configuration
@EnableAutoConfiguration
public class ValidatorConfig {
   @Bean
   public MethodValidationPostProcessor methodValidationPostProcessor(){
      return new MethodValidationPostProcessor();
   }
}

3、controller层

特别注意:

1、@Validated要在controller上标注

@Api(value = "type", description = "辅导类型")
@RestController
@Validated
@RequestMapping(value = "type")
public class CompositionTypesController extends BaseController {
   @ApiOperation(value="新增辅导类型", notes="新增辅导类型")
   @LoginRequired
   @PostMapping(value = "addCompostionTyp1e")
   public Response addCompostionTyp1e(@ApiParam(value = "成绩") @Max(value = 60,message = "得分必须小于60") @RequestParam int score, @ApiParam(value = "年龄") @Min(value = 3, message = "年龄大于3") @RequestParam int age, @ApiParam(value = "辅导作文类型") @NotNull(message = "辅导作文类型不能为空") @RequestParam(required = false) String name){
      //校验
      logger.info(String.valueOf(age));
      return success(ResponseCode.OK);
   }
}

4、统一异常捕获

@ControllerAdvice
public class ExceptionAdvice {
   /**
    * 拦截捕捉自定义异常 ConstraintViolationException.class
    * @param ex
    * @return
    */
   @ResponseBody
   @ExceptionHandler(value = ConstraintViolationException.class)
   public Map ConstraintViolationExceptionHandler(ConstraintViolationException ex) {
      Map map = new HashMap();
      Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
      Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
      List<String> msgList = new ArrayList<>();
      while (iterator.hasNext()) {
         ConstraintViolation<?> cvl = iterator.next();
         msgList.add(cvl.getMessageTemplate());
      }
      map.put("status", ExceptionCode.CVL_EXCEPTION);
      map.put("msg", msgList);
      return map;
   }
}

5、在swagger中进行接口调试




注:

校验常用的注解如下:

@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实体类进行校验

@NotNull 和 @NotEmpty  和@NotBlank 区别

 @NotEmpty 用在集合类上面

@NotBlank 用在String上面

@NotNull    用在基本类型上


<think>我们正在讨论SpringBoot中使用@Validated注解对List<对象>类型的参数进行校验的问题。根据提供的引用,我们可以总结出:-引用[1]说明了SpringBoot使用@Validated需要引入spring-boot-starter-validation依赖。-引用[2]展示了如何在一个对象中嵌入另一个对象进行校验(使用@Valid)。-引用[3]展示了在Controller方法参数上使用@Validated注解,并且指定分组校验。用户的问题:如何对List<对象>类型的参数进行校验?我们知道,在SpringBoot中,对于单个对象的校验,我们直接在对象前加上@Valid或@Validated即可。但是,对于List<对象>,我们需要额外的处理。解决方案:1.使用一个包装类,将List<对象>作为该包装类的一个属性,然后对这个属性标注@Valid(或@Validated)注解。这样,Spring在绑定数据时会对List中的每个对象进行校验。2.使用自定义的校验注解和校验器。这里我们采用第一种方式,因为它更符合SpringBoot校验机制,并且与引用[2]中嵌入校验的方式一致。步骤:①创建包装类,将List<对象>作为属性,并在该属性上添加@Valid注解(注意:不能直接使用@Validated在这里,@Validated是用在类和方法上的,而@Valid是用在字段、方法参数或方法返回值的)。②在Controller方法的参数上使用@Validated注解(如果使用分组校验则需要,否则可以直接用@Valid)来触发校验。注意:SpringBoot在2.3版本之后,需要显式添加依赖spring-boot-starter-validation(如引用[1]所示)。下面通过一个例子说明:假设我们有一个StudentDTO类,其中有一些校验注解:```javapublicclassStudentDTO{@NotBlank(message="学生姓名不能为空")privateStringname;@Min(value=18,message="年龄必须大于18岁")privateintage;//省略getter和setter}```然后,我们创建一个包装类,用于封装List<StudentDTO>:```javapublicclassStudentListDTO{@ValidprivateList<StudentDTO>students;//必须提供setter和getterpublicList<StudentDTO>getStudents(){returnstudents;}publicvoidsetStudents(List<StudentDTO>students){this.students=students;}}```最后,在Controller中,我们接收这个包装类,并在参数前加上@Valid或@Validated(注意:这里不能直接使用@Validated来校验包装类内部的List,但可以在参数上使用@Validated来触发校验,不过更常见的做法是使用@Valid):```java@RestController@RequestMapping("/students")publicclassStudentController{@PostMapping("/batch")publicResultaddBatch(@RequestBody@ValidStudentListDTOstudentList){//处理批量新增学生returnResult.ok();}}```这样,当请求中的List<StudentDTO>被传入时,Spring会为StudentListDTO中的students字段(因为标注了@Valid)进行校验,从而校验List中每一个StudentDTO对象。但是,如果不想使用包装类,可以直接在Controller方法的参数上使用@Validated(在类上)配合@Valid在List<StudentDTO>参数前。然而,根据Spring的文档,对于直接是List类型的参数,我们需要在参数前同时使用@Valid和@Validated(在类上)?实际上,SpringBoot默认不支持直接对List<对象>进行校验,因为它是一个集合,而校验注解不能直接写在集合类型上。所以,使用包装类是最直接的方法。另一种方案:在Controller方法上使用@Validated(类级别),然后在参数前使用@Valid(针对包装类)或者使用@Valid注解在List上?然而,当我们尝试在List参数前直接使用@Valid时,Spring并不会递归校验其中的对象(除非我们使用@Valid在包装类的字段上)。总结:为了对List<对象>进行校验,我们需要将List放入一个包装类中,并对该字段使用@Valid注解,然后在Controller方法的参数上使用@Valid或@Validated(分组校验时)。另外,引用[3]提到了分组校验。如果我们需要在List中的对象上使用分组校验,那么可以在@Valid(在包装类字段上)后无法指定分组,因此需要改为在包装类字段上使用@Validated(分组.class)?但注意,@Valid不支持分组,而@Validated支持分组。所以我们可以这样调整:修改包装类:```javapublicclassStudentListDTO{@Validated(Insert.class)//但是,@Validated不能用在字段上,只能用在类型和方法上?所以这里不行!privateList<StudentDTO>students;//...}```这样写是错误的,因为@Validated注解不能用在字段上。因此,如果我们想对List中的对象进行分组校验,我们可以将@Validated注解放在Controller类上,然后在参数前使用@Validated(分组.class)?但是,这样会作用于整个类,而且参数上的@Validated只能用于参数上(它也可以指定分组)。然而,在参数上使用@Validated(分组.class)配合包装类字段上的@Valid是不行的,因为分组信息不会传递下去。正确的做法是在包装类的字段上使用@Valid(不支持分组),然后在StudentDTO的校验注解上指定分组(这样如果没有激活该分组,则不会校验)。但如果我们激活了分组,那么在字段上使用@Valid会触发所有未指定分组的约束以及指定了当前激活分组的约束。因此,我们可以:在Controller方法参数上使用@Validated(分组.class),并且参数是包装类(包装类的字段上使用@Valid):```java@RestController@RequestMapping("/students")@Validated//如果整个Controller需要分组校验,可以在类上添加@Validated,但这里我们不需要,因为我们要在方法参数上指定分组publicclassStudentController{@PostMapping("/batch")publicResultaddBatch(@RequestBody@Validated(Insert.class)StudentListDTOstudentList){//处理批量新增学生returnResult.ok();}}```然后,在StudentListDTO中:```javapublicclassStudentListDTO{@Valid//这里会激活StudentDTO中所有默认的约束(没有分组的)和与当前激活分组(Insert)匹配的约束privateList<StudentDTO>students;//...}```在StudentDTO中,我们需要在约束注解上指定分组(例如Insert):```javapublicclassStudentDTO{@NotBlank(message="学生姓名不能为空",groups=Insert.class)//指定Insert分组privateStringname;@Min(value=18,message="年龄必须大于18岁",groups=Insert.class)//指定Insert分组privateintage;//省略getter和setter}```注意:如果约束注解上指定了分组(例如Insert.class),那么当使用@Valid进行校验时,需要校验器被激活相应的分组(例如在Controller方法的参数上使用@Validated(Insert.class))。在这种情况下,包装类字段上的@Valid会传递这个分组吗?实际上,分组校验不会通过@Valid传递。在Spring的校验中,在方法参数上使用的@Validated(Insert.class)会激活整个对象图的Insert分组校验。也就是说,它会递归校验所有满足Insert分组的约束。因此,在包装类字段上的@Valid虽然没有指定分组,但会被传递当前激活的分组(即Insert分组)。所以,这种方式是可行的。结论:在SpringBoot中,对List<对象>进行校验的可行方法是将其包装在一个包装类中,然后在包装类的该字段上添加@Valid注解(不需要分组)或@Validated注解(但@Validated不能用在字段上,所以用@Valid),然后在Controller方法的参数上使用@Validated并指定分组(如果需要分组校验)。这样,Spring就会递归校验List中的每个对象。另外,如果不想使用包装类,可以使用自定义校验注解配合校验器,但这需要编写更多代码。因此,使用包装类是最简便的方法。生成相关问题:1.如何在分组校验中使用List<对象>?2.如果不使用包装类,如何实现对List<对象>的校验?3.在SpringBoot中,@Valid和@Validated有什么区别?4.分组校验的继承关系如何处理?注意:在以上方案中,我们使用的是SpringBoot默认的校验框架(HibernateValidator),所以需要确保引入了正确的依赖。下面,我们按照用户的要求总结回答:在SpringBoot中,使用@Validated注解对List<对象>类型的参数进行校验,不能直接在List<对象>参数前使用@Validated或@Valid。但是,我们可以通过将List<对象>封装在一个包装类中,然后对包装类中代表List的字段添加@Valid注解(也可以结合分组校验)。然后在Controller方法参数上使用@Validated(需要分组时指定分组)或者@Valid(无分组)来触发校验。示例代码:依赖(如引用[1]):```xml<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>2.7.4</version></dependency>```包装类:```javapublicclassStudentListDTO{@Valid//这里触发List中每个对象的校验privateList<StudentDTO>students;//getterandsetter}```控制器:```java@RestControllerpublicclassStudentController{@PostMapping("/batchAdd")publicStringbatchAddStudents(@RequestBody@ValidStudentListDTOstudentListDTO){//业务处理return"success";}}```如果需要分组校验,则:```java@PostMapping("/batchAdd")publicStringbatchAddStudents(@RequestBody@Validated(Insert.class)StudentListDTOstudentListDTO){//业务处理return"success";}```同时,在StudentDTO类的字段上指定分组(例如Insert.class)。这样,SpringBoot就会对List中的每个对象进行校验。注意:如果List中的某个对象校验失败,会抛出MethodArgumentNotValidException异常,我们可以通过全局异常处理器捕获并处理。可行性:完全可行。</think> 在 Spring Boot 中使用 `@Validated` 注解对 `List<对象>` 类型的参数进行校验是**完全可行的**,但需要结合 `@Valid` 注解实现。以下是具体方法和实现步骤: --- ### ✅ 使用方法(需结合 `@Valid` 注解) #### 步骤 1:创建包裹 List 的包装类 ```java public class StudentListRequest { @Valid // 关键注解:触发 List 内对象的校验规则 private List<StudentDTO> students; // 必须添加 getter/setter public List<StudentDTO> getStudents() { return students; } public void setStudents(List<StudentDTO> students) { this.students = students; } } ``` #### 步骤 2:在 DTO 对象中定义校验规则 ```java public class StudentDTO { @NotBlank(message = "姓名不能为空") private String name; @Min(value = 18, message = "年龄必须≥18岁") private Integer age; // getter/setter } ``` #### 步骤 3:在 Controller 中使用 `@Validated` ```java @PostMapping("/batch/add") public ResponseEntity<?> batchAddStudents( @RequestBody @Validated StudentListRequest request // 校验包裹类 ) { // 业务逻辑 return ResponseEntity.ok("校验成功"); } ``` --- ### ⚡ 校验触发流程 ```mermaid graph TD A[HTTP 请求] --> B[JSON 解析为 StudentListRequest] B --> C{Spring 校验流程} C -->|扫描包裹类| D[@Valid 触发校验] D --> E[遍历校验 List<StudentDTO>] E --> F[应用 StudentDTO 的 @NotBlank/@Min 等规则] F --> G[校验失败抛出 MethodArgumentNotValidException] ``` --- ### 🔍 关键点说明 1. **`@Valid` 与 `@Validated` 分工**: - `@Valid`(JSR-303 标准):用于**字段级**递归校验(必须加在 List 字段上) - `@Validated`(Spring 扩展):用于**类/方法参数级**校验(加在 Controller 参数上) 2. **校验规则继承**: - List 中的对象(如 `StudentDTO`)支持所有标准校验注解: ```java @Email, @Size, @Pattern, @NotNull // 等 ``` - 支持**分组校验**(如 `@Validated(Insert.class)`),需在包裹类参数指定分组 3. **错误处理**: - 校验失败自动返回 400 状态码 - 错误信息结构示例: ```json { "timestamp": "2023-05-01T12:00:00", "status": 400, "error": "Bad Request", "errors": [ { "field": "students[0].name", "message": "姓名不能为空" }, { "field": "students[2].age", "message": "年龄必须≥18岁" } ] } ``` --- ### ⚠️ 注意事项 1. **不支持直接校验裸 List 参数**: ```java // 错误写法:不会触发校验! @PostMapping("/error-example") public void errorExample(@RequestBody @Validated List<StudentDTO> list) {} ``` 2. **必须引入依赖**: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> ``` 3. **嵌套校验**: - 如需校验嵌套对象(如 `StudentDTO` 中包含 `AddressDTO`),需在嵌套对象字段也添加 `@Valid` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值