分享
 
 
 

将状态模式应用于 WebSphere Portal Portlet — 第 1 部分:概述

王朝html/css/js·作者佚名  2006-12-17
窄屏简体版  字體: |||超大  

将状态模式应用于 WebSphere Portal Portlet — 第 1 部分:概述

将状态模式应用于 WebSphere Portal Portlet — 第 1 部分:概述

portlet 开发指南和示例实现使您能够很好地理解 portlet API。然而,复杂过程的控制的实现超出了 API 的范围。如果您没有设计完善的方法来解决如何最佳地实现控制逻辑,那么您最终创建的 portlet 的代码中有相当多的一部分专用于考虑用户请求的目的。

这些代码不仅是重复的,它们还使 portlet 更难被读懂,因为您需要费很大力气去理解控制逻辑以了解 portlet 正在进行的实际工作。控制逻辑也容易出现错误,因为它在 portlet 方法中依赖于字符串名称匹配以使事件与侦听器绑定、使侦听器操作与行为绑定。它还使业务逻辑变得更复杂,因为控制功能的实现可能类似于业务逻辑。

为了解决控制逻辑的这些问题,您可以把应用程序看成是一组 portlet 操作和状态。然后,在给出了定义完善的状态过渡的方法后,您就可以删除 portlet 应用程序中麻烦的控制逻辑代码。本文讨论如何把这种相同的方法应用到 portlet 开发的状态管理中并创建可再用的状态模式以使这个问题得到一般的处理。您将发现把状态模式应用于 portlet 会产生一个更干净的 portlet 实现。

在第一种情形中,控制器必须调用业务对象来创建合适的 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 处于哪个状态以及显示什么东西来返回给用户。

StateManagerPortlet。这是主要的 portlet 类。它是 portlet 无关的,一般来说,它也是您编写所有特定于 portlet 的代码的地方。该类被用作分派器以支持驻留着 portlet 代码的操作和状态类。StateManagerPortlet 实现了 actionPerformed 方法,也实现了 doView、doEdit、doHelp 和 doConfigure 方法。actionPerformed 方法只是获取操作类的当前的实例,然后分派到它的 actionPerformed 方法。类似地,do 方法获取当前的状态对象,然后分派到它的 perform 方法。所以,StateManagerPortlet 不需要知道当前的 portlet 实现的任何细节,也没有大量用来确定下一步处理什么的 if 和检查。只要您熟悉状态与操作之间的流程,处理就能正确地进行,而您不必编写太多的、多余的控制逻辑代码。 Action。实现这个接口的类将实现 actionPerformed 方法。该方法执行任何所需的操作以实现操作请求所需的函数。但是,实现的函数特定于正被调用的操作事件。某个操作类的个别的 actionPerformed 方法仅包含该操作的代码。该方法还为进一步的处理设置当前状态。在这个流程过程中,操作被调用后,它进行特定于它的函数的工作,然后为下一次过渡设置状态。 State。实现这个接口的类需实现 perform 方法。该方法可被 StateManagerPortlet 的 do 方法调用,它包含一般驻留在这些方法中的代码。同样,这些代码特定于它们所在的类的状态从而降低了复杂性。一般来说,State 的 perform 方法将调用 JSP 来显示它的结果。UI 可能让用户来设置 portlet 中的其他操作。JSP 使操作类与页面上的每个操作关联。当用户调用其中的一个操作时,StateManagerPortlet 的 actionPerformed 方法将调用合适的操作类实例,接着发生了状态过渡。状态类并不负责状态管理和过渡。 StateURI 定制标记。该类提供 JSP 所使用的定制标记。前面已提到,JSP 使操作实例与页面上的操作关联。这种关联是通过生成的 PortletURI 来完成的。在给出操作类名后,该定制标记提供的函数可生成 URI。您可以删除门户代码中的 URI 创建代码。有了这个标记和操作状态结构后,您不必再提供管理 portlet 中状态过渡的代码。

从可视的角度看,以上情形的实现可能需要以下页面:

主视图页面— 显示联系方式列表和用来选择一个联系方式以获取更多信息的选项 详细信息视图页面— 显示被选的联系方式的信息 主编辑页面— 显示联系方式列表和用于添加、删除或修改的选项 添加条目页面 — 显示表单以获取需添加的联系方式信息 修改条目页面— 显示相似的表单,其中插入了现有的数据以用于修改

在这种情况下,您没有删除条目的显式页面。其行为是这样的:用户可以从主编辑页面中选择需删除的联系方式条目。没有确认页面或成功执行的页面。进行条目删除处理并刷新主编辑页面。若出错,则显示适当的消息,但在正常处理时,没有与该操作关联的视图。

假设您想让有查看 portlet 的权限的用户使用主视图页面和详细信息视图页面、让有编辑 portlet 的权限的用户使用添加、编辑和删除功能。在这种情况下,您可在 doView portlet 方法中控制主视图页面和详细信息视图页面。您可在 doEdit 方法中控制剩余的页面。

public void doView(PortletRequest request, PortletResponse response)throws PortletException, IOException {String oid = request.getParameter('selectedContact');if (oid == null) {// Main view processing goes hereportletContext.include('main_view.jsp' request, response);else {// Detail view processing goes hereportletContext.include('detail_view.jsp' request, response);}}

然而,您意识到如果您试图在每次刷新时从 HTTP 请求中检索 selectedContact 索引,那么,当 portlet 因门户页面被刷新而被刷新时,即使用户正在使用页面中不同的 portlet,表单数据也会被丢失并且该实现将使 portlet 返回到主视图。所以,请使用操作侦听器来获取被选的联系方式的值并在会话中设置它以使今后的刷新可获取正确的值并保留适当的页面设置。现在,doView 代码与下面的代码相似,在操作侦听器中有 actionPerformed 方法的实现,该方法检索适当的值并把它放在会话中。当然,您还需要在 portlet URI 中指定操作事件以使侦听器被调用:

public void doView(PortletRequest request, PortletResponse response)throws PortletException, IOException {PortletSession session = request.getPortletSession(false);if (session != null) {String oid = (String)session.getAttribute('oid');if (oid == null) {// Main view processing goes here// URI and action listener for showing the contact detailsPortletURI portletURI = response.createURI();PortletAction portletAction =new DefaultPortletAction('detailRequest');portletURI.addAction(portletAction);request.setAttribute('detailURI', portletURI.toString());portletContext.include('main_view.jsp' request, response);else {// Detail view processing goes here// Get bean for given OIDsession.removeAttribute('oid');portletContext.include('detail_view.jsp? request, response);}}elseresponse.getWriter().println('You must log in first');}public void actionPerformed(ActionEvent event) throws PortletException {DefaultPortletAction portletAction =(DefaultPortletAction) event.getAction();if (portletAction instanceof DefaultPortletAction) {DefaultPortletAction action = (DefaultPortletAction) portletAction;PortletRequest request = event.getRequest();// Show the contact detail view. Get the contact oid number// of the selected contact and put it on the session objectif (action.getName().equals('detailRequest')) {String oid = request.getParameter('selectedContact');request.getSession(true).setAttribute('oid', oid);}}}

在这里,不少代码仅仅被用来管理主视图与详细信息视图之间的页面过渡。您还没有编写任何有关应用程序的业务逻辑的代码。在编写这些代码时很容易把错误引入到这些代码中。还有,您需要在各个地方实现组件的组成部分以使过程成功完成;这些组件常常依赖于字符串匹配以使事件与适当的操作绑定或在管理过程控制的代码中设置和读取标志。

如果在控制代码中包括更多的添加、编辑和修改操作,那么控制代码将变得更复杂。以下源代码显示的是该实现的 actionPerformed 方法。这里没有显示 doEdit 方法中相应的代码,这些代码用适当的操作来设置 portletURI、询问事件标志、设置和除去会话中的数据和标志。

public void actionPerformed(ActionEvent event) throws PortletException {DefaultPortletAction portletAction =(DefaultPortletAction) event.getAction();if (portletAction instanceof DefaultPortletAction) {DefaultPortletAction action = (DefaultPortletAction) portletAction;PortletRequest request = event.getRequest();PortletSession session = request.getPortletSession();// Show the contact detail view. Get the contact oid number// of the selected contact and put it on the session objectif (action.getName()Equals('detailRequest')) {String oid = request.getParameter('selectedContact');session.setAttribute('oid', oid);}// Handle the request to go to the add viewif (action.getName()Equals('ADD_REQUEST') {session.setAttribute('NEXT_EDIT_PAGE' 'ADD_PAGE';}// Handle the request to go to the edit viewif (action.getName()Equals('EDIT_REQUEST') {session.setAttribute('NEXT_EDIT_PAGE' 'MODIFY_PAGE);}// Handle the reqeust to delete contentif (action.getName()Equals('DELETE_REQUEST')ContactsManager.getInstance().(deleteContact(request));// Handle the Add Content eventif (action.getName()Equals('ADD_CONTACT')ContactsManager.getInstance().addContact(request));// Handle the Modify Content eventif (action.getName()Equals('EDIT_CONTACT')ContactsManager.getInstance().modifyContact(request));}}

状态是实现状态接口的类,这个类表示由于应用了操作而产生的 portlet 的效果。一般来说,这个类有可视组件。

这样的应用程序往往包括以下这些东西:

操作:

显示主页面 显示详细信息页面 显示主编辑页面 显示添加联系方式页面 添加联系方式 显示修改联系方式页面 修改联系方式 删除联系方式 状态:

主视图页面 详细信息视图页面 主编辑页面 添加联系方式页面 修改联系方式页面 现在来确定这个应用程序的可用状态过渡。通过把适当的操作应用到当前状态(这将导致应用程序进入另一个特定状态)来管理过渡。

图 1. 状态图

在理解了这些 portlet 知识后,您可以使用状态模式来创建这个应用程序。在构建应用程序时,您可以把公共的结构用于状态过渡,这一结构使您可以删除过多的 if语句(这些语句使用字符串匹配和多个被设置的标志。)。

Public void doView(PortletRequest request, PortletResponse response)throws PortletException, IOException {// Ensure we are logged inPortletSession session = request.getPortletSession();if (session == null)throw new MessageException('Login to the portal first');// Get the state request from session; main view as defaultState nextState = (State) session.getAttribute(Action.VIEW_STATE);if (nextState == null)nextState = new MainViewState();// Dispatch to state handlernextState.performView(request, response,getPortletConfig().getContext());}

下面的代码显示了 StateManagerPortlet 类的 actionPerformed 方法中的简单处理。同样,这个方法仅仅获取当前的操作类实例并调用它的 actionPerformed 方法。

Public void actionPerformed(ActionEvent event) throws PortletException {// Execute the perform action method for the eventPortletContext portletContext = getPortletConfig().getContext();PortletRequest request = event.getRequest();Action action = (Action) event.getAction();action.actionPerformed(request, portletContext);}

然后,操作类的 actionPerformed 方法执行正常的处理并使会话处于正确的状态以使流程控制正确地执行下去。请记住,一般来说,操作类和状态类的字段很少甚至于没有字段。所以,把它们添加到会话对象的开销是最小的。以下是操作类的 actionPerformed 方法的代码,这是一段添加联系方式的代码:

public void actionPerformed(PortletRequest request,PortletContext portletContext) {// Add the contactContactHelper contactHelper = ContactHelper.getInstance();contactHelper.addContact(request);// Set next portlet state ?Main EditState nextState = new MainEditState();PortletSession session = request.getPortletSession();session.setAttribute(EDIT_STATE, nextState);}

您不必为了在 portlet do 方法中实现这个模式而作任何更改,所以您不显示等同的状态类 perform 方法。但是,为了包括用于状态的刷新方法,您可以扩展这里的模式。刷新方法将逻辑地抽取负责 portlet 数据检索的应用程序代码,以使您可以分离所需的逻辑以确定 portlet 刷新导致刷新源数据还是导致从高速缓存中检索源数据。

在 StateManagerPortlet 要求状态类把 HTML 片断写给响应(或调用 JSP 来这样做)前,StateManagerPortlet 可以要求状态类刷新自己。在刷新方法中,您可以包括刷新或再次检索数据的逻辑以用于显示。例如,显示变化的数据的 portlet 可能需要在每次刷新屏幕时重访数据源。您可以把这样做的逻辑包括在刷新方法中。另一方面,显示稳定的信息的 portlet 很可能把数据访问逻辑放在初始状态惰性初始化逻辑中并在高速缓存中存储结果。用于这种类型的稳定数据状态的刷新方法不做任何事。

因为刷新方法中的业务逻辑可能导致过渡到不同的状态(包括错误状态),所以您可以扩展状态模式以支持状态之间的状态过渡。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有