Portlet 通信过程详解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Portlet 通信过程详解相关的知识,希望对你有一定的参考价值。
Portlet 通信过程详解
在 Portal 的开发过程中,Theme 与 portlet 之间的通信,以及 portlet 之间的通信是开发人员常常遇到的问题。通常 Portlet 之间需要能够互相通信,即一个 portlet 的状态发生改变,要通知其他的 portlet,这些收到通知的 Portlet 状态也要做相应的改变。根据 JSR 168 规范,Portlet 由容器管理,它们之间是相互独立的,并不共享 Session 对象。那么如何在 Portlet 之间传递参数呢?在本文中,将根据不同应用场景介绍参数传递的方式。
IBM Rational Application Developer V7.0 和 IBM Rational Software Architect V7.0 是 IBM Rational 软件交付平台产品系列中的第一款产品,它们包含了对 IBM WebSphere Portal V6.0 开发的完整支持。在下面的实例中,我们以 IBM Rational Software Architect V7.0 为开发平台,对 Portlet 的参数传递进行介绍。
概念介绍
首先,我们先介绍一些 portal 的基本概念。
Portal 的定义
Portal 是一个基于 web 的应用程序,它主要提供个性化、单点登录、不同来源的内容整合以及存放信息系统的表示层。
Portlet 的定义
Portlet 是基于 java 技术的 web 组件,它由 portlet 容器管理、并处理请求,并动态生成输出内容。就像 servlets 是专为将合成页面里的内容聚集在一起而设计的。通常请求一个 portal 页面会引发多个 portlets 被调用。每个 portlet 都会生成标记段,并与别的 portlets 生成的标记段组合在一起嵌入到 portal 页面的标记内。
Portal 规范
为规范 Portal,SUN 于 2003 年底制定了 JSR168,它定义了 portlet 标准,并给出了一个实现接口。
Portlet 组成
每个 portlet 页面由一个或多个 portlet 窗口组成,每个 portlet 窗口又分为两部分:一个是主题外观(Theme),它决定了 portlet 窗口的标题条、控制和边界的样式;另一个是 portlet 段,它由 portlet 应用填充。
同一页面内的不同 portlet 间的通信
对放在同一个页面上的 Portlet.,如果其中的某个 Portlet 做了提交等操作导致 portal 刷新, 这个页面内的每一个 portlet 都会被 render。要实现参数的传递通常有 3 个步骤:定义源 portlet,定义目标 portlet,关联源 portlet 和目标 portlet。
创建发送端 Portlet
首先我们先建立一个 Portlet Project,点击 Next;
图 1. 新建 Portlet Project
在 Project name中输入 MyProjectproj,Target Runtime选择 Websphere Portal v6.0,在 Portlet API中选择 JSR 168 Portlet,选中 Create a Portlet,在 Project Name中输入 SenderPortlet,在 Portlet Type中选择 Basic Portlet,选择 Show Advanced Settings,点击 Next;
图 2. 填写 Portlet Project 基本属性
图片看不清楚?请点击这里查看原图(大图)。
在 Project Facets面板中,选中 Java,在 version中选择 1.4,其他项保持不变,点击 Next;
图 3. 配置 Facets 属性
图片看不清楚?请点击这里查看原图(大图)。
在 Portlet Settings对话框中修改 Package Prefx为 com.ibm.myportlet,其他选项保持默认,点击 Finish。
图 4. 修改 Portlet 配置参数
图片看不清楚?请点击这里查看原图(大图)。
至此,我们已经创建了一个新的 Portlet 项目,其中包含一个名称为 SenderPortlet 的 Portlet。
创建接收端 Portlet
在 Project中点击右键,点击 New->Portlet,弹出 Portlet 创建向导对话框;
图 5. 新建 ReceiverPortlet
本文示例代码或素材下载
在 Project中选择 MyPortletproj,在 Project name中输入 ReceiverPortlet,Portlet中选择 Baisc Portlet,点击 Next;
图 6 Portlet 属性
在 Portlet Settings对话框中修改 Package Prefx为 com.ibm.myportlet,其他选项保持默认,点击 Finish。
图 7. 修改 Portlet 配置参数
这样我们就创建了 ReceiverPortlet,并把它加入到了 MyPortletproj项目中。
在 SenderPortlet上点击右键,点击 Coorperative-> Enable this Protlet to Send Data(Source) …
图 8. Portlet 协作-发送端配置
在 Coorperative对话框中,在输入框 Data Type URI中输入//myportletproj#MyDataType,在 Java Type中输入 java.lang.String,点击 Next;
图 9. 定义发送的数据类型
图片看不清楚?请点击这里查看原图(大图)。
在 Property Caption中保留默认值 outputProperty Property,在 Action Caption中保留默认值 SourceAction Action,点击 Next;
图 10. 定义发送端的 Action 名称和参数名称
图片看不清楚?请点击这里查看原图(大图)。
点击 Finish。
图 11. 使能发送数据
图片看不清楚?请点击这里查看原图(大图)。
SenderPortlet中 processAction代码片断。我们在上面定义了发送的参数名称为 outputProperty
清单 1. 发送端代码片断
String value=request.getParameter(FORM_TEXT); request.setAttribute("outputProperty", "Get the Parameter from same page:"+value);
在 ReceiverPortlet上点击右键,点击 Coorperative->Enable this Protlet to Receive Data(Target)…
图 12. Portlet 协作-接收端配置
在 Coorperative对话框中,在输入框 Data Type URI中输入//myportletproj#MyDataType,在 Java Type中输入 java.lang.String,点击 Next;
图 13. 定义接收的数据类型
图片看不清楚?请点击这里查看原图(大图)。
在 Action parameter中输入 FORM_TEXT,Action Value输入 TargetAction,在 Location中选择 Request Attribute,在 PropertyName中输入 inputProperty,点击 Next;
图 14. 定义接收端的 Action 名称和参数名称
图片看不清楚?请点击这里查看原图(大图)。
在 Property Caption中保留默认值 inputProperty Property,在 Action Caption中保留默认值 TargetAction Action,点击 Next;
图 15. 定义接收端的参数名称
图片看不清楚?请点击这里查看原图(大图)。
点击 Finish。
图 16. 使能接收数据
图片看不清楚?请点击这里查看原图(大图)。
部分代码实现
在发送端的 JSP 文件 SenderPortletView.jsp 中加入如下代码
清单 2 发送端 UI 代码片断
<DIV > <% /******** Start of sample code ********/ %> <FORM method="POST" action="<portlet:actionURL/>"> <INPUT name="WireAction" value="FORM_TEXT" type="hidden" /> <INPUT id="<%=com.ibm.myportlet.SenderPortlet.ACTION_TYPE%>" name="<%=com.ibm.myportlet.SenderPortlet.ACTION_TYPE%>" type="hidden"/> <LABEL for="<%=com.ibm.myportlet.SenderPortlet.FORM_TEXT%>"> Enter parameter value: </LABEL><BR> <INPUT name="<%=com.ibm.myportlet.SenderPortlet.FORM_TEXT%>" type="text" value="<%=formText%>"/> <INPUT name="<%=com.ibm.myportlet.SenderPortlet.FORM_SUBMIT%>" type="submit" onclick="javascript:document.getElementById( ‘<%=com.ibm.myportlet.SenderPortlet.ACTION_TYPE%>‘) .value=0;return true;" value="Pass parameter to Same Page"/> </FORM> <% /******** End of sample code *********/ %> </DIV>
本文示例代码或素材下载
ReceiverPortlet 中 processAction 代码片断。我们在上面定义了发送的参数名称为 inputProperty,接收到参数值后,把它放到 session 中以便在页面显示时使用。
清单 3 接收端代码片断
SessionBean sessionBean = getSessionBean(request); String inputProperty = (String)request.getAttribute("inputProperty"); inputProperty = request.getParameter("inputProperty"); if (inputProperty!=null) sessionBean.setFormText(inputProperty);
Portlet 发布以及配置
登录到 Portal 的控制台,将导出的 MyPortletproj.war部署到 portal server 上。操作步骤为点击 Portlet Management ->Web Moudles->Install,选择 MyPortletproj.war所在的路径,点击 Next;
图 17. 更新 Portlet 项目
图片看不清楚?请点击这里查看原图(大图)。
直接点击 Finish。
图 18. Portlet 列表
图片看不清楚?请点击这里查看原图(大图)。
在 Portal 控制台点击 Portal User Interface-> Manage Pages->Content Root->Home,点击 New Page,在 Title中输入 senderpage,点击 OK。
图 19. 新建 SenderPage
图片看不清楚?请点击这里查看原图(大图)。
在 Pages in Home 页面,点击 senderpage 右侧的 ,点击 add Portlet,选择 SenderPortlet,再次点击 addPortlet,选择 ReceiverPortlet,如图所示:
图 20. 修改 SenderPage 页面布局
图片看不清楚?请点击这里查看原图(大图)。
点击 Wires,关联 SenderPortlet 和 ReceiverPortlet。进行如下设置:
Source portlet :SenderPortlet Sending :outputProperty Property Target page :senderpage Target portlet :ReceiverPortlet Receiving :TargetAction Action,inputProperty Property Wire Type :Public
图 21. 连接 SenderPortlet 和 ReceiverPortlet
图片看不清楚?请点击这里查看原图(大图)。
点击 ,然后点击 Done。
不同页面之间的 portlet 的通信
不同页面的 portlet 参数传递主要用到了 Property Broker 的 API 实现,从原理上看,它采用发布 / 订阅(publish/subscribe)模式。在源 portlet 定义参数名称,参数类型并发布到 Property Broker,在目标 portlet 从 Property Broker 中取出参数并转换成相应的类型。
我们仍然使用上述的 SenderPortlet 作为源 Portlet,在 processAction 方法中加入如下代码。
清单 源 Portlet 传送参数到其他页面的 Portlet
部分代码实现
清单 4. 发送端代码片断
PropertyValue propertyValues[] = new PropertyValue[1]; Context ctx = new InitialContext(); PropertyFactory service = (PropertyFactory) ((PortletServiceHome)ctx .lookup("portletservice/com.ibm.portal.propertybroker .service.PropertyFactory")) .getPortletService(com.ibm.portal.propertybroker.service .PropertyFactory.class); PropertyController propertyKey = service.createProperty(request); propertyKey.setName(FORM_TEXT); propertyKey.setClassname("java.lang.String"); propertyKey.setDirection(Direction.OUT); String value=request.getParameter(FORM_TEXT); propertyValues[0] = service.createPropertyValue(request, propertyKey, "Get the Parameter from sender page: "+value); Name uniqueName = new CompositeName("portal:uniquename"); uniqueName.add("page.myreceiverpage"); ctx=new InitialContext(); ObjectID thisPage = (ObjectID)ctx.lookup(uniqueName); ctx=new InitialContext(); PropertyBrokerContextPassingService service1 = (PropertyBrokerContextPassingService) ((PortletServiceHome)ctx.lookup( "portletservice/com.ibm.portal.propertybroker .service.PropertyBrokerContextPassingService")) .getPortletService(com.ibm.portal.propertybroker .service.PropertyBrokerContextPassingService.class); service1.changedProperties(request,response,thisPage,propertyValues);
本文示例代码或素材下载
在发送端的 JSP 文件 SenderPortletView.jsp 中,我们新增一个按钮用来传递参数到不同页面
清单 5. 发送端 UI 代码修改
<INPUT name="<%=com.ibm.myportlet.SenderPortlet.FORM_SUBMIT%>" type="submit" onclick="document.getElementById(‘<%=com.ibm.myportlet .SenderPortlet.ACTION_TYPE%>‘).value=1;return true" value="Pass parameter to Another Page"/>
接下来我们创建接收端的 Portlet,创建 Portlet 的方法同上。我们将这个 Portlet 命名为 Receiver1Portlet。打开 Portlet.xml文件,在 Receiver1Portlet 部分加入如下代码,其作用是使目标 Portlet 能够访问 pagecontext 并接收参数。
清单 6. Portlet.xml 参数配置
<portlet-preferences> <preference> <name>com.ibm.portal.pagecontext.enable</name> <value>true</value> </preference> </portlet-preferences>
在 Receiver1Portlet 的 processAction 方法中加入如下代码,代码的作用是从 request 中获取 com.ibm.portantext 对象,然后解析出参数 FORM_TEXT:
清单 7. 接收端代码片断
SessionBean sessionBean = getSessionBean(request); String form_text=null; String specialAction = request.getParameter("com.ibm.portal.action"); Map map = null;; if ((specialAction!=null) && (specialAction.equals("com.ibm.portal.pagecontext.receive"))) { map = (java.util.Map) request.getAttribute("com.ibm.portantext"); } if( map!=null ) { form_text = (String) map.get(FORM_TEXT); } if( sessionBean != null ) sessionBean.setFormText(form_text);
我们再次导出 MyPortletproj.war,打开 Portal 控制台,点击 Portlet Management ->Web Moudles->Update,选择 MyPortletproj.war所在的路径,点击 Next;
Portlet 发布以及配置
图 22. 更新 Portlet 项目
图片看不清楚?请点击这里查看原图(大图)。
直接点击 Finish。
在 Portal 控制台点击 Portal User Interface-> Manage Pages->Content Root->Home,点击 New Page,在 Title中输入 receiverpage,点击 OK。
图 23. 新建 ReceiverPage
图片看不清楚?请点击这里查看原图(大图)。
在 Pages in Home页面,点击 receiverpage右侧的 ,点击 add Portlet,选择 Receiver1Portlet,点击 Done。如图所示:
图 24. 修改 ReceivePage 页面布局
图片看不清楚?请点击这里查看原图(大图)。
在 Portal 控制台点击 Portal Settings-> Custom Unique Names,在 Resource Type点击 Pages,点击 receiverpage右侧的 ,在 Unique name中输入 page.myreceiverpage,点击 OK。注意这里输入的 Unique name要与上面代码 清单 4中的 unique name一致。
图 25. 指定页面唯一标识
Theme 与 Portlet 的通信
在实际的开发中,从 theme 中传递参数到 Portlet 也是很常见的。通常我们用 HttpRequest 作为参数的媒介。
修改 Theme
通常 Theme 的根目录位于 C:IBMWebSphereprofileswp_profileinstalledApps%HOST_NAME%wps.ear wps.warthemes,在本文中,我们使用 IBM 的默认 theme,其路径位于 htmlIBM,在 banner_toolbar.jspf 中的 <div class="toolbar"> 下面,我们加入如下代码:
本文示例代码或素材下载
清单 8. Theme 中 UI 代码片断
<%if(request.getParameter("hello")!=null){ request.setAttribute("hello",request.getParameter("hello")); } %> <div class="toolbarLink"> <portal-navigation:urlGeneration contentNode="page.mythemepage" layoutNode="portlet.theme" > <form name="myForm" method="post" action="<% wpsURL.write(out); %>" > <input type="hidden" id="hello" name="hello" value="Hello World, I am from Theme."/> </form> <a class="toolbarLink" href="#" onclick="myForm.submit();" > </portal-navigation:urlGeneration>Say Hello</a></div>
部分代码实现
下面我们创建一个新的 Portlet 来接收从 Theme 中传来的参数。创建 Portlet 的方法同上。我们将这个 Portlet 命名为 ThemePortlet。在 doView 方法中,加入如下代码:
清单 9. ThemePortlet 接收参数代码片断
// Check if portlet session exists SessionBean sessionBean = getSessionBean(request); if( sessionBean==null ) { response.getWriter().println("<b>NO PORTLET SESSION YET</b>"); return; } PortletRequest portletRequest=(PortletRequest)request; HttpServletRequest (portletRequest).getHttpServletRequest(); String param = null; if (("hello")!=null) param = ("hello").toString(); if (param!=null) { System.out.println("get the parameter:"+param); sessionBean.setThemeParam(param); ("hello"); }
在接收到参数后,我们要从 HttpRequest 中移除 hello 属性,否则每次页面提交导致的 portlet 刷新都会接收到参数,而通常我们希望只接收一次。
我们再次导出 MyPortletproj.war,打开 Portal 控制台,点击 Portlet Management ->Web Moudles->Update,选择 MyPortletproj.war所在的路径,点击 Next;
Portlet 发布以及配置
图 26. 更新 Portlet 项目
图片看不清楚?请点击这里查看原图(大图)。
直接点击 Finish。
在 Portal 控制台点击 Portal User Interface-> Manage Pages->Content Root->Home,点击 New Page,在 Title 中输入 themepage,点击 OK。
图 27. 新建 ThemePage
图片看不清楚?请点击这里查看原图(大图)。
在 Pages in Home 页面,点击 themepage 右侧的 ,点击 add Portlet,选择 ThemePortlet,点击 Done。如图所示:
32 图 28. 修改 ThemePage 的页面布局
图片看不清楚?请点击这里查看原图(大图)。
至此,我们的代码编写以及 Portlet 配置已经完成。在验证结果前,需要重新启动 Portal Server。
验证结果
在重新启动 Portal server 后,进入到 Portal 的管理控制台,我们能够看到我们刚刚创建的 sernderpage,receiverpage,themepage 以及在 theme 中加入的“Say Hello”超链接。如下图所示:
图 29. 新增的页面和修改后的 Theme
图片看不清楚?请点击这里查看原图(大图)。
首先点击 Say Hello 超链接,可以页面跳转到 themepage,同时在 themeportlet 中接收到了从 theme 传来的参数。
图 30. 验证 Theme 与 Portlet 间的参数传递
以上是关于Portlet 通信过程详解的主要内容,如果未能解决你的问题,请参考以下文章
Microsoft Lync Server 集成为 portlet
Liferay7 BPM门户开发之33: Portlet之间通信的3种方式(sessionIPC Render ParameterIPC EventCookies)
如何自定义要在“添加更多 portlet”菜单中显示的 portlet