1 .1 概念与前提
要读懂这节内容,并学会使用状态模式开发 Portlet ,你必须具备这里提到的几种设计思路,并具备基本的 Java 开发技能。这里我们选用的开发工具是 IBM Rational Application Developer 以及 Portlet Toolkit ,你需要熟悉该工具,并懂得如何创建 Portlet 和 Portlet 所需的包、类、页面,以及运行环境所需的 .jar 。
1 .1.1 状态模式应用于 Portlet
StateManagerPortlet 是主要的 Portlet 类 , 并且是 Portlet 无关的。它用作分派器以支持驻留着 Portl et 代码的操作和状态类 , 特定于 Portlet 的控制器代码就存在于该类中。扩展 Action 抽象类的类实现了 actionPerformed 方法 , 该类执行实现特定的操作请求行为所必需的任何控制器功能。
实现状态接口的类将实现一个 performView 方法 , 该方法是由 StateManagerPortlet 的 service 方法调用的。该方法还包含通常驻留在这些方法中的代码。同样 , 这段代码也是特定于它所驻留的状态类的 , 因此就避免了确定请求的操作带来的所有额外的控制逻辑混乱。
应用状态模式会使实现变得简洁。而且 , 当在 Portlet 的各 种 模式之间切换时 , 状态总是被记住的。有了这种模式 ,你 就可以轻松地确定想要何时以及在何处从源检索数据 , 还可以确定何时应该从高速缓存检索数据。由于在门户页面刷新时不调用 actionPerformed 方法 , 所以可以将数据访问代码放在操作状态中并在那里高速缓存它们。状态类可以使用高速缓存中的数据 , 以避免刷新门户页面时多次存取数据。
1 .1.2 Portlet 为什么使用状态模式
考虑 到 简单的基于 MVC 的 Portlet , 它从 远程机器上将包含一个产品下载配置参数列表的 XML 文件拷贝到本地( Portal 系统所在的主机), 检索 各项参数, 并把列表呈现给用户。在用户选择了 某一 项后将显示详细的视图 , 该视图显示的是被选 择 项的详细信息。这个详细视图可能涉及向数据库再次发出请求。 有编辑权限的用户可以进入到 Portlet 的编辑模式,查看并修改 XML 文件的内容,保存后如果发现 XML 文件已经做了修改,则传回远程机器;否则,仍将文件包存在 Portal 本地,以免占用系统资源。
第一步 , 控制器必须调用业务对象来创建合适的 Bean ,该 Bean 被传递给 JSP 以用于主视图中的显示。第二步 , 控制器在用户的请求中检索被选 择 项的指示器 , 然后调用业务对象来创建合适的 Bean ,该 Bean 被传递给不同的 JSP 以用于详细视图中的显示。
在 MVC 实现中 , 视图组件显然是不同的 。 这两种视图需要有两种不同的 JSP 。 你 可能需要访问不同的业务模型组件来生成每个请求所需的 Bean 。控制器函数需要知道 :
— 调用哪些业务方法 ?
— 生成哪些 Bean ?
— 把这些请求对象上的 Bean 放在哪里 ?
— 如何调用合适的 JSP ?
这就是代码变得复杂的地方。如果使用 Servlet 编程 , 那么可能选择把它们实现为不同的 Servlet , 以使每个合适的 Servlet 类的服务方法自然地分隔每个请求的控制器函数。如果 你 更喜欢使用分派器方式而不是不同的 Servlet 实现 , 那么必须使用框架 ( 例如 Struts ) 来实现类似的 MVC 设计。
这是复杂的任务 , 因为不能选择使用多个 Portlet 类来实现一个 Portlet , 不能直接处理 Portlet 类。相同的 Portlet 的服务方法 用来 处理返回给 该 Portlet 的所有 HTTP 请求 , 因此 , 需要实现控制代码 类具有如下功能。
— 确定正在请求哪个操作 ?
— 需要进行哪些处理 ?
— 使 Portlet 处于哪 种 状态 ?
— 显示什么 内容 返回给用户 ?
1 .2 需求分析
1 .2.1 Portlet 功能 需求
我们在 Linux 主机 test.cn.ibm.com 上运行着一个自动下载的程序,要下载的产品列表及各产品的参数保存在 /home/isc/downLoadConfig/ 下,文件名为 AutodownConfig.xml 。我们在 Windows 2000 Server 主机 Netecauto01 上运行着 IBM WebSphere Portal 5.1 ,普通用户只能查看产品列表及配置权限,当该用户要查看配置信息时, Portlet 能从服务器上将文件 AutodownConfig.xml 拷贝到本地服务器,并读出 XML 文件中的内容,显示在列表中。具有管理权限的用户还有修改各配置信息的权限,能对产品配置信息的各项参数进行修改。修改完成后,要使该配置有效,必须将该 XML 文件回传到 pvcent07 的存放目录。
AutoDownLoadConfig Portlet 维护一个 自动下载的产品配置 列表 , 在编辑模式下 , 用户可以浏览 并 下载产品列表 , 查看一个选定的下载产品的详细信息 , 也可以修改一个 产品的配置信息 。在配置模式下 , 用户可以设置数据访问信息。虽然可用的数据源提供了包括配置模式 在内 的完整的实现 , 但为了 满足 设计目的 ,我们 只需注意查看和编辑模式的实现 即可 。 自动下载 Portlet 状态模式示意图如图 1- 1 所示。
图 1- 1 自动下载 Portlet 状态模式示意图
1 .2.2 基于 MVC 模型的角度架构逻辑
1 .以基于 MVC 架构的思路整理 Portlet 的逻辑
从可视的角度看 ,图 1- 1 所示的 场景 功能 的实现 至少 需要如下页面 。
— 主视图页面 ( Main V iew Page ) — — 显示 所有正在下载的产品 列表和用来选择一个 产品 以获取更多 详细 信息的选项 。
— 详细信息视图页面 ( Detail View Page ) — — 显示被选 择产品 的详细 配置 信息 。
— 主编辑页面 ( Main Edit Page ) — — 显示 用户有权限编辑的产品 列表和用于 修改 更多信息的选项 。
— 修改条目页面 ( Modify Entry Page ) — — 显示相似的表单 , 其中插入了现有的数据用于修改 ,包括修改单项参数,以及给某一参数增删条目列表。
在这种情况下 , 用户可以从主编辑页面中选择需 编辑 的 产品 条目。 修改后, 没有确认页面或成功执行的页面。进行条目 修改 处理并刷新主编辑页面 , 若出错 , 则显示适当的消息 , 但在正常处理时 , 没有与该操作关联的视图。
如何来改进这个实现呢?首先 , 请记住这个应用程序表示一组应用程序操作和状态 ;其次 操作是实现操作接口的类 , 这个类实际完成某个应用程序任务或操作处理。这就是目前存在于 actionListener 类的 actionPerformed 方法中的应用程序代码的一部分 , 只有这部分特定于单个操作事件。
状态是实现状态接口的类 , 这个类表示由于应用了操作而产生的 Portlet 的效果。一般来说 , 这个类有可视组件。
2 . Portlet 所包含的内容
根据以上分析,我们 将有下面这些操作 。
— 所有 产品配置信息 的主列表视图 。
— 显示选定 产品的配置 详细 信息 视图 。
— 显示 所有可编辑产品 的编辑视图列表 。
— 显示视图来修改 一个产品的配置信息。
— 为产品 添加 一个可选的下载项或邮件。
— 为产品 删除 一个可选的下载项或邮件。
执行这些操作会产生下列状态之一 。
— 主视图 。
— 详细信息视图 。
— 主编辑视图 。
— 添加下载产品视图 。
— 修改下载产品视图 。
从可视角度看 , 下载产品列表 Portlet 的实现包括如下视图 ( 页面 )。
( 1 ) 主视图 ( Main V iew ) — — 显示下载产品列表 , 并带有选项来选择下载产品以查看更多的信息。
( 2 ) 详细信息视图 ( Detail V iew ) — — 显示选定的下载产品的详细信息。
( 3 ) 主编辑视图 ( Main E dit V iew ) — — 显示下载产品列表 , 并带有选项来添加、删除和修改下载产品信息。
( 4 ) 添加下载产品视图 ( Add C ontact V iew ) — — 显示表单视图来输入新下载产品的信息。
( 5 ) 修改下载产品视图 ( Modify C ontact V iew ) — — 显示相似的表单视图来添加现有的下载产品的元素数据以供修改。
1 .3 Portlet 详细设计
1 .3.1 程序流程设计
下面以图示的方式来介绍程序的数据流转。
在显示模式下, Portlet 会从远程 pvcent07.cn.ibm.com 拷回 XML 文件,读出并显示所有正在下载的产品列表。单击列表中的任意项,将显示该项的详细视图。我们先来看产品下载列表,如图 1- 2 所示。
图 1- 2 产品下载列表
单击任意产品的链接后,将显示该产品的具体配置参数,如图 1- 3 所示。
图 1- 3 产品的具体配置参数
在编辑模式下,首先显示的是用户有权限编辑的产品配置列表,如图 1- 4 所示。
图 1- 4 用户有权限编辑的产品配置列表
单击任意产品的链接,进入到该产品的编辑界面,如图 1- 5 所示 。
图 1- 5 产品的编辑界面
用户可以为该产品添加 CD 介质,或者添加一个 E-mail ,如图 1- 6 所示。
图 1- 6 为产品添加要下载的 CD 介质
当然,用户也可以删除要下载的 CD 介质或者 E-mail ,如图 1 -7 所示。
图 1- 7 删除要下载的 CD 介质
用户可以修改任意参数,然后单击 “ Save To XML ”按钮, Portlet 将把这些参数保存到 XML 文件,并传回到 pvcent 机器,如图 1- 8 所示。
图 1- 8 将修改保存到 Portlet 配置文件
确认修改保存成功,如图 1 -9 所示。
图 1- 9 确认修改保存成功
1 .3.2 Actions 及 States 总体设计
1 . StateManagerPortlet
StateManagerPortlet 是主要的 Portlet 类 , 是 Portlet 无关的 , 一般包括所有特定于 Portlet 的代码。该类被用作分派器以支持驻留着 Portlet 代码的操作和状态类。 StateManagerPortlet 实现了 actionPerformed 、 doView 、 doEdit 、 doHelp 和 doConfigure 方法。
a ctionPerformed 方法只是获取操作类的当前实例 , 然后分派到它的 actionPerformed 方法 中 。类似地 , do 方法获取当前的状态对象 , 然后分派到它的 perform 方法 中 。所以 , StateManagerPortlet 不需要知道当前 Portlet 实现的任何细节 , 也没有大量用来确定下一步处理的 if 和检查。只要 你 熟悉状态与操作之间的流程 , 处理就能正确地进行 , 而不必编写太多的、多余的控制逻辑代码。
2 . ActionClassManager
在 WebSphere Portal 中 , ActionClassManager 方法把 Action 类实例添加到已弃用的 PortelURI 中。这个 API 是有用的 , 因为 你 可以从 PortletEvent 对象中检索 Action 子类实例 , 并把该实例作为状态转换的一部分分派到它的 actionPerformed 方法中。推荐的 API 将使用字符串而不是 Action 来添加到 PortletURI , 并且从 Portlet Event 中进行检索。 ActionClassManager 类提供了从给定的字符串到 Action 类的实例映射。
— Action
实现这个接口的类将实现 actionPerformed 方法 , 该方法 可 执行任何操作以实现操作请求所需的函数。但是 , 实现的函数特定于正被调用的操作事件。某个操作类的个别的 actionPerformed 方法仅包含该操作的代码 , 该方法还为进一步的处理设置当前状态。在这个流程中 , 操作被调用后 , 它进行特定于 其 函数的工作 , 然后为下一次转换设置状态。
— InitialStateManager
该类为支持的每个 Portlet 方式提供初始状态。
— State
一般来说 , State 的 perform 方法将调用 JSP 来显示它的结果。用户接口可能让用户来设置 Portlet 中的其他操作。 JSP 使操作类与页面上的每个操作关联。在用户调用其中的一个操作时 , StateManagerPortlet 的 actionPerformed 方法将调用合适的操作类实例 , 接着发生了状态转换。状态类并不负责状态管理和转换。
实现这个接口的类需实现 perform 方法 , 该方法可被 StateManagerPortlet 的 do 方法调用 , 它包含一般驻留在这些方法中的代码。同样 , 这些代码特定于它们所在类的状态 , 从而降低了复杂性。
1 .3.3 代码类设计、操作类清单
我们所创建的各个类的功能分别简单介绍如下。
1 . State 类功能逻辑介绍
子类 1 : ActionClassManager 类
ActionClassManager 类 负责返回一个操作子类实例 , 该实例给出一个类标识符 , 这个标识符是通过 addAction ( 字符串 ) 方法添加到 PortletURI 中的。我们遵循如下约定 : 使类标识符为全限定类名 , 这样我们就能够很容易地创建一个类的实例。然而 , 我们可以通过单独处理操作子类实例来避免不必要的对象创建 , 然后需要 ActionClassManager 为所引用的操作子类返回单一的实例。
子类 2 : ActionPerformed 类
抽象的操作类定义了两个抽象的方法 , 因此它的子类必须实现 actionPerformed 方法和 setState 方法。当 StateManagerPortlet 类从它的 actionPerformed 方法分派处理时 , 操作子类的 actionPerformed 方法得到调用。
setState 方法也可由 StateManagerPortlet 调用 , 确保操作子类的实现在该用户请求的操作处理完成之后设置下一个状态。操作类实现它自己的 setState 方法 , 子类必须调用该方法来真正设置下一个状态。这确保了操作类和状态类知道在哪 个 类设置和恢复下一个状态 , 而不需要子类知道这些机制。这些状态跨 HTTP 请求 , 并维持在每 种 Portlet 模式下。所以 , 当用户改变模式时 , 控制返回到最近一次访问的状态。
子类 3 : MainViewAction 操作类
MainViewAction 类并不需要任何特定的操作处理。事实上 , 我们需要将 下载产品 列表显示在主视图上。我们能够实现在 actionPerformed 方法中创建恰当的下载产品列表 Bean 的代码 , 将该代码设置在会话或请求对象里 , 然后将下一个状态设置到 MainViewState 里。 子 类 performView implementation 继承 MainViewAction 操作类, 能够简单地调用 JSP , 并提交来自会话或请求的 Bean 里的列表内容。然而 , 我们必须注意门户页面更新 , 以防更新时调用的是 Portlet 的 MainViewState 、 performView 方法, 而非 MainViewAction 的 actionPerformed 方法。所以 , 我们不能只是将 Bean 放置于请求对象里 , 而没有让 performView 方法重新创建该 Bean , 并将新的 Bean 放在该请求对象里。我们可以在会话里再次使用该 Bean 。但如果那样做的话 , 数据将会过时。如果我们在编辑模式下做了变动 , 就需要通知该变化 , 并在 State 方法里刷新数据 B ean 。为了简化这种处理 , 我们会只为 MainViewState 在 State 方法里得到数据 Bean 。
所以 , 在 MainViewState 类里 , actionPerformed 方法并没有另外处理 , 只是简单 地 设置了 MainViewState 而已。
子类 4 : StateManagerPortlet 类
当 actionPerformed 完成处理时 , 控制返回到门户容器 , 以便其他的侦听器通知处理程序执行。然后 , 门户容器通过调用 StateManagerPortlet 的 service 方法继续 Portlet 请求处理。
StateManagerPortlet 的 service 方法首先试图检索以前执行的操作类设置的状态类 , 如果没有发现状态类引用 ( 例如 , 最初的 Portlet 调用 ), 那么就使用一个助手类 InitialStateManager 来为每 种 Portlet 模式确定初始的状态类。 InitialStateManager 有一个 唯 一的方法叫做 getInitialState , 它根据 Portlet 的当前模式返回状态对象的一个实例。对于下载产品列表 Portlet , 这个类将为视图模式返回 MainViewState 的一个实例。
State 接口有一个 唯 一的方法 performView , 所有的状态类都必须实现它。 StateManagerPortlet 的 service 方法调用这个方法。
子类 5 : MainViewState 类
MainViewState 的 performView 方法负责在 Contacts Bean 的列表表单中获取下载产品列表 , 下载产品列表保存在数据库里 , 然后传递到 JSP 以便在主视图中呈现出来。
子类 6 : MainViewState 类
这个子类 允许用户单击一个下载产品条目 , 然后显示该下载产品的详细信息视图。
用于这个标记的 href 使用来自 Portlet 标记库中的 createURI 标记。该标记在 URIAction 中获得参数 , 而 URIAction 被我们设置为操作类中用于用户单击操作的事件处理方法的名称。
子类 7 : actionPerformed
actionPerformed 类用来查看 JSP 上显示的主要清单。 用户可以从主视图页面选择特定的下载产品条目来获得详细信息。我们还添加了一个锚标记将下载产品条目的 名称 作为可点击的链接显示出来 , 当 点 击时 , StateManagerPortlet 的 actionPerformed 方法被 DetailViewAction 类调用。
actionPerformed 方法得到所选择的下载产品条目的对象 id , 并调用持久性类的代理为该 id 获取实例化的下载产品对象。这个下载产品对象放在 State 类的会话中 , 用来呈现详细信息视图。如果该页面由于门户页面刷新而得以刷新 , 那么该 Bean 就将在会话中可用 , 既然该对象只会通过用户使用 Portlet 来获得更新 , 我们就不必担心数据过时了。
门户页 面刷新的另一个关键之处是表单数据没有 被重新初始化 。如果我们试图获得所选下载产品的对象 id 作为状态类的请求参数 , 它在门户页面刷新时将不可用。因此 , 为了使 Portlet 能正常运行 , 必须在刚开始时就检索数据元素 , 然后将其存储在某个地方 , 这样在随后的页面刷新时它才可以 被引用。由于 actionPerformed 方法曾被调用 , 所以这就是存放这段代码的好地方。
在 actionPerformed 方法中保留后端数据访问 , 可以确保我们在页面刷新时对于同一数据不需要多次访问数据库。当然 , 返回到数据源进行数据刷新的时间和频率取决于 Portlet 的需求 , 以及数据本身的因素。在这种情况下 , 数据不是动态的 , 当 Portlet 页面被刷新时 , 应该对其进行高速缓存。
最 后 , DetailViewState 被设置为这个 Portlet 的下一个状态 , 对于 Portlet , 其中的处理将继续。
子类 8 : DetailViewState 类
DetailViewState 简单地调用 JSP 来呈现详细信息视图 , JSP 从会话中获取下载产品 Bean 。在 UI 交互界面中 , 当用户单击 “ OK ” 按钮时 , 处理返回到主视图继续进行。 MainViewAction 的 actionPerformed 方法通过删除我们在 DetailViewAction 类中设置的下载产品对象 id 来简单地删除会话数据。
子类 9 : ViewProductAction 类
ViewProductAction 类用来显示 下载产品详细信息视图 的 JSP 页面。 流逻辑以一种组织良好的方式进行 ,你 不需要在 Portlet 中 使用 烦 冗的控制代码。 Portlet 的编辑和配置模式也以同样的方法实现。
2 . 完成 Portlet 实现
该应用程序的其余部分仍遵循 以上所述的开发 模式。编辑模式的处理控制逻辑流和视图模式的完全一样。我们实现一 种 配置模式 , 它允许用户指定数据源来保存下载产品数据。它将以同样的方式实现。配置模式只有一个视图来让用户访问数据源 , 另外有两个类来检验数据源和保存数据源为配置数据。
下面是实现状态模式的基本步骤。
所执行的特定模式的初始状态类由 InitialStateManager 类提供。
状态类的 performView 方法 ( 其调用是由 StateManagerPortlet 分派的 ) 进行任何必要的应用程序逻辑处理 , 然后调用它的 JSP 。
通过 PortletURI 上的一个参数将每个用户的操作与在其中进行事件处理的操作子类的名称相关联。每个用户操作一般都指定一个不同的操作子类 , 该子类实现一个单一的、特定的功能。
当 用户单击一个链接时 , 操作类的 actionPerformed 方法被调用 ( 由于通过 StateManagerPortlet 分派而被再次调用 ) 。执行操作逻辑 , 并设置适当的状态类以使处理继续进行。
当事件处理完成后 , StateManagerPortlet 的 service 方法被调用 , 并再次分派给在 Action 事件处理阶段设置的状态类 , 该状态类执行应用程序逻辑并调用它的 JSP 来呈现结果。
当用户浏览整个 Portlet 时 , 操作以这种方式继续。
3 . 持久性代理
访问数据库中的持久性数据需要额外的 Portlet 组件。 AbstractBroker 类提供 了 一般的 JDBC 数据库访问功能。它能够用来获取数据库的 DataSource 和 Connection ; 它在高速缓存中缓存 DataSource , 从而避免重复的、高代价的 JNDI 查找 ; 它也提供通用代码来执行 PreparedStatement , 并关闭 Connection 、 Statement 和 ResultSet 。
ContactListBroker 类继承了 AbstractBroker , 它实现 了 特定于 Portlet 需要的数据访问方法 , 如 getContact 方法和 getContactList 方法 , 用于保存 或 删除一个 列表中的 条目。同时它还有检验表 Schema 的功能 , 这样我们就可以检验用户在配置模式下指定的数据源。
4 . 异常处理
我们 已经为 Portlet 实现了大量的异常类 , 基本类 是 AIMException , AIMWrapperException 是 AIMException 的子类。 你 可以用 AIMWrapperException 封装其他抛出的异常 , 以便在 StateManagerPortlet 的 service 方法中高效地修改显示行为和管理异常处理。
AIMMessageException 是一个特殊的异常 , 它允许在终止处理时向 Portlet 生成一条报告性消息或错误消息。例如 , 可以抛出一个 AIMMessage 异常 , 用一条消息指出用户必须先登录。
actionPerformed 方法或 setState 方法中抛出的异常被捕获 , 并且被延迟到 service 方法。管理延迟的方法是捕获这些方法中抛出的所有异常 , 并将异常 ( 通常封装在一个 AIMWrapperException 中 ) 放在请求对象上。当调用 StateManagerPortlet 的 service 方法时 , 它首先查找有没有延迟异常 , 如果找到了 , 就从此处重新抛出并处理这些异常。
因此 , 所有的 Portlet 应用程序异常都是在 StateManagerPortlet 的 service 方法中处理的。如果发现了异常 ,则 在以下两种情况中调用异常方法 : 异常消息将在 Portlet 中被显示 ; 异常消息以及相关联的堆栈跟踪信息将被显示。将堆栈跟踪信息放在 Portlet 外有助于在开发时进行调试。由于不想向实际应用的用户显示这种级别的详细信息 , 所以该行为是可配置的。这是在部署描述符里定义的 debugTrace 参数。
5 . 建立开发环境
如果 你 使用 WebSphere Studio 来创建这个 Portlet , 请确保下列 JAR 文件 的 构建路径是可用的 , 以便 P ortlet 代码 可以 顺利编译。如果 你 在 Studio 中使用 Portal Toolkit 并创建 Portlet 应用项目 , 那么类路径会自动创建。不管哪种情况 ,你 都可以创建一个 Web 项目或 Portlet 应用项目 , 然后导入 下载 中的 WAR 文件 , 从而将这个 Portlet 应用程序载入 Studio 。
SERVERJDK_50_PLUGINDIR/jre/lib/rt.jar
WAS_50_PLUGINDIR/lib/dynacache.jar
WAS_50_PLUGINDIR/lib/j2ee.jar
WAS_50_PLUGINDIR/lib/servletevent.jar
WAS_50_PLUGINDIR/lib/ivjejb35.jar
WAS_50_PLUGINDIR/lib/runtime.jar
WAS_50_PLUGINDIR/lib/ras.jar
WAS_50_PLUGINDIR/lib/naming.jar
WAS_50_PLUGINDIR/lib/utils.jar
WPS_V5_PLUGINDIR/portlet-api.jar
WPS_V5_PLUGINDIR/wpsportlets.jar
WPS_V5_PLUGINDIR/wps.jar
如果 你 没有使用 Portal Toolkit 或者 Studio ,那么 可以在 <WAS_ROOT>/lib 和 <WPS_ROOT>/shared/app 中找到这些文件。
当 Portlet 部署到 WebSphere Portal 环境中时 , 所有 必需的 JAR 文件都 要同时打包进去 。 你 可以不 做 修改 , 而 是 在 Portal 中安装 Portlet WAR 文件。
1 .3.5 用 RAD 实现 Portlet
针对入门者,我们以图示的方式,向大家介绍使用 IBM 提供的开发工具 RAD ( Rational Application Develop er )来创建、开发、调试、打包 Portlet 。
原则上我是按照安装从始至终的次序来截图的,但为了使层次更清晰,我们还是分为以下 7 个步骤来分别介绍。
1 .安装 RAD ,创建 portlet
在 W indows 20 03 Server 系统的“控制面板” → “ 高级 ”选项中 , 单 击 “ 设置 ”按钮 ,在出现的对话框中选择 “ 数据执行保存 ” 面板, 单 击 “ 添加 ... ” 按钮,把安装后的 rationalsdp.exe 和 enroll.exe 添加到列表中。
打开 RAD ,单击“新建”按钮,选择“项目”→“ Portlet 项目”,然后依次输入各项参数,包括 Portlet 的名称、包名、是否使用凭证保险库等。
参数 值
Portlet 名称 DownLoadConfig
Portlet 类型 基本 Portlet
Web 功能部件 使用 Web 图与 JSP 标记库
是否需要添加操作侦听实例 不需要
是否需要添加凭证保险库 不需要
使用模式 显示模式、编辑模式、培植模式、帮助模式
单击 “完成”按钮, Rational 开始自动创建这个 Portlet ,创建完成后自动打开“ DownLoadConfigView.jsp ”文件,如图 1- 10 所示。
图 1- 10 在 RAD 中开发 Portle
2 .创建并设计所需的操作类( Actions )
创建一个 Action 包: com.ibm.csdl.portal.download.config.actions ,在这个包里分别创建以下类,如图 1- 11 所示。
图 1- 11 创建的操作类
这些类实现了 Portlet 的所有操作,我们以“为产品配置删去一个 CD 或者 E-mail ”为例,看一下 Action 实现了哪些功能。
在 actionPerformed 方法里,程序接收从 editAProduct.jsp 传过来的参数,也就是 CDs 和 Emails 两个选择框传过来的值,看要删除的是一个 CD 还是一个 E-mail ,然后从产品配置对象里面将对应的 CD 或者 E-mail 删除,最后写回到 XML 文件中。
在 setState () 方法里,程序实例化一个 RemoveOneCDsOrEmailState ,将逻辑交给 State 来处理。那么, State 又如何流转呢?看下面的 State 类。
3 .创建并开发所需的状态类 (States)
创建一个 State 包: com.ibm.csdl.portal.download.config.actions ,在这个包里分别创建以下类,如图 1 -12 所示。
图 1- 12 创建的状态类
这些类实现了 Portlet 的所有状态模式转换,我们以“为产品配置删去一个 CD 或者 E-mail ”为例,看一下 State 实现了哪些功能。
RemoveOneCDsOrEmailState.java 代码清单如下:
State 类里面只有两个方法,其中一个方法用于获得实例,我们就不管了;另一个方法是 performView ,它负责读出 XML 文件里的内容(现在已经是修改后的了),然后放入 Session ,调用并初始化一个新的指定的 JSP 文件。这个 JSP 从 Session 里面取出数据,然后初始化。
4 .创建并开发所需的数据结构( Data )以及 Portlet 类
Data 类主要定义了一些数据结构,用来存放 XML 文件中的数据,与 Portlet 的开发基本上无关。
Portlet 类主要用来初始化一些数据,以及根据 Portlet 的状态调用相应的 JSP 页面。
nls 下的资源文件与浏览器的多语言支持相关,可以根据客户端浏览器的设置,从相应的资源里取出静态描述文件 Portlet.xml ,然后在 JSP 文件中完成初始化的过程。
com.ibm.csdl.portal.download.config.utilities 包主要处理一些异常(见图 1- 13 ),这里不再赘述。
图 1- 13 com.ibm.csdl.portal.download.config.utilities 中默认带有常见的异常处理逻辑
5 .创建并开发所需的页面( Pages )
根据上面的详细设计,我们需要创建一些页面,如图 1- 14 所示。
图 1- 14 创建的页面
这些页面的功能如下。
页面的显示逻辑略。我们以 ViewAllTheProduct.jsp 为例,看一下 Rational 是怎样给一个链接添加操作事件侦听的。
ViewAllTheProduct.jsp 源代码如下:
其实很简单,用一个超链接就能添加该链接的操作事件侦听,代码如下:
其他的类似,这里不再赘述。
6 .调试 Portlet
假设在 9.181.66.250 上运行着一个 Portal 系统,超级管理员的用户名和密码都是 admin ,我们可以创建一个服务器用来测试 Portlet ,如图 1- 15 所示。
图 1- 15 在 RAD 中创建 Portal 服务器用于调试 Portlet
选择服务器的类型为 WebSphere Portal ,并输入相关参数。
右击项目名,选择 “运行”→“在服务器上运行”,如图 1- 16 所示。
图 1- 16 选择直接在 RAD 中运行 Portlet
几分钟后,会在工作区出现浏览页面,这样就可以调试该 Portlet 了。
7 .打包,生成产品
打包 Portlet 也非常简单,右击项目名,选择“导出”→“ WAR 文件”,再选择好存储位置就可以了,如图 1- 1 7 所示。
图 1- 1 7 将 Portlet 导出为 WAR 包部署到 Portal 服务器
拿这个 WAR 包,就可以发布或者更新到 Portal 系统上使用了。
1 .4 Portlet 开发指导原则和示例实现
熟 悉 Portlet 开发指导原则和示例实现 可以 对 Portlet API 有 很好的理解。然而 , 实现复杂的流程控制超出了 API 的范围。如果没有定义完善的方法来解决如何最好地实现控制逻辑这一问题 ,你 就不能够创建这样的 Portlet — — 它们包含有专门定位用户请求目的的简单合理的 代码。
除了重复之外 , 该代码使 Portlet 更难以读懂 , 因为 你 需要进入控制逻辑以获取 Portlet 正在做的实际工作。控制逻辑也容易出错 , 因为它依赖于多方面情况 , 比如 ,使用 字符串匹配 用来 连接事件和侦听器 , 或 者 侦听器操作和 Portlet 方法中的 Action 。为了解决控制逻辑的这些问题 ,你 可以将应用程序看 做 是 Portlet 的操作和状态的集合 , 然后通过一个定义完善的方法来进行状态转换 , 这样 你 就可以将 Portlet 应用程序中 烦 冗的控制逻辑代码删除。
开发人员也可以选择采用 S truts 框架来实现 Portlet 。 Struts 是一个 Jakarta 项目 , 它提供一个非常流行的开放源代码框架来建立 Web 应用程序。使用附带了 Portal 的 Struts Portlet Framework , 用 S truts 框架写成的 Portlet 就可以在 WebSphere Portal 上运行。 Struts 提供了值得考虑的 Web 应用程序 , 其功能远远超过页面导航 , 它是进行 Portlet 开发的一个很好的选择。对 S truts 不熟悉或者希望更直接访问 Portlet API 的开发人员会从用于页面导航的状态转换实现中获益。这种模式和 S truts 框架一样 , 使面向 MVC 设计的应用程序框架得以改进。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/9116427/viewspace-2221694/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/9116427/viewspace-2221694/