springMVC--数据验证以及国际化

简介: springMVC--数据验证以及国际化

springMVC–数据验证以及国际化


概述


  1. 1、在开发中,我们需要对输入的数据(比如表单数据),进行必要的验证,并给出相应的提示信息。
  2. 2、对于验证表单数据,springMVC 提供了很多实用的注解, 这些注解由JSR 303 验证框架提供.


JSR 303 验证框架


1、JSR 303 是Java 为Bean 数据合法性校验提供的标准框架,它已经包含在JavaEE 中,叫做Bean Validation,用来对参数的校验。


2、JSR 303 通过在Bean 属性上标注类似于@NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对Bean 进行验证。


3、JSR 303 提供的基本验证注解有:

eaebfca8cb964a3cac88f5d07b87dd1d.png

4、JSR 303 只是一个规范,我们不能直接使用。在规范的实现中我们常用的就是: Hibernate-Validator。


Hibernate Validator 扩展注解


1、Hibernate Validator 和Hibernate 没有关系,只是JSR 303 实现的一个扩展.

2、Hibernate Validator 是JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解:

8b97002864f546a7ab070e0e52299d32.png


应用实例


需求说明


前端页面显示

87dc0e0250574ffc9c71555d0fa929fd.png


代码实现


引入验证和国际化相关的jar 包


e25f22d81c54416aa66b11ca2b91a72e.png


修改Monster.java

@NotEmpty
    private String name;
    //@NotEmpty 表示name不能为空
    //Asserts that the annotated string, collection, map or array is not {@code null} or empty.
   //该注解应用于字符串、集合、数组等等不为空,集合长度必须大于0
@Range(min = 1,max = 100)
    private Integer age;
    //数据范围在1-100之间


修改MonsterHandler.java

  /**
     * 编写方法,处理添加妖怪
     * 1. springmvc可以将提交的数据,按照参数名和对象的属性名匹配
     * 2. 直接封装到对象中
     * String => Integer
     * 3. @Valid Monster monster :表示对monster接收的数据进行校验
     * 4. Errors errors 表示如果校验出现错误,将校验的错误信息保存 errors
     * 5. Map<String, Object> map  表示如果校验出现错误, 将校验的错误信息保存 map 同时保存monster对象
     * 6. 校验发生的时机: 在springmvc底层,反射调用目标方法时,会接收到http请求的数据,然后根据注解来进行验证
     * , 在验证过程中,如果出现了错误,就把错误信息填充到errors 和 map
     */
    @RequestMapping(value = "/save")
    public String save(@Valid Monster monster, Errors errors, Map<String, Object> map) {
        System.out.println("----monster---" + monster);
        //我们为了看到验证的情况,我们输出map 和 errors
        System.out.println("===== map ======");
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            System.out.println("key= " + entry.getKey() + " value=" + entry.getValue());
        }
        System.out.println("===== errors ======");
        if (errors.hasErrors()) {//判断是否有错误
            List<ObjectError> allErrors = errors.getAllErrors();
            for (ObjectError error : allErrors) {
                System.out.println("error=" + error);
            }
            return "datavalid/monster_addUI";
        }
        return "datavalid/success";
    }


测试效果

c77531cfaff146e3ab46134b81622473.png

自己输入一个不符合的值。

=====map=====
key=monster value=Monster{id=null, email='jack@sohu.com', age=900, name='',
birthday=Thu Nov 11 00:00:00 CST 1999, salary=11.11}
key=org.springframework.validation.BindingResult.monster
value=org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'monster' on field 'age': rejected value [900]; codes
[Range.monster.age,Range.age,Range.java.lang.Integer,Range]; arguments
[org.springframework.context.support.DefaultMessageSourceResolvable: codes
[monster.age,age]; arguments []; default message [age],100,1]; default message
[需要在1 和100 之间]
Field error in object 'monster' on field 'name': rejected value []; codes
[NotEmpty.monster.name,NotEmpty.name,NotEmpty.java.lang.String,NotEmpty];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable: codes
[monster.name,name]; arguments []; default message [name]]; default message
[不能为空]
=====errors=====
验证出现错误
验证错误=Field error in object 'monster' on field 'age': rejected value [900]; codes
[Range.monster.age,Range.age,Range.java.lang.Integer,Range]; arguments
[org.springframework.context.support.DefaultMessageSourceResolvable: codes
[monster.age,age]; arguments []; default message [age],100,1]; default message
[需要在1 和100 之间]
验证错误=Field error in object 'monster' on field 'name': rejected value []; codes
[NotEmpty.monster.name,NotEmpty.name,NotEmpty.java.lang.String,NotEmpty];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable: codes
[monster.name,name]; arguments []; default message [name]]; default message
[不能为空]


c77531cfaff146e3ab46134b81622473.png


配置国际化文件springDispatcherServlet-servlet.xml

    <!-- 配置国际化错误信息的资源处理bean -->
<bean id="messageSource" class=
    "org.springframework.context.support.ResourceBundleMessageSource">
    <!-- 配置国际化文件名字  如果这样配的话,表示messageSource 回到src/i18nXXX.properties 去读取错误信息 -->
    <property name="basename" value="i18n"></property>
</bean>


创建国际化文件springmvc\src\i18n.properties

NotEmpty.monster.name=\u7528\u6237\u540d\u4e0d\u80fd\u4e3a\u7a7a
typeMismatch.monster.age=\u5e74\u9f84\u8981\u6c42\u5728\u0031\u002d\u0031\u0035\u0030\u4e4b\u95f4
typeMismatch.monster.birthday=\u751f\u65e5\u683c\u5f0f\u4e0d\u6b63\u786e
typeMismatch.monster.salary=\u85aa\u6c34\u683c\u5f0f\u4e0d\u6b63\u786e


修改monster_addUI.jsp , 回显错误信息

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>添加妖怪</title>
</head>
<body>
<h3>添加妖怪</h3>
<!-- 这里的表单,我们使用springMVC的标签来完成
特别说明几点:
1. SpringMVC 表单标签在显示之前必须在 request 中有一个 bean, 该 bean 的属性和表单标签的字段要对应!
request 中的 key 为: form 标签的 modelAttribute 属性值, 比如这里的monsters
2. SpringMVC 的 form:form 标签的 action 属性值中的 / 不代表 WEB 应用的根目录.
3. 这里使用springmvc的标签的主要的目的是方便提示信息回显
-->
<form:form action="save" method="post" modelAttribute="monster">
    妖怪名字: <form:input path="name"/> <form:errors path="name"/>  <br><br>
    妖怪年龄~: <form:input path="age"/> <form:errors path="age"/> <br><br>
    电子邮件: <form:input path="email"/> <form:errors path="email"/>  <br><br>
    妖怪生日: <form:input path="birthday"/> <form:errors path="birthday"/> 要求以"9999-11-11"的形式<br><br>
    妖怪薪水: <form:input path="salary"/> <form:errors path="salary"/> 要求以"123,890.12"的形式<br><br>
    <input type="submit" value="添加妖怪"/>
</form:form>
</body>
</html>


完成测试


43076c1fbbab46909d12184401470d09.png


细节说明和注意事项


1.在需要验证的Javabean/POJO 的字段上加上相应的验证注解.

2.目标方法上,在JavaBean/POJO 类型的参数前, 添加@Valid 注解. 告知SpringMVC该bean 是需要验证的.

3.在@Valid 注解之后, 添加一个Errors 或BindingResult 类型的参数, 可以获取到验证的错误信息.

4.需要使用<form:errors path=“email”></form:errors> 标签来显示错误消息, 这个标签,需要写在form:form 标签内生效.

5.错误消息的国际化文件i18n.properties , 中文需要是Unicode 编码,使用工具转码.

√ 格式: 验证规则.表单modelAttribute 值.属性名=消息信息

√ NotEmpty.monster.name=\u540D\u5B57\u4E0D\u80FD\u4E3A\u7A7A

√ typeMismatch.monster.age=\u7C7B\u578B\u4E0D\u5339\u914D

6.SpingMVC 验证时,会根据不同的验证错误, 返回对应的信息


注解@NotNull 和@NotEmpty 的区别说明


1.查看源码可以知道: @NotEmpty Asserts that the annotated string, collection, map or array is not {@code null} or empty.

2.查看源码可以知道: @NotNull * The annotated element must not be {@code null}.*Accepts any type.

3.如果是字符串验证空, 建议使用@NotEmpty.


注解的结合使用


问题


由一个问题引出: age 没有, 是空的,提交成功了。

433a1253f0854f799b2c83d04ed7b18a.png


a9556f00a7204ae1bc80e8cdbb215536.png

这显然不符合我们的要求。


解决方案:注解组合使用


使用@NotNull + @Range 组合使用解决.


具体代码


修改Monster

public class Monster {
    private Integer id;
   //email是string,使用@NotEmpty
    @NotEmpty
    private String email;
    //@Range(min = 1,max = 100)
    //表示接收的age值,在 1-100之间
    @NotNull(message = "age不能为空")
    @Range(min = 1,max = 100)
    private Integer age;
    //@NotEmpty 表示name不能为空
    //Asserts that the annotated string, collection, map or array is not {@code null} or empty.
    @NotEmpty
    private String name;
    @NotNull(message = "生日不能为空")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birthday;
    @NotNull(message = "薪水不能为空")
    @NumberFormat(pattern = "###,###.##")
    private Float salary;
}


测试(页面方式)


这时age 不能为空,同时必须是1-100, (也不能输入haha, hello 等不能转成数字的内容)。


b047484d73f646edbef588bf49872596.png


数据类型转换校验核心类-DataBinder


DataBinder 工作机制-了解


图例Spring MVC 通过反射机制对目标方法进行解析,将请求消息绑定到处理方法的入参中。

数据绑定的核心部件是DataBinder,运行机制如下:

a011e11143be4b4991090dd2bd49f107.png


Debug 一下validate 得到验证errors 信息


从serverRequest拿到前端的数据,将拿到处理方法的信息使用DateBinder的内置转换器进行数据类型转换/格式化。


在数据类型转换过程中,如果发生不能转换的错误就直接放到BindingResult中。


然后我们再进行数据校验,如果出错了就继续放入BindingResult接收。


最后放到error中显示输出。

6bf75da483284a2dacea0974b7900ade.png

7297ed312f6342a0aad8c114e7ae3e56.png


@Valid 和 @Validated 比较


(1)@Valid 和 @Validated 两者都可以对数据进行校验,待校验字段上打的规则注解(@NotNull, @NotEmpty等)都可以对 @Valid 和 @Validated 生效;


(2)@Valid 进行校验的时候,需要用 BindingResult 来做一个校验结果接收。当校验不通过的时候,如果不手动return ,就不会阻止程序的执行;


(3)@Validated 进行校验的时候,当校验不通过的时候,程序会抛出400异常,阻止方法中的代码执行,这时需要再写一个全局校验异常捕获处理类,然后返回校验提示。


(4)总体来说,@Validated 使用起来要比 @Valid 方便一些,它可以帮我们节省一定的代码,并且使得方法看上去更加的简洁。


取消某个属性的绑定


在默认情况下,表单提交的数据都会和pojo 类型的javabean 属性绑定,如果程序员在开发中,希望取消某个属性的绑定,也就是说,不希望接收到某个表单对应的属性的值,则可以通过@InitBinder 注解取消绑定.


1.编写一个方法, 使用@InitBinder 标识的该方法,可以对WebDataBinder 对象进行初始化。WebDataBinder 是DataBinder 的子类,用于完成由表单字段到JavaBean 属性的绑定。

2.@InitBinder 方法不能有返回值,它必须声明为void。

3.@InitBinder 方法的参数通常是是WebDataBinder。


案例-不希望接收怪物的名字属性

修改MonsterHandler.java , 增加方法

//取消绑定 monster的name表单提交的值给monster.name属性
    @InitBinder
    public void initBinder(WebDataBinder webDataBinder) {
        /**
         * 1. 方法上需要标注 @InitBinder  springmvc底层会初始化 WebDataBinder
         * 2. 调用 webDataBinder.setDisallowedFields("name") 表示取消指定属性的绑定
         *    即:当表单提交字段为 name时, 就不在把接收到的name值,填充到model数据monster的name属性
         * 3. 机制:springmvc 在底层通过反射调用目标方法时, 接收到http请求的参数和值,使用反射+注解技术
         *    取消对指定属性的填充
         * 4. setDisallowedFields支持可变参数,可以填写多个字段
         * 5. 如果我们取消某个属性绑定,验证就没有意义了,应当把验证的注解去掉, name属性会使用默认值null
         */
        webDataBinder.setDisallowedFields("name");
    }


修改Monster.java

//如果希望取消某个属性绑定,验证就没有意义了,应当把验证的注解去掉, name属性会使用默认值null
//@NotEmpty
private String name;


完成测试(页面测试)。


注意事项和细节说明


1.setDisallowedFields() 是可变形参,可以指定多个字段。

2.当将一个字段/属性,设置为disallowed,就不在接收表单提交的值,那么这个字段/属性的值,就是该对象默认的值(具体看程序员定义时指定)。

3.一般来说,如果不接收表单字段提交数据,则该对象字段的验证也就没有意义了可以注销掉,比如注销//@NotEmpty。

相关文章
|
11月前
|
XML 前端开发 Java
SpringMVC中资源国际化使用实践
SpringMVC中资源国际化使用实践
118 0
|
Java
SpringMVC-国际化
SpringMVC-国际化
57 0
|
Java Spring
springmvc-国际化&中英文切换&文件上传&下载
springmvc-国际化&中英文切换&文件上传&下载
|
前端开发 Java 应用服务中间件
Spring MVC-08循序渐进之国际化(基于Session-SessionLocaleResolver)
Spring MVC-08循序渐进之国际化(基于Session-SessionLocaleResolver)
67 0
|
前端开发 IDE Java
Spring MVC-08循序渐进之国际化(AcceptHeaderLocaleResolver)
Spring MVC-08循序渐进之国际化(AcceptHeaderLocaleResolver)
159 0
|
前端开发 Java 数据库连接
SpringMVC的数据验证和JSR 303国际化显示(十一)下
SpringMVC的数据验证和JSR 303国际化显示(十一)下
377 0
SpringMVC的数据验证和JSR 303国际化显示(十一)下
|
前端开发 Java 数据库连接
SpringMVC的数据验证和JSR 303国际化显示(十一)中
SpringMVC的数据验证和JSR 303国际化显示(十一)中
213 0
SpringMVC的数据验证和JSR 303国际化显示(十一)中
|
前端开发 JavaScript Java
SpringMVC的数据验证和JSR 303国际化显示(十一)上
SpringMVC的数据验证和JSR 303国际化显示(十一)上
222 0
SpringMVC的数据验证和JSR 303国际化显示(十一)上
|
存储 前端开发
SpringMVC的国际化操作(十)下
SpringMVC的国际化操作(十)下
253 0
SpringMVC的国际化操作(十)下
|
前端开发 Java Spring
SpringMVC的国际化操作(十)上
SpringMVC的国际化操作(十)上
296 0
SpringMVC的国际化操作(十)上