基于事件侦听与状态模式转换的Portlet开发
1.1 概念与前提
要读懂这节内容,并学会使用状态模式开发Portlet,你必须具备这里提到的几种设计思路,并具备基本的Java开发技能。这里我们选用的开发工具是 IBM Rational Application Developer以及Portlet Toolkit,你需要熟悉该工具,并懂得如何创建Portlet和Portlet所需的包、类、页面,以及运行环境所需的.jar。
1.1.1 状态模式应用于Portlet
StateManagerPortlet是主要的Portlet类,并且是Portlet无关的。它用作分派器以支持驻留着Portlet代码的操作和状态类,特定于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 View Page)--显示所有正在下载的产品列表和用来选择一个产品以获取更多详细信息的选项。
- 详细信息视图页面(Detail View Page)--显示被选择产品的详细配置信息。
- 主编辑页面(Main Edit Page)--显示用户有权限编辑的产品列表和用于修改更多信息的选项。
- 修改条目页面(Modify Entry Page)--显示相似的表单,其中插入了现有的数据用于修改,包括修改单项参数,以及给某一参数增删条目列表。
在这种情况下,用户可以从主编辑页面中选择需编辑的产品条目。修改后,没有确认页面或成功执行的页面。进行条目修改处理并刷新主编辑页面,若出错,则显示适当的消息,但在正常处理时,没有与该操作关联的视图。
如何来改进这个实现呢?首先,请记住这个应用程序表示一组应用程序操作和状态;其次操作是实现操作接口的类,这个类实际完成某个应用程序任务或操作处理。这就是目前存在于 actionListener 类的 actionPerformed 方法中的应用程序代码的一部分,只有这部分特定于单个操作事件。
状态是实现状态接口的类,这个类表示由于应用了操作而产生的 Portlet 的效果。一般来说,这个类有可视组件。
2.Portlet所包含的内容
根据以上分析,我们将有下面这些操作。
- 所有产品配置信息的主列表视图。
- 显示选定产品的配置详细信息视图。
- 显示所有可编辑产品的编辑视图列表。
- 显示视图来修改一个产品的配置信息。
- 为产品添加一个可选的下载项或邮件。
- 为产品删除一个可选的下载项或邮件。
执行这些操作会产生下列状态之一。
- 主视图。
- 详细信息视图。
- 主编辑视图。
- 添加下载产品视图。
- 修改下载产品视图。
从可视角度看,下载产品列表 Portlet 的实现包括如下视图(页面)。
(1)主视图(Main View)--显示下载产品列表,并带有选项来选择下载产品以查看更多的信息。
(2)详细信息视图(Detail View)--显示选定的下载产品的详细信息。
(3)主编辑视图(Main Edit View)--显示下载产品列表,并带有选项来添加、删除和修改下载产品信息。
(4)添加下载产品视图(Add Contact View)--显示表单视图来输入新下载产品的信息。
(5)修改下载产品视图(Modify Contact View)--显示相似的表单视图来添加现有的下载产品的元素数据以供修改。
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方法。
actionPerformed方法只是获取操作类的当前实例,然后分派到它的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 方法里刷新数据Bean。为了简化这种处理,我们会只为 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文件的构建路径是可用的,以便Portlet代码可以顺利编译。如果你在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,那么可以在
当Portlet部署到WebSphere Portal 环境中时,所有必需的JAR文件都要同时打包进去。你可以不做修改,而是在 Portal 中安装 Portlet WAR 文件。
1.3.5 用RAD实现Portlet
针对入门者,我们以图示的方式,向大家介绍使用IBM提供的开发工具RAD(Rational Application Developer)来创建、开发、调试、打包Portlet。
原则上我是按照安装从始至终的次序来截图的,但为了使层次更清晰,我们还是分为以下7个步骤来分别介绍。
1.安装RAD,创建portlet
在Windows 2003 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-17所示。
图1-17 将Portlet导出为WAR包部署到Portal服务器
拿这个WAR包,就可以发布或者更新到Portal系统上使用了。
1.4 Portlet 开发指导原则和示例实现
熟悉Portlet 开发指导原则和示例实现可以对Portlet API有很好的理解。然而,实现复杂的流程控制超出了 API 的范围。如果没有定义完善的方法来解决如何最好地实现控制逻辑这一问题,你就不能够创建这样的Portlet--它们包含有专门定位用户请求目的的简单合理的 代码。
除了重复之外,该代码使Portlet更难以读懂,因为你需要进入控制逻辑以获取Portlet正在做的实际工作。控制逻辑也容易出错,因为它依赖于多方面情况,比如,使用字符串匹配用来连接事件和侦听器,或者侦听器操作和 Portlet 方法中的Action。为了解决控制逻辑的这些问题,你可以将应用程序看做是Portlet的操作和状态的集合,然后通过一个定义完善的方法来进行状态转换,这样你就可以将Portlet应用程序中烦冗的控制逻辑代码删除。
开发人员也可以选择采用Struts框架来实现Portlet。Struts是一个Jakarta项目,它提供一个非常流行的开放源代码框架来建立 Web 应用程序。使用附带了 Portal 的 Struts Portlet Framework,用Struts框架写成的Portlet就可以在WebSphere Portal上运行。Struts提供了值得考虑的Web应用程序,其功能远远超过页面导航,它是进行Portlet开发的一个很好的选择。对Struts不熟悉或者希望更直接访问 Portlet API 的开发人员会从用于页面导航的状态转换实现中获益。这种模式和Struts框架一样,使面向MVC设计的应用程序框架得以改进。