BEA WebLogic Portal 8.1™ 框架的核心任务之一是创建一致且正确的 URL , 以便用户在门户页面环境中与各种 portlet 进行 交互。撰写本文的目的是为了向读者介绍 WebLogic Portal 中 URL 创建过程的基础结构。本文介绍 WebLogic Portal 如何创建 URL , 可以创建的各种 URL , URL 背 后的 API 和 层 , 以及使用 Web Services for Remote Portlets ( WSRP ) 提供或消费 portlet 时 URL 将会发生什么变化。在介绍 URL 创建过程的同时,我还将重点强调一些最佳实践。阅读本文之后,您将有能力避免大多数常见的 URL 缺陷,并且可以利用 portlet 提供一致的用户体验。
问题 为什么创建 URL 是 WebLogic Portal 的核心任务 ? 为什么 portlet 不能像在 HTML/JSP 页面中创建 URL 那样在以下示例代码中创建 URL Click <a href="next.jsp">here</a> to continue. 当用户点击与此类似的链接时 , 下面的某种情况将发生 :
要避免这些情况的发生 , portlet 必须要求 WebLogic Portal 创建 URL 。为什么 portlet 将此任务委派给 WebLogic Portal ? 原因如下 : 提示 :在创建 portlet 时 , 不要假定关于 URL 结构的任何事情。实际结构不仅可以由部署在 portlet 的 Web 应用程序中的模板确定,而且也可以由客户确定,比如 WSRP 。
当您将 URL 的创建委托给 WebLogic Portal 时 , 它将对 portlet 屏蔽门户页面 URL 、域名称、代理服务器等。门户管理员和部署人员可以控制细节,无需破坏 portlet 中的任何 URL 。 如果您非常想知道上述链接的创建方式(假定您要在简单 JSP portlet 中创建这一链接),下面就是一个例子: Click <a href="<render:jspContentUrl contentUri="next.jsp"/>">here</a> to continue . 现在 , 我们来检查 WebLogic Portal 的 URL 的基础结构 URL模板 WebLogic Portal 使用称为 “ URL 模板 ” 的简短 URL 片断创建 URL 。它们不是有效的 URL , 需要进一步处理才能使用。要查看 URL 模板,需要创建门户项目并检查其 WEB-INF 目录。在此目录中,您将发现一个 url-templates-config.xml 文件。该文件中包含大量的默认 URL 模板。每个 URL 模板的外观如下所示: <url-template name="default"> {url:scheme}://{url:domain}:{url:port}/{url:path}?{url:queryString}{url:currentPage} </url-template> to continue. 提示 : 您可以使用已知值替换任何可选标志。例如 , 如果您认为永远不会通过 HTTP 访问门户页面 , 则可以在所有 URL 模板中使用 “ http ” 替换“url:scheme” 。 您将发现该文件不只是列出一个模板 , 而是列出多个模板。在讨论为何需要多个模板之前,我们先看一看 URL 模板的结构。 剖析URL模板 URL 模板是带有一个或多个标志的 URL 。这些标志由 WebLogic Portal 预定义,在使用远程 portlet 的情况下,是 WSRP 1.0 规范规定的。所有标志均由大括号包围 ( { , } ) 。使用 URL 模板创建 URL 时, WebLogic Portal 使用相应的值替代这些标志,这些值或者由 URL API 或者由 JSP 标记指定,或者从部署门户的方式自动派生。 每个 URL 模板中可以具有一个或多个下面的标志 :
提示 : 记住使用用于设置代理服务器的路径前缀替换url:prefix标志。 创建门户项目时创建的 url-templates-config.xml 文件中包含的模板列表 , 可以满足大多数常见开发需求。 URL的类型 WebLogic Portal 使用三种 URL
稍后我们将讨论在 JSP 中如何创建这些类型的 URL 。 参照前面的 url-templates-config.xml 文件 , 您将发现该文件具有两个主要部分。第一部分定义大量模板。 第二部分定义 Java 和 Page Flow portlet 如何使用这些模板。 文件中定义的每个 url-template 具有一个名称和一个字符串值。任何两个 URL 模板的名称都不能相同。 字符串值是带有一个或多个标志的 URL 模板字符串。 此文件的第二部分为 Java 和 / 或 Page Flow portlet 定义一个或多个 url-template-ref 元素。使用这些元素可以指定要用于给定 URL 的 URL 模板。例如 , 以下片断指定 , 名为 jpf-action 的 URL 模板可用于创建在页面流中使用的操作 URL , 而名为 jpf-secure-action 的 URL 模板 可用于在页面流中创建安全操作 URL : <jpf-url-templates> <url-template-ref type="action" name="jpf-action"/> <url-template-ref type="secure-action" name="jpf-secure-action"/> ... </jpf-url-templates> 使用URL模板 WebLogic Portal 提供了很多使用在前一节中定义的 URL 模板的方法。 显式使用URL模板 利用 URL 模板 , 您可以使用 com.bea.portlet.GenericURL 及其子类创建 URL 。下面是一个示例 : <% ResourceURL url = ResourceURL.createResourceURL(request, response); url.setScheme("http"); url.setDomain("my."); url.setPort(8001); url.setPathPrefix("/static"); url.setTemplate("my-resource-template"); url.setPath("/images/my.jpg"); %> <img src="<%=url.toString()%>"/> 此片断使用 my-resource-template 创建到图像的链接。执行时 , 该 JSP 生成以下代码 : <img src="http://my.:8001/static/images/my.jpg"/> 提示 : 确保正在使用的 URL 模板具有与 setter 方法相对应的标志。如果没有 , WebLogic Portal 将忽略到 setter 的调用。 注意 , 模板必须存在于 my-resource-template 文件中 , 此片断才能生效。模板还必须具有一个指定的 url:prefix 标志 , setPathPrefix() 方法将替换 该标志。 在 com.bea.portlet.GenericURL 或其子类的位置 , 您可以使用在呈现标记库中可用的 URL 标记创建 URL 来代替。例如 , 可以使用 renderUrl JSP 标记来重写上述 JSP 片断 :<%@ taglib uri="render.tld" prefix="render" %> <img src="<render:resourceUrl port="8001" template="default-complete" scheme="http" domain="my." pathPrefix="/static" path="/images/my.jpg"/> "/> 注意 , 所有的框架主干 JSP 均使用呈现标记创建到窗口模式 / 状态按钮的链接、到页面的链接 , 等等。 在Portlet中使用URL模板 使用 Page Flow 和 Struts 标记在 Page Flow 和 Struts portlet 中创建表单、链接等时 , 这些 JSP 标记通过 URL 重写程序将 URL 创建委派给 WebLogic Portal 。这些 URL 重写程序使用 jpf-url-templates 指定的 URL 模板创建 URL 。 WebLogic Portal 中的 portlet 容器使用类似的方法处理 Java portlet 。创建 javax.portlet.PortletURL 时, portlet 容器使用在 url-templates-config.xml 文件中指定的 java-portlet-url-templates 。下面是一个示例: <% PortletURL actionURL = renderResponse.createActionURL(); PortletURL renderURL = renderResponse.createRenderURL(); %> WebLogic Portal 将分别使用 “ 操作 ” 和 “ 资源 ” 类型的 URL 模板生成这两个 URL 的字符串值。 远程Portlet中的URL 当您使用WSRP消费远程portlet时,确保远程portlet返回的标记引用门户至关重要(WSRP Consumer)。使用远程portlet时,Consumer充当最终用户和WSRP Producer上部署的portlet的中间件。一般情况下,Producer可能设置安全性策略,限制最终用户对部署在Producer上的资源的访问权限。所以,未使用WebLogic Portal创建的链接在远程portlet上可能失败。 WSRP 1.0规范为URL创建指定了两种方法:“producer writing”和“consumer rewriting”。下面简要介绍一下这两种方法。 Producer Writing 此方法包括以下步骤:
在这三个步骤中 , 只有第三步依赖于 WSRP Consumer 的实现方式。如果 WebLogic Portal 就是 Consumer , 则 Producer 的 URL 的编写包括以下步骤 :
下面是一个示例。我们假定您使用以下 JSP 部署 Page Flow portlet : <%@ taglib uri="netui-tags-html.tld" prefix="netui"%> <netui:anchor action="next">Next</netui:anchor> 当您在 WebLogic Portal Consumer 中消费此 portlet 时 , 它将发送以下 SOAP 请求以获取该 portlet 的标记 : <soapenv:Envelope xmlns:soapenv="http://schemas./soap/envelope/"> <soapenv:Body> <urn:getMarkup xmlns:urn="urn:oasis:names:tc:wsrp:v1:types"> <urn:portletContext> <urn:portletHandle>portlet_1</urn:portletHandle> </urn:portletContext> <urn:runtimeContext> <urn:userAuthentication>wsrp:none</urn:userAuthentication> <urn:portletInstanceKey>portlet_1_2_1</urn:portletInstanceKey> <urn:namespacePrefix>portlet_1_2_1</urn:namespacePrefix> <urn:templates> <urn:defaultTemplate> http://localhost:7001/consumer/hello.portal?_nfpb=true& _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2& wsrp-urlType={wsrp-urlType}&wsrp-url={wsrp-url}& wsrp-requiresRewrite={wsrp-requiresRewrite}& wsrp-navigationalState={wsrp-navigationalState}& wsrp-interactionState={wsrp-interactionState}& wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState} </urn:defaultTemplate> <urn:blockingActionTemplate> http://localhost:7001/consumer/hello.portal?_nfpb=true& _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2& wsrp-urlType=blockingAction&wsrp-url={wsrp-url}& wsrp-requiresRewrite={wsrp-requiresRewrite}& wsrp-navigationalState={wsrp-navigationalState}& wsrp-interactionState={wsrp-interactionState}& wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState} </urn:blockingActionTemplate> <urn:renderTemplate> http://localhost:7001/consumer/hello.portal?_nfpb=true& _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2& wsrp-urlType=render&wsrp-url={wsrp-url}& wsrp-requiresRewrite={wsrp-requiresRewrite}& wsrp-navigationalState={wsrp-navigationalState}& wsrp-interactionState={wsrp-interactionState}& wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState} </urn:renderTemplate> <urn:resourceTemplate> http://localhost:7001/consumer/resource?_windowLabel=portlet_1_2_1& wsrp-urlType=resource&wsrp-url={wsrp-url}& wsrp-requiresRewrite={wsrp-requiresRewrite} </urn:resourceTemplate> <urn:secureDefaultTemplate> http://localhost:7002/consumer/hello.portal?_nfpb=true& _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2& wsrp-urlType={wsrp-urlType}&wsrp-url={wsrp-url}& wsrp-requiresRewrite={wsrp-requiresRewrite}& wsrp-navigationalState={wsrp-navigationalState}& wsrp-interactionState={wsrp-interactionState}& wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState} </urn:secureDefaultTemplate> <urn:secureBlockingActionTemplate><![CDATA[ https://localhost:7002/consumer/hello.portal?_nfpb=true& _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2& wsrp-urlType=blockingAction&wsrp-secureURL=true& wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}& wsrp-navigationalState={wsrp-navigationalState}& wsrp-interactionState={wsrp-interactionState}& wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}]]> </urn:secureBlockingActionTemplate> <urn:secureRenderTemplate><![CDATA[ https://localhost:7002/consumer/hello.portal?_nfpb=true& _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2& wsrp-urlType=render&wsrp-secureURL=true&wsrp-url={wsrp-url}& wsrp-requiresRewrite={wsrp-requiresRewrite}& wsrp-navigationalState={wsrp-navigationalState}& wsrp-interactionState={wsrp-interactionState}& wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}]]> </urn:secureRenderTemplate> <urn:secureResourceTemplate> https://localhost:7002/consumer/resource?_windowLabel=portlet_1_2_1& wsrp-urlType=resource&wsrp-secureURL=true& wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite} </urn:secureResourceTemplate> </urn:templates> <urn:runtimeContext> <urn:userContext xsi:nil="true" xmlns:xsi="http://www./2001/XMLSchema-instance"/> <urn:markupParams> <urn:secureClientCommunication>false</urn:secureClientCommunication> <urn:locales>en-US</urn:locales> <urn:mimeTypes>text/html</urn:mimeTypes> <urn:mimeTypes>*/*</urn:mimeTypes> <urn:mode>wsrp:view</urn:mode> <urn:windowState>wsrp:normal</urn:windowState> <urn:clientData> <urn:userAgent>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; FDM)</urn:userAgent> </urn:clientData> <urn:markupCharacterSets>UTF-8</urn:markupCharacterSets> </urn:markupParams> </urn:getMarkup> </soapenv:Body> </soapenv:Envelope> 在此请求中 , 要注意的主要细节是模板元素。将 URL 模板发送到任何 Producer 之前 , WebLogic Portal Consumer 会将 URL 模板中的所有 Consumer 特定的标志替换掉 , 仅留下 WSRP 1.0 特定的标志。替换 WSRP 1.0 特定的标志由 Producer 来完成。注意,出于可读性方面的考虑,上述消息中的模板的多个行被强制换行。 为了响应上述 SOAP 请求 , WebLogic Portal Producer 将返回以下响应 : <soapenv:Envelope xmlns:soapenv="http://schemas./soap/envelope/"> <soapenv:Body> <urn:getMarkupResponse xmlns:urn="urn:oasis:names:tc:wsrp:v1:types"> <urn:markupContext> <urn:mimeType>text/html; charset=UTF-8</urn:mimeType> <urn:markupString><![CDATA[ <a href="http://localhost:7001/consumer/hello.portal?_nfpb=true& _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2& wsrp-urlType=blockingAction&wsrp-url=&wsrp-requiresRewrite=& wsrp-navigationalState=& wsrp-interactionState=_action%3D%252Fhello%252FHelloWorld%252Fbegin& wsrp-mode=&wsrp-windowState=">Next</a> ]]></urn:markupString> <urn:locale>en-US</urn:locale> <urn:requiresUrlRewriting>false</urn:requiresUrlRewriting> </urn:markupContext> </urn:getMarkupResponse> </soapenv:Body> </soapenv:Envelope> 提示 : WebLogic Portal Producer 可以将 URL 模板存储在 HTTP 会话中 , 所以 , WebLogic Portal Consumer 每个会话发送一次 URL 模板。 注意 , Producer 使用 blockingActionTemplate 创建 netui:anchor 标记的链接。由于在这次响应中返回的 portlet 标记完全合格 , 不需要在 Consumer 上对其进行进一步地处理。 如果您有意了解关于这些 SOAP 消息内容的更多信息 , 请访问 OASIS WSRP TC 主页 , 并下载最新版本的 WSRP 1.0 Primer 。 Consumer Rewriting 在此方法中 , Consumer 不发送 URL 模板 , 而是执行以下步骤 : Consumer 为 portlet 标记发出请求。该请求不包括 URL 模板。 Producer 创建链接 , 这些链接被封装在由 WSRP 1.0 规范指定的特殊标记中。 Consumer 分析该标记 , 并使用适当的 URL 替换这些标记中的链接。 对于上述示例 portlet , Producer 返回如下响应 : <soapenv:Envelope xmlns:soapenv="http://schemas./soap/envelope/"> <soapenv:Body> <urn:getMarkupResponse xmlns:urn="urn:oasis:names:tc:wsrp:v1:types"> <urn:markupContext> <urn:mimeType>text/html; charset=UTF-8</urn:mimeType> <urn:markupString>Hello World <a href="wsrp_rewrite?wsrp-urlType=blockingAction&wsrp-secureURL=false &wsrp-interactionState=_action%3D%252Fhello%252FHelloWorld%252Fbegin/wsrp_rewrite">Begin </a></urn:markupString> <urn:locale>en-US</urn:locale> <urn:requiresUrlRewriting>true</urn:requiresUrlRewriting> </urn:markupContext> </urn:getMarkupResponse> </soapenv:Body> </soapenv:Envelope> 注意 , 链接的 href 值被封装在 wsrp_rewrite? 和 /wsrp_rewrite 标记之间。然后 , WebLogic Portal Consumer 分析这些记号中的标记 , 并使用部署在 Consumer 上的 URL 模板创建 URL 。 提示 : 如果将 WebLogic Portal 用作 Consumer , 则可以尝试对 Producer 进行设置 , 以便更好地使用 URL 模板。 Producer Writing还是Consumer Rewriting? URL 创建的两种方法的主要不同点在于 URL 模板的使用。由 WebLogic Portal Consumer 发送给 Producer 的那种模板不需要对 Producer 返回的标记进行进一步地处理。因此,将 WebLogic Portal 用作 Consumer 时,此方法执行地较好。 WebLogic Portal Producer ( 无论简单还是复杂 ) 默认的设置是使用 Producer writing 生成 URL 。您可以通过更新 Producer 的 WEB-INF 目录下的 wsrp-producer-config.xml文件改用 Consumer rewriting 。请参考 关于 WSRP 的 WebLogic Portal 文档资料 以获取更多细节。 结束语 在本文中 , 我的目的之一是想指出为什么创建 URL 对于提供一致的用户体验是关键一步。当您使用 WebLogic Portal 提供的 API 和 JSP 标记、 Page Flow 或 Struts 标记、或者 Java Portlet API 或标记时, URL 创建过程依赖于 URL 模板。 WebLogic Portal 具有消费本地部署的模板和远程 Consumer 发送的模板的能力。这些功能在设计上允许 URL 模板控制所有创建的链接,以声明的方式即可调整,无需更改代码。 反向工程生成的 URL 结构以手动创建链接 ( 即不使用任何 WebLogic Portal API 或标签 ), 也是很可能实现的。这种链接在有些情况下可以使用,但是当部署配置变更或使用 WSRP 时,则很可能失败。下面是最新的准则。始终使用以下标签创建链接:
您完全可以不使用这些标记 , 而按照自己的意思创建 URL 。但这样的 URL 有时可能不可用。 参考资料 关于 WSRP 的 WebLogic Portal 文档资料 WebLogic Portal GenericURL 文档资料 描述 WebLogic Portal Framework 的白皮书 关于作者 Subbu Allamaraju 是 BEA Systems 的 WebLogic Portal 开发团队的专职软件工程师。从事 WSRP 标准及其 WebLogic Portal 实现方面的工作。此外他还在 subbu.org 上扮演一个技术博客的角色。 |
|
来自: smoking_boy > 《我的图书馆》