@valid 无法触发BindingResult的解决

目录
  • 方法参数
  • 问题
  • 原因
  • 解决方案
  • @Validated和@Valid区别
    • 1. 分组
    • 2. 注解地方
    • 3. 嵌套验证

方法参数

public String listFireEvent(@Valid  FireSearch fireSearch, HttpServletRequest request, BindingResult bindingResult)

问题

如果验证失败会直接抛出异常,而不是放入bindingResult

原因

@Valid 和 BindingResult 不能有其它类

解决方案

把HttpServletRequest 放到最后

即:

public String listFireEvent(@Valid FireSearch fireSearch, BindingResult bindingResult,HttpServletRequest request)

@Validated和@Valid区别

Spring validation验证框架对入参实体进行嵌套验证必须在相应属性(字段)加上@Valid而不是@Validated

Spring Validation验证框架对参数的验证机制提供了@Validated(Spring's JSR-303规范,是标准JSR-303的一个变种),javax提供了@Valid(标准JSR-303规范),配合BindingResult可以直接提供参数验证结果。其中对于字段的特定验证注解比如@NotNull等网上到处都有,这里不详述

在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:

1. 分组

  • @Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制,这个网上也有资料,不详述。@Valid:作为标准JSR-303规范,还没有吸收分组的功能。

2. 注解地方

  • @Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
  • @Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上

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

3. 嵌套验证

在比较两者嵌套验证时,先说明下什么叫做嵌套验证。比如我们现在有个实体叫做Item:

public class Item {
    @NotNull(message = "id不能为空")
    @Min(value = 1, message = "id必须为正整数")
    private Long id;
    @NotNull(message = "props不能为空")
    @Size(min = 1, message = "至少要有一个属性")
    private List<Prop> props;
}

Item带有很多属性,属性里面有属性id,属性值id,属性名和属性值,如下所示:

public class Prop {
    @NotNull(message = "pid不能为空")
    @Min(value = 1, message = "pid必须为正整数")
    private Long pid;
    @NotNull(message = "vid不能为空")
    @Min(value = 1, message = "vid必须为正整数")
    private Long vid;
    @NotBlank(message = "pidName不能为空")
    private String pidName;
    @NotBlank(message = "vidName不能为空")
    private String vidName;
}

属性这个实体也有自己的验证机制,比如属性和属性值id不能为空,属性名和属性值不能为空等。

现在我们有个ItemController接受一个Item的入参,想要对Item进行验证,如下所示:

@RestController
public class ItemController {
    @RequestMapping("/item/add")
    public void addItem(@Validated Item item, BindingResult bindingResult) {
        doSomething();
    }
}

如上,如果Item实体的props属性不额外加注释,只有@NotNull和@Size,无论入参采用@Validated还是@Valid验证,Spring Validation框架只会对Item的id和props做非空和数量验证,不会对props字段里的Prop实体进行字段验证,也就是@Validated和@Valid加在方法参数前,都不会自动对参数进行嵌套验证。也就是说如果传的List<Prop>中有Prop的pid为空或者是负数,入参验证不会检测出来。

为了能够进行嵌套验证,必须手动在Item实体的props字段上明确指出这个字段里面的实体也要进行验证。由于@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能,那么我们能够推断出:@Valid加在方法参数时并不能够自动进行嵌套验证,而是用在需要嵌套验证类的相应字段上,来配合方法参数上@Validated或@Valid来进行嵌套验证。

我们修改Item类如下所示:

public class Item {
    @NotNull(message = "id不能为空")
    @Min(value = 1, message = "id必须为正整数")
    private Long id;
    @Valid // 嵌套验证必须用@Valid
    @NotNull(message = "props不能为空")
    @Size(min = 1, message = "props至少要有一个自定义属性")
    private List<Prop> props;
}

然后我们在ItemController的addItem函数上再使用@Validated或者@Valid,就能对Item的入参进行嵌套验证。此时Item里面的props如果含有Prop的相应字段为空的情况,Spring Validation框架就会检测出来,bindingResult就会记录相应的错误。

总结一下@Validated和@Valid在嵌套验证功能上的区别:

  • @Validated:用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。
  • @Valid:用在方法入参上无法单独提供嵌套验证功能。能够用在成员属性(字段)上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • SpringMVC中@Valid不起效BindingResult读取不到Error信息

    目录 Bug记录 首先检查jar包的导入 检查Bean实体类的注解 检查Springmvc的配置 检查View层的Spring MVC表单标签 检查JDK版本 总结 Bug记录 在写SpringMVC项目时,由于要对表单数据进行校验,使用Spring MVC框架时,有两种 常用的方式校验输入的数据. 利用Spring框架自带的验证框架 利用JSR 303实现 我使用的是JSR 303实现数据校验的,JSR 303 通过在Bean属性上标注类似于@NotNull.@Max等标准的注解指定校验规则,

  • 快速校验实体类时,@Valid,@Validated,@NotNull注解无效的解决

    目录 校验实体类参数内容不能为空时使用注解校验无效 使用@valid注解首先引入依赖 1.更换方法入参类型 2.错误内容过多 3.使用对象接收错误内容,按自己要求输出 springboot 校验机制 @Validated @Valid 1.探究原因 2.使用@Validated 实现校验机制 3.使用@Valid 实现校验机制 校验实体类参数内容不能为空时使用注解校验无效 使用@valid注解首先引入依赖 如果是SpringBoot项目,引入web开发包,就不需要再单独引入@valid依赖了.因

  • 一次踩坑记录 @valid注解不生效 排查过程

    一.背景 在进行一次Controller层单测时,方法参数违反Validation约束,发现却没有抛出预期的[违反约束]异常. 方法参数上的@Valid注解不生效?? 但是以Tomcatweb容器方式启动,请求该API,@Valid注解却生效了,甚是怪异. 代码如下: @RestController @RequestMapping("/api/user/") public class UserController @RequestMapping(value = ""

  • 使用@Validated 和 BindingResult 遇到的坑及解决

    @Validated和BindingResult 使用遇到的坑 @Validated 与BindingResult 需要相邻,否则 变量result 不能接受错误信息 控制台输出 Field error in object 'entity' on field '变量': rejected value [null]; codes [NotNull.entity.变量,NotNull.变量,NotNull.java.lang.String,NotNull]; arguments [org.sprin

  • @valid 无法触发BindingResult的解决

    目录 方法参数 问题 原因 解决方案 @Validated和@Valid区别 1. 分组 2. 注解地方 3. 嵌套验证 方法参数 public String listFireEvent(@Valid FireSearch fireSearch, HttpServletRequest request, BindingResult bindingResult) 问题 如果验证失败会直接抛出异常,而不是放入bindingResult 原因 @Valid 和 BindingResult 不能有其它类

  • @Valid 校验无效,BindingResult未获得错误的解决

    目录 @Valid 校验失效 问题描述 解决过程 使用bindingResult做参数校验 在控制类中 实体类OrderForm @Valid 校验失效 问题描述 使用@Valid校验实体类中的属性stuTele import javax.validation.constraints.Size; ... @Size(min = 11,max = 11,message = "请输入11位手机号码") private String stuTele; Controller中,用@Valid注

  • JS中mouseover和mouseout多次触发问题如何解决

    问题描述 我希望当鼠标移动到id1上的时候,id2显示,当鼠标离开id1的时候,id2显示.问题如下: 1.当鼠标从id1上移动到id2上的时候,id由有显示变为不显示,然后变为显示 2.当鼠标从id2上移动到id1上的时候, id2有显示变为不显示,然后变为显示 我希望的是当鼠标在id1或者id2上移动的时候,id2一直显示,不发生变化. <script type="text/javascript" src="https://code.jquery.com/jquer

  • bootstrap datepicker 与bootstrapValidator同时使用时选择日期后无法正常触发校验的解决思路

    一.前言 使用bootstrap-datepicker和bootstrapValidator也有一段时间了,在工作中发现两者同时使用时会出现的一种问题,当选择完日期后,并不会正确校验该字段.为了更加直观的展现问题,上图一张. 可以看出,当选择完日期后,校验结果并没有达到预期,是因为bootstrapValidator插件默认情况下,不会重复校验一个已经标记为验证通过或验证不通过的字段.so ,当开始触发校验后,没有通过校验,当正确选择日期后,并不会刷新校验结果,就会导致数据无法正常提交,当手动把

  • IE中鼠标经过option触发mouseout的解决方法

    本文实例讲述了IE中鼠标经过option触发mouseout的解决方法.分享给大家供大家参考.具体分析如下: 要实现的功能: 有一个DIV,当鼠标经过时此DIV完全展开,当鼠标移开时DIV收缩回去,其中DIV里面有一个select选择框: 操作select的时候在IE中会出现一个问题,当鼠标经过option时,DIV会收缩回去,而在其他浏览器中无此现象. 解决的方法: 在IE中,当鼠标移到option时 window.event.toElement 的值为null,在其他浏览器中的值为objec

  • Easyui 关闭jquery-easui tab标签页前触发事件的解决方法

    测试环境 jquery-easyui-1.5.3 需求场景 点击父页面tab 页关闭按钮时,需要做判断,判断该tab页面是否可以关闭:获取子页面js中定义的taskStatus,如果taskStatu不为taskEnd,则表示任务还在执行,不让关闭 解决方法 给tab标签页增加onBeforeClose事件处理函数,如下: $(function(){ $('#tabs').tabs({ onBeforeClose: function(title,index){ if (title.indexOf

  • vue首次赋值不触发watch的解决方法

    最近有个新需求,表单要求增量提交,但是身份证要求无则可提交,有错无法提交,只能新写个校验,但是还不能进组件就监控,后来发现watch有个immediate 选项 watch:{ "aaa":{ immediate:true, handler:function(){ } } 以上这篇vue首次赋值不触发watch的解决方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 快速移动鼠标触发问题及解决方法(ECharts外部调用保存为图片操作及工作流接线mouseenter和mouseleave)

    记录两个项目开发中遇到的问题,一个是ECharts外部调用保存为图片操作,一个是workflow工作流连接曲线onmouseenter和onmouseleave事件由于鼠标移动过快触发问题. 一.外部按钮调用ECharts图表的保存为图片操作 最近使用ECharts库绘制图表,依据需求希望可以把图表设置的保存为图片操作可以在图表外部调用,主要是希望可以和项目之前的下载图片操作界面保持一致.然后上网找了一些方法,看了看也没遇到一个可以满意的.后来,突然想到了echart开放了源码,可以看看源码,找

  • fastclick插件导致日期(input[type="date"])控件无法被触发该如何解决

    本文作为一名新手,写的不好地方还请各位大家多多指教,以下内容只是给大家共勉以下我的解决方案,也是我个人的一个见解,有不同意见不同解决方案的朋友还请多多分享自己的解决办法. 首先,我们使用fastclick插件的初衷是解决"tap"事件"点透"的BUG:fastclick与tap都是利用"touch"事件来模拟"click"事件的: 然后我们来大致的了解一下fastclick的工作原理(来自往上的copy): 在我们的app中跟

  • vue项目watch内的函数重复触发问题的解决

    问题描述: 有两个页面A和B,每个页面里都有一个getList()方法.这个两个方法都需要传一个相同的参数C,参数C的选择过程又比较麻烦.为了避免在切换A.B两个界面重复选择参数C的问题,我将参数C存入vuex中,然后在两个页面里都使用watch监听参数C来执行getList()方法.然后发现一个问题,从A页面进入B页面后,在B页面重新选择参数C,A页面的getList()方法竟然也会被执行,反之亦然,从B页面到A页面后,在A页面改变参数C也会执行B页面的getList()方法. 后来发现是使用

随机推荐