@Validated 统一参数检验

@Validated 统一参数检验

基本测试条件

DTO对象:requestBody

@Data
public class XxxUserGroupCreateReqVO {
   

    @NotNull(message = "组名不能为空")
    @Length(min = 6, max = 20, message = "组名长度不能超过 20 个字符")
    private String name;

    @NotEmpty(message = "描述不能为空")
    private String description;

    @NotNull(message = "成员编号数组不能为空")
    private Set<Long> memberUserIds;

    @NotNull(message = "状态不能为空")
    private Integer status;

}

参数接收:requestParam/PathVariable

请求参数①:JSON对象

{
   
  "name": "1",
  "memberUserIds": [1,2],
  "status": 0
}

请求参数②:param键值对传值

?name=1&status=0

测试分析

测试①: @Validated注解添加在Controller上,方法请求参数不添加@Validated

  • 参数验证无效
@RestController
@RequestMapping("/xxx/user-group")
@Validated
public class XxxUserGroupController {
   

    @Resource
    private XxxUserGroupService userGroupService;

    @PostMapping("/create")
    public CommonResult<Long> createUserGroup(XxxUserGroupCreateReqVO createReqVO) {
   
        return success(userGroupService.createUserGroup(createReqVO));
    }
}

测试②: @Validated注解添加在Controller的方法请求参数,但是请求参数没有添加@RequestBody

  • 触发异常:org.springframework.validation.BindException
@RestController
@RequestMapping("/xxx/user-group")
public class XxxUserGroupController {
   

    @Resource
    private XxxUserGroupService userGroupService;

    @PostMapping("/create")
    public CommonResult<Long> createUserGroup(@Validated XxxUserGroupCreateReqVO createReqVO) {
   
        return success(userGroupService.createUserGroup(createReqVO));
    }
}

测试③:@Validated注解添加在Controller的方法请求参数,且请求参数添加@RequestBody

  • 触发异常:org.springframework.web.bind.MethodArgumentNotValidException
@RestController
@RequestMapping("/xxx/user-group")
public class XxxUserGroupController {
   

    @Resource
    private XxxUserGroupService userGroupService;

    @PostMapping("/create")
    public CommonResult<Long> createUserGroup(@Validated @RequestBody XxxUserGroupCreateReqVO createReqVO) {
   
        return success(userGroupService.createUserGroup(createReqVO));
    }
}

测试④:@Validated注解添加在Controller的方法请求参数,但是请求参数没有添加@RequestBody,且传递的是请求参数②

  • 触发异常:org.springframework.validation.BindException
@RestController
@RequestMapping("/xxx/user-group")
public class XxxUserGroupController {
   

    @Resource
    private XxxUserGroupService userGroupService;

    @PostMapping("/create")
    public CommonResult<Long> createUserGroup(@Validated XxxUserGroupCreateReqVO createReqVO) {
   
        return success(userGroupService.createUserGroup(createReqVO));
    }
}

测试⑤:不添加@Validated,请求参数直接添加@NotNull等,传递的是请求参数②

  • 参数验证不生效
@RestController
@RequestMapping("/xxx/user-group")
public class XxxUserGroupController {
   

    @Resource
    private XxxUserGroupService userGroupService;

    @PostMapping("/create")
    public CommonResult<Long> createUserGroup(@Length(min = 6, max = 20) @NotNull(message = "组名不能为空") String name, Integer status) {
   
        return success(userGroupService.createUserGroup(createReqVO));
    }
}

测试⑥:@Validated注解添加在Controller的方法请求参数,请求参数再添加@NotNull等,传递的是请求参数②

  • 参数验证不生效
@RestController
@RequestMapping("/xxx/user-group")
public class XxxUserGroupController {
   

    @Resource
    private XxxUserGroupService userGroupService;

    @PostMapping("/create")
    public CommonResult<Long> createUserGroup(@Validated @Length(min = 6, max = 20) @NotNull(message = "组名不能为空") String name, Integer status) {
   
        return success(userGroupService.createUserGroup(createReqVO));
    }
}

测试⑦: @Validated注解添加在Controller上,请求参数再添加@NotNull等,传递的是请求参数②

  • 触发异常:javax.validation.ConstraintViolationException
@RestController
@RequestMapping("/xxx/user-group")
public class XxxUserGroupController {
   

    @Resource
    private XxxUserGroupService userGroupService;

    @PostMapping("/create")
    public CommonResult<Long> createUserGroup(@Validated @Length(min = 6, max = 20) @NotNull(message = "组名不能为空") String name, Integer status) {
   
        return success(userGroupService.createUserGroup(createReqVO));
    }
}

测试②和③的差异原因分析:@RequestBody对于@Validated的影响(测试④同理)

在Spring框架中,@Validated注解的使用及其与@RequestBody注解的结合会影响数据绑定和验证过程中抛出的异常类型。理解这一差异的关键在于明白Spring如何处理HTTP请求中的数据以及如何应用验证逻辑。

没有添加@RequestBody的情况

@Validated注解用于控制器方法的参数,但没有与@RequestBody一起使用时,Spring
MVC会将HTTP请求参数(如查询参数、表单数据等)映射到方法参数对象。在这个过程中,Spring使用WebDataBinder来进行数据绑定,即将请求中的数据填充到Java对象的属性中。

如果在数据绑定过程中发现问题(如类型不匹配、格式错误等),或者绑定后的对象违反了通过@Validated启用的验证约束,Spring会抛出org.springframework.validation.BindException。这是因为在这种情况下,验证是作为数据绑定过程的一部分进行的,且直接关联于表单提交和URL查询参数的处理。

添加了@RequestBody的情况

@Validated@RequestBody一起使用时,@RequestBody告诉Spring
MVC需要将HTTP请求体(通常是JSON或XML格式)反序列化为Java对象。这个过程通过HttpMessageConverter实现,与WebDataBinder的数据绑定过程是分开的。

在这种情况下,如果反序列化成功,但对象不符合@Validated启用的验证约束,Spring
MVC会抛出org.springframework.web.bind.MethodArgumentNotValidException。这个异常专门用于处理通过@RequestBody接收并验证的对象失败的场景,它与@Validated结合使用,确保了请求体中的对象在转换和验证过程中的问题能够被捕获和处理。

为什么会触发不同的异常
  • 处理流程不同:没有添加@RequestBody时,参数绑定和验证是通过WebDataBinder一起完成的,因此使用BindException来表示错误。而添加了@RequestBody后,参数的解析(反序列化)和验证是两个分开的步骤,这里使用MethodArgumentNotValidException来专门表示验证失败的情况。
  • 数据源不同:没有@RequestBody时,数据源是来自URL的查询参数或表单数据;而@RequestBody指示数据源是请求体中的内容,通常是JSON或XML,这需要不同的处理方式。
  • 异常设计理念:Spring设计不同的异常类型,以便于开发者更精确地理解和处理错误。BindException关注于表单和参数绑定,而MethodArgumentNotValidException专注于处理请求体内容的验证问题。

测试⑤⑥⑦结论:requestParam/PathVariable参数校验必须在Controller类上标注@Validated注解

GET请求一般会使用requestParam/PathVariable传参。如果参数比较多(比如超过6个),还是推荐使用DTO对象接收。

否则,推荐将一个个参数平铺到方法入参中。在这种情况下,必须在Controller类上标注@Validated注解,并在入参上声明约束注解(如@Min等)。如果校验失败,会抛出ConstraintViolationException异常。

统一异常处理

/**
 * 全局异常处理器
 * 
 * @author ruoyi
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
   
	 /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AjaxResult handleBindException(BindException e)
    {
   
        log.error(e.getMessage(), e);
         return AjaxResult.error("参数绑定错误!请检查参数是否正确。");
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
    {
   
        log.error(e.getMessage(), e);
        return AjaxResult.error("方法参数无效!请检查参数。");
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public AjaxResult handleBindException(ConstraintViolationException e)
    {
   
        log.error(e.getMessage(), e);
         return AjaxResult.error("参数绑定错误!请检查参数是否正确。");
    }
}

扩展:@Validated在service中的应用

测试①: @Validated注解添加在Service上,方法请求参数不添加@Validated

  • 触发异常:javax.validation.ConstraintViolationException
@Service
@Validated
public class XxxUserGroupServiceImpl implements BpmUserGroupService {
   

    @Resource
    private XxxUserGroupMapper userGroupMapper;

    @Override
    public Long createUserGroup( XxxUserGroupCreateReqVO createReqVO) {
   
        // 插入
        XxxUserGroupDO userGroup = XxxUserGroupConvert.INSTANCE.convert(createReqVO);
        userGroupMapper.insert(userGroup);
        // 返回
        return userGroup.getId();
    }
}

测试②: @Validated注解添加在Service的方法请求参数上

  • 参数验证无效
@Service
public class XxxUserGroupServiceImpl implements BpmUserGroupService {
   

    @Resource
    private XxxUserGroupMapper userGroupMapper;

    @Override
    public Long createUserGroup(@Validated XxxUserGroupCreateReqVO createReqVO) {
   
        // 插入
        XxxUserGroupDO userGroup = XxxUserGroupConvert.INSTANCE.convert(createReqVO);
        userGroupMapper.insert(userGroup);
        // 返回
        return userGroup.getId();
    }
}

相关推荐

  1. @Validated 统一参数检验

    2024-02-22 00:56:01       27 阅读
  2. Validation-参数校验框架

    2024-02-22 00:56:01       31 阅读
  3. 参数校验注解使用- validator

    2024-02-22 00:56:01       43 阅读
  4. SpringMVC使用validation参数校验

    2024-02-22 00:56:01       20 阅读
  5. Spring Bean参数校验Validator

    2024-02-22 00:56:01       9 阅读
  6. 参数校验: spring-boot-starter-validation

    2024-02-22 00:56:01       31 阅读
  7. gin中使用validator参数校验

    2024-02-22 00:56:01       40 阅读
  8. Spring Boot 使用validation校验参数

    2024-02-22 00:56:01       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-22 00:56:01       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-22 00:56:01       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-22 00:56:01       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-22 00:56:01       18 阅读

热门阅读

  1. 前端工程化

    2024-02-22 00:56:01       24 阅读
  2. SQL常用函数收藏

    2024-02-22 00:56:01       22 阅读
  3. 前端关于Vue跳转外部链接(百度为例)

    2024-02-22 00:56:01       30 阅读
  4. firewall防火墙配置实战

    2024-02-22 00:56:01       30 阅读
  5. Python提取xml节点

    2024-02-22 00:56:01       31 阅读
  6. Android批量加载图片OOM问题

    2024-02-22 00:56:01       29 阅读
  7. Android输入法相关(一)

    2024-02-22 00:56:01       23 阅读
  8. Mysql卸载

    2024-02-22 00:56:01       26 阅读
  9. C# action,delegate,func的用法和区别

    2024-02-22 00:56:01       28 阅读
  10. 如何解决AI场景下的冯诺伊曼陷阱?

    2024-02-22 00:56:01       26 阅读
  11. RESTful 风格是指什么

    2024-02-22 00:56:01       27 阅读
  12. vue从入门到进阶的30个vue代码示例

    2024-02-22 00:56:01       32 阅读
  13. Docker基于本地文件安装Nacos单机版

    2024-02-22 00:56:01       28 阅读
  14. SQL语句分为以下三种类型

    2024-02-22 00:56:01       29 阅读