@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)
    {
    	BindingResult bindingResult = e.getBindingResult();
        StringBuilder sb = new StringBuilder("校验失败:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
        }
        String msg = sb.toString();
        log.error(msg);
         return AjaxResult.error(msg);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
    {
        BindingResult bindingResult = e.getBindingResult();
        StringBuilder sb = new StringBuilder("校验失败:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", ");
        }
        String msg = sb.toString();
        log.error(msg);
         return AjaxResult.error(msg);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public AjaxResult handleConstraintViolationException(ConstraintViolationException e)
    {
        log.error(e.getMessage(), e);
         return AjaxResult.error(e.getMessage());
    }
}

扩展:@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();
    }
}
  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
@Validated是Spring框架中的一个注解,用于对方法的参数进行验证。它可以用于类、方法和方法参数上。@Valid是Java标准(javax.validation)中的一个注解,也用于对方法参数进行验证。 这两个注解在基本验证功能上没有太多区别,都可以用来验证参数是否符合规范。但在其他功能上有所不同。 @Validated注解可以使用分组、注解地方、嵌套验证等功能,而@Valid注解则没有这些功能。 @Validated注解的@Target包括ElementType.TYPE、ElementType.METHOD和ElementType.PARAMETER等,而@Valid注解的@Target只包括ElementType.PARAMETER。 在Spring框架中,我们可以使用@Validated注解来替代手动对参数进行校验,这样可以简化代码并提高代码的可读性。同时,@Validated注解还提供了更多的验证功能,可以根据需要进行灵活的配置。 总之,@Validated和@Valid都是参数检验工具,但在功能上有一些区别。具体使用哪个注解取决于项目的需求和框架的要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [@Validated、@Valid对比及详细用法](https://blog.csdn.net/liuerchong/article/details/123041734)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洪泽涛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值