spring mvc结合freemarker,使用hibernate validation框架做校验及国际化

搭建 Spring , Spring MVC , Mybatis , freemarker 等集成开发环境,为了增加数据校验和国际化花了好几天的时间 ( 其实可以手动编写校验代码,或者使用 spring mvc自带校验但不怎么好,故实现 hibernate validation) ,本来如果阅读源代码会可能更快,但是没有时间静下心来阅读,只有工作间隙中去网上查资料,但是尝试了很多次都没能成功,直到今天发现了 Spring mvc 集成 hibernate 的 validation 框架的潜规则后才算成功, Spring MVC 校验有两种: 1 是继承org.springframework.validation.Validator 类, 2 是 使用 JSR303 规范 Hibernate Validator ,下面讲第 2 种实现。

 

前提 spring 和 spring mvc 是 3.2.5 版, hibernate 的 validation 是 4.2.0 版, mybatis是 3.2.3 , freemarker 是 2.3.20 版(这里再废话下,网上找了一堆全是抄来抄去,就算抄也先验证 ok 后再转发)。这里主要采用的是 spring mvc 与 freemarker 结合做web 页面传入到 controller 的数据验证及国际化验证消息。目前我验证 freemarker 的 ftl文件有两种方式: (1) 结合 spring mvc 的 spring.tld 和 spring-form.tld 标签库实现; (2)结合 spring mvc 的 spring.ftl 宏定义文件实现。

 

两种实现都需要配合错误消息文件,消息文件: A 自定义消息文件名, B 使用hibernate 的默认的消息文件名,它是在 hibernate-validator-4.2.0.Final.jar 包中的/org/hibernate/validator/ValidationMessages.properties 中。建议使用 hibernate 的默认名称。

 

以下把两种共同的配置如下

1.        web.xml 的配置

< web-app xmlns = "http://java.sun.com/xml/ns/javaee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation = "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version = "3.0" >

   < display-name > mwsys-shop </ display-name >

   < context-param >

      < param-name > contextConfigLocation </ param-name >

      < param-value > /WEB-INF/classes/config/spring/*.xml </ param-value >

   </ context-param >

   < context-param >

      < param-name > log4jConfigLocation </ param-name >

      < param-value > /WEB-INF/classes/log4j.properties </ param-value >

   </ context-param >

   < context-param >

      < param-name > webAppRootKey </ param-name >

      < param-value > mwsys-shop </ param-value >

   </ context-param >

   < listener >

   < listener-class > freemarker.ext.jsp.EventForwarding </ listener-class >

   </ listener >

   < listener >

      < listener-class >

         org.springframework.web.context.ContextLoaderListener

      </ listener-class >

   </ listener >

   < listener >

      < listener-class >

         org.springframework.web.util.Log4jConfigListener

      </ listener-class >

   </ listener >

   < servlet >

      < servlet-name > remoting </ servlet-name >

      < servlet-class > org.springframework.web.servlet.DispatcherServlet </ servlet-class >

      < init-param >

         < param-name > contextConfigLocation </ param-name >

         < param-value > /WEB-INF/classes/config/spring/spring-mvc-main.xml </param-value >

      </ init-param >

      < load-on-startup > 1 </ load-on-startup >

   </ servlet >

   < servlet-mapping >

      < servlet-name > remoting </ servlet-name >

      < url-pattern > /* </ url-pattern >

   </ servlet-mapping >

</ web-app >

 

2.        spring mvc 配置 spring-mvc-main.xml 文件

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:context="http://www.springframework.org/schema/context"

   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xmlns:mvc="http://www.springframework.org/schema/mvc"

   xsi:schemaLocation="

        http://www.springframework.org/schema/beans     

        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context-3.0.xsd

        http://www.springframework.org/schema/mvc  

      http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

   <context:component-scan base-package="com.maowu.shop.view" />

   <mvc:annotation-driven />

   <!-- FreeMarker configuration -->

   <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">

      <property name="templateLoaderPath" value="/WEB-INF/ftl/" />

      <property name="freemarkerVariables">

         <map>

            <entry key="xml_escape" value-ref="fmXmlEscape" />

            <entry key="BASEPATH" value="http://localhost:8080/shop/"></entry>

             <entry key="IMGBASEPATH" value="http://localhost:8080/shop/res/file/"></entry>

            <entry key="RESBASEPATH" value="../../"></entry>

         </map>

      </property>

   </bean>

   <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">

      <property name="contentType" value="text/html;charset=UTF-8" />

      <property name="cache" value="true" />

      <property name="prefix" value="" />

      <property name="suffix" value=".ftl" />

   </bean>

   <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />

  

   <!-- exception handling configuration -->

   <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">

      <!-- 定义默认的异常处理页面,当该异常类型的注册时使用 -->  

      <property name="defaultErrorView" value="error/error" />

      <!-- 定义异常处理页面用来获取异常信息的变量名,默认名为 exception -->  

      <property name="exceptionAttribute" value="ex" />

      <!-- 全局异常记录到日志中,若 warnLogCategory 不为空, spring 就会使用apache 的 org.apache.commons.logging.Log 日志工具,记录这个异常级别是 warn -->

      <property name="warnLogCategory" value="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" />

      <property name="exceptionMappings">

         <map>

            <entry key="RemoteAccessException" value="error/remote_error" />

         </map>

      </property>

   </bean>

   <!-- bind i18n messages properties,this just setting zh_CN message -->

   <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">  

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

       <property name="defaultEncoding" value="UTF-8"/>  

       <property name="fallbackToSystemLocale" value="true"/>  

       <property name="basenames">  

           <list>  

               <value>classpath:bundle/messages</value>     

               <value>classpath:bundle/ValidationMessages</value>

           </list>  

       </property>  

   </bean>

   <!-- setting validation implementor,actually HibernateValidator is java validation interface default implementor-->

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

       <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>  

       <property name="validationMessageSource" ref="messageSource"/>  

   </bean>

  

</beans>

 

3.        UserVo 的源代码

import javax.validation.constraints.Max;

import javax.validation.constraints.Size;

public class UserVo

{

    @Size (min = 2, max = 6, message = "{size.u.name.len}" )

    private String name ;

    @Max (value = 1, message = "{Max.sex}" )

    private int sex ;

    public String getName()

    {

        return name ;

    }

    public void setName(String name)

    {

        this . name = name;

    }

    public int getSex()

    {

        return sex ;

    }

    public void setSex( int sex)

    {

        this . sex = sex;

    }

    @Override

    public String toString()

    {

        return String. format ( "UserVo [name=%s, sex=%s]" , name , sex );

    }

}

 

4.        需要把 spring.tld 和 spring-form.tld 两个文件加入 webapp 的目录下

 

5.        ValidationMessages.properties 国际化消息(校验的错误消息)

size.u.name.len=\u7528\u6237\u540D\u4E0D\u80FD\u4E3A\u7A7A\u957F\u5EA6\u5728{ min}\u548C{max}\u4E4B\u95F4

Max.sex= \u8D85\u8FC7\u6700\u5927\u503C{value}

 

6.        messages.properties 国家化消息(非校验的错误消息)

u.reg.welcome=\u6B22\u8FCE\u6CE8\u518C

 

7.        成功后的 user_reg_ok.ftl 页面:

         数据没问题,注册成功!

 

以下是不同部分

 

spring.ftl 结合 Hibernate Validator

1 ) Controller 的代码

@RequestMapping (value = "user/reg0" , method = RequestMethod. GET )

    public String reg0(ModelMap model)

    {

        UserVo userVo = new UserVo();

        model.addAttribute( "userVo" , userVo);

        return "user/user_reg0" ;

    }

    @RequestMapping (value = "user/reg0" , method = RequestMethod. POST )

    public String reg0( @Valid @ModelAttribute UserVo userVo, BindingResult result, ModelMap model)

    {

        System. out .println(userVo.toString());

        if (result.hasErrors())

        {

            return "user/user_reg0" ;

        }

        else

        {

            return "user/user_reg_ok" ;

        }

}

2 ) user_reg0.ftl 代码

<#import "/spring.ftl" as spring />

<html>

<style>  

.error {  

    color: #ff0000;  

    font-weight: bold;  

}  

</style>

   <body>

      <div><br/></div>

      <@spring.message code= "u.reg.welcome" />

      <br/>

      <form method= "POST" action= "/shop/user/reg0" id= "user_validator" >

         <@spring.bind "userVo.name" />

         <input type= "input" name= "name" value= "" />

         <@spring.showErrors "<br/>" />

         

         <@spring.bind "userVo.sex" />

         <input type= "input" name= "sex" value= "" />

         <input type= "submit" value= " 提交 " />

         <@spring.showErrors "<br/>" />

      </form>

   </body>

</html>

第二种: 使用 spring.tld 和 spring-form.tld 结合 Hibernate Validator

1)   Controller 代码

@RequestMapping (value = "user/reg1" , method = RequestMethod. GET )

    public String reg1(ModelMap model)

    {

        return "user/user_reg1" ;

    }

    @RequestMapping (value = "user/reg1" , method = RequestMethod. POST )

    public String reg1( @Valid @ModelAttribute UserVo userVo, BindingResult result, ModelMap model)

    {

        System. out .println(userVo.toString());

        if (result.hasErrors())

        {

            return "user/user_reg1" ;

        }

        else

        {

            return "user/user_reg_ok" ;

        }

    }

 

2)   user_reg1.ftl 代码文件

<#assign spring=JspTaglibs[ "/WEB-INF/spring.tld" ]/>

<#assign form=JspTaglibs[ "/WEB-INF/spring-form.tld" ]/>

<html>

<style>  

.error {  

    color: #ff0000;  

    font-weight: bold;  

}  

</style>

   <body>

      <@spring.message code= "u.reg.welcome" />

      <div><br/></div>

      <@form.form method= "POST" action= "/shop/user/reg1" commandName="userVo" id= "user_validator" >

         <input type= "input" name= "name" value= "" />

         <@form.errors path = "name" />

 

         <input type= "input" name= "sex" value= "" />

         <@form.errors path = "sex" />

         <input type= "submit" value= " 提交 " />

      </@form.form>

   </body>

</html>

以上就是两种配置的实际可以运行的源码,调试时注意各文件的存放路径。

 

以下是对上面的两种的总结:

 

验证错误消息文件名字:是默认名 ValidationMessages.properties ,编译后存放在classes 目录下则:消息 key 名可以自定义,消息内容可以包含参数(如上面代码中的“ {min} ”)

 

验证错误消息文件名字:是自定义名 ErrorMessages.properties ,编译后存放在classes 目录下则:消息 key 名不可自定义,需用 hibernate validation 的消息 key 格式(下面会讲解),消息内容不可包含参数(如上面代码中的“ {min} ”)

 

验证错误消息文件名字:是默认名 ValidationMessages.properties ,编译后不放在classes 目录下则:消息 key 名不可自定义,需用 hibernate validation 的消息 key 格式(下面会讲解),消息内容不可包含参数(如上面代码中的“ {min} ”)

 

如果消息内容中包含参数则会报: java.lang.IllegalArgumentException: can't parse argument number: xxx 异常。( xxx 是参数名)

 

 

以下是对 hibernate validation 默认的错误消息文件及默认错误消息键值说明:

默认的提供的错误消息文件名如下:

ValidationMessages.properties

ValidationMessages_de.properties

ValidationMessages_en.properties

ValidationMessages_es.properties

ValidationMessages_fr.properties

ValidationMessages_hu.properties

ValidationMessages_mn_MN.properties

ValidationMessages_pt_BR.properties

ValidationMessages_tr.properties

ValidationMessages_zh_CN.properties

 

 

默认的错误消息 Key :验证约束注解的全限定类名 .message ,默认将为验证的对象自动生成如下错误消息键:

验证错误注解简单类名 . 验证对象名 . 字段名

验证错误注解简单类名 . 字段名

验证错误注解简单类名 . 字段类型全限定类名

验证错误注解简单类名

使用的优先级是:从高到低,即最前边的具有最高的优先级,而且以上所有默认的错误消息键优先级高于自定义的错误消息键。

总结:一般来说消息 key 是要自定义的,而且消息内容可以传参数,所以我们使用默认文件名且存放在 classes 目录下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值