更新时间:2022-09-11 11:37:02
这是一篇关于使用IBM Rational Application Developer 6.0进行JSF (JavaServer Faces)和JSR (Java Specification Request)168开发的系列文章的第二部分(共两部分)。第一部分主要关注于JSF 和 JSR 168开发的基础产品特性并创建了两个portlet和三个CRMBrowser应用视图。在第二部分,你将会了解如何在JSR 168 portlet之间进行通信实现复杂的屏幕流。
这是一篇关于使用IBM?; Rational? Application Developer 6.0(IRAD)进行portal开发的系列文章的第二部分(共两部分,第一部分见Resources部分)。除了理解这些功能性的知识外,你也可以学到有关包含在IRAD中基础的JavaServer? Faces (JSF) 和 IBM ? WebSphere Portal Server 5.1特性。最后,这篇文章将会讨论如何去实现:
使用混合型技术开发协作性portlet,这些技术包括以下几个重要步骤:
首先,我接着第一部分开始,完成这些步骤实现我们CRMBrowser应用程序中的整个概要-细节的浏览功能.你可以从该篇文章的下载部分下载这些实例代码.
在定义如何在Summary 和Detail portlet之间启动交互之前,该篇文章将首先论述一下这些Portlet如何在运行期进行交互.不管你什么时候点击Summary Portlet中链接事件,它都会发送一个消息给 Detail Portlet,让它显示相应的实体和数据。
Summary portlet通过你所点击的事件链接向Detail portlet发送不同的数据.比如:当你点击customer id链接时,Summary portlet将向Detail portlet发送一个com.ibm.sample.crmbrowser.CustomerDetailInfo bean的实例.同样,如果你点击了issue id 链接,那么Summary portlet将会向这个Detail portlet发送一个com.ibm.sample.crmbrowser.Issue bean的实例.
要想让WebSphere Portal Server属性代理器知道两个portlet是如何进行交互的话,你必须在他们两个portlet之间定义一个wire。 使用WSDL(接下来会有更具体的介绍)来对这个连接进行描述。这个连接的源数据和目标数据必须是相同的;因此,要想把你的bean从Summary Portal传送到Detail Portal中,你必须定义一个额外的bean作为CustomerDetailInfo和Issue bean实例的持有者。com.ibm.sample.crmbrowser.ShowDetailMessage bean的实例将会在Summary portlet 和Detail portlet之间传输。通过你在CustomerSummaryView.jsp中所点击的链接,它将会很准确的容纳CustomerDetailInfo bean或Issue bean中的一个实例。
接下来将描述如何配置这个连接来体现出这些语义,以及如何实现在portlet和源、目标JSP(JavaServer? Pages)中需要的java代码。
启动这个源portlet包括以下几个步骤:
JSR168 portlet可以通过属性代理交换属性达到相互协作。一个WSDL文件描述了那些源portlet发布(或传递)给属性代理的属性。在接下来的处理过程中,你将会了解到一些IRAD用来支持协作性portlet开发的工具。
要想把我们的Summary portlet作为一个属性源,可以简单的右击Project Explorer 视图中的portlet来显示上下文菜单。如图1所示点击Cooperative > Enable Source。
图1、启动可协作性源的向导
可协作性源向导启动后(如图2所示),输入下面示例的值:
图2、可协作性源向导
这个参数(Parameter)术语涉及到这个值如何从源portlet传递到目标portlet中。
RenderRequest
>对象上。这个render参数可以在动作阶段设置并且在portlet生命周期的render阶段获得。但是它不能在动作阶段取得。ActionRequest
对象上,并且可以在portlet的生命周期的动作处理阶段得到。这个参数值在请求处理的结束时没有任何意义。(也就是说,当它离开了单个调用时不能持续)。ActionRequest
对象上。生命周期方面和Request 参数一样。
你将把属性值作为request的一个属性。这样你就可以使用复杂的Java类型在portlet之间传递信息,而不用通过在session中存储多余的信息而降低了服务性能。
可协作性源向导生成了一个WSDL文件(如图3所示),它为属性代理描述了这个portlet。注意到这个Summary portlet由一个特殊的图标标记着,表明这是一个属性源。这个WSDL文件包括以下几个部分:
图3.由可协作性源向导生成的结果
这个可协作性源向导将会自动的产生一个表示消息的简单类型(见列表1)。你需要手动修改所产生的WSDL来描述一个复杂的类型(这是因为我们的portlet需要相互传递值――而不是简单的字符)。列表2显示了这个复杂类型的定义
<xsd:schema targetNamespace="http://crmbrowser.sample.ibm.com"> <xsd:simpleType name="ShowDetailMessageType"> <xsd:restriction base="xsd:string"></xsd:restriction> </xsd:simpleType> </xsd:schema> |
你需要改变这个简单的类型从而正确的描述这个Summary portlet将要发送给细节portlet的消息。这个WebSphere Portal Server Wiring工具稍后将会使用这个类型定义来定义在源和目标之间的一个连接。
<xsd:complexType name="ShowDetailMessageType"> <xsd:all> <xsd:element name="customerDetail" type="tns:CustomerDetailType" minOccurs="0" maxOccurs="1"/> <xsd:element name="issueDetail" type="tns:IssueType" minOccurs="0" maxOccurs="1"/> </xsd:all> </xsd:complexType> <xsd:complexType name="CustomerDetailType"> <xsd:all> <xsd:element name="customerId" type="xsd:string" /> <xsd:element name="firstName" type="xsd:string" /> <xsd:element name="lastName" type="xsd:string" /> <xsd:element name="workPhone" type="xsd:string" /> <xsd:element name="homePhone" type="xsd:string" /> </xsd:all> </xsd:complexType> <xsd:complexType name="IssueType"> <xsd:all> <xsd:element name="issueId" type="xsd:string" /> <xsd:element name="shortDesc" type="xsd:string" /> <xsd:element name="desc" type="xsd:string" /> <xsd:element name="openDate" type="xsd:string" /> <xsd:element name="status" type="xsd:string" /> </xsd:all> </xsd:complexType> |
在你的WSDL中的这些复杂类型是属性代理定义一个连接用的元数据。他们应能够正确的描述从Summary portlet传递到Detail portlet中的bean的内容(目的是为了正确描述这些连接和他们所实现的功能)。然而,在WebSphere Portal Server 5.1中属性代理并不能在运行期执行校验来保证你所传递的bean与这些抽象的定义相对应。
除了类型定义以外,你需要对生成的绑定信息做一些修改。列表3中显示了工具所生成的默认的绑定,而列表4显示了你在制作可协作性行为时所做的手动的修改。
<binding name="Summaryportlet_Binding" type="tns:Summaryportlet_Service"> <portlet:binding /> <operation name="Summaryportlet"> <portlet:action type="standard" /> <output> <portlet:param name="CustomerDetailType" partname="CustomerDetailType_Output" boundTo="request-attribute" /> </output> </operation> </binding> |
<binding name="Summaryportlet_Binding" type="tns:Summaryportlet_Service"> <portlet:binding /> <operation name="Summaryportlet"> <portlet:action type="standard" name="sendShowDetailResponse" caption="Send.Detail.Response" description="Send Detail Response" /> <output> <portlet:param name="detailInfo" class="com.ibm.sample.crmbrowser.bean.ShowDetailMessage" partname="ShowDetailType_Output" boundTo="request-attribute" caption="Detail.Info.Type" description="Detail Info Type" /> </output> </operation> </binding> |
生成的WSDL描述的关键变化包括以下几点:
在列表4中的标记的变化不是简单的格式上的变化,而是在制作portlet消息时本质上的变化。除了在列表3和列表4中所强调的绑定部分的类型变化以外,也建议你修改文件中的消息和端口类型,从而给这些消息和操作提供更多描述性的名称。这在创建更复杂的用户接口包括它们之间的多portlet和连接时有很大的帮助。
假如你选择采用这些变化,你将需要保证这个WSDL在匹配消息、端口类型和绑定部分(这该篇文章的下载部分提供的实例源中有所阐述)中的消息和操作名称时的合法性。
为完成启动你的源portlet,你需要再完成两步:
第一步,先在页面设计器中打开CustomerSummaryView.jsp,并选择Customer Id指令超链接。如图4所示在属性视图中编辑动作的属性。
图4. 输入动作参数,该动作触发了通过WPS属性代理传输属性值。
你需要定义的关键参数是com.ibm.portal.propertybroker.action,这个值必须与操作绑定(列表4中的sendShowDetailResponse
)的动作名称属性的定义的值相同
剩下的步骤包括将你的复杂类型――com.ibm.sample.crmbrowser.bean.ShowDetailMessage bean――放入请求对象中。接下来,通过点击在属性视图(如图5所示)中Quick Edit图标为Customer Info链接生成一个动作句柄方法。
图5.为CustomerId生成一个动作句柄代码
如下面的列表5所示完成动作句柄的实现。
列表5.将CustomerDetailInfo放入请求对象中
public String doLink1Action() { // Determine which action link has been clicked and dispatch the corresponding // object to the property broker ShowDetailMessage message = new ShowDetailMessage(); message.setCustomerDetail(getCustomerSummary().getCustomerD etailInfo()); getRequestScope().put("detailInfo", message); return ""; } |
完成上述步骤后。你的Summary portlet能有效的作为一个属性源。尽管如此,假如你回到最初的应用场景中,这个Summary portlet可以向Detail portlet发送两个不同类型的消息。
因此本质上,你所要做的是为issueId链接产生动作句柄代码。
创建一个参数,它将会持有第2步所选择的论题的值:
issueId
的名称。
图6.将issueId参数映射到一个变量上
这个变量将会传输选定的issueId到我们的动做句柄代码中。这个动作句柄代码(如列表6所示)使用这个参数来取得合适的Issue对象。
public String doLink2Action() { // Type Java code that runs when the component is clicked ShowDetailMessage message = new ShowDetailMessage(); String issueId = (String)getRequestParam().get("issueId"); if (issueId != null) { for (int i = 0; i < getCustomerSummary().getIssues().size(); i++) { Issue issue = (Issue)getCustomerSummary().getIssues().get(i); if (issueId.equals(issue.getIssueId())) { message.setIssueDetail(issue); getRequestScope().put("detailInfo", message); break; } } } return ""; } |
完成这些步骤以后,你的Summary portlet可以作为一个属性源支持你应用设计。
因此本质上,你所要做的是为issueId链接产生动作句柄代码。
创建一个参数,它将会持有第2步所选择的论题的值:
issueId
的名称。
图6.将issueId参数映射到一个变量上
这个变量将会传输选定的issueId到我们的动做句柄代码中。这个动作句柄代码(如列表6所示)使用这个参数来取得合适的Issue对象。
public String doLink2Action() { // Type Java code that runs when the component is clicked ShowDetailMessage message = new ShowDetailMessage(); String issueId = (String)getRequestParam().get("issueId"); if (issueId != null) { for (int i = 0; i < getCustomerSummary().getIssues().size(); i++) { Issue issue = (Issue)getCustomerSummary().getIssues().get(i); if (issueId.equals(issue.getIssueId())) { message.setIssueDetail(issue); getRequestScope().put("detailInfo", message); break; } } } return ""; } |
完成这些步骤以后,你的Summary portlet可以作为一个属性源支持你应用设计。
要想为属性值启动这个Detail portlet作为目标,你需要执行下面的几个步骤:
processAction
()
方法。它可以处理来自于属性代理的动作请求,并重定位到相应的视图中。
你将使用可协作性目标向导生成WSDL。启动这个向导,在Project Explorer视图中选择这个portlet,右击它,并点击Cooperative > Enable Target(这个步骤和启动协作性源很相似)。
可协作性源向导如图7所示。你需要填写下面一些值:
ActionRequest
对象的属性传递给目标portlet。
图7.可协作性目标向导
可协作性目标向导生成了一个WSDL文件(如图3所示), 它描述了目标portlet通过属性代理取得的属性。要想启动这个目标,你需要手动编辑所生成的WSDL:
图8.由可协作性目标向导生成目标WSDL文件
列表7显示了这个生成的WSDL 绑定。列表7显示了为启动协作性行为在绑定信息中进行的手动的修改。
<binding name="Detailportlet_Binding" type="tns:Detailportlet_Service"> <portlet:binding /> <operation name="Detailportlet"> <portlet:action name="receiveShowDetailRequest" type="standard" caption="Receive.Detail.Request" description="Receive Detail Request" /> <input> <portlet:param name="detailInfo" partname="ShowDetailMessageType_Input" boundTo="request-attribute" /> </input> </operation> </binding> |
<binding name="DetailPortlet_Binding" type="tns:DetailPortlet_Service"> <portlet:binding /> <operation name="receiveShowDetailRequest"> <portlet:action name="receiveShowDetailRequest" type="standard" caption="Receive.Detail.Request" description="Receive Detail Request" /> <input> <portlet:param name="detailInfo" class= "com.ibm.sample.crmbrowser.bean.ShowDetailMessage" partname="ShowDetailType_Input" boundTo="request-attribute" caption="Detail.Info.Type" description="Detail Info Type" /> </input> </operation> </binding> |
对绑定信息(并不仅仅依据你的习惯性的选择)的相当重要的修改包括添加一个类属性,它描述了整个符合条件的java类型通过属性代理传递给目标。这个类型必须与启动源portlet使用的属性一样。在这种情况下它就是com.ibm.sample.crmbrowser.bean.ShowDetailMessage。你同样也必须添加标题和描述信息到这个param
元素中。这在你创建连接时很有帮助。
完成这个目标属性的WSDL描述后,你需要重写所提供的portlet类和实现processAction()方法。IRAD JSR 168 Faces portlet项目提供一个促进JSF portlet开发的类-- com.ibm.faces.webapp.FacesGenericPortlet。这个类可以在jsf-portlet.jar文件中找到。
该类的实现包括一些限制和不能处理的地方:
为了克服这些限制,你需要重写目标portlet中的processAction()方法。此外你需要在目标portlet中写某个processAction方法。还要写某些客户代码处理来自于源portlet的消息。
创建重写方法,按照以下几个简单的步骤:
编辑器将会生成一个processAction()重写的内核实现,它包括一个对基类的调用。
列表9显示了你的DetailPortlet.processAction()方法。在这个方法的实现中,你需要执行一些关键的动作:
列表9. DetailPortlet.processAction()方法的实现。
public void processAction(ActionRequest request, ActionResponse response) throws PortletException { // Reterive target action name String actionName = (String)request.getParameter ("com.ibm.portal.propertybroker.action"); if (actionName != null) { // Invoke custom processing only if property broker action String actionURL = ""; if(actionName.equals("receiveShowDetailRequest")) { ShowDetailMessage detailInfo = (ShowDetailMessage)request.getAttribute ("detailInfo"); if (detailInfo.getCustomerDetail() != null) actionURL = "/CustomerDetailView.jsp"; else actionURL = "/IssueDetailView.jsp"; request.getportletession().setAttribute("detailInfo", detailInfo); } if (!actionURL.equals("")) request.getportletession().setAttribute ("com.ibm.faces.portlet.page.view", actionURL); } // Otherwise invoke default behaviour super.processAction(request, response); } |
|
|
剩下的编码是要确保目标视图在portlet加载它时能适当地进行初始化。按照JSF架构,***的时机是当作为JSF页的模型的bean被创建的时候。IRAD JSF工具生成JavaBean,你可以与JSF控制器进行程序上的交互(如图9中所示)。
图9. JSF工具生成的包和bean
列表10显示了在IssueDetailView.java 中pagecode.IssueDetailView.getIssue() 方法的实现。该方法在JSF运行时重构对象树时的任意时间内被调用,这棵树将会最终为终端用户创建一个HTML网页。在这个方法的实现中关键的是:
列表10.实现pagecode.IssueDetailView.getIssue()方法。
public Issue getIssue() { if (issue == null) { ShowDetailMessage detailInfo = (ShowDetailMessage)getSessionScope().get("detailInfo"); if (detailInfo != null) issue = detailInfo.getIssueDetail(); if (issue == null) issue = new Issue(); } return issue; } |
为了使这个应用更加完整的实现,需要为pagecode.CustomerDetailView.getCustomerDetail()写一个类型的方法实现。(你可以在这篇文章的下载部分看到更多的有关代码的信息)。
剩下的最后一步是对该应用进行单元测试。如果你还没有这样做的话,按照下面的步骤创建一个新的服务器:
在Project Explorer视图中选择CRMBrowser动态Web项目。
你的WebShere Portal UTE现在可以打开,并且一个显示你的portlet的浏览器将会自动打开。
下一步你需要定义你的Summary portlet和Detail portlet之间的连接。这需要完成下面的几个步骤:
图10.Portlet连接工具
现在你可以开始使用CRMBrowser应用。需要变更Detail portlet中的视图――显示客户具体信息或问题的具体信息――通过Summary portlet视图中你所点击的动作链接。
WebSphere Portal Server Property Broker使得你可以在portlet之间传递复杂的数据。你可以使用这个特性实现portlet之间复杂的用户接口流。IRAD提供了能够帮助你在开发中利用Property Broker的特性的工具。你可以通过IRAD重写所生成的代码从而加强它的性能并增强应用的行为。要想学习这方面更多的技术,请浏览下面的Resourses部分中列出的其它文章和参考资料。
本文转自kenty博客园博客,原文链接http://www.cnblogs.com/kentyshang/archive/2008/03/06/1093234.html如需转载请自行联系原作者
kenty