本文描述并举例说明了如何利用 Jakarta Struts Framework(已并入 IBM Struts Portlet Framework)来开发和部署一个作为 Portlet 运行在 IBM WebSphere Portal V5 中的的应用程序。
引言
本文讨论了如何利用 Struts Portlet Framework 来实现一个为 IBM WebSphere Portal Version 5(以下称为 WebSphere Portal)编写的 Portlet。Struts 是一个 Apache Jakarta 项目,它为创建 Web 应用程序提供了一个非常流行的开放源码框架。WebSphere Portal V5.0 提供了 Struts Portlet Framework 来支持把 Struts 应用程序作为 Portlet 部署。Struts Portlet Framework 还支持 Struts 应用程序中的 Portal 模式和设备。
如果您阅读了前面我们描述利用状态模式来实现 Portlet 的文章,您将熟悉本文使用的示例应用程序。它遵循相同的设计原理,不过这里是使用 Struts 来进行开发和部署。这个应用程序维护一个特定于登录到 Portal 的用户的联系人列表(地址本条目)。联系人列表存储在数据库或内存中。用户可以个别地查看列表中的联系人以了解更详细的信息。Portlet 的编辑模式允许用户添加、删除或修改联系人信息。
本文的重点不在于开发一个 Struts Web 应用程序;而在于开发一个作为 Portlet 的 Struts 应用程序所需的的实现和配置。您可以了解到如何利用 Jakarta Struts Framework(已并入 IBM Struts Portlet Framework)来创建一个 Portlet。在 WebSphere Portal V5 中,Struts Portlet Framework 附带了 Jakarta Struts 1.1.0。
在示例应用程序的开发和部署中用到了下列产品:
- IBM WebSphere Portal Server Version 5.0
- IBM WebSphere Application Server Version 5
- 一个用于保存联系人条目的数据库(可选)
- IBM WebSphere Studio Version 5 (可选)
关于示例 Portlet 应用程序
示例应用程序实现了对一组持久性数据的 Create/Read/Update/Delete(CRUD) 操作。它维护了特定用户的联系人列表(例如简单的地址本)。这个应用程序允许用户个别地查看联系人条目或查看一个列表中的联系人条目。
从视觉的角度来看,联系人列表应用程序的实现包括如下视图(页面):
- 登录视图(Login view)—— 显示用户登录的视图。
- 主视图(Main view)—— 显示联系人列表并带有选项来选择联系人以查看更多的信息。
- 详细视图(Detail view)—— 显示选定的联系人的详细信息。
- 主编辑视图(Main edit view)—— 显示联系人列表并带有选项来添加、删除和修改联系人信息。
- 添加联系人视图(Add contact view)—— 显示表单视图来输入新联系人的信息。
- 修改联系人视图(Modify contact view)—— 显示表单视图来展示现有的联系人的元素数据并允许更新。
这个应用程序并未提供一个显式的页面来删除条目。取而代之的是,要删除一个条目,用户需要从主编辑页面选择一个联系人条目,然后进行条目删除处理并刷新主编辑页面。如果有错误发生,系统就会显示适当的消息。没有确认页面和成功执行页面。
前面关于利用状态模式实现 Portlet 的系列文章与下面的讨论是类似的,因为 Struts 实现和状态模式是基本相似的。
考虑组成这个应用程序的操作和视图。可以把操作看作是您想要为 Portlet 实现的用户级功能或行为。例如,您可能需要一种操作来添加联系人或显示特定的视图。视图是完成用户操作之后应用程序的表现。例如,添加一个新联系人的操作可能产生的结果是,编辑模式下 Portlet 的视图显示联系人主列表。
接下来考虑您想要该应用程序在视觉上如何表现。在本例中,您需要一个主视图页面来列出已创建的联系人的。这个页面应该可以让用户选择一个联系人并获得关于此人的其他详细信息。
您想要联系人列表对每个用户是惟一的;因此,这个 Portlet 需要位于一个已验证的页面上,这样,用户(User)对象就可以与登录的用户相关联。
您想允许用户在列表中添加、删除和修改联系人。您可以提供一个主编辑页面来列出联系人并支持对所选条目的删除和修改操作。您不需要为用户删除一个所选条目实现另外一个视图;您只需要允许用户删除一个选定条目,然后用已修改的联系人列表来刷新主编辑页面。
如果用户选择一个联系人进行修改,您可以显示一个详细页面,用户可以在其中更新此联系人条目的任意属性。在用户完成了修改之后,您就可以重新显示主编辑页面。
同样地,您可以让用户从主编辑页面添加一个新的联系人。您可以显示另一个详细页面,用户可以在其中输入并保存联系人条目的属性。在用户保存之后,您可以重新显示带有已更新列表的主编辑页面。
现在,您可以确定可用于这个应用程序的状态转移。通过应用适当的操作来使应用程序生成特定的视图,您可以管理转移。在下图中,用椭圆表示视图(JSP),用矩形表示操作。
本设计需要您实现 7 个操作类。在本文所提供的实现中,这些操作定义为:
- MainViewAction
- DetailViewAction
- MainEditAction
- AddContactAction
- DeleteContactAction
- ModifyAction
- ModifyContactAction
从状态图中您可以看出,Add contact 视图实际上就是从主视图到 Add contact JSP 的直接转向(direct forward)。因为在呈现 Add contact 视图之前不需要也无逻辑,所以您可以简单地直接调用 Add contact JSP,然后将其配置为全局转向(global forward)而不是操作。
要在 WebSphere Studio 中启动一个基于 Struts 的 Portle 项目,您需要遵循下列步骤:
- 创建一个新的 J2EE level 1.3 Enterprise Application 工程。
- 把 Struts Portlet Framework 导入项目。
在标准 WebSphere Portal V5.0 安装程序中,您将会在<portal_root>/dev/struts/StrutsPortlet/PortalStrutsBlank.war
目录中找到PortalStrutsBlank.war
文件。导入这个 war 文件会为 Jakarta Struts 和 IBM 的 Struts Portlet Framework 把 Struts jar 文件添加到项目 lib 目录中。 - 在导入完成之后,您可能会在项目的 WebSphere Studio 任务列表中看到一些验证警告和一个错误。
- XML 验证错误:
Attribute "bundle" must be declared for element type "field"
invalidation.xml
- 警告:
Target welcome does not exist in the following modules: /
- 警告:
Target /Welcome.do does not exist in the following modules: /
in index.jsp and struts-config.xml.
您现在可以忽略这些消息。在您更新了缺省的
validation.xml
之后,就可以解决验证错误。WebSphere Studio 中的验证器给出了关于不能在基本模块里面找到的资源的警告。您现在同样可以忽略这些消息。这就完成了在 Studio 中开发 Struts 应用程序的基本设置。
- XML 验证错误:
如果您没有使用 Studio,请确保下列 jar 文件(以及您导入的 Struts jar 文件)在构建路径中是可用的。您可以在如下 WebSphere Application Server 和 WebSphere Portal 目录中找到这些文件。
<was-root>/lib/ivjejb35.jar
<was-root>/lib/j2ee.jar
<was-root>/lib/runtime.jar
<was-root>/lib/servletevent.jar
<was-root>/java/jre/lib/rt.jar
<wp-root>/shared/app/portlet-api.jar
在考虑操作类、Bean、表单和支持的类的实现细节之前,请确定应用程序配置文件的实现。这些文件包括:
- Web 应用程序部署描述符,
web.xml
- Struts 表单验证 xml 文件,
validation.xml
- Portlet 部署描述符,
portlet.xml
- Struts 配置文件,
struts-config.xml
您需要更新所有这些文件。
Web 部署描述符 —— web.xml
缺省的 web.xml
文件是作为 Portal Struts Framework 的一部分提供的。您需要根据特定的应用程序来更改部署描述符。首先,把 <display-name>
更改为对应用程序有意义的名称,比如 Contacts List
。<servlet id="Unique_Servlet_Name">
id 在已部署的 Portal 环境中必须是惟一的。把此值更改为惟一的字符串。
构建在该框架中的 Struts 1.1 支持把应用程序划分成模块。当使用模块时,一个程序的配置信息和目录结构按模块划分。因此,代替应用程序的单个 struts-config.xml
文件,您有多个具有独立目录结构的控制文件,它们由应用程序 URI 中与模块有关的部分来识别。Struts Portlet Framework 利用模块支持来提供 Struts 配置模式和设备(标记)区别。搜索路径用于确定要用到的模块和 struts-config.xml
文件。它还确定了用于定位 JSP 的基本目录。当搜索模块时,添加以下初始参数会将搜索路径设置为在搜索模块时考虑标记名称和模式。
|
您为这个应用程序创建了两个模块,一个用于编辑模式,而另一个用于帮助模式。视图模式是通过基本 Struts 配置来配置的。这两个模块以这样的形式作为初始参数进行配置:/config/<device>/<mode>
。 因此,您有 config/html/edit
和 config/html/help
。添加与这些模块定义相关的参数值来指示在哪里开始搜索 Struts 配置文件。
|
添加两个特定于应用程序的初始参数 persist_to_db 和 datasource 来支持持久化类,它是下载的一部分。将此值设置为 true
会导致部署数据库代理。如果您使用数据库代理,您就还需要设置数据源。将数据源的值设置为此数据源的名称。如果您使用的是内存中的持久性,您可以忽略数据源的值。
最后,更改欢迎文件列表。Struts Portlet Framework 允许您指定设备/模式的初始视图。这可以通过欢迎文件列表来指定。
|
您还必须更改缺省的 portlet.xml
文件,该文件由空白的 Struts Portlet 提供。
- 将
<portlet-app-name>
和<portlet-name>
更改为有意义的名字。 - 将
<portlet-app uid>
更改为惟一的标识符。 - 将 href 更改为相关的 Servlet id,它是作为
web.xml <servlet id>
值指定的。例如,如果您在web.xml
中为 Servlet id 指定ContactsListPortlet
,您就可以在portlet.xml
中为 Portlet href 指定WEB-INF/web.xml#ContactsListPortlet
。 - 指定 html 设备的编辑和帮助模式支持、以及视图模式。
- 对于具体的 Portlet 应用程序,为
portlet-app-name
和portlet-name
两者指定惟一的 uid 和有意义的名称。 - 更该 concrete-portlet href 的值以与 Portlet 应用程序
<portlet id>
的值相匹配。 - 最后,为标题(title)、短标题(title-short)、描述(description)和关键字(keywords)的特定于语言的属性指定有意义的值。
清单 1. portlet.xml
|
Struts 配置文件 —— struts-config.xml
文件包含 Struts Framework 用于控制、导航和配置设置(包括所需的表单 Bean)的应用程序定义。
struts-config.xml
如上所述,在更改 web.xml
文件时,与两个应用程序模块定义中每一个都相关的参数值指示了从哪里开始搜索特定于模块的 Struts 配置文件。因此,您需要创建新的 struts-config.xml
文件,它将驻留在 /WEB-INF/html/edit/
和 /WEB-INF/html/help/
中。这些文件将包含特定于其模块的 Struts 配置信息。
首先,将 /WEB-INF
目录中的 struts-config.xml
文件更改为视图模式的 Structs 配置。您需要在 xml 中创建操作元素来支持在转移图中标识的操作。指定的操作有 7 种。这些操作可以如下定义,并且将使用在示例实现中所定义的类名来显示。您还为每个操作指定适当的转向设置,以便指示用于呈现请求视图的 JSP。同样在状态转移图中指定了这些呈现状态。您可以把这些适当的操作和转向包含在特定于模块的配置文件中。
接下来,在上面指定的目录中创建新的 struts-config.xml
文件。
struts-config.xml
|
您还可以指定全局转向、消息源文件和验证 xml 文件引用。全局转向使逻辑名称与指向 JSP 或操作的引用的 URI 相关联。
清单 2. VIEW - /WEB-INF/struts-config.xml
|
清单 3. EDIT - /WEB-INF/html/edit/struts-config.xml
|
清单 4. HELP - /WEB-INF/html/help/struts-config.xml
|
Struts 验证 —— validation.xml
您在这个应用程序中没有用到 Struts 输入验证。您可以删除 validation.xml
中的缺省验证规范。
|
目录结构更改
回顾一下,您更改了 web.xml
文件中的欢迎文件列表。这个列表用于指示已定义的模块的起点。根据 web 应用程序的根上下文,您需要为编辑和帮助模式创建目录,并且把每个模式的 index.jsp
放在这些目录中。
每个模块的 struts-config.xml
文件(表示 Portal 模式)都没有显示 JSP 文件的附加路径信息;因此,在这些相同的目录的每一个中您都需要为该模块添加适当的 JSP。在 /html/edit
目录中,您有 add_contact.jsp
、edit_contact.jsp
和 main_edit.jsp
以及 index.jsp
文件。在根目录中,您有 detail_view.jsp
和 main_view.jsp
。在 /html/help
目录中,我们只有 index.jsp
文件。
操作类的实现
接下来,您将实现这个应用程序所需的操作类。这里不讨论每个类的细节,因为在下载部分中提供了这些类的完整实现。 您需要实现类来扩展在状态转移图中标识的且在 struts-config.xml
文件中定义的每个操作的 org.apache.struts.action.Action
。
请查看 DeleteContactAction 类的代码,它实现了删除联系人的功能。您也可以看到我们的操作类扩展的抽象类,因此,您可以把用于实现所有的操作类的通用代码放入其中。例如,您可以在此添加代码来验证用户在执行该功能之前是否等录。
清单 5. DeleteContactAction 类
|
抽象操作类扩展 org.apache.struts.action.Action
并实现 execute
方法。此实现确保用户已登录,然后调用已调用的操作类中的 performAction
方法,传送与已传送到 execute
方法以及在登录验证时检索到的用户 Bean 的参数相同的参数。当您把应用程序迁移到 Portal 环境中时,您将只需删除登录操作,并且将此代码更改为从 portletRequest
对象中检索用户对象。然后,您就可以更改访问用户对象的任何应用程序代码来以使用 wps 用户对象 API。
清单 6. PostLoginAbstractAction 类
|
其余的操作类的实现是非常类似的,而且如果假定这个应用程序有最低限度的逻辑处理,那么它们根本就不是复杂的实现。
如 DeleteContactAction
类中所示,一些操作类使用持久化类的服务。Persistence 方法是作为下载实现的一部分提供的。现在,可以查看 ContactListBroker
接口,它定义了联系人列表处理所需的函数。代理类的实现管理数据存储(在本例中,或者为数据在数据库中的表示,或者为数据在内存中的表示)的数据访问。这个函数是该 Portlet 所需要的,但是它与与本文的要点无甚关系,您可以在下载部分中查看特定代理的实现。
清单 7. ContactListBroker 接口
|
应用程序 Bean
我们为这个应用程序定义了两个 Bean。我们在 struts-config.xml 文件中定义了一个联系人表单 Bean。它扩展了 org.apache.struts.validator.ValidatorForm,并且包含映射到联系人数据库表的列的特性(带有存取器)。请参阅为我们的示例表定义设置数据库的部分。另一个 Bean 是一个助手类,它提供了通用函数来添加和删除联系人。同样在下载中提供了这些代码,这里不再显示。
应用程序资源
在 struts-config.xml 文件中定义了消息特性文件。我们的文件命名为 ApplicationResources.properties,它位于一个资源文件夹中。这个资源包提供了封装在包中的可显示字符串,这样使应用程序更易于转换。
Java Server Page(JSP)文件
其余的应用程序组件是 JavaTM Server Page(JSP)文件。正如您在 struts-config.xml
文件中定义的,基于状态转移图,您需要实现 5 个 JSP 来呈现一个页面,用于以下目的:
- 添加联系人信息
- 编辑联系人信息
- 主视图页面(Main view page)
- 主编辑页面(Main edit page)
- 联系人详细信息视图页面(Detail contact view page)
您同样需要更新 index.jsp
文件来为每种模式调用初始化操作。
考察这个 JSP 文件的一些关键部分,即用于呈现主视图的部分以及此 JSP 呈现的内容的示例。这个 JSP 需要一个在会话期间存在的 Bean 来包含联系人列表。您定义了几个在 JSP 中使用的标准 Struts 标签库。当用户在呈现的列表中选择了一个联系人时,您想要继续进行 detailview
操作,将所选联系人 oid
作为参数与请求表单数据一起传送。
清单 8. 主视图 JSP
|
设置数据库
您可以为此应用程序创建两个用于数据持久化的选项:一个带有数据库代理实现,另一个带有内存中的实现。为了快速开发和测试的目的,您可能只想使用内存中的形式,因为它不需要后续数据库设置的步骤。当然,每当应用程序服务器重启时数据都会丢失。下载部分提供了这两种代理类型的代码(与这个示例应用程序的余下部分一起提供),代理类型是通过 Web 部署描述符文件 web.xml
中设置的配置参数来选择的。
然而,如果您选择把应用程序数据保存到数据库中,您就需要首先创建数据库表来存放联系人列表数据。要创建该表,需要从命令行运行下列 SQL 命令,用您选择的名称来替代 Schema 名称,但请保留指定的表名。您可以为该表创建一个新的数据库(数据空间)或者把它添加到现有的数据库中。如果使用 DB2,则在命令中心(Command Center)建立一个到适当数据库的连接,再复制下列命令,然后运行它。
|
现在,您可以把一个条目添加到联系人列表数据库表中,这样您就可以在开发 Portlet 时更容易地对其进行测试。您可以执行下列 SQL 命令来创建一个新的条目。如果您出于测试的目的想用不同于 wpsadmin
的 userID 登录到 Portal,就请用这个用户 ID 来代替下面 SQL 声明中的 wpsadmin
。
|
接下来,在 WebSphere Application Server 中为您创建的联系人表所在的数据库创建数据源。这个 Portlet 是作为 J2EE 1.3 应用程序打包的,因此您需要指定 Application Server V5 数据源。J2EE Level 1.3 包括 Servlet Specification Level 2.3 和 JSP Specification Level 1.2。
- 在 Application Server 中使用 DB2 Legacy CLI-based Type 2 JDBC Driver JDBC 驱动程序并指定 Data Sources 而不是 Data Sources(版本 4)。
- 在 Application Server Administrative Console 上,选择 Resources =>JDBC Providers。
- 如果您已经安装了 DB2 Legacy CLI-based Type 2 JDBC Driver,就选择它。否则,通过选取 New 命令并完成下一个页面来添加它。
- 在 DB2 Legacy CLI-based Type 2 JDBC Driver 页面上,确保把类路径设置为
db2java.zip
文件的正确位置。 - 选择 Data Sources,接下来选取 New 以创建一个新的 V5 数据源。指定数据源的名称。对于 JNDI 名,用
jdbc/
子上下文作为名称的前缀。
例如,如果您想要一个数据源 jndi 名为aim
,就可以输入jdbc/aim
。Portlet 在进行 JNDI 名称查找时会预先考虑jdbc/
子上下文。 - 如果您的数据库需要用户 id 和密码用于身份验证,就请在 Component-managed Authentication Alias 中指定一个身份验证别名。
- 如果您还没有定义一个别名,您就可以在 Security => JAAS Configuration => J2C Authentication Data 中创建一个。
- 确保保存配置的更改,并测试数据源连接。
图 5. WebSphere Application Server Administrative Console
最后,在 Application Developer 中为这同一个数据库创建数据源。如果您想要利用 Application Developer 来测试和调试这个 Struts 应用程序,这也是需要的。从 Application Developer Server 透视图中编辑 WebSphere Portal Server V5 Test Environment 定义,在编辑窗格中选取数据源选项卡,添加 DB2 Legacy CLI-based Type 2 JDBC Driver 驱动程序,然后添加 V5 数据源。确保使用 jdbc/
作为您的 JNDI 名的上下文前缀。与在 Application Server 中一样,您可能需要添加安全性验证别名(如果您还没有创建的话)。
实现类摘要
下表列出了用于实现示例应用程序的 JAVA 类实现(可以在下载部分中找到)和对每个类的简要描述。
包 | 类 | 描述 |
com.ibm.sample.contacts.struts.beans | ContactHelper | 助手类,用于为联系人调用持久化管理函数 |
Contact | 表示联系人的 Struts 表单对象 | |
com.ibm.sample.contacts.struts.action | AddContactAction | 处理添加联系人信息的请求 |
DeleteContactAction | 处理删除联系人信息的请求 | |
DetailViewAction | 处理显示联系人详细情况视图的请求 | |
ModifyAction | 处理修改联系人信息的请求 | |
ModifyContactAction | 处理保存已编辑的联系人信息更改的请求 | |
MainEditAction | 处理显示主编辑视图的请求 | |
MainViewAction | 处理显示主联系人列表视图的请求 | |
AbstractAction | 用于操作的抽象类 | |
com.ibm.sample.contacts.struts.persistence | ContactListBroker | 持久性类接口 |
AbstractDBBroker | 用于数据库代理的通用函数的抽象类 | |
ContactListDBBroker | 数据库代理实现,它扩展 DbAbstractBroker 并实现 ContactListBroker | |
ContactListMemBroker | 实现 ContactListBroker 的内存代理实现, | |
com.ibm.sample.contacts.struts.utilities | AIMException | 基本异常类 |
AIMWrapperException | 包装另一个(基本)异常的 AIMException | |
AIMMessageException | 终止处理和发出用户消息的的异常 | |
Constants | 定义应用程序常量的接口 | |
com.ibm.sample.contacts.struts.nls | ApplicationResources.properties | 包含可打印字符串的缺省资源包 |
ApplicationResources_en.properties | 包含可打印字符串的特定于地点的资源包 |
结束语
本文讨论了如何使用 Struts Portlet Framework 实现一个示例应用程序。您了解了如何使用 Struts 模块以及如何使用它们与 WebSphere Struts Portlet Framework 来支持多 Portal 模式。在下面的下载部分中提供了本例的完整实现。