目录
Spring MVC数据格式化
基本介绍
ConversionService converters =
基本数据类型和字符串自动转换
代码实例 -页面演示方式
创建Monster 类
创建data_valid.jsp
创建MonsterHandler类
创建monster_addUI.jsp
解读:
说明
阶段测试一下
编辑
继续完成功能
创建success.jsp
修改 MonsterHandler.java , 增加处理添加请求
测试
-Postman 完成
特殊数据类型和字符串间的转换
应用实例 -页面演示方式
修改 Monster.java , 增加 birthday 和 salary 字段
修改 monster_addUI, 增加 birthday 和salary字段
测试
验证以及国际化
● 概述
● JSR 303 验证框架
● Hibernate Validator 扩展注解
使用实例-代码实现上面的需求
引入验证和国际化相关的 jar 包
修改 Monster.java
修改 MonsterHandler.java
---这里可以测试一下,看看效果----
配置国际化文件 springDispatcherServlet-servlet.xml
创建国际化文件i18n.properties
修改 monster_addUI.jsp , 回显错误信息
完成测试
细节说明和注意事项
注解的结合使用
● 解决方案注解组合使用
使用@NotNull + @Range 组合使用解决
测试
数据类型转换校验核心类-DataBinder
● DataBinder 工作机制-了解
取消某个属性的绑定
说明
● 案例-不希望接收怪物的名字属性
修改 Monster.java
中文乱码处理
自定义中文乱码过滤器
● 说明
创建过滤器MyCharacterFilter
配置 web.xml , 将该过滤器配置在最前
完成测试
Spring 提供的过滤器处理中文
完成测试
Spring MVC数据格式化
基本介绍
说明: 在我们提交数据(比如表单时)SpringMVC 怎样对提交的数据进行转换和处理的
基本数据类型可以和字符串之间自动完成转换,
比如:Spring MVC 上下文中内建了很多转换器,可完成大多数 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
- …….
基本数据类型和字符串自动转换
代码实例 -页面演示方式
需求->基本数据类型可以和字符串之间自动完成转换
创建Monster 类
public class Monster {
private Integer id;
private String email;
private Integer age;
private String name;
public Monster(Integer id, String email, Integer age, String name,) {
this.id = id;
this.email = email;
this.age = age;
this.name = name;
}
public Monster() {
}
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 + '\'' +
'}';
}
}
创建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>
</body>
</html>
创建MonsterHandler类
@RequestMapping(value = "/addMonsterUI")
public String addMonsterUI(Map<String, Object> map) {
map.put("monster", new Monster());
return "datavalid/monster_addUI";
}
创建monster_addUI.jsp
<html>
<head>
<title>添加妖怪</title>
</head>
<body>
<h3>添加妖怪</h3>
<form:form action="save" method="post" modelAttribute="monster">
妖怪名字: <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>
解读:
1. 这里的表单,我们使用springMVC的标签来完成
2. SpringMVC 表单标签在显示之前必须在 request 中有一个 bean,
该 bean 的属性和表单标签的字段要对应!
request 中的 key 为: form 标签的 modelAttrite 属性值, 比如这里的monster
3. SpringMVC 的 form:form 标签的 action 属性值中的 / 不代表 WEB 应用的根目录.
4. <form:form action="?" method="POST" modelAttribute="monster">
这里需要给request增加一个 monster,因为jsp 页面 的modelAttribute="monster"需要这时是springMVC的内部的检测机制 即使是一个空的也需要,否则报错.
说明
如果你跳转的页面使用springmvc标签就需要准备一个对象,放入request域中,这个对象的属性名 monster, 对应springmvc表单标签的 modelAttribute="monster"
阶段测试一下
继续完成功能
创建success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加成功</title>
</head>
<body>
<h1>恭喜, 添加成功~</h1>
</body>
</html>
修改 MonsterHandler.java , 增加处理添加请求
编写方法,处理添加妖怪
1. springmvc可以将提交的数据,按照参数名和对象的属性名匹配
2. 直接封装到对象中->前面讲解模型数据时,讲过String => Integer
@RequestMapping(value = "/save")
public String save(Monster monster) {
System.out.println("----monster---" + monster);
return "datavalid/success";
}
测试
浏览器: http://localhost:8080/springmvc/data_valid.jsp
1) 如果age 输入的是 数字,则通过, 说明SpringMVC可以将提交的字符串 数字,比如"28",转成 Integer/int
2) 如果不是数字,则给出 400 的页面
3) 如何给出对应的提示,我们后面马上讲解
-Postman 完成
1) 如果age 输入的是 数字,则通过, 说明SpringMVC可以将提交的字符串 数字,比如"28", 转成 Integer/int
2) 如果不是数字,则给出 400 的页面 与上面测试一模一样
特殊数据类型和字符串间的转换
应用实例 -页面演示方式
1. 特殊数据类型和字符串之间的转换使用注解(比如日期,规定格式的小数比如货币形式
等)
2. 对于日期和货币可以使用 @DateTimeFormat 和 @NumberFormat 注解. 把这两个注
解标记在字段上即可
修改 Monster.java , 增加 birthday 和 salary 字段
public class Monster {
private Integer id;
private String email;
private Integer age;
private String name;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
@NumberFormat(pattern = "###,###.##")
private Float salary;
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 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 Monster() {
}
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 + '\'' +
", birthday=" + birthday +
", salary=" + salary +
'}';
}
}
修改 monster_addUI, 增加 birthday 和salary字段
妖怪年龄~: <form:input path="age"/> <br><br>
妖怪生日: <form:input path="birthday"/> 要求以"9999-11-11"的形式<br><br>
妖怪工资: <form:input path="salary"/> 要求以"123,890.12"的形式<br><br>
测试
1) 如果 birthday 和 salary 是按照指定格式输入,则通过, 说明 SpringMVC 可以按注解指定
格式转换
2) 如果没有按照注解指定格式,则给出 400 的页面
3) 如何给出对应的提示,我们后面马上讲解
验证以及国际化
● 概述
1. 对输入的数据(比如表单数据),进行必要的验证,并给出相应的提示信息。
2. 对于验证表单数据,springMVC 提供了很多实用的注解, 这些注解由 JSR 303 验证框架提供.
● JSR 303 验证框架
1. JSR 303 是 Java 为 Bean 数据合法性校验提供的标准框架,它已经包含在 JavaEE 中
2. JSR 303 通过在 Bean 属性上标注类似于 @NotNull、@Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean 进行验证
3. JSR 303 提供的基本验证注解有:
● Hibernate Validator 扩展注解
1. Hibernate Validator 和 Hibernate 没有关系,只是 JSR 303 实现的一个扩展.
2. Hibernate Validator 是 JSR 303 的一个参考实现,除支持所有标准的校验注解外,它还支持以下的扩展注解:
3. 扩展注解有如下
使用实例-代码实现上面的需求
引入验证和国际化相关的 jar 包
修改 Monster.java
@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;
修改 MonsterHandler.java
- @Valid Monster monster :表示对monster接收的数据进行校验
- Errors errors 表示如果校验出现错误,将校验的错误信息保存 errors
- Map<String, Object> map 表示如果校验出现错误, 将校验的错误信息保存 map 同时保存monster对象
- 校验发生的时机: 在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";
}
---这里可以测试一下,看看效果----
配置国际化文件 springDispatcherServlet-servlet.xml
<!-- 配置国际化错误信息的资源处理bean -->
<bean id="messageSource" class=
"org.springframework.context.support.ResourceBundleMessageSource">
<!-- 配置国际化文件名字
如果你这样配的话,表示messageSource回到 src/i18nXXX.properties去读取错误信息
-->
<property name="basename" value="i18n"></property>
</bean>
创建国际化文件i18n.properties
这是Unicode码 不知道也没有关系 可以百度搜索转换工具就好了 因为直接输入中文可能会导致乱码或者解析所以这里使用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
修改 monster_addUI.jsp , 回显错误信息
<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>
完成测试
细节说明和注意事项
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
5. 注解@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
6. SpingMVC 验证时,会根据不同的验证错误, 返回对应的信息
注解的结合使用
● 问题提出, age 没有, 是空的,提交确是成功了
● 解决方案注解组合使用
使用@NotNull + @Range 组合使用解决
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;
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 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 Monster() {
}
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 + '\'' +
", birthday=" + birthday +
", salary=" + salary +
'}';
}
}
测试
这时 age 不能为空,同时必须是 1-100, (也不能输入 haha, hello 等不 能转成数字的内容)
数据类型转换校验核心类-DataBinder
● DataBinder 工作机制-了解
图例 Spring MVC 通过反射机制对目标方法进行解析,将请求消息绑定到处理方法的入参中。
数据绑定的核心部件是 DataBinder,运行机制如下
- Debug 一下 validate 得到验证 errors
流程先进行数据类型的转换如果发送错误直接放到BindingResult
在进行数据校验如果出错了就继续放入
最后放到error和map中显示输出
取消某个属性的绑定
说明
在默认情况下,表单提交的数据都会和 pojo 类型的 javabean 属性绑定,如果程序员在开发中,希望取消某个属性的绑定,也就是说,不希望接收到某个表单对应的属性的值,则可以通过 @InitBinder 注解取消绑定.
1. 编写一个方法, 使用@InitBinder 标识的该方法,可以对 WebDataBinder 对象进行初始化。WebDataBinder 是 DataBinder 的子类,用于完成由表单字段到 JavaBean 属性的绑定
2. @InitBinder 方法不能有返回值,它必须声明为 void。
3. @InitBinder 方法的参数通常是是 WebDataBinder
● 案例-不希望接收怪物的名字属性
修改 MonsterHandler.java
@InitBinder
public void initBinder(WebDataBinder webDataBinder) {
//测试完,记得注销了.
webDataBinder.setDisallowedFields("name");
}
解读
1. 方法上需要标注 @InitBinder springmvc底层会初始化 WebDataBinder
2. 调用 webDataBinder.setDisallowedFields("name") 表示取消指定属性的绑定
即:当表单提交字段为 name时, 就不在把接收到的name值,填充到model数据的monster的name属性
3. 机制:springmvc 在底层通过反射调用目标方法时, 接收到http请求的参数和值,使用反射+注解技术取消对指定属性的填充
4. setDisallowedFields支持可变参数,可以填写多个字段
5. 如果我们取消某个属性绑定,验证就没有意义了,应当把验证的注解去掉, name属性会使用默认值null
一般来说,如果不接收表单字段提交数据,则该对象字段的验证也就没有意义了可以注 销掉,比如 注销 //@NotEmpt
修改 Monster.java
中文乱码处理
自定义中文乱码过滤器
● 说明
当表单提交数据为中文时,会出现乱码,我们来解决一下(提示:先恢复 name 属性的绑定)
创建过滤器MyCharacterFilter
public class MyCharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
//这里加入对编码的处理
servletRequest.setCharacterEncoding("utf-8");
//放行请求,这个规则和前面讲过的java web的过滤器一样
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
配置 web.xml , 将该过滤器配置在最前
<!--配置处理中文乱码的过滤器
拦截所有请求,处理编码, 提醒,把过滤器配置到web.xml前面
-->
<filter>
<filter-name>MyCharacterFilter</filter-name>
<filter-class>com.wyxdu.web.filter.MyCharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyCharacterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
完成测试
Spring 提供的过滤器处理中文
<!--配置处理中文乱码的过滤器
拦截所有请求,处理编码, 提醒,把过滤器配置到web.xml前面
-->
<!-- <filter>-->
<!-- <filter-name>MyCharacterFilter</filter-name>-->
<!-- <filter-class>com.wyxdu.web.filter.MyCharacterFilter</filter-class>-->
<!-- </filter>-->
<!-- <filter-mapping>-->
<!-- <filter-name>MyCharacterFilter</filter-name>-->
<!-- <url-pattern>/*</url-pattern>-->
<!-- </filter-mapping>-->
<!--配置Spring提供的过滤器,解决中文乱码问题-->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>