SpringMVC数据校验

使用SpringMVC时配合hibernate-validate进行参数的合法性校验,验证客户输入的数据是否合法,能节省一定的代码量。

1. 搭建Web工程并引入hibernate-validate依赖

  <dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.1.2.Final</version>
  </dependency>
  <dependency>
     <groupId>org.glassfish</groupId>
     <artifactId>jakarta.el</artifactId>
     <version>3.0.3</version>
  </dependency>
  <dependency>
     <groupId>org.hibernate.validator</groupId>
     <artifactId>hibernate-validator-cdi</artifactId>
     <version>6.1.2.Final</version>
  </dependency>

2. SpringMVC.xml配置

    <!-- 将校验器交给适配器 -->
    <mvc:annotation-driven validator="validator"></mvc:annotation-driven>
    <!-- 配置校验器 -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!-- 提供校验的类 -->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
        <!-- 可以配置国际化错误信息保存的文件,也可在校验注解使用message属性进行配置但会失去国际化的功能 -->
        <property name="validationMessageSource" ref="messageSource"></property>
    </bean>
<!-- 读取外部配置文件 -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!-- 文件路径 -->
        <property name="basenames">
            <array>
                <value>classpath:CustomValidationMessages</value>
            </array>
        </property>
        <!-- 设置编码格式 -->
        <property name="defaultEncoding" value="utf-8"></property>
        <!-- 文件缓存的时间 :以秒为单位 -->
        <property name="cacheSeconds" value="60"></property>
    </bean>

自定义校验信息提示文件CustomValidationMessages.properties

emp.empno=\u96C7\u5458\u7F16\u53F7\u53EA\u80FD\u4E3A\u56DB\u4F4D\u6570\u5B57\u7EC4\u6210  //雇员编号只能为四位数字组成
emp.ename=\u96C7\u5458\u59D3\u540D\u53EA\u80FD\u7531\u6570\u5B57\u3001\u5B57\u6BCD\u3001\u4E0B\u5212\u7EBF\u3001\u957F\u77ED\u5FC5\u987B\u57286-10\u4F4D\u4E4B\u95F4  //雇员编号只能为四位数字组成
emp.job=\u804C\u4F4D\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A  //职位名称不能为空
emp.email=\u975E\u6CD5\u90AE\u7BB1 //非法邮箱

3. 使用校验注解标注在属性上(DTO)



*每个注解都有message属性,该属性用于填写校验失败时的异常描述信息,当校验失败时可以获取对应的message属性值。

4. Spring MVC 数据校验

  • Spring 4.0 拥有自己独立的数据校验框架,同时支持 JSR 303 标准的校验框架。
  • Spring 在进行数据绑定时,可同时调用校验框架完成数据校验工作。在 Spring MVC 中,可直接通过注解驱动的方式进行数据校验
  • Spring 的 LocalValidatorFactroyBean 既实现了 Spring 的 Validator 接口,也实现了 JSR 303 的 Validator 接口。只要在 Spring 容器中定义了一个 LocalValidatorFactoryBean,即可将其注入到需要数据校验的 Bean 中。
  • Spring 本身并没有提供 JSR303 的实现,所以必须将 JSR303 的实现者的 jar 包放到类路径下。

  • <mvc:annotation-driven/> 会默认装配好一个 LocalValidatorFactoryBean,通过在处理方法的入参上标注 @valid 注解即可让 Spring MVC 在完成数据绑定后执行数据校验的工作
  • Spring MVC 是通过对处理方法签名的规约来保存校验结果的:前一个表单/命令对象的校验结果保存到随后的入参中,这个保存校验结果的入参必须是 BindingResult 或 Errors 类型,这两个类都位于 org.springframework.validation 包中

  • 需校验的 Bean 对象和其绑定结果对象或错误对象时成对出现的,它们之间不允许声明其他的入参
  • Errors 接口提供了获取错误信息的方法,如 getErrorCount() 或 getFieldErrors(String field)
  • BindingResult 扩展了 Errors 接口


    image.png

5. 使用@Validated/@Valid注解开启对参数的校验

  • @Validated注解表示开启Spring的校验机制,支持分组校验,声明在入参上。
  • @Valid注解表示开启Hibernate的校验机制,不支持分组校验,声明在入参上。
  • 在DTO后面紧跟BindingResult对象,那么当参数不符合时,能通过该对象直接获取不符合校验的message描述信息。
  • 若使用了@Validated/@Valid注解开启校验,但DTO后面没有紧跟BindingResult对象,那么当参数不符合时,将直接返回400 Bad Request状态码。

6. 在页面上显示错误(需要引入SpringMVC表单标签库)

  • Spring MVC 除了会将表单/命令对象的校验结果保存到对应的 BindingResult 或 Errors 对象中外,还会将所有校验结果保存到 “隐含模型”
  • 即使处理方法的签名中没有对应于表单/命令对象的结果入参,校验结果也会保存在 “隐含对象” 中。
  • 隐含模型中的所有数据最终将通过 HttpServletRequest 的属性列表暴露给 JSP 视图对象,因此在 JSP 中可以获取错误信息
  • 在 JSP 页面上可通过 <form:errors path=“userName”> 显示错误消息

7. 示例

public class Emp {
    @Max(value = 9999L)
    @Min(value = 1000)
    private int empno;

    @Pattern(regexp = "[0-9A-Za-z_]{6,10}", message = "雇员姓名只能由数字、字母、下划线、长短必须在6-10位之间")
    private String ename;

    @NotBlank(message = "工作不能为空")
    private String job;

    private int mgr;

    private Date hiredate;

    @Email(message = "非法邮箱!")
    private String email;

    private double sal;

    private double comm;

    private Dept dept;

    ...
    @RequestMapping("/adduser")
    public void addUser(@Validated Emp emp, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            List<ObjectError> errors = bindingResult.getAllErrors();
            for (ObjectError objectError : errors) {
                System.out.println(objectError.getDefaultMessage());
            }
        }
        System.out.println(emp.getHiredate());
    }

8. 提示消息的国际化

上述例子代码中,我们自定义错误消息,使用了message 属性来自定义消息描述,但是这样做我们就失去了国际化的功能,消息国际化我们可以通过编写国际化配置文件来实现

当使用 Spring MVC 标签显示错误消息时, Spring MVC 会查看 WEB 上下文是否装配了对应的国际化消息,如果没有,则显示默认的错误消息,否则使用国际化消息。

配置校验器以及国际化配置文件

    <!-- 将校验器交给适配器 -->
    <mvc:annotation-driven validator="validator"></mvc:annotation-driven>
    <!-- 配置校验器 -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!-- 提供校验的类 -->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
        <!-- 可以配置国际化错误信息保存的文件,也可在校验注解使用message属性进行配置但会失去国际化的功能 -->
        <property name="validationMessageSource" ref="messageSource"></property>
    </bean>
<!-- 读取外部配置文件 -->
    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!-- 文件路径 -->
        <property name="basenames">
            <array>
                <value>classpath:CustomValidationMessages</value>
            </array>
        </property>
        <!-- 设置编码格式 -->
        <property name="defaultEncoding" value="utf-8"></property>
        <!-- 文件缓存的时间 :以秒为单位 -->
        <property name="cacheSeconds" value="60"></property>
    </bean>

自定义校验信息提示文件CustomValidationMessages.properties

emp.empno=\u96C7\u5458\u7F16\u53F7\u53EA\u80FD\u4E3A\u56DB\u4F4D\u6570\u5B57\u7EC4\u6210  //雇员编号只能为四位数字组成
emp.ename=\u96C7\u5458\u59D3\u540D\u53EA\u80FD\u7531\u6570\u5B57\u3001\u5B57\u6BCD\u3001\u4E0B\u5212\u7EBF\u3001\u957F\u77ED\u5FC5\u987B\u57286-10\u4F4D\u4E4B\u95F4  //雇员编号只能为四位数字组成
emp.job=\u804C\u4F4D\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A  //职位名称不能为空
emp.email=\u975E\u6CD5\u90AE\u7BB1 //非法邮箱

校验目标类

public class Emp {
    @Max(value = 9999L)
    @Min(value = 1000)
    private int empno;
    @Pattern(regexp = "[0-9A-Za-z_]{6,10}", message = "{emp.ename}")
    private String ename;
    @NotBlank(message = "{emp.job}")
    private String job;
    private int mgr;
    private Date hiredate;
    @Email(message = "{emp.email}")
    private String email;
    private double sal;
    private double comm;
    private Dept dept;// 一对一
    ...

9.分组校验

9.1. 什么是分组校验?

校验规则是在pojo 制定的,而同一个pojo可以被多个Controller使用,此时会有问题,即:不同的Controller方法对同一个pojo进行校验,此时这些校验信息是共享在这不同的Controller方法中,但是实际上每个Controller方法可能需要不同的校验,在这种情况下,就需要使用分组校验来解决这种问题。
通俗的讲,一个pojo中有很多属性,controller中的方法1可能只需要校验pojo中的属性1,controller中的方法2只需要校验pojo中的属性2,但是pojo中的校验注解有很多,怎样才能使方法1只校验属性1,方法二只校验属性2呢?就需要用分组校验来解决了。

9.2. 定义分组

定义分组

就是定义空的接口,接口类只作为这个分组标识来使用,看下面的用法,就知道其意义何在了

9.3. 使用分组

image.png

9.4. controller方法

在这个方法中,那么就只会校验Emp这个pojo中有Group1.class这个分组的校验注解,而不会在校验其他的


image.png

10 扩展知识

使用SpringMVC表单标签库来参数校验https://www.cnblogs.com/hemou/p/12356175.html
SpringMVC表单标签库https://www.jianshu.com/p/b1f2d50b671c
SpringMVC_数据校验https://blog.csdn.net/qq_40794973/article/details/97967016

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容