5.2.3 CookieLocaleResolver 基于Cookie的国际化
5.2 Spring MVC的国际化处理 5.2.2 基于Cookie的国际化实现
CookieLocaleResolver
不是默认的语言区域解析器,需要显式对其进行配置。使用它,Spring MVC
会从Cookie
中获取用户所设置的语言区域,来确定使用哪个语言区域.
实例 基于Cookie的国际化实现
springmvc-config.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
加载国际化资源文件
指定国际化资源文件的路径,以及文件的编码。
1 | <!-- 国际化 --> |
国际化拦截器
使用Cookie来实现国际化,必须设置国际化操作拦截器:
1 | <mvc:interceptors> |
创建CookieLocaleResolver
注意,此处将默认配置的localeResolver
换成了CookieLocaleResolver
1 | <bean |
UserController.java
1 | @Controller |
UserController
的loginForm
方法根据提交的request_locale
参数值,创建CookieLocaleResolver
对象并调用CookieLocaleResolver
对象的setLocale
方法将语言环境设置在Cookie
中,从而进行语言环境切换.
loginForm.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
loginForm.jsp
中通过<spring:message code="国际化文本" />
的形式来填写相应的国际化文本.
success.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
success.jsp
页面中通过spring:message
表单来显示格式化文本,该文本的名称为welcome
,并且该welcome
文本带有参数.使用参数可以创建动态的格式化文本。
1 | welcome = 欢迎 {0} |
测试
默认
中文环境
5.2.2 SessionLocaleResolver 基于HttpSession的国际化
5.2 Spring MVC的国际化处理 5.2.2 基于 Httpsession的国际化
SessionLocaleResolver
SessionLocaleResolver
不是默认的语言区琙解析器,需要对其进行显式配置。如果使用它,Spring MVC
会从HttpSession
作用域中获取用户所设置的语言区域,来确定使用哪个语言区域。
实例 基于Httpsession的国际化实现
loginForm.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
在loginForm.jsp
页面的最上面增加了两个超链接,分别用于切换中文和英文语言环境。注意请求后面的参数request_locale
,如果请求中文环境则传递的值是”zh_CN
“,如果请求英文环境则传递的值是”en_US
“.
springmvc-config.xml
1 | <beans |
国际化配置
1 | <!-- p:basenames属性指定国际化资源文件的路径 --> |
UserController.java
1 | @Controller |
loginForm
方法根据提交的 request_ locale
参数值,获取 Session
对象,并调用setAttribute
方法进行语言环境切换。
测试
进入登陆表单,默认显示英文.如下图所示:
切换中文环境
点击中文链接,切换中文环境.如下图所示:
填写账户密码,登陆,效果如下图:
切换英文环境
填写表单:
登陆效果:
5.2.1 AcceptHeaderLocaleResolver 基于浏览器请求的国际化
5.2 Spring MVC的国际化处理
5.2.1 AcceptHeaderLocaleResolver
AcceptHeaderLocaleResolver
是默认的,也是最容易使用的语言区域解析器。使用它,Spring MVC
会读取浏览器的accept-language
标题,来确定使用哪个语言区域。AcceptHeaderLocaleResolver
可以不用显式配置,当然也可以显式配置。
示例:基于浏览器请求的国际化实现
首先,准备两个资源文件
message_enUs.properties
第一个资源文件是message_enUs.properties
,该文件内容如
1 | loginname= Login name: |
message_zh_CN.properties
第二个资源文件的内容如下:
1 | loginname=登录名: |
将上面两个国际化资源文件保存为UTF-8
编码.接下来在JSP
页面中通过<spring:message/>
标签来输出国际化消息。
loginForm.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
springmvc-config.xml
接下来在Spring MVC
配置文件中加载国际化资源文件。
1 | <?xml version="1.0" encoding="UTF-8"?> |
国际化配置
国际化配置如下:
1 | <!-- 国际化 p:basenames属性用于指定国际化资源文件名 --> |
指定国际化资源文件路径
其中p:basenames
属性用于指定国际化文件的路径,这个路径是相对于src目录的路径,例如这里对应的路径为:src/message_en_US.properties
和message_zh_CN.properties
,指定国际化路径的时候只需要指定文件的前缀就行类,后面的语言
,地区
以及文件名后缀
不需要指出.也就是对于:
1 | message_zh_CN.properties |
指定国际化资源文件编码
p:defaultEncoding="UTF-8"
这个属性用于指定这些国际化文件使用的编码,默认编码是ISO-8859-1
,这样中文将会变成unicode
代码,不方便我们阅读修改.所以我这里使用UTF-8
编码
这组国际化资源文件,只需要指定message
即可
UserController.java
1 | @Controller |
login()
方法接收请求,如果验证通过,则使用RequestContext
对象的getMessage()
方法来获取国际化消息,并跳转到success.jsp
页面。
success.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
在success.Jjsp
页面中,使用message
标签读取资源文件中名为welcome
的消息,并设置了一个参数,参数值为user
对象的username
属性
测试
正确填写登陆名xiaoming
,密码123456
,
将会成功跳转到成功界面如下图所示:
测试国际化
设置浏览器语言
点击火狐浏览器右边的菜单按钮,然后选中选项:
找到语言,点击右边的选择按钮:
把英语(美国)移动到最上面:
显示效果
刷新登陆表单,即可看到提示信息变成英文的了:
5.1 Spring MVC国际化的相关知识
5.1 Spring MVC国际化的相关知识
5.1.1 messageSource接口
在Spring MVC
中,不直接使用java.util.ResourceBundle
,而是使用名为messageSource
的Bean
告诉Spring MVC
国际化的属性文件保存在哪里。配置信息代码如下所示:
1 | <!-- 国际化配置 --> |
上面的配置使用了ResourceBundleMessageSource
类作为messageSourceBean
的实现。basenames
属性用来指定国际化的属性文件名称。如果项目中只有一组属性文件,则可以使用baseman
来指定国际化的属性文件名称,实例代码如下
1 | <!-- 国际化 p:basenames属性用于指定国际化资源文件名 --> |
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
可以不用显式配置,而Sessionlocaleresolver
和Cookielocale-Resolver
需要手动显式配置
5.1.3 message标签
在Spring MVC
中显示本地化消息通常使用Spring
的message
标签。使用message
标签需要在JSP
页面最前面使用taglib
指令导入Spring
的标签库,如下所示:
1 | <%@taglib prefix="spring" uri="http://www.springframework.org/tags"%> |
message
标签的属性如表5.1所示,所有属性都是可选的
属性 | 描述 |
---|---|
arguments |
标签的参数,可以是一个字符串、数组或对象 |
argumentSeparator |
用来分隔该标签参数的字符 |
code |
获取消息的key |
htmlEscape |
boolean 值,表示被渲染的值是否应该进行HTM 转义 |
javaScriptEscape |
boolean 值,表示被渲染的值是否应该进行 JavaScript 转义 |
message |
MessageSourceResolvable 参数 |
scope |
保存var 属性中定义的变量的作用域 |
text |
如果code 属性不存在,所显示的默认文本 |
var |
用于保存消息的变量 |
5.0 第5章 Spring MVC的国际化
第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.RequestContext
的getMessage()
方法来完成。
- 在视图页面上输出国际化消息,需要使用
6.5 本章小结
6.4.2 JSR 303校验
6.4 数据校验 6.4.2 JSR 303校验
JSR 303
是Java
为Bean
数据合法性校验所提供的一个标准规范,叫作Bean Validation
。2009年12月Java EE6
发布**,Bean Validation
作为一个重要特性被包含其中,用于对JavaBean
中的字段值进行验证。官方参考实现是Hibernate Validation
。Bean Validation
为 JavaBean
验证定义了相应的元数据类型和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 |
@NotNull |
验证对象是否不为null ,无法检查长度为0的字符串,用于验证基本数据类型 |
@NotNull |
@NotBlank |
检查约束字符串是不是null,被Trim的长度是否大于0,只作用于字符串,且会去掉前后空格 | @NotBlank |
@AssertTrue |
验证Boolean 对象是否为true |
@AssertTrue |
@AssertFalse |
验证Boolean 对象是否为false |
@AssertTrue |
@Max(value) |
验证Number 和String 对象是否小于或者等于指定的值 |
@Max(0) |
@Min(value) |
验证Number 和String 对象是否大于或者等于指定的值 |
@Min(160) |
@DecimalMax(value) |
被标注的值必须不大于约束中指定的最大值.。这个约束的参数是一个通过BigDecimal 定义的最大值的字符串表示,小数存在精度 |
@DecimalMax(1.1) |
@DecimalMin(value) |
被标注的值必须不小于约束中指定的最小值.。这个约束的参数是一个通过BigDecimal 定义的最小值的字符串表小数存在精度 |
@DecimalMax(0.5) |
@Digits(integer,fraction) |
验证字符串是否是符合指定格式的数字,Integer 指定整数精度,fraction 指定小数精度 |
@Digits(integer=5, fraction=2) |
@Size(min,max) |
验证对象(Array 、Collection 、Map 、String) 长度是否在给定的范围之内 |
@Size(min=15, max=60) |
@Email |
验证是否是合法的邮件地址 | @Email |
@Past |
验证Date 和Calendar 对象是否在当前时间之前 |
@Past |
@Future |
验证Date 和Calendar 对象是否在当前时间之后 |
@FutureDate |
@Pattern |
验证String 对象是否符合正则表达式的规则 |
Pattern(regexp="[1][3,8][3,6,9][0-9]{8}") |
Hibernate Validator扩展注解
Hibernate Validator
是JSR 303
的一个参考实现,除了支持所有标准的校验注解之外,它还扩展了如下表所示的注解.
注解 | 功能 | 实例 |
---|---|---|
@URL |
验证是否是合法的URL |
@URL |
@CreditCardNumber |
验证是否是合法的信用卡号码 | @CreditCardNumber |
@Length(min,max) |
验证字符串的长度必须在指定的范围内 | @Length(min=6, max=8) |
@NotEmpty |
检查元素是否为Null 或者 Empty 。用于Array ,Collection ,Map ,String |
@NotEmpty |
@Range(min ,max ,message) |
验证属性值必须在合适的范围内 | @Range(min=18, max=60, message="学生的年龄必须在18岁到60岁之间") |
示例 测试JSR 303校验
registerForm.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
registerForm.jsp
是一个注册页面,用于提交用户注册信息,注册信息包括用户名、密码、邮箱、电话等。之后将在后台使用JSR 303
进行验证。
User.java
1 | public class User |
User
类使用了Hibernate Validator
的注解对前台提交的数据进行验证。
UserController.java
1 | @Controller |
在UserController
中的login
方法使用@Valid
注解对提交的数据进行校验,后面跟着Errors
对象保存校验信息。如果errors
中有错误信息,则返回registerForm
页面,验证通过则跳转到success
页面.
success.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
由于<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 | NotBlank.user.loginname= Loginname is not null |
message_zh_CN.properties
1 | NotBlank.user.loginname=登录名不能为空 |
接下来还需要在springmvc-config.xml
配置文件中增加国际化的配置,如下所示:
1 | <!-- 国际化配置 --> |
springmvc-config.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
测试
乱填表单
错误提示
6.4.1 Spring的Validation校验框架
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接口
Errors
是Spring
用来存放错误信息的接口。Spring MVC
框架在将请求数据绑定到入参对象后,就会调用校验框架实施校验,而校验结果保存在处理方法的入参对象之后的参数对象当中。这个保存校验结果的参数对象必须是Errors
或者BindingResult
类型。一个Errors
对象中包含了一系列的FieldError
和ObjectError
对象。FieldError
表示与被校验的对象中的某个属性相关的一个错误。BindingResult
扩展了Errors
接口,同时可以获取数据绑定结果对象的信息.
ValidationUtils工具类
ValidationUtils
是Spring
提供的一个关于校验的工具类。它提供了多个为 Errors
对象保存错误的方法。
LocalValidatorFactoryBean类
LocalValidatorFactoryBean
位于org.springframework.validation.beanvalidation
包中,该类既实现了Spring
的Validator
接口,也实现了JSR303
的Validator
接口。只要在Spring
容器中定义一个LocalValidatorFactoryBean
,即可将其注入到需要数据校验的Bean
中。定义一个LocalValidatorFactoryBean
的Bean
非常简单,如下代码所示:
<mvc:annotation-driven/>
会默认装配好一个LocalValidatorFactoryBean
,所以在实际开发中不需要手动配置LocalValidatorFactoryBean
。需要注意的是,Spring
本身没有提供JSR303
的实现,如果要使用JSR303
完成验证,则必须将JSR303
的实现(注入Hibernate Validator)jar
文件加入到应用程序的类路径下,这样Spring
会自动加载并配好JSR303
的实现.
实例 表单输入校验
loginForm.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> |
页面使用<form: errors>
标签显示属性的错误信息。
User.java
1 | // 域对象,实现序列化接口 |
UserValidator.java
1 | // 实现Spring的Validator接口 |
UserValidator
实现了Spring
的Validator
接口,其可以对User
对象进行数据校验,并分别使用ValidationUtils
的rejectIfEmpty
方法和Errors
的rejectValue
方法对User
进行数据校验。
写在类定义上面的@Repository("userValidator")
注解将该对象声明为Spring
容器中的一个Bean
,名字为”userValidator
“。
UserController.java
1 | @Controller |
login
方法对传进来的参数进行校验,注意方法的最后一个参数errors
,该参数是个Spring
校验框架的Errors
对象。在该方法中调用了之前写的userValidator
类进行数据校验,如果校验失败,则跳转到”loginForm
“视图.
测试
错误填写
显示效果
最后说一句
由于早期Spring
就提供了Validation
框架,所以之前的很多应用都使用Validation
框架进行数据校验。由于Validation
框架通过硬编码
完成数据校验,在实际开发中会显得比较麻烦,因此现代开发更加推荐使用JSR 303
完成数据校验。
3.使用AnnotationFormatterFactory格式化数据
6.3 数据格式化 3.使用AnnotationFormatterFactory格式化数据
testForm.jsp
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
User.java
1 | // 域对象,实现序列化接口 |
User
类的多个属性使用了@DateTimeFormat
和@NumberFormat
注解,用于将页面传递的String
转换成对应的格式化数据。
FormatterController.java
1 | @Controller |
success.jsp
如果希望在视图页面中将模型属性数据以格式化的方式进行渲染,则需要使用Spring
的页面标签显示模型数据。所以form:form
标签,并且绑定了User
对象.
1 | <%@ page language="java" contentType="text/html; charset=UTF-8" |
springmvc-config.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
在配置文件中只是使用了默认装配方案: mvc:annotation-driven
标签,而该标签内部默认创建的 Conversionservice
实例就是一个FormattingConversionServiceFactoryBean
,这样就可以支持注解驱动的格式化功能了,不需要过多的配置.
测试
填写表单
转换效果
控制台输出
1 | User [birthday=Tue Mar 04 00:00:00 CST 1253, total=155123, discount=0.15, money=123.0] |