七.完成程序的国际化
因为一个企业应用经常要面对多区域的用户,因此,程序国际化是一个企业应用必须实现的功能.Struts2提供了非常好的程序国际化的支持.
(1) 定义国际化资源文件
程序国际化设计思想是非常简单的,其主要的思想就是:程序界面中需要输出国际化信息的地方,我们不要再页面中直接输出信息,而是输出一个key值,该key值在不同的语言下对应不同的字符串.当程序需要显示的时候,程序将根据不同的语言环境,加载该key对应语言环境下的字符串,这样就可以完成程序的国际化.
为了给本应用增加程序国际化支持(支持中文和英文),则应该提供两份语言资源文件,下面是本应用程序所使用的中文语言环境下的资源文件的代码:
loginPage=登录页面 errorPage=错误页面 succPage=成功页面 failTip=对不起,您不能够登录 viewLink=查看图书列表 bookPageTitle=所有图书列表 bookName=书名 user=用户名 pass=密码 login=登录
因为资源文件中包含了非西欧字符,因此必须使用native2ascii命令来处理该文件,将上面的文件保存在WEB-INF/classes路径下,文件名称为”messageResource.properties”保存该文件后,使用native2ascii命令来处理该文件,处理该文件的命令格式为:
native2ascii messageResource.properties messageResources_zh_CN.properties
上面命令将包含非西欧字符的资源文件处理成ASCII格式,处理完成后生成了一份新的文件:messageResource_zh_CN.properties文件.这个文件的文件名符合资源文件的命名格式,资源文件的文件名的命名格式为:
basename_语言代码_国家代码.properties
当请求来自简体中文的语言环境的时候,系统将自动的使用这种资源文件的内容输出.
除此之外,还应该提供如下英文语言环境下的资源文件:
loginPage=Login Page errorPage=Error Page succPage=Welcome Page failTip=Sorry,you can't log in! viewLink=View Books bookPageTitle=All Books List bookName=Book Name user=User Name pass=Password login=Login
将上面的资源文件保存在/WEB-INF/classes路径下面,文件名字为”messageResource_cn_US.properties”.当请求来自美国的时候,系统自动使用这份资源文件内容输出.
(2) 加载资源文件
Struts2支持在JSP页面当中临时加载资源文件,也支持通过全局属性来加载资源文件,通过全局属性加载资源文件更加简单,本应用使用全局属性加载Struts2国际化资源文件.
加载资源文件可以通过struts.properties文件来定义,本应用的struts.properties文件仅有一行代码:
//定义Struts 2的资源文件的baseName是messageResource struts.custom.i18n.resources=messageResource
在struts.properties文件中增加上面的代码定义之后,表明该应用使用的资源文件的baseName为”messageResource”这与我们的前面保存的资源文件的baseName是一直的.
Struts2默认加载WEB-INF/classes下面的资源文件,如果将该资源文件放在/WEB-INF/classes中的子路径下面,则需要修改struts.properties中的定义如下:
struts.custom.i18n.resources=supermos.messageResource
(3) 输出国际化信息
为了让程序可以显示国际化信息,则需要在JSP页面中输出key,而不是直接输出字符串常量.
Struts2中提供了如下两种方式来输出国际化信息
①<s:text name=”messageKey”/>:使用s:text标签来输出国际化信息.
②<s:property value=”%{getText(“messageKey”)}”/>使用表达式方式输出国际化信息.
因此,我们再次修改表现层的JSP页面,使用国际化标签输出国际化信息.修改后的showBook.jsp页面代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <!-- -导入struts2的标签库 --> <%@taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <!-- 使用s:text输出国际化信息 --> <title><s:property value="%{getText('bookPageTitle')}"/></title> </head> <body> <table align="center" border="1"> <!-- 使用s:text输出国际化信息 --> <caption><h3><s:text name="viewLink"/></h3></caption> <!-- 迭代输出ValueStack中的books对象,其中status是迭代的序号 --> <s:iterator value="books" status="index"> <!-- 判断序号是否为奇数 --> <s:if test="#index.odd==true"> <tr style="background-color:#cccccc" mce_style="background-color:#cccccc"> </s:if> <!-- 判断迭代元素的序号是不是为偶数 --> <s:else> <tr> </s:else> <!-- 使用s:text输出国际化信息 --> <td><s:text name="bookPageTitle"/></td> <td><s:property/></td> </tr> </s:iterator> </table> </body> </html>
我们发现,上面的JSP页面不再包含任何直接字符串,而是全部通过<s:text name=”…”/>来输出国际化信息.
我们可以通过调整系统语言环境来观看本系统的运行状况.
八.增加数据校验
在上面的应用中,即使浏览器输入任何的用户名,密码系统也会处理用户的请求,在我们的整个Helloworld应用中,这种空用户名,空密码的问题不会引起太大的问题,但是如果数据需要保存到数据库,或者需要根据用户输入的用户名,密码查询数据,这些数据就可能会引发异常.
为了避免用户的输入引起底层的异常,通常,我们会在进行业务逻辑的操作之前,先执行基本的数据校验.
(1) 继承ActionSupport
ActionSupport类是一个工具类,它已经实现了Action接口,除此之外,它还实现了Validateable接口,提供了数据的校验功能.通过继承该ActionSupport类,可以简化Struts2的Action开发.
在Validatable接口中定义了一个validate()方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到ActionSupport类中的fieldErrors域中,然后通过OGNL表达式负责输出.
为了让Struts2增加输入数据校验功能,改写程序中的LoginAction,增加重写validate方法,修改后的LoginAction类代码如下:
package com.supermos.app; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport implements Action { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String execute() throws Exception { if ("supermos".equalsIgnoreCase(username) && "ziwen".equalsIgnoreCase(password)) { // 通过ActionContext对象访问Web应用的Session ActionContext.getContext().getSession().put("user", getUsername()); return SUCCESS; } else { return ERROR; } } // 完成输入校验需要重写的validate方法 public void validate() { // 如果用户名为空,或者用户名为空字符串 if (getUsername() == null || getUsername().trim().equals("")) { // 添加表单校验错误 addFieldError("username", "user.required"); } // 如果密码为空,或者用户名为空字符串,添加表单校验错误 if (getPassword() == null || getPassword().trim().equals("")) { // 添加表单校验错误 addFieldError("password", "password.required"); } } }
上面的Action重写了validate方法,该方法会在执行系统的execute方法之前执行,如果执行该方法之后,Action类的fieldErrors中已经包含了数据校验的错误,请求将被转发到input逻辑视图处.
为了在校验失败之后,系统能够将试图转入input处,必须在配置Action时候配置input属性,下面是修改之后的loginAction的配置片段:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd"> <struts> <package name="strutsqs" extends="struts-default"> <action name="login" class="com.supermos.app.LoginAction"> <result name="input">/login.jsp</result> <result name="success">/success.jsp</result> <result name="error">/fail.jsp</result> </action> <action name="GetBooks" class="com.supermos.app.GetBooksAction"> <result name="login">/login.jsp</result> <result name="success">/showBook.jsp</result> </action> </package> </struts>
运行测试一下,我们发现我们并未在输入页面输出这些校验错误信息,但是页面上却自己输出了..这是因为struts2的标签,上面的JSP页面中表单使用的不是HTML表单,而是使用了<s:form…./>标签,这种标签已经具备了输出校验错误的能力.(Struts 2的<s:form….?>默认已经提供了输出校验错误的能力)
但是上面的程序还有一个问题:校验信息的国际化,查看上面的Action代码发现,重写validate方法的时候,如果发生校验失败的问题,校验错误的提示信息时以硬编码的形式写死了..这样就是去了国际化的能力.
实际上,ActionSupport类已经提供了国际化信息的能力,它提供了一个getText(String key)的方法,该方法用于从资源文件中获取国际化信息,为了让校验信息支持国际化,再次改写Action里的validate方法,修改之后的validate方法代码如下:
package com.supermos.app; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport implements Action { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String execute() throws Exception { if ("supermos".equalsIgnoreCase(username) && "ziwen".equalsIgnoreCase(password)) { // 通过ActionContext对象访问Web应用的Session ActionContext.getContext().getSession().put("user", getUsername()); return SUCCESS; } else { return ERROR; } } // 完成输入校验需要重写的validate方法 public void validate() { // 如果用户名为空,或者用户名为空字符串 if (getUsername() == null || getUsername().trim().equals("")) { // 添加表单校验错误 addFieldError("username", getText("user.required")); } // 如果密码为空,或者用户名为空字符串,添加表单校验错误 if (getPassword() == null || getPassword().trim().equals("")) { // 添加表单校验错误 addFieldError("password", getText("password.required")); } } }
在上面的validate方法中,添加校验错误提示的时候,并不是直接给出了错误的字符串,而是调用了getText方法来获取错误提示.在国际化资源文件中添加这两条提示信息.(ActionSupport增加了让提示信息国际化的能力,ActionSupport提供的getText方法可以根据资源文件加载获得国际化提示信息.)
(2) 使用Struts2的校验框架
上面的方法是通过重写ActionSupport类的validate方法来实现的,这种方法虽然不错,但是需要大量重写validate方法,毕竟重复书写相同的代码不是一件吸引人的事情.
就像Struts1一样,Struts2也允许通过定义配置文件来完成数据的校验,Struts2的校验框架实际上是基于Xwork的validator框架:
下面还是使用原来的Action类(即不重写validate方法),却增加了一个校验配置文件,校验配置文件通过使用Struts2已有的校验器,完成对表单域的校验.Struts2提供了大量的数据校验器,包括表单域校验器和非表单域校验器两种.
本应用主要使用了requiredstring校验器,该校验器是一个必填校验器---指定某个表单域必须输入.
下面是校验规则的定义文件:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd"> <validators> <field name="username"> <field-validator type="requiredstring"> <message key="user.required"/> </field-validator> </field> <field name="password"> <field-validator type="requiredstring"> <message key="password.required"/> </field-validator> </field> </validators>
定义完该校验规则文件之后,该文件的命名应该遵守如下规则:
ActionName-validate.xml:其中ActionName就是需要校验的Action的类名
因此上面的校验规则文件就应该命名为”LoginAction-validate.xml”且,该文件应该与Action类的class文件位于同一个路径下.
当然,在struts.xml文件的Action定义中,一样需要定义input的逻辑视图名,并将input逻辑视图映射到login.jsp表单.
如果不输入用户名,密码而提交表单,将再次看到如图2.14所示的界面.在这种校验方式下,无需书写校验代码,只要通过配置文件配置指定的校验规则就可以了.因此提供了更好的可维护性.
(参考:Struts2权威指南-基于WebWork核心的MVC开发,作者:李刚)
本文介绍了Struts2框架中的程序国际化与数据校验方法,包括定义资源文件、加载资源文件及输出国际化信息等步骤,并详细说明了如何通过重写validate方法及使用Struts2校验框架来进行数据校验。
157

被折叠的 条评论
为什么被折叠?



