天天看点

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

bean validation 1.1当前实现是hibernate validator 5,且spring4才支持。接下来我们从以下几个方法讲解bean validation 1.1,当然不一定是新特性:

 集成bean validation 1.1到springmvc

 分组验证、分组顺序及级联验证

 消息中使用el表达式

 方法参数/返回值验证

 自定义验证规则

 类级别验证器

 脚本验证器

 cross-parameter,跨参数验证

混合类级别验证器和跨参数验证器

组合多个验证注解

本地化

因为大多数时候验证都配合web框架使用,而且很多朋友都咨询过如分组/跨参数验证,所以本文介绍下这些,且是和springmvc框架集成的例子,其他使用方式(比如集成到jpa中)可以参考其官方文档:

1.1、项目搭建

首先添加hibernate validator 5依赖:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

<dependency>  

    <groupid>org.hibernate</groupid>  

    <artifactid>hibernate-validator</artifactid>  

    <version>5.0.2.final</version>  

</dependency>  

如果想在消息中使用el表达式,请确保el表达式版本是 2.2或以上,如使用tomcat6,请到tomcat7中拷贝相应的el jar包到tomcat6中。

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

    <groupid>javax.el</groupid>  

    <artifactid>javax.el-api</artifactid>  

    <version>2.2.4</version>  

    <scope>provided</scope>  

请确保您使用的web容器有相应版本的el jar包。

对于其他pom依赖请下载附件中的项目参考。

1.2、spring mvc配置文件(spring-mvc.xml):

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

<!-- 指定自己定义的validator -->  

<mvc:annotation-driven validator="validator"/>  

<!-- 以下 validator  conversionservice 在使用 mvc:annotation-driven 会 自动注册-->  

<bean id="validator" class="org.springframework.validation.beanvalidation.localvalidatorfactorybean">  

    <property name="providerclass" value="org.hibernate.validator.hibernatevalidator"/>  

    <!-- 如果不加默认到 使用classpath下的 validationmessages.properties -->  

    <property name="validationmessagesource" ref="messagesource"/>  

</bean>  

<!-- 国际化的消息资源文件(本系统中主要用于显示/错误消息定制) -->  

<bean id="messagesource" class="org.springframework.context.support.reloadableresourcebundlemessagesource">  

    <property name="basenames">  

        <list>  

            <!-- 在web环境中一定要定位到classpath 否则默认到当前web应用下找  -->  

            <value>classpath:messages</value>  

            <value>classpath:org/hibernate/validator/validationmessages</value>  

        </list>  

    </property>  

    <property name="usecodeasdefaultmessage" value="false"/>  

    <property name="defaultencoding" value="utf-8"/>  

    <property name="cacheseconds" value="60"/>  

此处主要把bean validation的消息查找委托给spring的messagesource。

1.3、实体验证注解:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

public class user implements serializable {  

    @notnull(message = "{user.id.null}")  

    private long id;  

    @notempty(message = "{user.name.null}")  

    @length(min = 5, max = 20, message = "{user.name.length.illegal}")  

    @pattern(regexp = "[a-za-z]{5,20}", message = "{user.name.illegal}")  

    private string name;  

    @notnull(message = "{user.password.null}")  

    private string password;  

}  

1.4、错误消息文件messages.properties:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

user.id.null=用户编号不能为空  

user.name.null=用户名不能为空  

user.name.length.illegal=用户名长度必须在5到20之间  

user.name.illegal=用户名必须是字母  

user.password.null=密码不能为空  

1.5、控制器

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@controller  

public class usercontroller {  

    @requestmapping("/save")  

    public string save(@valid user user, bindingresult result) {  

        if(result.haserrors()) {  

            return "error";  

        }  

        return "success";  

    }  

1.6、错误页面:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

<spring:hasbinderrors name="user">  

    <c:if test="${errors.fielderrorcount > 0}">  

        字段错误:<br/>  

        <c:foreach items="${errors.fielderrors}" var="error">  

            <spring:message var="message" code="${error.code}" arguments="${error.arguments}" text="${error.defaultmessage}"/>  

            ${error.field}------${message}<br/>  

        </c:foreach>  

    </c:if>  

    <c:if test="${errors.globalerrorcount > 0}">  

        全局错误:<br/>  

        <c:foreach items="${errors.globalerrors}" var="error">  

            <c:if test="${not empty message}">  

                ${message}<br/>  

            </c:if>  

</spring:hasbinderrors>  

1.7、测试

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

name------用户名必须是字母  

name------用户名长度必须在5到20之间  

password------密码不能为空  

id------用户编号不能为空  

基本的集成就完成了。

如上测试有几个小问题:

1、错误消息顺序,大家可以看到name的错误消息顺序不是按照书写顺序的,即不确定;

2、我想显示如:用户名【zhangsan】必须在5到20之间;其中我们想动态显示:用户名、min,max;而不是写死了;

3、我想在修改的时候只验证用户名,其他的不验证怎么办。

接下来我们挨着试试吧。

如果我们想在新增的情况验证id和name,而修改的情况验证name和password,怎么办? 那么就需要分组了。

首先定义分组接口:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

public interface first {  

public interface second {  

分组接口就是两个普通的接口,用于标识,类似于java.io.serializable。

接着我们使用分组接口标识实体:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

    @notnull(message = "{user.id.null}", groups = {first.class})  

    @length(min = 5, max = 20, message = "{user.name.length.illegal}", groups = {second.class})  

    @pattern(regexp = "[a-za-z]{5,20}", message = "{user.name.illegal}", groups = {second.class})  

    @notnull(message = "{user.password.null}", groups = {first.class, second.class})  

验证时使用如:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@requestmapping("/save")  

public string save(@validated({second.class}) user user, bindingresult result) {  

    if(result.haserrors()) {  

        return "error";  

    return "success";  

即通过@validate注解标识要验证的分组;如果要验证两个的话,可以这样@validated({first.class, second.class})。

接下来我们来看看通过分组来指定顺序;还记得之前的错误消息吗? user.name会显示两个错误消息,而且顺序不确定;如果我们先验证一个消息;如果不通过再验证另一个怎么办?可以通过@groupsequence指定分组验证顺序:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@groupsequence({first.class, second.class, user.class})  

    @length(min = 5, max = 20, message = "{user.name.length.illegal}", groups = {first.class})  

通过@groupsequence指定验证顺序:先验证first分组,如果有错误立即返回而不会验证second分组,接着如果first分组验证通过了,那么才去验证second分组,最后指定user.class表示那些没有分组的在最后。这样我们就可以实现按顺序验证分组了。

另一个比较常见的就是级联验证:

如:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

public class user {  

    @valid   

    @convertgroup(from=first.class, to=second.class)  

    private organization o;  

 1、级联验证只要在相应的字段上加@valid即可,会进行级联验证;@convertgroup的作用是当验证o的分组是first时,那么验证o的分组是second,即分组验证的转换。

假设我们需要显示如:用户名[name]长度必须在[min]到[max]之间,此处大家可以看到,我们不想把一些数据写死,如name、min、max;此时我们可以使用el表达式。

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@length(min = 5, max = 20, message = "{user.name.length.illegal}", groups = {first.class})  

错误消息:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

user.name.length.illegal=用户名长度必须在{min}到{max}之间  

其中我们可以使用{验证注解的属性}得到这些值;如{min}得到@length中的min值;其他的也是类似的。

到此,我们还是无法得到出错的那个输入值,如name=zhangsan。此时就需要el表达式的支持,首先确定引入el jar包且版本正确。然后使用如:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

user.name.length.illegal=用户名[${validatedvalue}]长度必须在5到20之间  

使用如el表达式:${validatedvalue}得到输入的值,如zhangsan。当然我们还可以使用如${min > 1 ? '大于1' : '小于等于1'},及在el表达式中也能拿到如@length的min等数据。

另外我们还可以拿到一个java.util.formatter类型的formatter变量进行格式化:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

${formatter.format("%04d", min)}  

有时候默认的规则可能还不够,有时候还需要自定义规则,比如屏蔽关键词验证是非常常见的一个功能,比如在发帖时帖子中不允许出现admin等关键词。

1、定义验证注解

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

package com.sishuok.spring4.validator;  

import javax.validation.constraint;  

import javax.validation.payload;  

import java.lang.annotation.documented;  

import java.lang.annotation.retention;  

import java.lang.annotation.target;  

import static java.lang.annotation.elementtype.*;  

import static java.lang.annotation.retentionpolicy.*;  

/** 

 * <p>user: zhang kaitao 

 * <p>date: 13-12-15 

 * <p>version: 1.0 

 */  

@target({ field, method, parameter, annotation_type })  

@retention(runtime)  

//指定验证器  

@constraint(validatedby = forbiddenvalidator.class)  

@documented  

public @interface forbidden {  

    //默认错误消息  

    string message() default "{forbidden.word}";  

    //分组  

    class<?>[] groups() default { };  

    //负载  

    class<? extends payload>[] payload() default { };  

    //指定多个时使用  

    @target({ field, method, parameter, annotation_type })  

    @retention(runtime)  

    @documented  

    @interface list {  

        forbidden[] value();  

2、 定义验证器

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

import org.hibernate.validator.internal.engine.constraintvalidation.constraintvalidatorcontextimpl;  

import org.springframework.beans.factory.annotation.autowired;  

import org.springframework.context.applicationcontext;  

import org.springframework.util.stringutils;  

import javax.validation.constraintvalidator;  

import javax.validation.constraintvalidatorcontext;  

import java.io.serializable;  

public class forbiddenvalidator implements constraintvalidator<forbidden, string> {  

    private string[] forbiddenwords = {"admin"};  

    @override  

    public void initialize(forbidden constraintannotation) {  

        //初始化,得到注解数据  

    public boolean isvalid(string value, constraintvalidatorcontext context) {  

        if(stringutils.isempty(value)) {  

            return true;  

        for(string word : forbiddenwords) {  

            if(value.contains(word)) {  

                return false;//验证失败  

            }  

        return true;  

 验证器中可以使用spring的依赖注入,如注入:@autowired  private applicationcontext ctx; 

3、使用

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

    @forbidden()  

4、当我们在提交name中含有admin的时候会输出错误消息:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

forbidden.word=您输入的数据中有非法关键词  

问题来了,哪个词是非法的呢?bean validation 和 hibernate validator都没有提供相应的api提供这个数据,怎么办呢?通过跟踪代码,发现一种不是特别好的方法:我们可以覆盖org.hibernate.validator.internal.metadata.descriptor.constraintdescriptorimpl实现(即复制一份代码放到我们的src中),然后覆盖buildannotationparametermap方法;

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

private map<string, object> buildannotationparametermap(annotation annotation) {  

    ……  

    //将collections.unmodifiablemap( parameters );替换为如下语句  

    return parameters;  

 即允许这个数据可以修改;然后在forbiddenvalidator中:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

for(string word : forbiddenwords) {  

    if(value.contains(word)) {  

        ((constraintvalidatorcontextimpl)context).getconstraintdescriptor().getattributes().put("word", word);  

        return false;//验证失败  

通过((constraintvalidatorcontextimpl)context).getconstraintdescriptor().getattributes().put("word", word);添加自己的属性;放到attributes中的数据可以通过${} 获取。然后消息就可以变成:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

forbidden.word=您输入的数据中有非法关键词【{word}】  

这种方式不是很友好,但是可以解决我们的问题。

典型的如密码、确认密码的场景,非常常用;如果没有这个功能我们需要自己写代码来完成;而且经常重复自己。接下来看看bean validation 1.1如何实现的。

6.1、定义验证注解

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

import javax.validation.constraints.notnull;  

@target({ type, annotation_type})  

@constraint(validatedby = checkpasswordvalidator.class)  

public @interface checkpassword {  

    string message() default "";  

        checkpassword[] value();  

6.2、 定义验证器

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

import com.sishuok.spring4.entity.user;  

public class checkpasswordvalidator implements constraintvalidator<checkpassword, user> {  

    public void initialize(checkpassword constraintannotation) {  

    public boolean isvalid(user user, constraintvalidatorcontext context) {  

        if(user == null) {  

        //没有填密码  

        if(!stringutils.hastext(user.getpassword())) {  

            context.disabledefaultconstraintviolation();  

            context.buildconstraintviolationwithtemplate("{password.null}")  

                    .addpropertynode("password")  

                    .addconstraintviolation();  

            return false;  

        if(!stringutils.hastext(user.getconfirmation())) {  

            context.buildconstraintviolationwithtemplate("{password.confirmation.null}")  

                    .addpropertynode("confirmation")  

        //两次密码不一样  

        if (!user.getpassword().trim().equals(user.getconfirmation().trim())) {  

            context.buildconstraintviolationwithtemplate("{password.confirmation.error}")  

其中我们通过disabledefaultconstraintviolation禁用默认的约束;然后通过buildconstraintviolationwithtemplate(消息模板)/addpropertynode(所属属性)/addconstraintviolation定义我们自己的约束。

6.3、使用

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@checkpassword()  

 放到类头上即可。

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@scriptassert(script = "_this.password==_this.confirmation", lang = "javascript", alias = "_this", message = "{password.confirmation.error}")  

通过脚本验证是非常简单而且强大的,lang指定脚本语言(请参考javax.script.scriptenginemanager jsr-223),alias是在脚本验证中user对象的名字,但是大家会发现一个问题:错误消息怎么显示呢? 在springmvc 中会添加到全局错误消息中,这肯定不是我们想要的,我们改造下吧。

7.1、定义验证注解

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

import org.hibernate.validator.internal.constraintvalidators.scriptassertvalidator;  

import static java.lang.annotation.elementtype.type;  

import static java.lang.annotation.retentionpolicy.runtime;  

@target({ type })  

@constraint(validatedby = {propertyscriptassertvalidator.class})  

public @interface propertyscriptassert {  

    string message() default "{org.hibernate.validator.constraints.scriptassert.message}";  

    string lang();  

    string script();  

    string alias() default "_this";  

    string property();  

    @target({ type })  

    public @interface list {  

        propertyscriptassert[] value();  

和scriptassert没什么区别,只是多了个property用来指定出错后给实体的哪个属性。

7.2、验证器

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

import javax.script.scriptexception;  

import javax.validation.constraintdeclarationexception;  

import com.sishuok.spring4.validator.propertyscriptassert;  

import org.hibernate.validator.constraints.scriptassert;  

import org.hibernate.validator.internal.util.contracts;  

import org.hibernate.validator.internal.util.logging.log;  

import org.hibernate.validator.internal.util.logging.loggerfactory;  

import org.hibernate.validator.internal.util.scriptengine.scriptevaluator;  

import org.hibernate.validator.internal.util.scriptengine.scriptevaluatorfactory;  

import static org.hibernate.validator.internal.util.logging.messages.messages;  

public class propertyscriptassertvalidator implements constraintvalidator<propertyscriptassert, object> {  

    private static final log log = loggerfactory.make();  

    private string script;  

    private string languagename;  

    private string alias;  

    private string property;  

    private string message;  

    public void initialize(propertyscriptassert constraintannotation) {  

        validateparameters( constraintannotation );  

        this.script = constraintannotation.script();  

        this.languagename = constraintannotation.lang();  

        this.alias = constraintannotation.alias();  

        this.property = constraintannotation.property();  

        this.message = constraintannotation.message();  

    public boolean isvalid(object value, constraintvalidatorcontext constraintvalidatorcontext) {  

        object evaluationresult;  

        scriptevaluator scriptevaluator;  

        try {  

            scriptevaluatorfactory evaluatorfactory = scriptevaluatorfactory.getinstance();  

            scriptevaluator = evaluatorfactory.getscriptevaluatorbylanguagename( languagename );  

        catch ( scriptexception e ) {  

            throw new constraintdeclarationexception( e );  

            evaluationresult = scriptevaluator.evaluate( script, value, alias );  

            throw log.geterrorduringscriptexecutionexception( script, e );  

        if ( evaluationresult == null ) {  

            throw log.getscriptmustreturntrueorfalseexception( script );  

        if ( !( evaluationresult instanceof boolean ) ) {  

            throw log.getscriptmustreturntrueorfalseexception(  

                    script,  

                    evaluationresult,  

                    evaluationresult.getclass().getcanonicalname()  

            );  

        if(boolean.false.equals(evaluationresult)) {  

            constraintvalidatorcontext.disabledefaultconstraintviolation();  

            constraintvalidatorcontext  

                    .buildconstraintviolationwithtemplate(message)  

                    .addpropertynode(property)  

        return boolean.true.equals( evaluationresult );  

    private void validateparameters(propertyscriptassert constraintannotation) {  

        contracts.assertnotempty( constraintannotation.script(), messages.parametermustnotbeempty( "script" ) );  

        contracts.assertnotempty( constraintannotation.lang(), messages.parametermustnotbeempty( "lang" ) );  

        contracts.assertnotempty( constraintannotation.alias(), messages.parametermustnotbeempty( "alias" ) );  

        contracts.assertnotempty( constraintannotation.property(), messages.parametermustnotbeempty( "property" ) );  

        contracts.assertnotempty( constraintannotation.message(), messages.parametermustnotbeempty( "message" ) );  

和之前的类级别验证器类似,就不多解释了,其他代码全部拷贝自org.hibernate.validator.internal.constraintvalidators.scriptassertvalidator。

7.3、使用

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@propertyscriptassert(property = "confirmation", script = "_this.password==_this.confirmation", lang = "javascript", alias = "_this", message = "{password.confirmation.error}")  

和之前的区别就是多了个property,用来指定出错时给哪个字段。 这个相对之前的类级别验证器更通用一点。

直接看示例;

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

<bean class="org.springframework.validation.beanvalidation.methodvalidationpostprocessor">  

    <property name="validator" ref="validator"/>  

8.2、service 

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@validated  

@service  

public class userservice {  

    @crossparameter  

    public void changepassword(string password, string confirmation) {  

通过@validated注解userservice表示该类中有需要进行方法参数/返回值验证;   @crossparameter注解方法表示要进行跨参数验证;即验证password和confirmation是否相等。

8.3、验证注解 

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

//省略import  

@constraint(validatedby = crossparametervalidator.class)  

@target({ method, constructor, annotation_type })  

public @interface crossparameter {  

    string message() default "{password.confirmation.error}";  

8.4、验证器 

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@supportedvalidationtarget(validationtarget.parameters)  

public class crossparametervalidator implements constraintvalidator<crossparameter, object[]> {  

    public void initialize(crossparameter constraintannotation) {  

    public boolean isvalid(object[] value, constraintvalidatorcontext context) {  

        if(value == null || value.length != 2) {  

            throw new illegalargumentexception("must have two args");  

        if(value[0] == null || value[1] == null) {  

        if(value[0].equals(value[1])) {  

        return false;  

其中@supportedvalidationtarget(validationtarget.parameters)表示验证参数; value将是参数列表。 

8.5、使用

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@requestmapping("/changepassword")  

public string changepassword(  

        @requestparam("password") string password,  

        @requestparam("confirmation") string confirmation, model model) {  

    try {  

        userservice.changepassword(password, confirmation);  

    } catch (constraintviolationexception e) {  

        for(constraintviolation violation : e.getconstraintviolations()) {  

            system.out.println(violation.getmessage());  

调用userservice.changepassword方法,如果验证失败将抛出constraintviolationexception异常,然后得到constraintviolation,调用getmessage即可得到错误消息;然后到前台显示即可。

从以上来看,不如之前的使用方便,需要自己对错误消息进行处理。 下一节我们也写个脚本方式的跨参数验证器。

9.1、验证注解

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@constraint(validatedby = {  

        crossparameterscriptassertclassvalidator.class,  

        crossparameterscriptassertparametervalidator.class  

})  

@target({ type, field, parameter, method, constructor, annotation_type })  

public @interface crossparameterscriptassert {  

    string message() default "error";  

    string property() default "";  

    constrainttarget validationappliesto() default constrainttarget.implicit;  

}   

此处我们通过@constraint指定了两个验证器,一个类级别的,一个跨参数的。validationappliesto指定为constrainttarget.implicit,表示隐式自动判断。

9.2、验证器

请下载源码查看

9.3、使用

9.3.1、类级别使用

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@crossparameterscriptassert(property = "confirmation", script = "_this.password==_this.confirmation", lang = "javascript", alias = "_this", message = "{password.confirmation.error}")  

指定property即可,其他和之前的一样。

9.3.2、跨参数验证

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@crossparameterscriptassert(script = "args[0] == args[1]", lang = "javascript", alias = "args", message = "{password.confirmation.error}")  

public void changepassword(string password, string confirmation) {  

通过args[0]==args[1] 来判断是否相等。

这样,我们的验证注解就自动适应两种验证规则了。  

有时候,可能有好几个注解需要一起使用,此时就可以使用组合验证注解

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@target({ field})  

@notnull(message = "{user.name.null}")  

@length(min = 5, max = 20, message = "{user.name.length.illegal}")  

@pattern(regexp = "[a-za-z]{5,20}", message = "{user.name.length.illegal}")  

@constraint(validatedby = { })  

public @interface composition {  

这样我们验证时只需要:

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

@composition()  

private string name;  

简洁多了。 

即根据不同的语言选择不同的错误消息显示。

1、本地化解析器

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

<bean id="localeresolver" class="org.springframework.web.servlet.i18n.cookielocaleresolver">  

    <property name="cookiename" value="locale"/>  

    <property name="cookiemaxage" value="-1"/>  

    <property name="defaultlocale" value="zh_cn"/>  

此处使用cookie存储本地化信息,当然也可以选择其他的,如session存储。

2、设置本地化信息的拦截器

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

<mvc:interceptors>  

    <bean class="org.springframework.web.servlet.i18n.localechangeinterceptor">  

        <property name="paramname" value="language"/>  

    </bean>  

</mvc:interceptors>  

即请求参数中通过language设置语言。

3、消息文件

Spring4新特性——集成Bean Validation 1.1(JSR-349)到SpringMVC

4、 浏览器输入

http://localhost:9080/spring4/changepassword?password=1&confirmation=2&language=en_us

转自:http://jinnianshilongnian.iteye.com/blog/1990081