day09-数据格式化&验证以及国际化
数据格式化&验证以及国际化
1.数据格式化
1.1基本介绍
说明:在我们提交数据(比如表单时),SpringMVC 是怎样对提交的数据进行转换和处理的
基本数据类型可以和字符串之间自动进行转换,比如:SpringMVC 上下文中内建了很多转换器,可以完成大多数 java 类型的转换工作。[相互转换,这里只列出部分]
ConversionService converters = java.lang.Boolean-> java.lang.String:org.springframework.core.convert.support.ObjectToStringConverter@f874ca java.lang.Character -> java.lang.Number : CharacterToNumberFactory@f004c9 java.lang.Character -> java.lang.String : ObjectToStringConverter@68a961 java.lang.Enum -> java.lang.String : EnumToStringConverter@12f060a java.lang.Number -> java.lang.Character : NumberToCharacterConverter@1482ac5 java.lang.Number -> java.lang.Number : NumberToNumberConverterFactory@126c6f java.lang.Number -> java.lang.String : ObjectToStringConverter@14888e8 java.lang.String -> java.lang.Boolean : StringToBooleanConverter@1ca6626 java.lang.String -> java.lang.Character : StringToCharacterConverter@1143800 java.lang.String -> java.lang.Enum : StringToEnumConverterFactory@1bba86e java.lang.String -> java.lang.Number : StringToNumberConverterFactory@18d2c12 java.lang.String -> java.util.Locale : StringToLocaleConverter@3598e1 java.lang.String -> java.util.Properties : StringToPropertiesConverter@c90828 java.lang.String -> java.util.UUID : StringToUUIDConverter@a42f23 java.util.Locale -> java.lang.String : ObjectToStringConverter@c7e20a java.util.Properties -> java.lang.String : PropertiesToStringConverter@367a7f java.util.UUID -> java.lang.String : ObjectToStringConverter@112b07f ……
1.2基本数据类型和字符串自动转换
应用实例:基本数据类型可以和字符串之间自动地完成转换
(1)Monster.java
package com.li.web.datavalid.entity; /** * @author 李 * @version 1.0 */ public class Monster { private Integer id; private String email; private Integer age; private String name; public Monster() {} public Monster(Integer id, String email, Integer age, String name) { this.id = id; this.email = email; this.age = age; this.name = name; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Monster{" + "id=" + id + ", email='" + email + '\'' + ", age=" + age + ", name='" + name + '\'' + '}'; } }
(2)data_valid.jsp:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>SpringMVC[数据格式/验证等]</title> </head> <body> <h1>SpringMVC[数据格式/验证等]</h1> <hr/> <a href="<%=request.getContextPath()%>/addMonsterUI">添加妖怪</a> </body> </html>
(3)MonsterHandler.java
package com.li.web.datavalid; import com.li.web.datavalid.entity.Monster; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import java.util.Map; /** * @author 李 * @version 1.0 * MonsterHandler 处理器响应用户提交数据 * @Scope(value = "prototype")表示每次请求MonsterHandler都会生成一个新的对象 */ @Controller @Scope(value = "prototype") public class MonsterHandler { /** * 显示添加monster的页面 * 这里的 map,当我们向 map添加数据时,会默认存放到 request域中 * @param map * @return */ @RequestMapping(value = "/addMonsterUI") public String addMonsterUI(Map<String, Object> map) { //如果你跳转的页面使用了SpringMVC标签,就需要准备一个对象放入到request域中, //该对象的属性名要对应SpringMVC的form标签的modelAttribute的属性名,否则报错 map.put("monster", new Monster()); return "datavalid/monster_addUI"; } /** * SpringMVC可以将提交的数据,按照参数名和形参对象的属性名匹配, * 然后直接封装到对象中[模型数据] * @param monster * @return */ @RequestMapping(value = "/save") public String save(Monster monster) { System.out.println("monster---" + monster); return "datavalid/success"; } }
(4)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> <%-- 1. 这里的表单,我们使用SpringMVC的标签来完成,目的是方便提示信息的回显 2. SpringMVC表单标签在显示之前,必须在request域中有一个 bean(java对象), 该 bean的属性名和表单标签的字段要对应! 3. request 域中的 key 为 form 标签的 modelAttribute的属性值,比如这里的 monsters 4.SpringMVC 的 form:form 标签的 action 属性值中的 / 不代表 WEB应用的根目录。 --%> <form:form action="save" method="post" modelAttribute="monster"> 妖怪id:<form:input path="id"/><br/><br/> 妖怪名字:<form:input path="name"/><br/><br/> 妖怪年龄:<form:input path="age"/><br/><br/> 电子邮件:<form:input path="email"/><br/><br/> <input type="submit" value="添加妖怪"/> </form:form> </body> </html>
(5)success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>添加成功</title> </head> <body> <h1>恭喜你,添加成功</h1> </body> </html>
(6)测试

后台成功拿到了数据,并将 String 类型的字符串转化为相应的数据类型,赋给 Monster 对象属性。说明 SpringMVC 底层可以自动进行基本数据类型转换。

1.3特殊数据类型和字符串间的转换
- 特殊数据类型和字符串之间的转换可以使用注解来完成(比如日期,规定格式的小数比如货币形式)
- 对于日期和货币可以使用 @DataTimeFormat 和 @NumberFormat 注解。
应用实例
(1)修改Monster.java,增加 birthday 和 salary 字段。修改相应的构造器,getter 和 setter 等。

(2)data_valid.jsp 不变
(3)MonsterHandler.java 不变
(4)修改 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> <%-- 1. 这里的表单,我们使用SpringMVC的标签来完成,目的是方便提示信息的回显 2. SpringMVC表单标签在显示之前,必须在request域中有一个 bean(java对象), 该 bean的属性名和表单标签的字段要对应! 3. request 域中的 key 为 form 标签的 modelAttribute的属性值,比如这里的 monsters 4.SpringMVC 的 form:form 标签的 action 属性值中的 / 不代表 WEB应用的根目录。 --%> <form:form action="save" method="post" modelAttribute="monster"> 妖怪id:<form:input path="id"/><br/><br/> 妖怪名字:<form:input path="name"/><br/><br/> 妖怪年龄:<form:input path="age"/><br/><br/> 妖怪生日:<form:input path="birthday"/><br/><br/> 妖怪工资:<form:input path="salary"/><br/><br/> 电子邮件:<form:input path="email"/><br/><br/> <input type="submit" value="添加妖怪"/> </form:form> </body> </html>
(5)success.jsp 不变
(6)redeployTomcat,进行测试
提交的数据:

后台输出:
monster---Monster{id=22, email='king@sohu.com', age=99, name='king', birthday=Tue Jan 01 00:00:00 CST 1924, salary=124567.22}
如果转换失败,将会提示:
Field error in object 'monster' on field 'birthday': rejected value [192401-01]; codes [typeMismatch.monster.birthday,typeMismatch.birthday,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [monster.birthday,birthday]; arguments []; default message [birthday]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'birthday'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.format.annotation.DateTimeFormat java.util.Date] for value '192401-01'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [192401-01]]]
2.验证以及国际化
2.1概述
(1)概述
- 对于输入的数据(比如表单数据),进行必要的验证,并给出相应的提示信息
- 对于验证表单数据,SpringMVC 提供了很多使用的注解,这些注解由 JSR 303验证框架提供。
(2)JSR 303 验证框架
- JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 中
- JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标注的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证
- JSR 303 提供的基本验证注解有:
注解 | 功能说明 |
---|---|
@Null | 被注释的元素必须为null |
@NotNull | 被注释的元素不能为null |
@AssertTrue | 被注释的元素必须为true |
@AssertFalse | 被注释的元素必须为false |
@Min(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max,min) | 被注释的元素的大小必须在指定的范围内 |
@Digits(integer,fraction) | 被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
(3)Hibernate Validator 扩展注解
-
Hibernate Validator 和 Hibernate 没有关系,只是 JSR 303 实现的一个扩展
-
Hibernate Validator 是 JSR 303的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解:
注解 | 功能说明 |
---|---|
被注释的元素必须是电子邮件地址 | |
@Length | 被注释的字符串的大小必须在指定的范围内 |
@NotEmpty | 被注释的字符串必须非空 |
@Range | 被注释的元素必须在合适的范围内 |
2.2应用实例
需求说明
指定表单的数据格式,后端在接收到数据后,能够对数据进行校验,并给不符合格式的数据返回提示信息,显示在前端页面

2.2.1代码实现
(1)引入验证和国际化相关的jar包

(2)Monster.java,属性添加注解以验证格式
package com.li.web.datavalid.entity; import org.hibernate.validator.constraints.Email; import org.hibernate.validator.constraints.NotEmpty; import org.hibernate.validator.constraints.Range; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.NumberFormat; import java.util.Date; /** * @author 李 * @version 1.0 */ public class Monster { @NotEmpty private Integer id; @Email private String email; //表示接收到的age的值必须在1-100之间 @Range(min = 1, max = 100) private Integer age; //Asserts that the annotated string, collection, // map or array is not {@code null} or empty. @NotEmpty private String name; @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birthday; @NumberFormat(pattern = "###,###.##") private Float salary; public Monster() { } public Monster(Integer id, String email, Integer age, String name, Date birthday, Float salary) { this.id = id; this.email = email; this.age = age; this.name = name; this.birthday = birthday; this.salary = salary; } public Integer getId() { return id; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Float getSalary() { return salary; } public void setSalary(Float salary) { this.salary = salary; } public void setId(Integer id) { this.id = id; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Monster{" + "id=" + id + ", email='" + email + '\'' + ", age=" + age + ", name='" + name + '\'' + ", birthday=" + birthday + ", salary=" + salary + '}'; } }
(3)MonsterHandler.java
package com.li.web.datavalid; import com.li.web.datavalid.entity.Monster; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.validation.Errors; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.validation.Valid; import java.util.Map; /** * @author 李 * @version 1.0 */ @Controller @Scope(value = "prototype") public class MonsterHandler { /** * 1.SpringMVC可以将提交的数据,按照参数名和形参对象的属性名匹配, * 然后直接封装到对象中[模型数据] * 2.@Valid Monster monster 表示对monster接收的数据进行校验 * 3.校验的发生的时机:在SpringMVC底层反射调用目标方法时,会接收到http请求接收到的数据, * 然后根据注解来进行验证。在验证过程中,如果出现了错误,就把错误信息填充到errors和 map中 * @param monster * @param errors 表示如果校验出现了错误,会将校验的错误信息保存到errors中 * @param map map不但会保存monster对象,如果校验出现错误,也会将校验的错误信息放到map中 * @return */ @RequestMapping(value = "/save", method = RequestMethod.POST) 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("--------"); } System.out.println("=======errors======="); for (ObjectError error : errors.getAllErrors()) { System.out.println("error="+error); } return "datavalid/success"; } }
(4)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> <form:form action="save" method="post" modelAttribute="monster"> 妖怪id:<form:input path="id"/><br/><br/> 妖怪名字:<form:input path="name"/><br/><br/> 妖怪年龄:<form:input path="age"/><br/><br/> 妖怪生日:<form:input path="birthday"/> 要求以"yyyy-MM-dd"的格式<br/><br/> 妖怪工资:<form:input path="salary"/> 要求以"###,###.##"的格式<br/><br/> 电子邮件:<form:input path="email"/><br/><br/> <input type="submit" value="添加妖怪"/> </form:form> </body> </html>
(5)测试
提交的数据:年龄这里故意填写不符合格式的数据(1-100)

后台输出了默认的错误信息:
----monster----Monster{id=1, email='king@sohu.com', age=999, name='king', birthday=Tue Jan 01 00:00:00 CST 1924, salary=1267.22} =======map======= key=monster value=Monster{id=1, email='king@sohu.com', age=999, name='king', birthday=Tue Jan 01 00:00:00 CST 1924, salary=1267.22} -------- key=org.springframework.validation.BindingResult.monster value=org.springframework.validation.BeanPropertyBindingResult: 1 errors Field error in object 'monster' on field 'age': rejected value [999]; 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之间] -------- =======errors======= error=Field error in object 'monster' on field 'age': rejected value [999]; 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之间]
(6)自定义错误信息:配置 springDispatcherServlet-servlet.xml
<!--配置国际化错误信息的资源处理 bean--> <bean class="org.springframework.context.support.ResourceBundleMessageSource" id="messageSource"> <!-- 配置国际化文件名字 如果下面这样配置,表示 messageSource对象会到src/i18nXXX.properties 去读取错误信息 --> <property name="basename" value="i18n"/> </bean>
(7)在src 目录下创建国际化文件 i18n.properties
中文要使用 unicode 编码处理
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
(8)修改 monster_addUI.jsp 的 form ,回显错误信息
<form:form action="save" method="post" modelAttribute="monster"> 妖怪id:<form:input path="id"/><form:errors path="id"/><br/><br/> 妖怪名字:<form:input path="name"/><form:errors path="name"/><br/><br/> 妖怪年龄:<form:input path="age"/><form:errors path="age"/><br/><br/> 妖怪生日:<form:input path="birthday"/><form:errors path="birthday"/> 要求以"yyyy-MM-dd"的格式<br/><br/> 妖怪工资:<form:input path="salary"/><form:errors path="salary"/> 要求以"###,###.##"的格式<br/><br/> 电子邮件:<form:input path="email"/><form:errors path="email"/><br/><br/> <input type="submit" value="添加妖怪"/> </form:form>
(9)再次进行测试
没有在properties文件中配置的提示,将会按照默认的错误信息回显

2.2.2细节说明和注意事项
-
在需要验证的 Javabean/POJO 的字段上添加相应的验证注解
-
目标方法上,在 Javabean/POJO 类型的参数前,添加 @Valid 注解以告知 SpringMVC 该 Bean 是需要验证的
-
在 @Valid 注解之后,添加一个 Errors 或 BindingResult 类型的参数,可以获取到验证的错误信息
校验的发生的时机:SpringMVC 底层反射调用目标方法前,会接收到 http 请求接收到的数据,然后根据验证注解来进行验证。在验证过程中,如果出现了错误,就把错误信息填充到 errors,map 等参数中
-
需要使用
<form:errors path="xxx"></form:errors>
标签来显示错误信息,该标签需要写在<form:form>
标签内生效 -
自定义错误消息的国际化文件 i18n.properties,如果是中文需要使用 unicode 编码处理。
格式为:
验证规则.表单modelAttribute值.属性名=错误提示信息
-
注意@NotNull 和 @NotEmpty 的区别
@NotEmpty:
Asserts that the annotated string, collection, map or array is not {@code null} or empty. @NotNull:
The annotated element must not be {@code null}. Accepts any type. 如果是字符串验证空,建议使用 @NotEmpty
-
SpringMVC 验证时,同一个属性,会根据不同的验证错误,返回不同的错误信息
2.3注解的结合使用
2.3.1问题提出
在之前的例子中,表单中的数据虽然不符验证格式,但是仍然可以提交:
这显然是不合理的,我们想要在提交的时候,如果age的字段为空,也应该基于一个提示信息,并且不应该提交表单,这个问题应该如何解决?
答案是注解组合使用。
上面的例子中,表单字段所对应的 age 属性只添加了@Range 注解,程序只会检查提交的 age 的范围,其他的错误无法检出,因此会出现即使提交的数据为空,也能提交成功的情况。
2.3.2解决问题
根据上面的分析,可以使用 @NotNull + @Range 组合来解决问题
(1)修改 Monster.java:
可以直接在验证注解中添加 message 属性,作为错误提示,这样就不必在 properties 文件中配置错误信息

(2)测试如下:

注意:这里不要使用 @NotEmpty 注解,否则会出错。

因为 @NotEmpty 注解修饰的是 String,Collection,Map 和 Array 类型,而 @NotNull 任何类型都可以使用。其他的属性同理,如果是 String 等类型,使用 @NotEmpty 注解,如果是其他类型,应使用 @NotNull 注解。
2.4数据类型转换校验核心类-DataBinder
- DateBinder 工作机制

图例,SpringMVC 通过反射机制对目标方法进行解析,将请求信息绑定到处理方法(目标方法)的入参中。
数据绑定的核心部件是 DataBinder,运行机制如下:
-
首先 url 请求发送到服务器 Handler 的某个方法,然后 tomcat 给我们传入一个 ServletRequest 对象
-
在 SpringMVC 底层反射调用目标方法前,DataBinder 对象处理目标方法的入参对象(得到目标方法的形参的一些信息,将请求信息绑定到处理方法(目标方法)的入参中),在这个过程中:
-
通过调用 ConversionService 接口的实现类的方法,进行数据类型的转换/格式化。
-
接着进行数据的校验,数据校验会调用校验器 Validator(SpringMVC 的数据校验器也有很多种)
-
在校验的过程中一旦出现错误,会将错误信息封装到 BindingResult(BindingResult 其实是一个接口,下面有很多实现类)
之前的例子中,Errors 是 BindingResult 的父类接口
-
debug 一下 Validator 得到验证 errors 信息
(1)在 DataBinder 的 validate 方法中打上断点,点击debug

(2)在前端表单提交错误格式的信息

(3)提交表单后光标跳转到断点处,可以看到此时的 target 就是目标方法中要进行校验的 Monster 对象,因为我们在目标方法的 Monster 形参前添加了 @Valid 注解。
此时前端提交的数据已经提填充进去了:

(4)点击 step over,可以看到方法中创建了BindingResult对象,该对象用于存储数据类型转换和数据校验中可能出现的错误信息。

(5)之后遍历校验器,对 target 对象进行校验,如果出现错误信息就将其放到 BindingResult 中
public void validate(Object... validationHints) { Object target = getTarget(); Assert.state(target != null, "No target to validate"); BindingResult bindingResult = getBindingResult(); // Call each validator with the same binding result for (Validator validator : getValidators()) { if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) { ((SmartValidator) validator).validate(target, bindingResult, validationHints); } else if (validator != null) { validator.validate(target, bindingResult); } } }
(6)在目标方法中打上断点,点击 resume

2.5取消某个属性的绑定
- 说明
在默认情况下,表单提交的数据都会和 pojo/entity 类型的 Javabean 的属性绑定。如果在开发中,希望取消某个JavaBean 的属性的绑定,也就是说不希望接收到某个表单对应的属性的值(比如说有一个Javabean,我们已经赋予其初始值,不希望被接收表单对应的属性值给覆盖),可以通过 @InitBinder 注解取消绑定。
- 编写一个方法(方法名随意),使用 @InitBinder 标识该方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成表单字段到 JavaBean 属性的绑定。
- @InitBinder 标识的方法不能有返回值,它必须声明为 void
- @InitBinder 标识的方法的参数通常是 WebDataBinder
2.5.1使用实例
案例:不希望接收Monster的 name 和 age 属性
(1)修改Monster.java:

(2)修改MonsterHandler.java,增加方法
package com.li.web.datavalid; import com.li.web.datavalid.entity.Monster; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.Errors; import org.springframework.validation.ObjectError; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.validation.Valid; import java.util.List; import java.util.Map; /** * @author 李 * @version 1.0 */ @Controller @Scope(value = "prototype") public class MonsterHandler { @RequestMapping(value = "/save", method = RequestMethod.POST) 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("--------"); } 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"; } //取消绑定 monster的name表单提交值给 monster.name属性 @InitBinder public void initBinderExample(WebDataBinder webDataBinder) { /** * 1.方法上需要标注 @InitBinder 注解,SpringMVC 底层会初始化 WebDataBinder * 2.调用webDataBinder.setDisallowedFields("xxx"); * 表示取消xxx属性的绑定 * 3.即当表单提交字段有name时,不再将该参数填充到model(monster)的name属性中 * 4.机制:SpringMVC 在底层通过反射调用目标方法前,在接收到http请求的参数和值, * 会使用反射+注解,取消对指定属性的填充。 * 5.setDisallowedFields 支持可变参数,可以填写多个字段 * 6.如果取消了某个属性绑定,验证就没有意义了,应当把javabean中验证的注解去掉,否则可能会出错 * //@NotEmpty * private String name; * * //@NotNull(message = "年龄age不能为空111") * //@Range(min = 1, max = 100) * private Integer age; * 如上,name和age属性将会使用默认值(这里为null) */ webDataBinder.setDisallowedFields("name", "age"); } }
(3)测试,提交的数据如下:

后台接收的数据:
----monster----Monster{id=12, email='jack@sohu.com', age=null, name='null', birthday=Tue Jan 01 00:00:00 CST 1924, salary=9999.0}
可以看到 monster的 age 和 name 属性仍然使用的是默认值 null ,这说明取消属性绑定的操作成功了。
注意:这里 age 和 name 的值为 'null',之所以有俩个单引号,是因为重写了 toString 方法,其实这两个属性的值就是 null

2.5.2注意事项和使用说明
- setDisallowedFields() 是可变形参,可以指定多个字段/属性
- 当将一个字段/属性设置为 disallowed,就不会再接收表单提交的对应值。这个字段的值就会使用默认的值
- 一般来说,如果不接收表单某个字段的提交数据,则 Javabean 对象中的对应的属性的验证就没有意义,可以将该属性的验证注解去掉
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!