级别: 初级 Bei Shu (shub@cn.ibm.com), 资深软件工程师, User Technologies, IBM China Software Development Laboratory Xiao Hui Zhu, 软件咨询工程师, User Technologies, IBM China Software Development Laboratory
2006 年 1 月 12 日 本文介绍 Global Business Object(GBO),这种 IBM alphaWorks 技术为全球化应用程序提供了对文化敏感的 GUI 元素的一组 Java™ 库。Shu Bei 和 Zhu Xiao Hui 将帮助您了解 GBO 的体系结构和全球化特性。还详细描述了一个 GBO 组件,从而说明 GBO 如何与基于 Web 的应用程序集成。
如果您计划为全球市场提供软件,那么此软件需要适应和尊重使用它的地区的文化期望。大家都知道,应用程序应该向它的顾客提供友好的全球化的界面。例如,GUI 应该采用用户首选的语言,而且日期、时间、数字和货币值格式也都应该符合用户的文化习惯。
从根本上说,Java 技术为构建全球化应用程序提供了良好的基础。这个基础包括 Unicode 支持、丰富的国际化类以及用于生成单一的且地区敏感的可执行文件的设施。但是,有一类文化敏感功能是 Java 语言或其他现有技术当前还不支持的,而这些功能对于全球化电子商务应用程序又是必不可少的。
缺少的这些功能集中于对文化问题高度敏感的图形控件。例如,用来输入用户名和地址的输入域。这种输入域常常出现在由 J2EE 应用程序生成的 HTML 表单上。这种域的麻烦在于,根据国家的不同,各个数据片段的次序很不一致;例如,在某些国家,一个人的姓氏应该出现在他的名字前面,而在其他地方情况正好相反。图 1 和图 2 说明了这些域需要以何种方式适应不同的地区:
图 1. 姓名格式在地区之间很不一致
图 2. 地址格式在地区之间很不一致
另一种通常会出现同样问题的图形控件是弹出式日历:根据国家的不同,每周的第一天和周末的表示方式也不一样,如图 3 所示:
图 3. 日历格式在地区之间很不一致
当前,开发人员必须手工修改代码来解决这种差异。这种情况常常导致复杂的代码,这些代码存在 bug 的可能性很大而且不一致。清单 1 给出了开发人员为了提供文化敏感的地址表单通常会采用的逻辑:
清单 1. 实现文化敏感的地址表单的传统方法
if (UserLocale == "en_US"){
render(street_address);
render(city);
render(state);
render(zipcode);
render(country);
}else if ( UserLocale == "zh_CN"){
render(country);
render(province);
render(city);
render(street_address);
render(zipcode);
} else if (UserLocale == "de_DE") {
...
} else if ...
render(street_address) {
...}
render(City) {
...}
...
|
无论程序员花多大的工夫来研究每个国家的文化习惯,这样的代码都会包含许多重复的内容,而且如果需要进行任何修改(比如添加一种新语言),都不可避免地需要修改和重新编译应用程序。
我们需要一种机制,能够将这种逻辑从应用程序主代码中分离出来。程序员需要一组可重用的库,帮助他们轻松且快速地使图形控件能够根据最终用户的文化调整表示形式。
GBO 来帮忙了
Global Business Object(GBO)是一种 IBM alphaWorks 技术,提供了一组用于构造感知文化的图形控件的库。GBO 使用了 JavaServer Pages(JSP)和 JavaServer Faces(JSF)技术。通过将功能封装在一个可重用的全球化标记库中,GBO 向程序员提供了一种机制,让他们能够方便地在 JSP 文件中创建全球化 GUI 功能。
GBO 的标记可以显示 HTML 表单中输入的姓名或地址,使这些数据的输入域、标签和次序符合用户的文化期望。GBO 的标记还可以显示弹出式日历窗口,其中的每周首日和周末符合用户的文化习惯。
清单 2 给出了一个 GBO name 标记的例子:
清单 2. GBO name 标记的例子
<gbo:nameInput id="test"
value="#{NameModel}"
language="#{NameInfo.language}"
locale="#{NameInfo.locale}"
template="N001"
validateInput="true"/> |
当 NameInfo.locale 等于 en_US 时,编译此标记会导致清单 3 所示的输出:
清单 3. 对于 U.S.-English 地区,清单 2 中 name 标记的输出
<TABLE border="0"> <TBODY> <TR> <TD> <LABEL for="_id0:test:7">Honorific</LABEL>
</TD> <TD> <SELECT id="_id0:test:7" name="_id0:test:7" > <option > Mr.</option>
<option > Mrs.</option> <option > Ms.</option> <option > Dr.</option> </SELECT>
</TD> </TR> <TR> <TD> <LABEL for="_id0:test:0"><img
src="/gbo/gboresources/requiredSmall.gif" alt="Required Field" title="Required
Field"/> First Name</LABEL> </TD> <TD> <INPUT type="text" name="_id0:test:0"
id="_id0:test:0" value="" size="25" > </TD> </TR> <TR> <TD> <LABEL
for="_id0:test:1">Middle Name</LABEL> </TD> <TD> <INPUT type="text"
name="_id0:test:1" id="_id0:test:1" value="" size="25" > </TD> </TR> <TR> <TD>
<LABEL for="_id0:test:2"><img src="/gbo/gboresources/requiredSmall.gif"
alt="Required Field" title="Required Field"/> Last Name</LABEL> </TD> <TD>
<INPUT type="text" name="_id0:test:2" id="_id0:test:2" value="" size="25" >
</TD> </TR> </TBODY></TABLE> |
最终用户现在会在浏览器中看到英文的 Name 控件,如图 4 所示:
图 4. U.S.-English 地区的 Name 控件
当 NameInfo.locale 等于 zh_CN 时,编译清单 2 中的标记会导致清单 4 所示的输出:
清单 4. 对于中国地区,清单 2 中 name 标记的输出
<TABLE border="0"> <TBODY> <TR> <TD> <LABEL for="_id0:test:2"><img
src="/gbo/gboresources/requiredSmall.gif" alt="该项是必填项"
title="该项是必填项"/> 姓氏</LABEL> </TD> <TD> <INPUT type="text"
name="_id0:test:2" id="_id0:test:2" value="" size="15" > </TD> </TR> <TR> <TD>
<LABEL for="_id0:test:0"><img src="/gbo/gboresources/requiredSmall.gif"
alt="该项是必填项" title="该项是必填项"/> 名字</LABEL> </TD> <TD> <INPUT
type="text" name="_id0:test:0" id="_id0:test:0" value="" size="15" > </TD> </TR>
<TR> <TD> <LABEL for="_id0:test:7">尊称</LABEL> </TD> <TD> <SELECT
id="_id0:test:7" name="_id0:test:7" > <option Selected> </option> <option >
先生</option> <option > 女士</option> <option > 小姐</option> <option >
博士</option> </SELECT></TD> </TR> </TBODY></TABLE> |
最终用户现在会在浏览器中看到中文的 Name 控件,如图 5 所示:
图 5. 中国地区的 Name 控件
使用 GBO,开发人员不再需要从头开发这样的文化敏感代码。另外,GBO 允许程序员对图形控件的显示进行定制以匹配整个页面的 UI 风格,并提供了丰富的选项来增强 GBO 特性的可用性。
GBO 体系结构
GBO 将全球化数据从应用程序业务逻辑中分离出来。为了创建文化敏感的交互式 GUI 控件,GBO 使用了三层,将地区数据、用户数据以及依赖于应用程序的 UI 布局分离开来:
-
存储库层 存储文化敏感功能所需的地区数据。
-
逻辑层 对地区数据进行解析来处理应用程序用户数据,并生成与 UI 无关的中间结果。
-
表示层 获取中间结果并用一个可定制的模板解释它,从而显示最终输出。
图 6 展示了 GBO 体系结构:
图 6. GBO 体系结构
这种体系结构的主要组成部分如下:
-
应用程序控制台: 最终用户通过这个应用程序用户界面与应用程序进行交互。
-
地区 ID: 不同地区的标识符,比如
en_US、zh_CN 或 fr_FR。
-
用户数据: 最终用户输入的应用程序数据。这些数据与文化数据和布局数据结合在一起,在应用程序控制台中生成全球化输出。这些数据可能包括最终用户输入的姓名数据、地址数据或当前日期和时间。
-
CDR(culture data repository,文化数据存储库): 存储文化敏感功能所需数据的存储库,这些数据包括不同地区的姓名标签、次序、域和日期或时间模式。这个存储库按照地区进行组织;所以,在添加一个新地区时,只需复制一个文化的数据定义并为相同结构创建另一个定义。
-
CDD(culture data descriptor,文化数据描述符): 一个文件或数据对象,它以 GBO 可以处理的格式描述一个地区的文化数据。
-
UDD(user data descriptor,用户数据描述符): 一个文件或数据对象,它以 GBO 可以处理的格式描述用户和文化数据。
-
TR(template repository,模板存储库): 存储各种模板的存储库,这些模板定义布局信息来显示 UDD,例如垂直或水平布局、宽度和长度、字体和样式。每个模板定义一种布局。有许多预先编写好的模板,程序员也可以定制和创建模板。
-
CSAO(culturally sensitive application output,文化敏感的应用程序输出): GBO 的文化敏感输出,它结合了用户数据、文化数据和布局数据。应用程序控制台使用 CSAO 生成显示给最终用户的最终结果。
如果想在自己的代码中调用 GBO,可以使用以下过程:
- 客户机用它们的首选地区向应用程序控制台发出请求。应用程序控制台通过调用表示层的 API 来调用 GBO。
- 表示层将地区 ID 和用户数据传递给逻辑层。
- 逻辑层将地区 ID 传递给存储库层。
- 存储库层访问 CDR 来获取对应的文化数据定义。
- 存储库层将文化数据定义组合成 CDD 并返回给逻辑层。
- 逻辑层用用户数据处理 CDD,形成 UDD 并返回给表示层。
- 表示层处理 UDD,根据模板 ID 从 TR 选择模板,形成 CSAO 并返回给应用程序控制台。
- 应用程序控制台获取 CSAO,将它与控制台内容的其余部分结合在一起,然后返回给客户机。
当前,GBO 包含五个全球化控件:Name(姓名)、Address(地址)、Pop-up Calendar(弹出式日历)、Date Chooser(日期选择器)和 Time Chooser(时间选择器)。详细讨论所有这些控件超出了本文的范围。但是,在本文的其余部分中,我们将集中讨论一个组件 —— Name 控件,详细了解它的工作方式。这可以使您理解如何将 GBO 组件集成到应用程序中。如果想更多地了解其他组件,请参考 参考资料 中的链接。
Name 控件
在不同的国家,人名的各个组成部分的次序和标签是不一样的,人名上使用的尊称也不一样。GBO name 标记生成一个文化敏感的姓名输入控件(这个控件由一个输入表单组成,用户可以在表单上输入并编辑他们的姓名信息)和一个文化敏感的姓名输出控件(它只在表中显示姓名)。在不同语言和地区之间姓名输入控件的行为是不一样的,这些差异表现在可应用的姓名域、这些域的标签和次序以及尊称方面。图 7 给出了不同地区中 Name 控件的一些例子:
图 7. 不同地区中的 GBO Name 控件
在使用 Name 控件时,除了基本的外观和感觉之外,应用程序常常需要进行其他定制。例如,可能希望改变布局、使用另一种风格或者删除某些域。GBO 允许对布局(水平或垂直排列)、风格(改变字体、颜色、背景等等)和姓名模式(例如,使用完整的、长的或短的输入域版本)进行各种定制。通过使用标记属性指定模式、布局和 HTML 风格属性,可以对姓名输入控件的外观和感觉进行调整,使它与所在的 Web 页面保持一致。图 8 和图 9 给出了例子:
图 8. 水平的姓名布局,标签在上面
图 9. 模式属性设置为 SHORT 的 Name 控件
在默认情况下,Name 控件中的风格符合整个页面的风格。但是,开发人员可以根据自己的特殊需要针对每个 HTML 元素改变风格,如图 10 所示:
图 10. 具有定制风格的 Name 控件
另外,GBO 提供了有效性检验功能并可以将错误消息回显给用户。一些标记属性可以将某些域定义为必填项并启用错误消息机制。
图 11. 输入的有效性检验
关键概念
现在,您已经看到了 Name 控件的表现。那么,它是如何工作的呢?在本节中,我们将讨论它背后的一些关键概念。这些概念很多也适用于其他 GBO 组件。
模板
模板 是一种机制,GBO 使用这种机制管理输出布局。真实的应用程序对于姓名输入表单的布局有各种各样的需求。为了支持这些需求,GBO 将组件的布局从它的行为中分离出来。它利用了一个标准的 HTML 文件,其中包含一个 GBO 占位符。在运行时,GBO 元素会替换这个占位符。所以,用户可以以简单且标准的方式定义布局。GBO 还提供了几种预定义的模板。
例如,清单 5 和清单 6 包含两个用于 Name 组件的预定义模板(N001 和 N002)。图 12 和图 13 显示了这些模板在 Web 浏览器中的样子:
清单 5. N001 模板的定义
<TABLE border="0">
<TBODY>
<TR>
<TD>_GBONAMELABEL:0</TD>
<TD>_GBONAMEINPUT:0</TD>
</TR>
<TR>
<TD>_GBONAMELABEL:1</TD>
<TD>_GBONAMEINPUT:1</TD>
</TR>
...
<TR>
<TD>_GBONAMELABEL:5</TD>
<TD>_GBONAMEINPUT:5</TD>
</TR>
</TBODY>
</TABLE>
|
图 12. N001 模板的输出示例
清单 6. N002 模板的定义
<TABLE border="0">
<TBODY>
<TR>
<TD>_GBONAMELABEL:0</TD> <TD>_GBONAMELABEL:1</TD>
...
<TD>_GBONAMELABEL:2</TD> <TD>_GBONAMELABEL:3</TD>
<TD>_GBONAMELABEL:4</TD> <TD>_GBONAMELABEL:5</TD>
</TR>
<TR>
<TD>_GBONAMEINPUT:0</TD> <TD>_GBONAMEINPUT:1</TD>
...
<TD>_GBONAMEINPUT:2</TD> <TD>_GBONAMEINPUT:3</TD>
<TD>_GBONAMEINPUT:4</TD> <TD>_GBONAMEINPUT:5</TD>
</TR>
</TBODY>
</TABLE>
|
图 13. N002 模板的输出示例
模式
即使是在单一地区中,也可能希望根据不同情况以不同方式表示姓名。例如,您可以有一个完整的姓名,包括尊称头衔、名、中间名和姓氏。还可以有姓名的短版本,只包括名和姓氏。在 GBO 中,姓名的不同表示方式被抽象成模式(pattern) 的概念。有四种可能的模式:full、long、medium 和 short。full 模式包括所有姓名域,其他模式有不同程度的省略。但是,每个模式的具体内容由地区决定。
表 1 说明了这一概念,其中显示了针对 en_US 地区的四种姓名模式:
表 1. 不同的姓名模式
| Full |
|
|---|
| Long |
|
|---|
| Medium |
|
|---|
| Short |
|
|---|
name 标记
name 标记生成 GBO Name 组件。它包括一个输入 模式(mode)和一个输出 模式。
name 标记的输入模式生成一个表格,用户可以在其中输入姓名。在这种模式中,姓名标签由使用的语言决定,姓名域的次序和尊称列表由地区决定。
姓名输入模式的标记是 <gbo:nameInput>。下面是一个例子:
<gbo:nameInput value="#{user1}" language="en" locale="en_US"/>
|
属性 value=#{user1} 将这个姓名输入组件指向一个托管 bean,这个 bean 代表数据模型。本文后面将更详细地讨论这个特性。
图 14 显示了姓名输入标记在 Web 页面上的样子:
图 14. 姓名输入标记
name 标记的输出模式使用文本生成一个姓名输出表格。在这种模式中,姓名标签由语言决定(和输入模式一样);域的次序由输入姓名内容的地区决定。
姓名输出模式的标记是 <gbo:nameOutput>。下面是一个例子:
<gbo:nameOutput value="#{user1}" language="en"/>
|
图 15 显示了姓名输出标记在 Web 页面上的样子。在这里,假设 value 属性指向一个现有的姓名数据模型,其中包含 John F. Kennedy 的数据:
图 15. 姓名输出标记
基本标记属性
在本节中,我们将研究 GBO Name 组件的基本属性。利用这些属性,可以很容易地在页面上建立 GBO Name 组件。这些属性既可以应用于输入标记,也可以应用于输出标记,但是 locale 属性例外:
-
language:这个属性指定组件的显示语言。它影响标签的语言。可接受的值是 ISO Language ID,比如 en 和 ar。
-
pattern:这个属性指定 Name 组件的输出模式。前面提到过,模式决定应该在客户机上显示哪些域。这个属性接受以下值之一:FULL、LONG、MEDIUM 或 SHORT。
-
template:这个属性指定输出布局的模板。这个属性可以接受一个预定义模板的名称,从 N001 到 N008。它还可以接受用户定义的模板文件的有效相对路径,比如 \usrtempl\mytempl.htm。
-
value:这个属性指定这个组件的托管 bean。这个 bean 的内容将由这个 Name 组件显示和更新。它接受 JSF 表达式,比如 #{user1}。
-
locale:这个属性指定组件的内容地区。它影响姓名输入组件的次序和模式。可以接受的值是 ISO language ID,比如 en 或 ar。locale 属性只能 应用于姓名输入标记,因为它将用作姓名模型的初始地区设置。因为姓名输出标记用于显示现有的姓名模型,所以 GBO 姓名输出标记将使用模型中的地区,而不需要用户在标记中显式地设置地区。
表 2 给出了这些标记属性的一些例子:
表 2. 基本 name 标记属性示例
| <gbo:nameInput language="en_US" locale="zh_CN" pattern="full" template="N001" value="#{User.name}" /> |
|---|
这个标记将生成一个采用输入模式的 Name 组件,语言设置为 English,地区设置为 zh_CN,采用 FULL 模式和预定义的模板 N001。value="#{User.name} 表示用户输入的数据将填充到后端模型 #{User.name} 中(这是一个 JSF 托管 bean)。 | | <gbo:nameInput language="en_US" locale="zh_CN" pattern="full" template="N001" value="#{User.name}" validateInput="true" trailingColon="true" mandatorySymbol="/img/mymandatorySymbol.gif" allowSpaceSymbol="/img/myAllowSpaceSymbol.gif" errorSymbol="/img/myErrorSymbol.gif"
inputFieldLength="10" classLabel="myLabelStyle" classInput="myInputStyle" classSelect="mySelectStyle" /> |
|---|
| 这个标记使用与第一个标记相同的基本属性值;另外,还添加了许多其他属性来控制这个姓名输入组件的外观和感觉。我们将在本文后面的几节中详细讨论这些属性。
| | <gbo:nameOutput language="en_US" pattern="full" template="N001" value="#{User.name}" /> |
|---|
这个标记将生成一个采用输出模式的 Name 组件,语言设置为 English,使用 FULL 模式和 N001 预定义模板。value="#{User.name}" 表示用户输入的数据将填充到后端模型 #{User.name} 中(这是一个 JSF 托管 bean)。这个标记的属性基本上与第一个标记一样。惟一的区别是 nameOutput 标记没有 locale 属性,因为输出标记将使用模型的地区作为自己的地区。
| | <gbo:nameOutput language="en_US" pattern="full" temlate="N001" value="#{User.name}" trailingColon="true" mandatorySymbol="/img/mymandatorySymbol.gif" allowSpaceSymbol="/img/myAllowSpaceSymbol.gif" errorSymbol="/img/myErrorSymbol.gif" classLabel="myLabelStyle" classOutputValue="myOutputValueStyle" /> |
|---|
与第二个 nameInput 标记示例相似,这个 nameOutput 标记使用了基本属性之外的许多其他属性,以便以更精确的方式控制组件的外观和感觉。我们将在后面的几节中介绍这些属性。 |

 |

|
给示例应用程序添加 GBO Name 控件
现在,我们构建一个包含 GBO Name 控件的简单页面,以此展示如何在实践中使用 GBO。在这个例子中,将使用 Rational Application Developer(RAD)作为开发环境,以 WebSphere Application Server 6.0 作为运行时环境,但是这里展示的基本技术应该可以应用于任何开发设置。
步骤 1:设置环境
首先,在 RAD 的 Web 透视图中创建一个新的 Dynamic Web Project,如图 16 所示:
图 16. 创建 Dynamic Web Project
接下来,输入 GBODemo 作为 Web 项目的名称并单击 Next,如图 17 所示:
图 17. 指定项目名
对于这个项目,接受默认的特性列表,如图 18 所示:
图 18. 选择特性
对于这个站点,我们不使用 RAD 模板,所以只需单击 Finish:
图 19. 结束向导
现在,已经在工作区中创建了一个新的 Web 项目,如图 20 所示:
图 20. 新创建的项目
我们需要将 GBO 库导入项目中。需要的所有文件都可以在项目的 alphaWorks 站点上找到(参见 参考资料)。首先,将 gbo.jar 和 GBO_2.0_lib.jar 复制到 WebContent\WEB-INF\lib 中。还需要将 gboresources 目录复制到 WebContent 目录中。项目目录结构应该像图 21 这样:
图 21. 复制 GBO 资源和库
接下来,修改 web.xml,在其中插入清单 7 中的代码。这包括所需的 GBO 配置资源:
清单 7. 添加到 web.xml 中的代码
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>com.ibm.sgl.gbo.faces.filter.CharacterEncodingFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>GBOServlet</servlet-name>
<servlet-class>
com.ibm.sgl.gbo.servlet.GBOServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>AddressServlet</servlet-name>
<servlet-class>
com.ibm.sgl.gbo.servlet.AddressServlet
</servlet-class>
</servlet>
|
我们已经成功地将 GBO 基础设施导入到了项目中。GBO 已经可以使用了!
步骤 2:创建 Faces JSP 文件
接下来,需要在 RAD 中创建一个 Faces JSP 文件,如图 22 所示:
图 22. 创建新的 Faces JSP
将这个 JSP 命名为 namedemo.jsp 并保持所有其他参数为默认值,如图 23 所示:
图 23. 为 JSP 起名字
为了让页面能够显示多语言内容,需要将默认的内容类型改为 UTF-8,如图 24 所示:
图 24. 修改内容类型以支持 UTF-8 编码
现在,可以用以下代码行将 GBO 的标记库导入这个页面中(见图 25):
<%@ taglib uri="http://ut.cn.ibm.com/gbo" prefix="gbo"%>
|
图 25. 导入 GBO 标记库
导入标记库之后,就可以在这个页面中用前缀 gbo 引用 GBO 标记。
步骤 3:在 faces-config.xml 中创建托管 bean
与大多数 JSF 组件相似,GBO 组件也与一个后端数据模型相关联。在使用 Name 组件之前,先为它定义一个托管 bean。在 WebContent\WEB-INF 目录中的 faces-config.xml 文件中插入以下代码行,如清单 8 和图 26 所示:
清单 8. 添加托管 bean
<managed-bean>
<managed-bean-name>user1</managed-bean-name>
<managed-bean-class>com.ibm.sgl.gbo.model.NameModel</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
|
图 26. 定义托管 bean
这个托管 bean 名为 user1。它的类是 com.ibm.sgl.gbo.model.NameModel。GBO Name 组件使用这个模型对象来更新用户输入数据
。现在,可以在页面中使用 GBO name 标记了。
在真实的应用程序中,用户数据一般会被持久存储到关系型数据库中。GBO 为此提供了两种方式。一种是将模型对象直接串行化到一个数据库字段中,以后检索时再从数据库中将它解串行化出来。这种方法很容易使用,但是有一个严重的缺点:数据在数据库中存储为不可阅读的字节形式,所以用户无法从数据库中查询数据的片段,比如某人的名字。用户需要先将对象从数据库中读出来,然后再查看它的内容。
所以,GBO 还为满足这种需求提供了另一种解决方案。GBO 模型有一个被覆盖的方法 NameModel getModel(),这个方法可以将对象转换为纯文本字符串。用户可以将这个字符串直接存储在数据库字段中。GBO 模型还有另一个方法 void setModel(String),这个方法将字符串转换为模型对象。例如,假设已经通过 GBO Name 组件输入了一个英文姓名 “John F. Kennedy”。在用户提交这一数据之后,getModel() 返回以下字符串:
LANGUAGE:en_US;LOCALE:en_US;2:Kennedy;1:F.;0:John;
|
开发人员可以将这个字符串存储到数据库字段中,以后检索时将它传递给 setModel() 方法;这样,就会构造出一个完全一样的模型实例。按照这种方式,用户可以在数据库中存储纯文本字段,而不是存储串行化的 Object。因此,可以对这个字符串执行查询。
步骤 4:插入 GBO name 标记
现在,我们在页面中添加一个 GBO name 输入标记,并使用 en 作为语言,使用 en_US 作为地区。还将把这个标记的值绑定到 user1,也就是我们在 faces-config.xml 中定义的托管 bean。清单 9 中完成了这个步骤:
清单 9. namedemo.jsp
<f:view >
<BODY>
<hx:scriptCollector id="scriptCollector1">
<h:form styleClass="form" id="form1">
<%
////////////////////////////////////////////////////
//These two lines are added only for demonstration,
//In a real app, a locale attribute should be set for
//current user before enter this page
request.setAttribute("curLocale","en_US");
request.setAttribute("curLanguage","en");
/////////////////////////////////////////////////////
String curLocale = (String)request.getAttribute("curLocale");
String curLanguage = (String)request.getAttribute("curLanguage");
%>
<gbo:nameInput value="#{user1}" template="N001" pattern="FULL"
language="<%=curLanguage%>" locale="<%=curLocale%>" />
</h:form>
</hx:scriptCollector>
</BODY>
</f:view>
|
将清单 9 中的代码保存为 namedemo.jsp。接下来,需要在服务器上运行这个 JSP,如图 27 所示。
图 27. 对页面进行测试
我们选择 WebSphere 6.0 作为服务器,如图 28 所示:
图 28. 手工定义服务器
保留所有默认值,如图 29 所示:
图 29. 完成定义服务器的过程
服务器一旦启动,就会在 RAD 中打开一个浏览器,如图 30 所示:
图 30. namedemo.jsp 的结果
步骤 5:使页面更具交互性
在真实的应用程序中,可能会使用姓名输入组件来收集用户数据,然后用姓名输出组件来显示它。现在,我们来实现这种最常见的场景。按照清单 10 编辑 namedemo.jsp:
清单 10. 修改后的 namedemo.jsp
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<%-- jsf:pagecode language="java"
location="/JavaSource/pagecode/Namedemo.java" --%><%-- /jsf:pagecode --%>
<HTML>
<HEAD>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://ut.cn.ibm.com/gbo" prefix="gbo"%>
<%@taglib uri="http://www.ibm.com/jsf/html_extended" prefix="hx"%>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="ISO-8859-1"%>
<%@ page import="com.ibm.sgl.gbo.model.*" %>
</HEAD>
<f:view >
<BODY>
<hx:scriptCollector id="scriptCollector1">
<h:form styleClass="form" id="form1">
<%
////////////////////////////////////////////////////
//These two lines are added only for demonstration,
//In a real app, a locale attribute should be set for
//current user before enter this page
request.setAttribute("curLocale","en_US");
request.setAttribute("curLanguage","en");
/////////////////////////////////////////////////////
String curLocale = (String)request.getAttribute("curLocale");
String curLanguage = (String)request.getAttribute("curLanguage");
%>
<gbo:nameInput value="#{user1}" pattern="FULL"
language="<%=curLanguage%>" locale="<%=curLocale%>" />
<gbo:nameOutput value="#{user1}" template="N001" pattern="FULL"
language="<%=curLanguage%>" />
<hx:commandExButton type="submit" value="Submit"
styleClass="commandExButton" id="button1"></hx:commandExButton>
</h:form>
</hx:scriptCollector>
</BODY>
</f:view>
</HTML>
|
此代码定义一个表单,其中包含一个 nameInput、一个 nameOutput 和一个 Submit 按钮。注意,nameOutput 也与托管 bean user1 相关联。所以,每当用户在 nameInput 中输入数据并单击 Submit 按钮时,nameOutput 会自动更新,如图 31 所示:
图 31. 交互式 namedemo.jsp
步骤 6:对用户输入进行有效性检验
GBO Name 组件支持对用户输入进行有效性检验。GBO 姓名输入控件可以检验两种基本属性:它可以进行检查以确保必填域已经填写了,还可以检查一个域是否可以接受包含空格字符的文本。如果打开了有效性检验(在默认情况下是关闭的),GBO 会检查每个域,查看必填域是否是空的,或者在要求没有空格字符的域中是否有空格字符。如果有效性检验失败,就不会更新数据模型。输入表单上会显示一个错误符号和消息。
为了打开有效性检验,需要将 nameInput 标记的 validateInput 属性设置为 true。为了看到有效性检验的效果,我们将按照清单 11 修改 namedemo.jsp:
清单 11. namedemo.jsp 的已修改部分
...
<f:view >
...
<gbo:nameInput value="#{user1}" template="N001"
pattern="FULL" validateInput="true"
language="<%=curLanguage%>" locale="<%=curLocale%>" />
...
</f:view>
...
|
修改后的页面看起来与以前一样。但是,如果忽略了一个必填域(前面有红色 * 符号的域)并单击 Submit 按钮,则会收到一个错误消息,如图 32 所示:
图 32. 必填域上出现有效性检验错误
步骤 7:改为另一个地区和语言
当页面包含多个 Name 组件时,只需针对文档根指定地区一次;所有 GBO 组件就会随着这一修改而变化。在清单 12 中,我们将 namedemo.jsp 的地区改为 zh_CN:
清单 12. namedemo.jsp 的根地区被改为 zh_CN
<HTML>
<HEAD>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://ut.cn.ibm.com/gbo" prefix="gbo"%>
<%@taglib uri="http://www.ibm.com/jsf/html_extended" prefix="hx"%>
<%@taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="ISO-8859-1"%>
...HTML Head...
</HEAD>
<f:view locale="zh_CN">
<BODY>
<h:form styleClass="form" id="form1">
<gbo:nameInput value="#{user1}" template="N001" pattern="FULL"
language="zh" />
<gbo:nameOutput value="#{user1}" template="N001" pattern="FULL"
language="zh" />
<hx:commandExButton type="submit" value="Submit"
styleClass="commandExButton" id="button1"></hx:commandExButton>
</h:form>
</BODY>
</f:view>
</HTML>
|
注意,nameInput 标记中删除了 locale 属性。但是在 <f:view> 中添加了 locale="zh_CN"。对于 <f:view>,locale 属性不能是 <%=curLocale%> 这样的运行时表达式。但是,可以使用 #{User.locale} 这样的 JSF 表达式。然而,在这里,我们只使用静态的设置。图 33 显示修改后的页面:
图 33. 修改后的 namedemo.jsp 的结果
步骤 8:应用其他定制
通过组合姓名输入和输出标记的不同属性,可以实现不同的外观和行为。为此,我们修改 namedemo.jsp 来演示不同的属性设置。修改的属性的意义是一目了然的。
首先,将模板设置为 N002,如清单 13 和图 34 所示:
清单 13. 将模板设置为 N002
<gbo:nameInput value="#{user1}" template="N002"
pattern="FULL" language="<%=curLanguage%>" locale="<%=curLocale%> />
|
图 34. 将模板设置为 N002
接下来,将姓名模式设置为 SHORT,如清单 14 和图 35 所示:
清单 14. 将模式设置为 SHORT
<gbo:nameInput value="#{user1}" template="N001" pattern="SHORT"
language="<%=curLanguage%>" locale="<%=curLocale%> />
|
图 35. 将模式设置为 SHORT
在清单 15 和图 36 中,我们将必填符号(红色的 *)从姓名输入表单中去掉了。如果关闭了输入有效性检验,那么可以采用这种设置:
清单 15. 省略必填符号
<gbo:nameInput value="#{user1}" template="N001" pattern="FULL"
language="<%=curLanguage%>" locale="<%=curLocale%>
displayMandatorySymbol="false"/>
|
图 36. 省略必填符号
更多的标记属性
在 基本标记属性 一节中,已经看到了基本 GBO 功能所需的标记属性。Name 控件还提供了一组属性来控制它的外观和行为。尽管我们没有时间详细讨论所有这些属性,但是下面的列表可以让您体会一下 GBO 提供的功能和定制能力:
-
validateInput:这个属性指定组件是否应该对用户输入进行有效性检验。它的值可以是 true 或 false。
-
inputFieldLength:这个属性指定姓名输入组件的一个输入域的长度。值可以是任何正整数。
-
mandatorySymbol:这个属性指定用来表示必填域的符号的图像路径;这个图像会插入到这个域的标签前面。值应该是指向图像的路径字符串,比如 \img\symbol.gif。
-
displayMandatorySymbol:这个属性指定是否应该在域前面显示表示必填域的符号。它的值可以是 true 或 false。
-
allowSpaceSymbol:这个属性指定用来表示域是否允许空格的符号。这个图像会插入到这个域的标签前面。它的值应该是指向图像的路径字符串,比如 \img\symbol.gif。
-
displayAllowSpaceSymbol:这个属性指定是否应该在域前面显示表示域是否允许空格的符号。它的值可以是 true 或 false。
-
errorSymbol:这个属性指定当输入到域中的数据造成错误时显示的符号的文件。这个图像会插入到这个域的标签前面。值应该是指向图像的路径字符串,比如 \img\symbol.gif。
-
styleInput:这个属性指定姓名输入组件的输入域 CSS 样式。值应该是 CSS 样式表达式,比如 color:red,font-size:18px。
-
classInput:这个属性指定姓名输入组件的输入域 CSS 样式类名。值应该是一个 CSS 类名,比如 mystyle,这要求页面已经定义了具有这个名字的 CSS 样式。
-
styleLabel:这个属性指定标签的 CSS 样式。值应该是 CSS 样式表达式,比如 color:red,font-size:18px.
-
classLabel:这个属性指定标签的 CSS 样式类名。值应该是一个 CSS 类名,比如 mystyle,这要求页面已经定义了具有这个名字的 CSS 样式。
-
styleSelect:这个属性指定姓名输入组件的选中组件 CSS 样式。
-
classSelect:这个属性指定姓名输入组件的选中组件 CSS 样式类名。值应该是一个 CSS 类名,比如 mystyle,这要求页面已经定义了具有这个名字的 CSS 样式。
-
trailingColon:这个属性指定是否应该在表单标签的末尾加上冒号。它的值应该是 true 或 false。

 |

|
结束语
在本文中,您了解了文化的多样性,在开发面向全球顾客的应用程序时应该注意这些问题。还看到了 GBO 如何帮助开发人员创建文化敏感的用户控件,使他们不必研究所有目标市场的文化习惯并为每种文化从头编写代码。看到了在实践中如何实现 GBO Name 控件,这使您对 GBO 的总体工作方式有所体会。
如果您打算了解开发 GBO 代码的细节,请参考 参考资料 中给出的 GBO Developer's Guide。
致谢
感谢浙江大学的 Fei Jia,他为有关 GBO Name 控件的各节提供了帮助。
参考资料 学习
获得产品和技术
讨论
作者简介  | 
|  | Shu Bei 是位于上海的 IBM 中国软件开发实验室的用户技术组的资深软件工程师。她在上海交通大学获得计算机科学硕士学位。Shu 女士于 2001 年加入 IBM 并在 2003 年开始领导 GBO 项目。她从事过各种全球化解决方案和集成项目。 |
 | |  | Zhu Xiao Hui 是位于上海的 IBM 中国软件开发实验室的用户技术组的软件咨询工程师。她从事过各种全球化项目,包括翻译协调、全球化解决方案、全球化测试、GB18030 一致性和全球化集成。Zhu 女士在 IBM 的主要工作集中于全球化技术。 |
对本文的评价
|