5.3 本章小结

本章介绍了Spring MVC的国际化知识,包括Spring MVC的国际化文件messageSource国际化语言区域解析器接口LocaleReolver以及接口的常用类AcceptHeaderLocaleReolverSessionLocaleReolverCookieLocaleReolver的使用。
第6章将重点介绍Spring MVC的数据转换、格式化和数据校验.

5.2 Spring MVC的国际化处理 5.2.2 基于Cookie的国际化实现

CookieLocaleResolver不是默认的语言区域解析器,需要显式对其进行配置。使用它,Spring MVC会从Cookie中获取用户所设置的语言区域,来确定使用哪个语言区域.

实例 基于Cookie的国际化实现

springmvc-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件,
如果扫描到有Spring的相关注解的类,则把这些类注册为Spring的bean -->
<context:component-scan base-package="org.fkit"/>
<!-- 默认配置方案 -->
<mvc:annotation-driven/>
<!-- 静态资源处理 -->
<mvc:default-servlet-handler/>
<!-- 视图解析器 p:prefix属性表示前缀 p:suffix 表示后缀 -->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/content/"
p:suffix=".jsp"/>
<!-- 国际化 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="message"
p:defaultEncoding="utf-8">
</bean>
<mvc:interceptors>
<!-- 国际化操作拦截器 如果采用基于(请求/Session/Cookie)则必需配置 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>
<bean
id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>
</beans>

加载国际化资源文件

指定国际化资源文件的路径,以及文件的编码。

1
2
3
4
5
6
7
<!-- 国际化 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="message"
p:defaultEncoding="utf-8">
</bean>

国际化拦截器

使用Cookie来实现国际化,必须设置国际化操作拦截器:

1
2
3
4
<mvc:interceptors>
<!-- 国际化操作拦截器 如果采用基于(请求/Session/Cookie)则必需配置 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>

创建CookieLocaleResolver

注意,此处将默认配置的localeResolver换成了CookieLocaleResolver

1
2
3
<bean
id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/>

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Controller
public class UserController {
@RequestMapping(value = "/loginForm")
public String loginForm(String request_locale, Model model, HttpServletRequest request,
HttpServletResponse response)
{
System.out.println("request_locale = " + request_locale);
if (request_locale != null)
{
if (request_locale.equals("zh_CN"))
{
Locale locale = new Locale("zh", "CN");
(new CookieLocaleResolver()).setLocale(request, response, locale);
} else if (request_locale.equals("en_US"))
{
Locale locale = new Locale("en", "US");
(new CookieLocaleResolver()).setLocale(request, response, locale);
} else
{
(new CookieLocaleResolver()).setLocale(request, response,
LocaleContextHolder.getLocale());
}
}
User user = new User();
model.addAttribute("user", user);
// 跳转页面
return "loginForm";
}
@PostMapping(value = "/login")
public String login(@ModelAttribute User user, Model model, HttpServletRequest request)
{
// System.out.println(user);
if (user.getLoginname() != null && user.getLoginname().equals("xiaoming")
&& user.getPassword() != null && user.getPassword().equals("123456"))
{
// 从后台代码获取国际化信息
RequestContext requestContext = new RequestContext(request);
String username = requestContext.getMessage("username");
user.setUsername(username);
model.addAttribute("user", user);
return "success";
}
return "error";
}
}

UserControllerloginForm方法根据提交的request_locale参数值,创建CookieLocaleResolver对象并调用CookieLocaleResolver对象的setLocale方法将语言环境设置在Cookie中,从而进行语言环境切换.

loginForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试基于ConversionService的国际化</title>
</head>
<body>
<a href="loginForm?request_locale=zh_CN">中文</a> |
<a href="loginForm?request_locale=en_US">英文</a>
<br />
<h3>
<!-- 显示国际化title文本 -->
<spring:message code="title" />
</h3>
<form:form modelAttribute="user" method="post" action="login">
<table>
<tr>
<!-- 显示国际化loginname文本 -->
<td><spring:message code="loginname" /></td>
<td><form:input path="loginname" /></td>
</tr>
<tr>
<!-- 显示国际化password文本 -->
<td><spring:message code="password" /></td>
<td><form:input path="password" /></td>
</tr>
<tr>
<td><input type="submit" value="<spring:message code="submit"/>" /></td>
</tr>
</table>
</form:form>
</body>
</html>

loginForm.jsp中通过<spring:message code="国际化文本" />的形式来填写相应的国际化文本.

success.jsp

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试基于ConversionService的国际化</title>
</head>
<body>
<spring:message code="welcome" arguments="${requestScope.user.username}" />
</body>
</html>

success.jsp页面中通过spring:message表单来显示格式化文本,该文本的名称为welcome,并且该welcome文本带有参数.使用参数可以创建动态的格式化文本。

1
welcome = 欢迎 {0}

测试

默认

这里有一张图片
这里有一张图片

中文环境

这里有一张图片
这里有一张图片

5.2 Spring MVC的国际化处理 5.2.2 基于 Httpsession的国际化

SessionLocaleResolver

SessionLocaleResolver不是默认的语言区琙解析器,需要对其进行显式配置。如果使用它,Spring MVC会从HttpSession作用域中获取用户所设置的语言区域,来确定使用哪个语言区域。

实例 基于Httpsession的国际化实现

loginForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试基于SessionLocaleResolver的国际化</title>
</head>
<body>
<!-- 用户可以选择切换语言环境 -->
<a href="loginForm?request_locale=zh_CN">中文</a> |
<a href="loginForm?request_locale=en_US">英文</a>
<br />
<h3>
<spring:message code="title" />
</h3>
<form:form modelAttribute="user" method="post" action="login">
<table>
<tr>
<td><spring:message code="loginname" /></td>
<td><form:input path="loginname" /></td>
</tr>
<tr>
<td><spring:message code="password" /></td>
<td><form:input path="password" /></td>
</tr>
<tr>
<td><input type="submit" value="<spring:message code="submit"/>" /></td>
</tr>
</table>
</form:form>
</body>
</html>

loginForm.jsp页面的最上面增加了两个超链接,分别用于切换中文和英文语言环境。注意请求后面的参数request_locale,如果请求中文环境则传递的值是”zh_CN“,如果请求英文环境则传递的值是”en_US“.

springmvc-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件,
如果扫描到有Spring的相关注解的类,则把这些类注册为Spring的bean -->
<context:component-scan base-package="org.fkit"/>
<!-- 默认配置方案 -->
<mvc:annotation-driven/>
<!-- 静态资源处理 -->
<mvc:default-servlet-handler/>
<!-- 视图解析器 p:prefix属性表示前缀 p:suffix 表示后缀 -->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/content/"
p:suffix=".jsp"/>
<!-- p:basenames属性指定国际化资源文件的路径 -->
<!--p:defaultEncoding属性指定国际化资源文件编码 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="message"
p:defaultEncoding="utf-8"/>
<mvc:interceptors>
<!-- 国际化操作拦截器 如果采用基于(Session/Cookie)则必需配置 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>
<!-- SessionLocaleResolver 配置 -->
<bean
id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>
</beans>

国际化配置

1
2
3
4
5
6
7
8
9
10
11
<!-- p:basenames属性指定国际化资源文件的路径 -->
<!--p:defaultEncoding属性指定国际化资源文件编码 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="message"
p:defaultEncoding="utf-8"/>
<!-- SessionLocaleResolver 配置 -->
<bean
id="localeResolver"
class="org.springframework.web.servlet.i18n.SessionLocaleResolver"/>

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@Controller
public class UserController {
@RequestMapping(value = "/loginForm")
public String loginForm(String request_locale, Model model, HttpServletRequest request)
{
// 先设置语言环境
System.out.println("request_locale = " + request_locale);
if (request_locale != null)
{
// 设置中文环境
if (request_locale.equals("zh_CN"))
{
Locale locale = new Locale("zh", "CN");
request.getSession()
.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}
// 设置英文环境
else if (request_locale.equals("en_US"))
{
Locale locale = new Locale("en", "US");
request.getSession()
.setAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, locale);
}
// 使用之前的语言环境
else
{
request.getSession().setAttribute(
SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME,
LocaleContextHolder.getLocale());
}
}
// 创建一个user用户给表单使用
User user = new User();
model.addAttribute("user", user);
// 跳转页面
return "loginForm";
}
@PostMapping(value = "/login")
public String login(@ModelAttribute User user, Model model, HttpServletRequest request)
{
// System.out.println(user);
if (user.getLoginname() != null && user.getLoginname().equals("xiaoming")
&& user.getPassword() != null && user.getPassword().equals("123456"))
{
// 从后台代码获取国际化信息
RequestContext requestContext = new RequestContext(request);
String username = requestContext.getMessage("username");
user.setUsername(username);
model.addAttribute("user", user);
return "success";
}
return "error";
}
}

loginForm方法根据提交的 request_ locale参数值,获取 Session对象,并调用setAttribute方法进行语言环境切换。

测试

进入登陆表单,默认显示英文.如下图所示:
这里有一张图片

切换中文环境

点击中文链接,切换中文环境.如下图所示:
这里有一张图片
填写账户密码,登陆,效果如下图:
这里有一张图片

切换英文环境

填写表单:
这里有一张图片
登陆效果:
这里有一张图片

5.2 Spring MVC的国际化处理

5.2.1 AcceptHeaderLocaleResolver

AcceptHeaderLocaleResolver是默认的,也是最容易使用的语言区域解析器。使用它,Spring MVC会读取浏览器的accept-language标题,来确定使用哪个语言区域。AcceptHeaderLocaleResolver可以不用显式配置,当然也可以显式配置。

示例:基于浏览器请求的国际化实现

首先,准备两个资源文件

message_enUs.properties

第一个资源文件是message_enUs.properties,该文件内容如

1
2
3
4
5
6
loginname= Login name:
password = Password:
submit = Submit
welcome = Welcom {0}
title = Login Page
username = administrator

message_zh_CN.properties

第二个资源文件的内容如下:

1
2
3
4
5
6
loginname=登录名:
password=密码:
submit=提交
welcome=欢迎 {0}
title=登录页面
username=管理员

将上面两个国际化资源文件保存为UTF-8编码.接下来在JSP页面中通过<spring:message/>标签来输出国际化消息。

loginForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试基于浏览器请求的国际化</title>
</head>
<body>
<!-- 使用message标签来输出国际化信息 -->
<h3>
<spring:message code="title" />
</h3>
<form:form modelAttribute="user" method="post" action="login">
<table>
<tr>
<td><spring:message code="loginname" /></td>
<td><form:input path="loginname" /></td>
</tr>
<tr>
<td><spring:message code="password" /></td>
<td><form:input path="password" /></td>
</tr>
<tr>
<td><input type="submit" value="<spring:message code="submit"/>" /></td>
</tr>
</table>
</form:form>
</body>
</html>

springmvc-config.xml

接下来在Spring MVC配置文件中加载国际化资源文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件,
如果扫描到有Spring的相关注解的类,则把这些类注册为Spring的bean -->
<context:component-scan base-package="org.fkit"/>
<!-- 默认配置方案 -->
<mvc:annotation-driven/>
<!-- 静态资源处理 -->
<mvc:default-servlet-handler/>
<!-- 视图解析器 p:prefix属性表示前缀 p:suffix 表示后缀 -->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/content/"
p:suffix=".jsp"/>
<!-- 国际化 p:basenames属性用于指定国际化资源文件名 -->
<!-- 国际化 p:defaultEncoding属性指定国际化资源文件的编码 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="message"
p:defaultEncoding="UTF-8"/>
<mvc:interceptors>
<!-- 国际化操作拦截器 如果采用基于(Session/Cookie)则必需配置 -->
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
</mvc:interceptors>
<!-- AcceptHeaderLocaleResolver 配置,因为AcceptHeaderLocaleResolver是默认语言区域解析器,不配置也可以 -->
<bean
id="localeResolver"
class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"/>
</beans>

国际化配置

国际化配置如下:

1
2
3
4
5
6
7
<!-- 国际化 p:basenames属性用于指定国际化资源文件名 -->
<!-- 国际化 p:defaultEncoding属性指定国际化资源文件的编码 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="message"
p:defaultEncoding="UTF-8"/>

指定国际化资源文件路径

其中p:basenames属性用于指定国际化文件的路径,这个路径是相对于src目录的路径,例如这里对应的路径为:src/message_en_US.propertiesmessage_zh_CN.properties,指定国际化路径的时候只需要指定文件的前缀就行类,后面的语言,地区以及文件名后缀不需要指出.也就是对于:

1
2
message_zh_CN.properties
message_en_US.properties

指定国际化资源文件编码

p:defaultEncoding="UTF-8"这个属性用于指定这些国际化文件使用的编码,默认编码是ISO-8859-1,这样中文将会变成unicode代码,不方便我们阅读修改.所以我这里使用UTF-8编码
这组国际化资源文件,只需要指定message即可

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Controller
public class UserController {
@RequestMapping(value = "/loginForm")
public String loginForm(Model model)
{
// 创建一个user对象给表单标签库使用
User user = new User();
model.addAttribute("user", user);
// 跳转页面
return "loginForm";
}
@PostMapping(value = "/login")
// @ModelAttribute User user:将提交表单的数据保存到user对象中
public String login(@ModelAttribute User user, Model model, HttpServletRequest request)
{
System.out.println(user);
// 如果登录名是xiaoming,密码是123456,则验证通过
if (user.getLoginname() != null && user.getLoginname().equals("xiaoming")
&& user.getPassword() != null && user.getPassword().equals("123456"))
{
// 从后台代码获取国际化信息username
RequestContext requestContext = new RequestContext(request);
String username = requestContext.getMessage("username");
// 将获取的username信息设置到User对象并设置到Model当中
user.setUsername(username);
model.addAttribute("user", user);
return "success";
}
return "error";
}
}

login()方法接收请求,如果验证通过,则使用RequestContext对象的getMessage()方法来获取国际化消息,并跳转到success.jsp页面。

success.jsp

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试基于浏览器请求的国际化</title>
</head>
<body>
<spring:message code="welcome" arguments="${requestScope.user.username}" />
</body>
</html>

success.Jjsp页面中,使用message标签读取资源文件中名为welcome的消息,并设置了一个参数,参数值为user对象的username属性

测试

正确填写登陆名xiaoming,密码123456,
这里有一张图片
将会成功跳转到成功界面如下图所示:
这里有一张图片

测试国际化

设置浏览器语言

点击火狐浏览器右边的菜单按钮,然后选中选项:
这里有一张图片
找到语言,点击右边的选择按钮:
这里有一张图片
把英语(美国)移动到最上面:
这里有一张图片

显示效果

刷新登陆表单,即可看到提示信息变成英文的了:
这里有一张图片
这里有一张图片

5.1 Spring MVC国际化的相关知识

5.1.1 messageSource接口

Spring MVC中,不直接使用java.util.ResourceBundle,而是使用名为messageSourceBean告诉Spring MVC国际化的属性文件保存在哪里。配置信息代码如下所示:

1
2
3
4
5
6
7
8
9
10
<!-- 国际化配置 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<!-- 国际化资源文件名 -->
<property name="basenames">
<value>message1</value>
<value>message2</value>
</property>
</bean>

上面的配置使用了ResourceBundleMessageSource类作为messageSourceBean的实现。basenames属性用来指定国际化的属性文件名称。如果项目中只有一组属性文件,则可以使用baseman来指定国际化的属性文件名称,实例代码如下

1
2
3
4
5
6
<!-- 国际化 p:basenames属性用于指定国际化资源文件名 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basenames="message"/>
</bean>

5.1.2 localResolver接口

如何知道用户使用的语言

为用户选择语言区域时,最常用的方法是通过读取用户浏览器的accept-language标题值, accept- language标题提供了关于用户浏览器语言的信息。选择语言区域的其他方法还包括读取 HttpSession或者 Cookie

语言区域解析器

Spring MVC中选择语言区域,可以使用语言区域解析器。Spring MVC提供了一个语言区域解析器接口LocaleResolver,该接口的常用实现类都在org.springframework.web.servlet.i18n包下面,包括:

  • AcceptHeaderLocaleResolver
  • SessionLocaleResolver
  • CookieLocaleResolver

其中,AcceptHeaderLocaleResolver是默认的,也是最容易使用的语言区域解析器。使用它,Spring MVC会读取浏览器的accept-language标题,来确定使用哪个语言区域。默认的AcceptHeaderLocaleResolver可以不用显式配置,而SessionlocaleresolverCookielocale-Resolver需要手动显式配置

5.1.3 message标签

Spring MVC中显示本地化消息通常使用Springmessage标签。使用message标签需要在JSP页面最前面使用taglib指令导入Spring的标签库,如下所示:

1
<%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>

message标签的属性如表5.1所示,所有属性都是可选的

表5.1 message标签的属性
属性 描述
arguments 标签的参数,可以是一个字符串、数组或对象
argumentSeparator 用来分隔该标签参数的字符
code 获取消息的key
htmlEscape boolean值,表示被渲染的值是否应该进行HTM转义
javaScriptEscape boolean值,表示被渲染的值是否应该进行 JavaScript转义
message MessageSourceResolvable参数
scope 保存var属性中定义的变量的作用域
text 如果code属性不存在,所显示的默认文本
var 用于保存消息的变量

第5章 Spring MVC的国际化

本章要点

  • messageSource接口
  • localeResolver接口
  • message标签
  • AcceptHeaderLocaleResolver国际化
  • SessionLocaleResolver国际化
  • CookieLocaleResolver国际化

程序国际化是商业系统的一个基本要求, 今天的软件系统不再是简单的单机程序, 往往都是一个开放的系统, 需要面对来自全世界各个地方的访问者, 因此, 国际化成为商业系统必不可少的一部分。

Spring MVC的国际化是建立在Java国际化的基础之上的, 一样也是首先提供不同国家/语言环境的消息资源, 然后通过ResourceBundle加载指定Locale对应的资源文件, 再取得该资源文件中指定key对应的消息。 这整个过程与Java程序的国际化完全相同, 只是Spring MVC框架对Java程序国际化进行了进一步的封装, 从而简化了应用程序的国际化。

国际化步骤

Spring MVC的国际化的步骤与Java国际化的步骤基本相似,只是实现起来更加简单。Spring MVC的国际化可按如下步骤进行

  • 给系统加载国际化资源文件
  • 输出国际化消息。SpringMVC输出国际化消息有两种方式:
    • 在视图页面上输出国际化消息,需要使用SpringMVC的标签库。
    • Controller的处理方法中输出国际化消息,需要使用org.springframework.web.servlet.support.RequestContextgetMessage()方法来完成。

6.5 本章小结

本章介绍了Spring MVC的数据转换、格式化和数据校验。

  • 数据转换Converter可以将任意类型转换成另一种类型,
  • 格式化Formatter则只能将String转换成另一种Java类型,Formatter更适用于Web层。
  • 对于数据校验,现阶段更多的是使用JSR303验证规范,需要重点掌握。

6.4 数据校验 6.4.2 JSR 303校验

JSR 303JavaBean数据合法性校验所提供的一个标准规范,叫作Bean Validation。2009年12月Java EE6发布**,Bean Validation作为一个重要特性被包含其中,用于对JavaBean中的字段值进行验证。官方参考实现是Hibernate Validation
Bean ValidationJavaBean验证定义了相应的元数据类型和API。在应用程序中通过在Bean属性上标注类似于@NotNull@Max等标准的注解指定校验规则,并通过标注的验证接口对Bean进行验证。Bean Validation是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
可以通过http://jcp.org/en/jsr/detail?id=303了解JSR 303的详细内容。
JSR 303是一个规范,它的
核心接口是Javax.validation.Validator**,该接口根据目标对象类中所标注的校验注解进行数据校验,并得到校验结果。

下载JSR 303

JSR 303目前有两个实现第一个实现是 Hibernate Validator,可以从以下网站下载:
https://sourceforge.net/projects/hibernate/files/hibernate-validator/
第二个实现是Apache bval,可以从以下网站下载:
http://bval.apache.org/downloads.html

JSR 303注解

JSR 303中定义了一套可标注在成员变量、属性方法上的校验注解

注解 功能 范例
@Null 验证对象是否为null @Null
String desc;
@NotNull 验证对象是否不为null,无法检查长度为0的字符串,用于验证基本数据类型 @NotNull
String name;
@NotBlank 检查约束字符串是不是null,被Trim的长度是否大于0,只作用于字符串,且会去掉前后空格 @NotBlank
String name;
@AssertTrue 验证Boolean对象是否为true @AssertTrue
String isEmpty;
@AssertFalse 验证Boolean对象是否为false @AssertTrue
String isEmpty;
@Max(value) 验证NumberString对象是否小于或者等于指定的值 @Max(0)
int age;
@Min(value) 验证NumberString对象是否大于或者等于指定的值 @Min(160)
int age;
@DecimalMax(value) 被标注的值必须不大于约束中指定的最大值.。这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示,小数存在精度 @DecimalMax(1.1)
BigDecimal price;
@DecimalMin(value) 被标注的值必须不小于约束中指定的最小值.。这个约束的参数是一个通过BigDecimal定义的最小值的字符串表小数存在精度 @DecimalMax(0.5)
BigDecimal price;
@Digits(integer,fraction) 验证字符串是否是符合指定格式的数字,Integer指定整数精度,fraction指定小数精度 @Digits(integer=5, fraction=2)
BigDecimal price
@Size(min,max) 验证对象(ArrayCollectionMapString)长度是否在给定的范围之内 @Size(min=15, max=60)
int age;
@Email 验证是否是合法的邮件地址 @Email
String email;
@Past 验证DateCalendar对象是否在当前时间之前 @Past
Date birthDate;
@Future 验证DateCalendar对象是否在当前时间之后 @FutureDate
shippingDate;
@Pattern 验证String对象是否符合正则表达式的规则 Pattern(regexp="[1][3,8][3,6,9][0-9]{8}")
String phone;

Hibernate Validator扩展注解

Hibernate ValidatorJSR 303的一个参考实现,除了支持所有标准的校验注解之外,它还扩展了如下表所示的注解.

注解 功能 实例
@URL 验证是否是合法的URL @URL
String url;
@CreditCardNumber 验证是否是合法的信用卡号码 @CreditCardNumber
String creditCard;
@Length(min,max) 验证字符串的长度必须在指定的范围内 @Length(min=6, max=8)
String password;
@NotEmpty 检查元素是否为Null或者 Empty。用于Array,Collection,Map,String @NotEmpty
String name
@Range(min,max,message) 验证属性值必须在合适的范围内 @Range(min=18, max=60, message="学生的年龄必须在18岁到60岁之间")
int age;

示例 测试JSR 303校验

registerForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试JSR 303</title>
</head>
<body>
<h3>注册页面</h3>
<!-- 绑定到模型中的user对象 -->
<form:form modelAttribute="user" method="post" action="login">
<table>
<tr>
<td>登录名:</td>
<!-- 绑定到模型中user对象的loginname属性 -->
<td><form:input path="loginname" /></td>
<!-- 当user对象的loginname验证失败时显示 -->
<td><form:errors path="loginname" cssStyle="color:red" /></td>
</tr>
<tr>
<td>密码:</td>
<!-- 绑定到模型中user对象的password属性 -->
<td><form:input path="password" /></td>
<td><form:errors path="password" cssStyle="color:red" /></td>
</tr>
<tr>
<td>用户名:</td>
<!-- 绑定到模型中user对象的username属性 -->
<td><form:input path="username" /></td>
<!-- 当user对象的username验证失败时显示 -->
<td><form:errors path="username" cssStyle="color:red" /></td>
</tr>
<tr>
<td>年龄:</td>
<!-- 绑定到模型中user对象的age属性 -->
<td><form:input path="age" /></td>
<td><form:errors path="age" cssStyle="color:red" /></td>
</tr>
<tr>
<td>邮箱:</td>
<!-- 绑定到模型中user对象的email属性 -->
<td><form:input path="email" /></td>
<!-- 当user对象的email验证失败时显示 -->
<td><form:errors path="email" cssStyle="color:red" /></td>
</tr>
<tr>
<td>生日:</td>
<td><form:input path="birthday" /></td>
<td><form:errors path="birthday" cssStyle="color:red" /></td>
</tr>
<tr>
<td>电话:</td>
<td><form:input path="phone" /></td>
<td><form:errors path="phone" cssStyle="color:red" /></td>
</tr>
<tr>
<td><input type="submit" value="提交" /></td>
</tr>
</table>
</form:form>
</body>
</html>

registerForm.jsp是一个注册页面,用于提交用户注册信息,注册信息包括用户名、密码、邮箱、电话等。之后将在后台使用JSR 303进行验证。

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
@NotBlank
private String loginname;
@NotBlank
@Length(min = 6,max = 8)
private String password;
@NotBlank
private String username;
@Range(min = 15,max = 60)
private int age;
@Email
private String email;
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Past
private Date birthday;
@Pattern(regexp = "[1][3,8][3,6,9][0-9]{8}")
private String phone;
public User()
{
super();
// TODO Auto-generated constructor stub
}
// 此处省略getter和setter方法,请自己补上
@Override
public String toString()
{
return "User [loginname=" + loginname + ", password=" + password + ", email=" + email
+ ", username=" + username + ", birthDate=" + birthday + ", phone=" + phone + "]";
}
}

User类使用了Hibernate Validator的注解对前台提交的数据进行验证。

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Controller
public class UserController {
@GetMapping(value = "/registerForm")
public String registerForm(Model model)
{
// 创建一个user对象给表单绑定
User user = new User();
// 把user对象设置到模型中
model.addAttribute("user", user);
// 跳转到注册页面
return "registerForm";
}
// 数据校验使用@Valid,后面跟着Errors对象保存校验信息
@PostMapping(value = "/login")
public String login(@Valid @ModelAttribute User user, Errors errors, Model model)
{
System.out.println(user);
if (errors.hasErrors())
{
return "registerForm";
}
model.addAttribute("user", user);
return "success";
}
}

UserController中的login方法使用@Valid注解对提交的数据进行校验,后面跟着Errors对象保存校验信息。如果errors中有错误信息,则返回registerForm页面,验证通过则跳转到success页面.

success.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试JSR 303</title>
</head>
<body>
<h3>测试JSR 303</h3>
<br>登录名:${requestScope.user.loginname }
<br> 密码:${requestScope.user.password }
<br> 用户名:${requestScope.user.username }
<br> 年龄:${requestScope.user.age }
<br> 邮箱:${requestScope.user.email }
<br> 生日:
<fmt:formatDate value="${requestScope.user.birthday}" pattern="yyyy年MM月dd日" />
<br> 电话:${requestScope.user.phone }
<br>
</body>
</html>

由于<mvc:annotation-driven/>会默认装配好一个LocalValidatorFactoryBean,因此springmvc-config.xml配置文件中只是基本配置,不需要增加其他的配置。

国际化错误提示信息

而在实际项目中,我们希望错误信息更加人性化、更具可读性,同时还希望显示国际化的错误信息。接下来我们就为项目加入国际化的错误信息。
Spring MVC支持国际化显示数据校验的错误信息。每个属性在数据绑定数据校验发生错误时,都会生成一个对应的FieldError对象,FieldError对象实现了org.springframework.context.MessageSourceResolvable接口,顾名思义MessageSourceResolvable是可用国际化资源进行解析的对象MessageSourceResolvable接口有如下3个方法:

方法 描述
Object[] getArguments() 返回一组参数对象。
String[] getCodes() 返回一组消息代码,每一个代码对应一个属性资源,可以使用getArguments()返回的参数对资源属性值进行参数替换。
String getDefaultEessage() 默认的消息,如果没有装配相应的国际化资源那么显示的所有错误信息都是默认的.

错误消息代码

当一个属性校验失败后,校验框架会为该属性生成4个消息代码,这些代码以校验注解类名为前缀,结合类名、属性名以及属性类型名生成多个对应的消息代码。
例如之前的User类的loginname属性上标注了一个@NotBlank注解,当该属性的值不满足@NotBlank所定义的限制规则时,就会产生以下4种错误代码:

错误代码 描述
NotBlank.user.loginname 根据类名、属性名产生的错误代码。
NotBlank.loginname 根据属性名产生的错误代码。
NotBlank.java.lang.String 根据属性类型产生的错误代码
NotBlank 根据验证注解名产生的错误代码。
当使用 Spring MVC标签显示错误信息时, Spring MVC会查看Web上下文是否装配了对应的国际化消息,如果没有,则显示默认的错误消息,否则使用国际化消息对错误代码进行显示。

知道错误对象的错误码是对应国际化消息的键名称后,接下来就非常简单了,定义两个国际化资源文件,在国际化资源文件中为错误代码定义相应的本地化消息内容

message_en_US.properties

1
2
3
4
5
6
7
8
NotBlank.user.loginname= Loginname is not null
NotBlank.user.password= Password is not null
Length.user.password=Password length must be between 6 and 8
NotBlank.user.username= Username is not null
Range.user.age=Age must be between the ages of 15 to 60
Email.user.email=Must be a legitimate email address
Past.user.birthday=Birthday must be a date in the past
Pattern.user.phone=Invalid phone number

message_zh_CN.properties

1
2
3
4
5
6
7
8
NotBlank.user.loginname=登录名不能为空
NotBlank.user.password=密码不能为空
Length.user.password=密码长度必须在6位到8位之间
NotBlank.user.username=用户名不能为空
Range.user.age=年龄必须在1560岁之间
Email.user.email=必须是合法的邮箱地址
Past.user.birthday=生日必须是一个过去的日期
Pattern.user.phone=无效的手机号码

接下来还需要在springmvc-config.xml配置文件中增加国际化的配置,如下所示:

1
2
3
4
5
6
7
8
9
<!-- 国际化配置 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<!-- 国际化资源文件名 -->
<property
name="basenames"
value="message"/>
</bean>

springmvc-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件,
如果扫描到有Spring的相关注解的类,则把这些类注册为Spring的bean -->
<context:component-scan base-package="org.fkit"/>
<!-- 默认装配方案 -->
<mvc:annotation-driven/>
<!-- 静态资源处理 -->
<mvc:default-servlet-handler/>
<!-- 视图解析器 p:prefix属性表示前缀 p:suffix 表示后缀 -->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/content/"
p:suffix=".jsp"/>
<!-- 国际化配置 -->
<bean
id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<!-- 国际化资源文件名 -->
<property
name="basenames"
value="message"/>
</bean>
</beans>

测试

乱填表单

这里有一张图片

错误提示

这里有一张图片

6.4 数据校验

输入校验

遇到非法输入时应用程序直接返回,提用户必须重新输入,也就是将那些非法输入过滤掉。这种对非法输入的过滤,就是输入校验,也称为数据校验”
输入校验分为客户端校验服务器端校验,

  • 客户端校验主要是过滤正常用户的误操作通常通过 JavaScript代码完成;
  • 服务器端校验是整个应用阻止非法数据的最后防线,主要通过在应用中编程实现

Spring MVC提供了强大的数据校验功能,其中有两种方法可以验证输入:

  • 一种是利用 Spring自带的 Validation校验框架;
  • 另一种是利用JSR303(Java验证规范)实现校验功能。

6.4.1 Spring的Validation校验框架

Spring拥有自己独立的数据校验框架。Spring在进行数据绑定时,可同时调用校验框架来完成数据校验工作。
Spring的校验框架在org.springframework.validation包中,其中重要的接口和类如下

Validator接口

Validator。最重要的接口。该接口有两个方法:

方法 描述
boolean supports(Class<?> clazz) 该校验器能够对clazz类型的对象进行校验
void validate(Object target,Errors errors) 对目标类target进行校验,并将校验错误记录在errors当中。

Errors接口

ErrorsSpring用来存放错误信息的接口。Spring MVC框架在将请求数据绑定到入参对象后,就会调用校验框架实施校验,而校验结果保存在处理方法的入参对象之后的参数对象当中。这个保存校验结果的参数对象必须是Errors或者BindingResult类型。一个Errors对象中包含了一系列的FieldErrorObjectError对象。FieldError表示与被校验的对象中的某个属性相关的一个错误。BindingResult扩展了Errors接口,同时可以获取数据绑定结果对象的信息.

ValidationUtils工具类

ValidationUtilsSpring提供的一个关于校验的工具类。它提供了多个为 Errors对象保存错误的方法。

LocalValidatorFactoryBean类

LocalValidatorFactoryBean位于org.springframework.validation.beanvalidation包中,该类既实现了SpringValidator接口,也实现了JSR303Validator接口。只要在Spring容器中定义一个LocalValidatorFactoryBean,即可将其注入到需要数据校验的Bean中。定义一个LocalValidatorFactoryBeanBean非常简单,如下代码所示:

<mvc:annotation-driven/>会默认装配好一个LocalValidatorFactoryBean,所以在实际开发中不需要手动配置LocalValidatorFactoryBean。需要注意的是,Spring本身没有提供JSR303的实现,如果要使用JSR303完成验证,则必须将JSR303的实现(注入Hibernate Validator)jar文件加入到应用程序的类路径下,这样Spring会自动加载并配好JSR303的实现.

实例 表单输入校验

loginForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试Validator接口验证</title>
</head>
<body>
<h3>登录页面</h3>
<!-- 绑定到user对象 -->
<form:form modelAttribute="user" method="post" action="login">
<table>
<tr>
<td>登录名:</td>
<!-- 绑定user对象的loginname属性 -->
<td><form:input path="loginname" /></td>
<!-- 显示loginname属性的错误信息 -->
<td><form:errors path="loginname" cssStyle="color:red" /></td>
</tr>
<tr>
<td>密码:</td>
<!-- 绑定user对象的password属性 -->
<td><form:input path="password" /></td>
<!-- 显示password属性的错误信息 -->
<td><form:errors path="password" cssStyle="color:red" /></td>
</tr>
<tr>
<td><input type="submit" value="提交" /></td>
</tr>
</table>
</form:form>
</body>
</html>

页面使用<form: errors>标签显示属性的错误信息。

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 域对象,实现序列化接口
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
private String loginname;
private String password;
public User()
{
super();
// TODO Auto-generated constructor stub
}
// 此处省略getter和setter方法,请自己补上
@Override
public String toString()
{
return "User [loginname=" + loginname + ", password=" + password + "]";
}
}

UserValidator.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 实现Spring的Validator接口
@Repository("userValidator")
public class UserValidator
implements Validator
{
// 该校验器能够对clazz类型的对象进行校验。
@Override
public boolean supports(Class<?> clazz)
{
// User指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。
return User.class.isAssignableFrom(clazz);
}
// 对目标类target进行校验,并将校验错误记录在errors当中
@Override
public void validate(Object target, Errors errors)
{
/**
* 使用ValidationUtils中的一个静态方法rejectIfEmpty()来对loginname属性进行校验,
* 假若'loginname'属性是 null 或者空字符串的话,就拒绝验证通过 。
*/
ValidationUtils.rejectIfEmpty(errors, "loginname", null, "登录名不能为空");
ValidationUtils.rejectIfEmpty(errors, "password", null, "密码不能为空");
User user = (User) target;
if (user.getLoginname().length() > 10)
{
// 使用Errors的rejectValue方法验证
errors.rejectValue("loginname", null, "用户名不能超过10个字符");
}
if (user.getPassword() != null && !user.getPassword().equals("")
&& user.getPassword().length() < 6)
{
errors.rejectValue("password", null, "密码不能小于6位");
}
}
}

UserValidator实现了SpringValidator接口,其可以对User对象进行数据校验,并分别使用ValidationUtilsrejectIfEmpty方法和ErrorsrejectValue方法对User进行数据校验。
写在类定义上面的@Repository("userValidator")注解将该对象声明为Spring容器中的一个Bean,名字为”userValidator“。

UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Controller
public class UserController {
// 注入UserValidator对象
@Autowired
@Qualifier("userValidator")
private UserValidator userValidator;
@GetMapping(value = "/loginForm")
public String loginForm(Model model)
{
// 创建一个user对象给登录表单使用
User user = new User();
// 添加到模型中,登陆表单会绑定这个对象
model.addAttribute("user", user);
// 跳转到登录页面
return "loginForm";
}
@PostMapping(value = "/login")
// @ModelAttribute User user表示使用user来绑定表单提交的数据
public String login(@ModelAttribute
User user, Model model, Errors errors)
{
System.out.println(user);
// 更新模型中的数据
model.addAttribute("user", user);
// 调用userValidator的验证方法
userValidator.validate(user, errors);
// 如果验证不通过跳转到loginForm视图
if (errors.hasErrors())
{
// 重新登录
return "loginForm";
}
return "success";
}
}

login方法对传进来的参数进行校验,注意方法的最后一个参数errors,该参数是个Spring校验框架的Errors对象。在该方法中调用了之前写的userValidator类进行数据校验,如果校验失败,则跳转到”loginForm“视图.

测试

错误填写

这里有一张图片

显示效果

这里有一张图片

最后说一句

由于早期Spring就提供了Validation框架,所以之前的很多应用都使用Validation框架进行数据校验。由于Validation框架通过硬编码完成数据校验,在实际开发中会显得比较麻烦,因此现代开发更加推荐使用JSR 303完成数据校验

6.3 数据格式化 3.使用AnnotationFormatterFactory格式化数据

testForm.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试AnnotationFormatterFactory</title>
</head>
<body>
<h3>测试表单数据格式化</h3>
<form action="test" method="post">
<table>
<tr>
<td><label>日期类型: </label></td>
<td><input type="text" id="birthday"
name="birthday"></td>
</tr>
<tr>
<td><label>整数类型: </label></td>
<td><input type="text" id="total" name="total"></td>
</tr>
<tr>
<td><label>百分数类型: </label></td>
<td><input type="text" id="discount"
name="discount"></td>
</tr>
<tr>
<td><label>货币类型: </label></td>
<td><input type="text" id="money" name="money"></td>
</tr>
<tr>
<td><input id="submit" type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 域对象,实现序列化接口
public class User
implements Serializable
{
private static final long serialVersionUID = 1L;
// 日期类型
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
// 正常数字类型
@NumberFormat(style = Style.NUMBER, pattern = "#,###")
private int total;
// 百分数类型
@NumberFormat(style = Style.PERCENT)
private double discount;
// 货币类型
@NumberFormat(style = Style.CURRENCY)
private double money;
public User()
{
super();
// TODO Auto-generated constructor stub
}
// 此处省略getter和setter方法,请自己补上
@Override
public String toString()
{
return "User [birthday=" + birthday + ", total=" + total + ", discount="
+ discount + ", money=" + money + "]";
}
}

User类的多个属性使用了@DateTimeFormat@NumberFormat注解,用于将页面传递的String转换成对应的格式化数据。

FormatterController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
public class FormatterController {
@GetMapping(value = "/testForm")
public String registerForm()
{
// 跳转到测试表单数据格式化
return "testForm";
}
@PostMapping(value = "/test")
public String test(@ModelAttribute
User user, Model model)
{
System.out.println(user);
model.addAttribute("user", user);
return "success";
}
}

success.jsp

如果希望在视图页面中将模型属性数据以格式化的方式进行渲染,则需要使用Spring的页面标签显示模型数据。所以form:form标签,并且绑定了User对象.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>测试AnnotationFormatterFactory</title>
</head>
<body>
<h3>测试表单数据格式化</h3>
<form:form modelAttribute="user" method="post" action="">
<table>
<tr>
<td>日期类型:</td>
<td><form:input path="birthday" /></td>
</tr>
<tr>
<td>整数类型:</td>
<td><form:input path="total" /></td>
</tr>
<tr>
<td>百分数类型:</td>
<td><form:input path="discount" /></td>
</tr>
<tr>
<td>货币类型:</td>
<td><form:input path="money" /></td>
</tr>
</table>
</form:form>
</body>
</html>

springmvc-config.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8"?>
<beans
...
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- spring可以自动去扫描base-pack下面的包或者子包下面的java文件, -->
<!--如果扫描到有Spring的相关注解的类,则把这些类注册为Spring的bean -->
<context:component-scan base-package="org.fkit.controller" />
<!-- 默认装配方案 -->
<mvc:annotation-driven />
<!-- 静态资源处理 -->
<mvc:default-servlet-handler />
<!-- 视图解析器 p:prefix属性表示前缀 p:suffix 表示后缀 -->
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/content/"
p:suffix=".jsp" />
</beans>

在配置文件中只是使用了默认装配方案: mvc:annotation-driven标签,而该标签内部默认创建的 Conversionservice实例就是一个FormattingConversionServiceFactoryBean,这样就可以支持注解驱动的格式化功能了,不需要过多的配置.

测试

填写表单

这里有一张图片

转换效果

这里有一张图片

控制台输出

1
User [birthday=Tue Mar 04 00:00:00 CST 1253, total=155123, discount=0.15, money=123.0]