Struts的Message Resources
Struts的资源绑定
在使用Struts时,我在我的struts-config.xml中配置了两个资源文件,如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.1//EN" " http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<data-sources />
<form-beans >
<form-bean name="loginForm" type="zy.pro.shd.controller.form.LoginForm" />
</form-beans>
<global-exceptions />
<global-forwards />
<action-mappings >
<action
attribute="loginForm"
input="/web/user/loginForm.jsp"
name="loginForm"
path="/login"
scope="request"
type="zy.pro.shd.controller.action.LoginAction">
<forward name="success" path="/web/user/loginResult.jsp" />
<forward name="failure" path="/web/user/loginResult.jsp" />
</action>
</action-mappings>
<message-resources parameter="zy.pro.shd.res.ApplicationResources_en" />
<message-resources parameter="zy.pro.shd.res.ApplicationResources_en1" />
注意:这样就会出现错误,因为设定了两个默认资源。
</struts-config>
我在我的jsp页面中使用如下方式来访问我的资源文件
<body>
<br>
<a href="web/user/loginForm.jsp" target="_blank">user login </a>
<br>
<bean:message key="user.login"/>
<bean:message key="user.go"/>
<br>
</body>
结果就出现了以下异常:
javax.servlet.ServletException: Missing message for key "a.label"
org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:825)
org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:758)
org.apache.jsp.web.index_jsp._jspService(index_jsp.java:79)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
zy.pro.shd.filter.ChineseFilter.doFilter(ChineseFilter.java:51)
如果我们的资源设置如下:
<message-resources parameter="zy.pro.shd.res.ApplicationResources_en" />
<message-resources key=”res1”
parameter="zy.pro.shd.res.ApplicationResources_en1" />
注意:这样,前者为默认,后者不是。
记住:<message-resources/>配置的是默认资源。如果需要配置多个则需要设置其键值。
如果在程序(如在Action)中要访问另外的资源文件,可以使用如下办法:
Local local=getLocal(request);
MessageResources message=getResources(request,”res1”);
String msg=messages.getMessage(locale,”hello.no.username”);
这样,就可以访问res1中的信息了。
Struts Message Resources
总览
许多刚刚学习Struts的程序员在使用Struts的MessageResources特性的时候会遭遇很多困难。本文将试图阐述MessageResources特性的优点并给出了具体的例子说明它的用法。
作者: Nick Heudecker, System Mobile Inc.
概述
类MessageResources可以使开发者方便地支持多语言,包括支持多时间格式和数字格式。使用资源包的另一个好处是允许开发者将标签字符 串集中存储在一个位置,而不是分散在不同的JSP页面里。例如,对于每个用户的名字的标签"First Name" ,我们可以将它写在资源包中,在适当的地方通过Struts标签简单的进行引用:
<bean:write key="label.first.name"/>
这样做将会让你对程序的更改变的简单容易,你不必在每一个JSP页面里更改标签的内容了。
用法
使用消息资源包需要你做下面的事情:
1. 为你想要支持的地方创建一个消息资源包。
2. 配置WEB应用,加载消息资源包。
3. 使用相应的JSP标签加载资源或者...
4. ...在一个Action类中加载资源。
创建资源包
MessageResources 类的默认的实现是一个包含"key=value" 对的文件,下面的一个消息资源包文件的例子。
label.username=Username
label.password=Password
label.first.name=First Name
label.last.name=Last Name
label.email=Email Address
label.phone.number=Phone Number
label.welcome=Welcome back {0} {1}!
error.min.length=The input must be at least {0} characters in length.
error.max.length=The input cannot be longer than {0} characters in length.
大括号包围的整数是对java.text.MessageFormat 类的支持,程序员可以向value字符串中传递参数,对每个value字符串你最多可以传递4个参数。
配置
有两种途径通知Struts你的资源包的位置:web.xml 文件或者struts-config.xml 文件。首先来看web.xml 文件的配置:
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>
application
</param-name>
<param-value>
com.systemmobile.example.ApplicationResources
</param-value>
</init-param>
</servlet>
这个配置说明你的资源包的名字是ApplicationResources.properties,它位于 com.systemmobile.example 包中。后缀".properties" 是隐含的,你不必显式地写出来。如果你还有另一个资源文件在相同的包中,例如ApplicationResources_fr.properties ,用来支持法语,你只需要象上面定义的那样列出文件名字即可。
定义资源文件的第二中方法(上面已经提到),是在struts-config.xml 文件中配置:
<message-resources parameter="com.systemmobile.example.ApplicationResources"/>
属性parameter 是必须的。和在web.xml文件中配置一样, 需要注意的是文件在包中的位置。
使用struts-config.xml 文件来配置消息资源文件是推荐的做法,因为它更有可扩展性,更灵活。
· 你可以使用message-resources 标签从不同的资源文件取不同的消息,前提是在配置的时候为不同的资源文件给出不同的key 属性的值。例如:
· <message-resources key="myResources" parameter="com.systemmobile.example.
ApplicationResources"/>
<message-resources key="moreResources" parameter="com.systemmobile.example.
MoreApplicationResources"/>
然后你必须这样使用bean:message 标签:
<bean:message bundle="moreResources" key="some.message.key"/>
· 设置属性null 的值为"false" 后,如果某个资源字符串不存在将返回???key??? 而不是仅仅显示null。这样很容易在JSP页面中看到你没有定义的资源,使得内部测试的速度更快。(关于如何从资源文件中获得消息的详细内容参见国际化 一节)
<message-resources parameter="com.systemmobile.example.ApplicationResources" null="false"/>
· 另外,message-resources 标签允许你使用自己实现的MessageResourcesFactory 接口,这不在本文的讨论范围。
资源文件放在哪里
关于资源文件最常见的问题是将资源文件放在WAR文件的哪里。简单的回答是该文件必须放在你的classpath下面,这意味着将资源文件放在一个 JAR 文件中,或者放在/WEB-INF/classes 目录极其子目录下。下表给出了资源文件的位置,在message-resources 标签中"parameter" 属性的值以及简短的说明。
Resources Location
parameter Value
Description
/WEB-INF/classes/ApplicationResources.properties
ApplicationResources
文件放在classes 目录下, 该目录在web应用的classpath中.
/WEB-INF/classes/resources/ApplicationResources.properties
resources.ApplicationResources
该文件放在"resources" 目录下, 所以包名也就是路径名要给出。
In the app.jar file, in the com.systemmobile.example package/directory.
com.systemmobile.example.ApplicationResources
文件在JAR文件中的全路径。
Tags
最常用Struts 标签是bean:message 标签。使用这个标签的"key" 可以从资源文件中读特定的消息资源。你还可以传入四个参数中的一个或全部:
<bean:message key="label.password"/>
<bean:message key="error.min.length" arg0="6"/>
<bean:message key="label.welcome" arg0="Ralph" arg1="Nader"/>
html:message 可以让你向用户显示错误信息(默认)或消息信息,而html:errors 只显示错误信息。很明显,错误信息或消息信息一定要保存在request里,否则就什么也不会显示。这里有一个显示消息信息的例子:
<logic:messagesPresent message="true">
<html:messages id="msg" message="true">
<div class="success">
<bean:write name="msg"/>
</div><br/>
</html:messages>
</logic:messagesPresent>
还有一些标签也有限地支持消息资源,比如html:link。html:link标签通过定义"titleKey" 属性来显示标题文本。许多html 使用 "altKey" 属性从资源文件里获得alternate(替代)文本。
Actions
你还可以在Action 类中使用消息资源文件。Action 类有两个方法得到一个MessageResource 类的实例:
// 返回一个request里的资源文件
protected MessageResources getResources(HttpServletRequest request);
// 返回一个request里的资源文件,
// 该资源文件的标志上<message-resources/> 元素的内容
protected MessageResources getResources(javax.servlet.http.HttpServletRequest request,
java.lang.String key);
MessageResources类可以让你从资源文件中得到本地化的消息。The API for MessageResources 可以在资源中找到。比较常用的方法有:
// these methods load a resources key for the given locale
public String getMessage(java.util.Locale locale, java.lang.String key);
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object arg0);
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object[] args);
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object arg0, java.lang.Object arg1)
public String getMessage(java.util.Locale locale, java.lang.String key,
java.lang.Object arg0, java.lang.Object arg1, java.lang.Object arg2);
public String getMessage(java.util.Locale locale, java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1, java.lang.Object arg2, java.lang.Object arg3);
// these methods load a resources key for the locale retrieved
// from the HttpServletRequest
public String getMessage(java.lang.String key);
public String getMessage(java.lang.String key, java.lang.Object arg0);
public String getMessage(java.lang.String key, java.lang.Object[] args);
public String getMessage(java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1);
public String getMessage(java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1, java.lang.Object arg2);
public String getMessage(java.lang.String key, java.lang.Object arg0,
java.lang.Object arg1, java.lang.Object arg2, java.lang.Object arg3);
这些返回的字符串可以被设置成request 或 session 的参数并串会表现层。你可能注意到了一些重载方法getMessage(...) 选择了参数Object,而另外一些采用了参数arg0...arg3。这和 bean:message arg0...arg3 属性等价。
除了MessageResources 类,还有一些类使用了资源文件。ActionMessage类被用来从action 向JSP之间传递消息资源中的keys 。消息被用来作为bean 的属性。ActionError, ActionMessage的子类,使用消息资源中的keys 存储验证失败后的错误信息。
国际化
从资源文件中提取一个本地化信息可以由类MessageResources 来处理,或者由它的直接子类PropertyMessageResources类处理。既然类PropertyMessageResources 等经常地被用到,那么我们就来看看它是怎样使用getMessage(Locale, String) 方法来从资源文件中读取消息的。
举例说明:
1. 如果你在ApplicationResources_pt_br.properties (Brazilian Portuguese)中没有发现消息的定义,系统将在ApplicationResources_pt.properties 文件中找,如果ApplicationResources_pt.properties 文件不存在或者也没有该消息,那就去ApplicationResources.properties 文件里查找了。
2. 如果消息找到了,它就被加到本地化的缓存中并返回java.lang.String型数据。
3. 如果消息没有找到,此时如果returnNull 属性被为默认的true,将返回 null。 否则将返回类似 ???key??? 的字符串,key 就是那个被传递的参数。
JSTL
JSTL (JavaServer Pages Standard Tag Library) 的fmt标签最近开始流行起来,用来向JSP中显示资源文件的信息。它能很好地和Struts结合在一起。使用它非常简单,只要下载JSTL 的jar 文件和TLDs 并把它们拷贝到你的应用的正确的位置,然后在web.xml文件中加入下面的内容:
<context-param>
<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
<param-value>ApplicationResources</param-value>
</context-param>
上面的配置是假定你的ApplicationResources.properties文件是放在/WEB-INF/classes 目录下的。 参见above 更多情况。
然后将这个标签库直接放在你的JSP中:
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt" %>
最后,下面的标签将显示资源文件的内容:
<fmt:message key="label.first.name"/>
还有一个使用fmt 标签获得资源的例子。(注意: 该段程序取自Jakarta JSTL examples。)
// loading a resource from a specific bundle and populating a parameter
<fmt:message key="currentTime" bundle="${deBundle}">
<fmt:param value="${currentDateString}"/>
</fmt:message>
// using the forEach iterator to populate paramters
<fmt:message key="serverInfo" bundle="${deBundle}">
<c:forEach var="arg" items="${serverInfoArgs}">
<fmt:param value="${arg}"/>
</c:forEach>
</fmt:message>
结论
在向JSP文件方便地传递消息的同时,Struts使用消息资源文件还帮助我们创建国际化的Web应用。我们既可以使用正在快速发展中的JSTL标 签,也可以使用Struts标签,或直接在action中得到一条具体的消息。我希望这篇文章为您阐明了一些Struts中常用的但有时会混淆的东西。
关于作者
Nick Heudecker 是一位软件开发人员,具有6年的企业应用的开发经验。 他所在的公司, System Mobile, Inc.,专门从事应用集成,定制软件开发和无线应用。 他还是Sun认证JAVA程序员,现在居住在Ann Arbor, Michigan。
资源
下面的资源也许对您了解更多的关于Struts资源文件有帮助:
· JavaDoc for the classes of interest:
· java.util.ResourceBundle
· java.util.Locale
· org.apache.struts.util.MessageResources
· org.apache.struts.action.ActionError
· org.apache.struts.action.ActionMessage
· Ted Husted's Struts Tips: Very handy advice, especially for resource bundle usage.
· Struts Home Page
· Struts-User Mailing List Archive: Many people use Struts, so there is a very good chance that your question has be answered already. Please use all available resources before asking your question on the mailing list.
· JSTL Homepage and the Jakarta JSTL Implementation
注意事项 Packages are just directory structures used to avoid naming conflicts. If you put a message bundle in a directory named resources under /WEB-INF/classes, this is the equivalent of putting the file in a package named resrouces. While basic, this point seems to trip up many new programmers.