科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道探索 WebSphere Application Server V6.1 Portlet 容器: 第 2 部分:进一步研究

探索 WebSphere Application Server V6.1 Portlet 容器: 第 2 部分:进一步研究

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本系列文章对 IBM® WebSphere® Application Server V6.1 中提供的 JSR 168 Portlet 容器进行了分析,并说明了其与 WebSphere Portal 中使用方法的区别。

作者:ibm 来源:ibm 2007年10月9日

关键字: IBM WEBSPHERE 技术 中间件

  • 评论
  • 分享微博
  • 分享邮件

引言

目前,门户用户已习惯于在一个页面上包含多个 Portlet,习惯于在窗口框架(可提供控制图标或链接来更改 Portlet 模式或窗口状态)内嵌入每个 Portlet 的内容。WebSphere Application Server V6.1 提供了一组扩展功能,可用来通过 URL Addressability 自定义 Portlet,也可用来创建简单的门户框架。

要设计自定义门户框架,需要创建 JSP。通过引用新 JSP 标记库,可以方便地聚合 Portlet。这个聚合标记库允许您在窗口框架内呈现 Portlet 内容,或将多个 Portlet 聚合到一个页面上。

为了管理 Portlet,门户框架需要知道系统中提供了哪些 Portlet。WebSphere Application Server V6.1 提供了用于 Portlet 和 Portlet 应用程序的新托管 Bean (MBean)。您可以使用这些 MBean 来访问任何已部署 Portlet 的部署描述符中的信息。

Portlet URL Addressablity 本身就支持 HTML。如果您希望支持其他标记,可以使用 PortletDocumentFilters 来方便地添加不同的标记支持。与 Servlet 筛选器类似,将在 Portlet 前调用它们来更改行为或缺省输出。

本文将向您说明如何使用聚合标记库来构建自己的门户框架、如何使用 MBean API,以及如何自定义 Portlet 来支持其他标记。本文还将讨论这些功能与 WebSphere Portal 中类似功能的比较,以便了解二者的差异以及如何在这两个产品中实现相同的结果。





回页首


关于示例

您可以下载本文中描述的示例的示例代码,以便能够在阅读本文的过程中将其作为参考。各个示例均基于本系列文章的第 1 部分中讨论的 WorldClock Portlet 应用程序;为了便于您下载,示例代码包括在下载部分中。有关 WorldClock Portlet 的详细描述,请参见文章“将 WorldClock portlet 从 IBM Portlet API 转换到 JSR 168 portlet API”(请参见参考资料)。





回页首


聚合多个 Portlet

门户框架可以对门户页面上的 Portlet 内容进行管理、组织和排列。通过 URL Addressability,WebSphere Application Server 提供了门户页显示单个 Portlet 的最简单方法,无需使用任何图标或菜单链接。您可以通过使用新 JSP 标记库来方便地扩展此功能。此聚合库提供了一种方法来创建简单的自定义门户框架,用以处理 Portlet 操作和将多个 Portlet 呈现于窗口框架中,同时提供 Portlet 标题和用于更改 Portlet 模式或窗口状态的控制链接。

此库包含两类标记:

  1. 门户标记定义 Portlet 在其中运行的门户上下文。

    例如,此上下文定义 Portlet URL 的 URL 格式以及如何处理 Portlet 首选项。与 Servlet 不同,Portlet 必须始终呈现在门户框架的上下文中。

    init 标记指定门户框架的 URL,以便 Portlet 的 URL 引用门户。您还可以将其他请求参数与门户 JSP 一起使用,以便对流进行控制。

    <init
    portletURLPrefix="<portal URL>"
    portletURLSuffix="<portal specific URL suffix>"
    portletURLQueryParams="<portal specific query parameters">

  2. Portlet 标记包括一个 URL creation 标记(用于创建 Portlet 链接)和一个 Portlet invocation 标记(用于检索 Portlet 内容)。

    由于 Portlet 需要使用门户上下文,因此必须将这些 Portlet 标记嵌入到门户 init 标记中。

    • state 标记创建用于引用具有特定状态 Portlet 的 URL 字符串。门户框架可以使用返回的 URL 为 Portlet 提供控制链接。每个 URL 都可以通过定义另一个 Portlet 模式或窗口状态来引用新 Portlet 状态。
      <state
      url="<portlet URL>"
      windowId="<portlet window identifier>"
      action="<whether this is an action URL: true|false>"
      portletMode="<portlet mode>"
      portletWindowState="<window state"
      var="<variable name for this portlet URL>"
      scope="<scope for var: page|request|session|application>">
      <urlParam name="<parameter name>" value="<parameter value>"/>
      </state>

    • insert 标记调用 Portlet 并检索 Portlet 状态的 Portlet 内容。您可以使用此标记检索 Portlet 可在呈现期间动态指定的 Portlet 标题。
      <insert
      url="<portlet URL>"
      windowId="<portlet window identifier>"
      contentVar="<variable name for this portlet content>"
      contentScope="<scope for contentVar:
      page|request|session|application>">
      titleVar="<variable name for the dynamic portlet title"/>
      titleScope="<scope for titleVar: page|request|session|application>">

      所有 Portlet 标记都提供了一个 portlet URL 属性,用于指定 Portlet 上下文和 Portlet 名称。可以使用其他属性来指定更多的细节,如窗口标识符等。

      某些 Portlet 标记的属性允许将结果写入变量,而不直接写入到输出流;写入输出流会导致存入缓冲区,因为内容将临时存储在字符串中。由于存入缓冲区会对性能造成影响,因此一般不建议使用此功能。

门户框架常常为 Portlet 内容指定变量,以在实际 Portlet 输出上显示动态 Portlet 标题。应该转而使用 Javascript,如下面的示例所示。

示例

让我们通过一个示例门户 JSP 来了解如何使用聚合标记库。如果您尚未获得示例代码,可以下载示例代码,以便在阅读下面的说明的过程中可以参考它。

此示例将两个 Portlet 呈现于窗口框架中,此框架为每个 Portlet 提供了控制链接,用于更改 Portlet 模式。

首先,在 JSP Header 中,引用聚合标记库并定义命名空间前缀。

<%@ taglib uri="http://ibm.com/portlet/aggregation" prefix="portlet" %>

此声明使得 JSP 能够识别此标记库,这样您就可以使用所有聚合标记。

接下来,使用 init 标记定义聚合框架的门户上下文。在属性 portletURLPrefix 中声明用于访问门户 JSP 的 URL。

<portlet:init portletURLPrefix="/sample/portal/">

门户框架通常由 Servlet 组成,其中包含门户 JSP;不过,此示例仅使用了 JSP。因此,在本例中,您必须在 web.xml 中定义 JSP,以获得引用门户 JSP 的有效门户 URL。门户 URL 不应以 .jsp 等作为结尾。

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
		http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>SamplePortal</display-name>
    …
    <servlet>
        <servlet-name>SamplePortal</servlet-name>
            <jsp-file>portal.jsp</jsp-file>
        </servlet>
    <servlet-mapping>
        <servlet-name>SamplePortal</servlet-name>
        <url-pattern>/portal/*</url-pattern>
    </servlet-mapping>
</web-app>

现在,您可以在指定门户上下文的 init 标记内使用若干 Portlet 标记。

可以通过普通 JSP 或 HTML 处理来获得 Portlet 链接和 Portlet 内容,以实现良好的外观设计。

只要在页面上放置了 Portlet 链接,您就可以使用聚合标记库的 state 标记创建相应的 Portlet URL。下面的 JSP 代码片段显示了如何创建指向 WorldClock Portlet 的视图模式的链接。

<a href="<portlet:state url='worldclock/StdWorldClock' windowId='birga'
 portletMode='view'/>">view</a>

windowId 提供了一个标识符,用于保持此 Portlet 的唯一性。然后,您可以将相同的 WorldClock Portlet 再次放置到该页上,同时使用另一个 windowId。上述链接对定义了不同窗口标识符的 Portlet 没有任何效果。每个 Portlet 窗口必须提供自己的链接。

<a href="<portlet:state url='worldclock/StdWorldClock' 
   windowId='stephan' portletMode='view'/>">view</a> 
   

使用窗口框架和每个 Portlet 的 Portlet 控制链接设计了页面布局后,通过使用引用 Portlet URL 和窗口标识符的 insert 标记将 Portlet 内容插入到页面中。

<portlet:insert url="worldclock/StdWorldClock" windowId="birga" 
   titleVar="portlettitle_1"/> 

通过为 Portlet 设置的动态标题定义变量,可以使用 Javascript 来将标题嵌入到窗口框架中。

清单 1 显示了已完成的 portal.jsp 的情况。


清单 1. 使用聚合标记库的 portal.jsp

				
<%@ taglib uri="http://ibm.com/portlet/aggregation" prefix="portlet" %>
<%@ page isELIgnored ="false"%>
<portlet:init portletURLPrefix="/sample/portal/">
<!-- create portal table of two columns -->
<TABLE BORDER="5" WIDTH="100%">
 <TR BGCOLOR="BBBBFF">
  <TD>
   <!-- insert portlet title bar into left column -->
   <TABLE WIDTH="100%">
     <TR>
        <TD>
          <B><span id="title_1">Portlet 1</span></B>
        </TD>
          <TD ALIGN="right">
            <a href="<portlet:state url='worldclock/StdWorldClock' 
				windowId='birga' portletMode='view'/>">view</a>
            <a href="<portlet:state url='worldclock/StdWorldClock' 
				windowId='birga' portletMode='edit'/>">edit</a>
            <a href="<portlet:state url='worldclock/StdWorldClock' 
				windowId='birga' portletMode='help'/>">help</a>
        </TD>
      </TR>
   </TABLE>
  </TD>
  <TD>
   <!-- insert portlet title bar into right column -->
   <TABLE WIDTH="100%">
     <TR>
        <TD>
          <B><span id="title_2">Portlet 2</span></B>
        </TD>
          <TD ALIGN="right">
            <a href="<portlet:state url='worldclock/StdWorldClock' 
				windowId='stephan' portletMode='view'/>">view</a>
            <a href="<portlet:state url='worldclock/StdWorldClock' 
				windowId='stephan' portletMode='edit'/>">edit</a>
            <a href="<portlet:state url='worldclock/StdWorldClock' 
				windowId='stephan' portletMode='help'/>">help</a>
        </TD>
      </TR>
   </TABLE>
  </TD>
 </TR>
 <TR>
  <TD>
<!-- insert portlet into left column -->
    <portlet:insert url="worldclock/StdWorldClock" 
		windowId="birga" titleVar="portlettitle_1"/>
  </TD>
  <TD>
<!-- insert portlet into right column -->
    <portlet:insert url="worldclock/StdWorldClock" 
		windowId="stephan" titleVar="portlettitle_2"/>
  </TD>
 </TR>
</TABLE>
<!-- insert portlet title -->
<script type="text/javascript">
  document.getElementById("title_1").firstChild.nodeValue = "${portlettitle_1}";
  document.getElementById("title_2").firstChild.nodeValue = "${portlettitle_2}";
</script>
</portlet:init>

要查看示例门户页(如图 1 中所示),请执行以下操作:

  • 将 portal.jsp 打包到 Web 应用程序中并进行安装。
  • 然后,在浏览器中使用此 URL 访问门户聚合:http://localhost:9080/sample/portal


图 1. 门户聚合 JSP 的示例输出
图 1. 门户聚合 JSP 的示例输出

与 WebSphere Portal 的比较

WebSphere Portal 提供了成熟的聚合框架,您可以使用自己的主题和皮肤对其进行自定义。例如,在 WebSphere Portal 中,您可以在聚合框架内应用细粒度访问控制。

WebSphere Portal 中没有与 WebSphere Application Server V6.1 Portlet 容器提供的聚合标记库对应的功能。聚合标记库允许创建很简单的门户框架来在一个页面上聚合多个 Portlet;它旨在供 Portlet 开发系统使用。





回页首


访问 Portlet 信息

围绕 Portlet 内容创建窗口框架的门户框架常常提供额外的图标来支持更改 Portlet 模式或窗口状态。为了显示正确的图标,门户框架必须知道 Portlet 支持哪些模式或状态。例如,在显示具有指向 Portlet 的编辑 模式的链接的图标前,门户需要知道 Portlet 是否支持编辑 模式。每个 Portlet 应用程序都会通过 Portlet 部署描述符提供此类信息。MBean 可以访问此类信息。

通常,WebSphere Application Server 的 AdminClient 能够访问所有 MBean。有关如何检索 AdminClient 以及如何使用 MBean 的一般信息,请参见 WebSphere Application 信息中心(在参考资料中列出)的 Developing an administrative client program 部分。

启动 Portlet 应用程序后,将创建以下 Portlet 特定的 MBean:

  • 已在 Portlet 部署描述符中为 Portlet 应用程序定义了一个 PortletApplication 类型的 MBean。

    其名称由 Portlet 应用程序文件名和后缀 _portletapplication 组成。例如:

    StdWorldClock.war_portletapplication

  • 已在 Portlet 应用程序中为每个 Portlet 定义了一个 Portlet 类型的 MBean。

    其名称由上述 PortletApplication MBean 名称和作为后缀的 Portlet 名称组成。例如:

    StdWorldClock.war_portletapplication.StdWorldClock

有关描述 PortletPortletApplication MBeans 的 Javadoc 的信息,请参见 WebSphere Application Server 信息中心(在参考资料中列出)的 Mbean interfaces 部分。

可以将 MBean API 用于多种用途。此类示例有:

  • 检索对系统中所有可用的 Portlet 应用程序和 Portlet 的访问,以便门户能够将其列出,并提供导航或 Portlet 管理功能。
  • 检索 Portlet 标题,以便门户能够在围绕 Portlet 内容的窗口框架中的 Portlet 内容上方显示标题。
  • 检索 Portlet 定义的自定义窗口状态,以便门户对其提供支持。
  • 检索 Portlet 支持的所有 Portlet 模式,以便门户能够仅显示适用的控制链接。

希望确定为 Portlet 提供哪些控制图标或链接的门户框架可能针对特定内容类型检索受支持的 Portlet 模式列表。请参见以下代码片段,以了解如何为 StdWorldClock Portlet 和内容类型 text/html 完成此任务:

ObjectName on = new 
ObjectName("WebSphere:name=StdWorldClock.war_portletapplication.StdWorldClock,*");
on = (ObjectName) adminService.queryNames(on, null).iterator().next();
HashMap contentTypes = (HashMap) adminService.getAttribute(on, "contentTypes");
List list = (List) contentTypes.get("text/html");

除了 Portlet 部署描述符提供的所有信息外,PortletApplication MBean 还定义通知常量,门户可以通过注册 NotificationListener 对此进行侦听。有关如何注册和处理通知事件的信息,请参见 WebSphere Application 信息中心的(在参考资料中列出)Developing an administrative client program 部分。

示例

此示例说明了可以使用 Portlet 特定的 MBean 的一个场景。它将收集关于所有已部署的 Portlet 的信息,以在门户聚合上提供已部署的 Portlet 列表。用户可以从此列表中选择 Portlet,所选的 Portlet 随后显示在聚合中。

要获得对系统中所有 MBean 的访问,请检索 AdminClient:

Properties p = new Properties();
p.put("port", "8880");
p.put("host", "localhost");
p.put("type", "SOAP");
AdminClient adminService = AdminClientFactory.createAdminClient(p);

所有 Portlet 应用程序都具有 PortletApplication 类型的注册 MBean。因此,可以创建一个 ObjectName 模式来指定 MBean 类型,从而返回系统中所有可用 PortletApplication Mbean 列表。

ObjectName paons = new ObjectName("WebSphere:type=PortletApplication,*");
Iterator iter = adminService.queryNames(paons, null) .iterator();
while (iter.hasNext()) {
    ObjectName paon = (ObjectName) iter.next();
    …
}

每个 Portlet 应用程序都提供了使用 MBean 属性 portletMBeanNames 访问其 Portlet 列表的功能。要检索对 MBeans 的访问,请创建一个指定 Portlet MBean 名称的 ObjectName 模式。这样可返回所有使用该名称的可用 Mbean 列表。(尽管返回的是列表,但此列表永远不会包含多个条目。)

Iterator innerIter =  ((List) adminService.getAttribute(paon, 
  "portletMBeanNames")).iterator();
while (innerIter.hasNext()) {
    String name = (String)innerIter.next();
    ObjectName pons = new ObjectName("WebSphere:name=" + name + ",*");
    ObjectName pon = (ObjectName) adminService.queryNames(pons, null).iterator().next();
    …
}

既然您已经能够访问系统中所有的 Portlet 应用程序和 Portlet,就可以查找所需的信息来提供下拉列表,以便从中选择 Portlet。此列表中包含每个可用 Portlet 的 Portlet URL。

当门户使用聚合标记库来显示 Portlet 时,它需要知道对应的 Portlet URL。此 URL 由 Web 应用程序上下文和 Portlet 名称组成,例如 worldclock/StdWorldClock

一个应用程序内的所有 Portlet 的 Web 应用程序上下文都是相同的,因此可以将其作为 PortletApplication MBean 的一个属性进行检索。

String context = (String) adminService.getAttribute(paon, "webApplicationContextRoot");

对于 Portlet 名称,请访问 Portlet MBean 的属性 name

String portletName = (String) adminService.getAttribute(on, "name");

最后,需要调整门户聚合来提供所有 Portlet URL 的列表,以便用户选择 Portlet。portal.jsp 将随后使用此选择在其聚合中调用该 Portlet。

清单 2 显示了用于将使用 MBean 收集的所有 Portlet url 存储到 Bean 中的代码。


清单 2. 将 Portlet URL 存储到列表中

				
PortletListBean bean = new PortletListBean();
// add all available portlet URLs to PortletListBean
try {
    Iterator iter = adminService.queryNames(paons, null).iterator();
    while (iter.hasNext()) {
      ObjectName paon = (ObjectName) iter.next();
      String context = (String)
              adminService.getAttribute(paon,
              "webApplicationContextRoot");
      Iterator innerIter = ((List)
              adminService.getAttribute(paon,
              "portletMBeanNames")).iterator();
        while (innerIter.hasNext()) {
          String name = (String)innerIter.next();
          ObjectName on = new ObjectName("WebSphere:name=" + name + ",*");
          on = (ObjectName) adminService.queryNames(on, null).iterator().next();
          String portletName = (String) adminService.getAttribute(on, "name");
          bean.addURL(context + "/" + portletName);
        }
    }
} catch (Exception e) {
   …
}

以此 Bean 为基础,我们将创建一个所有可用 Portlet 的选择列表。更新了 portal.jsp 后,可以通过以下网址安装和访问门户聚合:http://localhost:9080/sample/portal


图 2. 提供所有可用 Portlet 选择的门户聚合
图 2. 提供所有可用 Portlet 选择的门户聚合

与 WebSphere Portal 的比较

用于访问 Portlet 信息的 MBean API 是 WebSphere Application Server 独有的。在 WebSphere Portal 中,尚未公开任何对应的 Portlet 模型访问机制。

检索系统中可用 Portlet 的信息的需求主要源自门户框架。WebSphere Portal 提供了自己的 Portlet 部署和对象模型来保存和访问有关已安装的 Portlet 的所有信息。因此,WebSphere Portal 并没有必要根据此需求提供公共 API。





回页首


筛选 Portlet 以修改输出

当通过 URL 直接访问 Portlet 时,可以使用嵌入到筛选器链中名为 PortletDocumentFilters 的筛选器对 Portlet 输出进行修改。预定义的缺省筛选器会将 Portlet 的 Portlet 片段输出转换为有效的文档。这样,Portlet 就可以像 Servlet 一样作为完整文档显示在浏览器中。

所提供的即时可用的 DefaultFilter 能将 Portlet 内容转换为简单的有效 HTML 文档。您可以使用自定义 PortletDocumentFilters 对其进行替换或扩展。

PortletDocumentFilters 为普通 Servlet 筛选器,实现了 javax.servlet.Filter 并遵循 Servlet 筛选器链机制。这里的差异在于声明和进行部署的方式不同。

不应采用直接在 web.xml 中指定筛选器的方式,而应在 plugin.xml 中的扩展点注册 PortletDocumentFilters(plugin.xml 位于包含 PortletDocumentFilter 的 JAR 文件的根目录中)。

<extension point=
  "com.ibm.ws.portletcontainer.portlet-document-filter-config">
  <portlet-document-filter 
     class-name="sample.WindowFrameFilter" order="1200" />
</extension>

可以采用两种不同的方式部署 PortletDocumentFilter

  1. 将筛选器 JAR 文件添加到 Application Server 的 lib 目录。此 JAR 文件的结构如下:
    • plugin.xml 位于根目录中
    • 筛选器类文件位于 JAR 文件中相应的包目录中
  2. 将筛选器作为 osgi 包在 Application Server 的 plugins 目录中提供。此 JAR 文件的结构如下:
    • plugin.xml 位于根目录中
    • 筛选器类文件位于 JAR 文件内相应的包目录中
    • 指定包细节的 MANIFEST.MF 文件位于 META-INF 目录中。

普通的 Servlet 筛选器概念并不能为希望创建 PortletDocumentFilter 的开发人员提供任何 Portlet 支持。因此,为 PortletDocumentFilters 提供了两个 Helper 来实现 Portlet 特定的需求:

  • com.ibm.wsspi.portletcontainer.util.FilterRequestHelper
  • com.ibm.wsspi.portletcontainer.util.PortletURLHelper

FilterRequestHelper 提供了用于控制筛选器流的简单访问。在后台,将由请求属性传输流信息。例如,isDocument 方法将验证之前是否已由某个筛选器将片段转换为文档了。因此,每个筛选器都可以使用 setRedirectsetDocument 方法指定特殊需求。

重要:系统并不使用这些属性。每个筛选器必须在转换标记前检查这些属性,以防止筛选器将已经转换的文档再次转换为文档。

PortletURLHelper 将分析 Servlet 请求 URL,以根据 URL Addressability 模式标识 Portlet 信息。这样,Helper 就允许筛选器方便地确定是否请求了 Portlet 操作 URL 或调用的是哪个 Portlet 模式。

为了支持 WML 等其他标记,需要创建新的 PortletDocumentFilter,对其进行注册,然后在缺省 HTML 筛选器之前调用它。新筛选器必须通过对 FilterRequestHelper 调用 setDocument 方法来标记文档转换。此标记可防止 DefaultFilter 将片段转换为 HTML 文档。这样,您就可以使用 PortletDocumentFilters 添加标记支持或修改文档输出。

示例

门户通常会将 Portlet 内容呈现到窗口框架中,并同时提供到不同 Portlet 模式和窗口状态的链接。使用 URL Addressability 时,不会在 Portlet 内容周围显示窗口框架。在此示例中,您将了解如何使用自定义 PortletDocumentFilter 添加简单的窗口框架。

  1. 首先,创建一个新筛选器类(该类实现 javax.servlet.Filter),并将其命名为 WindowFrameFilter。主要使用的方法是 doFilter 方法。
    public class WindowFrameFilter implements Filter 
    {
    public void init(FilterConfig config) throws ServletException {}
    public void doFilter(ServletRequest request, 
    ServletResponse response, 
    FilterChain chain)
    throws IOException, ServletException {
    …
    }
    public void destroy() {}
    }
    			

  2. doFilter 中,分析 URL 以确定请求是否满足添加窗口框架的对应先决条件:
    • 验证是否标记了相应的请求,以指示其已完成了文档转换。为了围绕 Portlet 内容添加窗口框架,需要使用一个有效的文档。因此,如果不是这样,您需要忽略该请求。
      // do nothing if document cannot be found 
      if (!FilterRequestHelper.isDocument(request))
      {
        chain.doFilter(request, response);
        return;
      }
      			

    • 根据系统中的文档筛选器的不同,可能还有必要添加一项检查来确定请求文档是否为 HTML 文档。
    • 检查请求 url 是否为操作 URL,以确定是否也需要忽略此请求。请使用 PortletURLHelper 进行此项检查。如果出现了 InvalidURLException,则筛选器必须将此信息传输给 HttpServletResponse,如下所示。
      // analyze request url
      HttpServletRequest servletRequest = (HttpServletRequest) request;
      HttpServletResponse servletResponse = (HttpServletResponse) response;
      String portleturl = null;
      try {
        PortletURLHelper urlHelper = new PortletURLHelper("","",servletRequest.getPathInfo());
        // do nothing if action called
        if (urlHelper.isAction()) 
        {
           chain.doFilter(request, response);
           return;
        }
        portleturl = createPortletURL(servletRequest, urlHelper);
      }
      catch (InvalidURLException e) 
      {   
        servletResponse.sendError(
          e.getStatusCode(),
          e.getMessage());
        return; 
      }     
      

  3. 如果请求满足这些先决条件,则可以将 Portlet 内容嵌入到窗口框架中。创建简单的 HTML 表,以在 Portlet 内容上添加一行链接。
    PrintWriter writer = response.getWriter();
    writer.println("<TABLE BORDER='5'>");
    writer.println("<TR BGCOLOR='BBBBFF'><TD>");
    writer.println("<TABLE WIDTH='100%'>");
    writer.println("<TR><TD>");
    writer.println("<B><span id='portlet_title_1'>Portlet</span></B>");
    writer.println("</TD>");
    writer.println("<TD ALIGN='right'>");
    writer.println("<a href='" + portleturl + "/state=normal'>normal</a>");
    writer.println("<a href='" + portleturl + "/state=maximized'>maximized</a>");
    writer.println("<a href='" + portleturl + "/state=minimized'>minimized</a>");
    writer.println("</TD></TR>");
    writer.println("</TABLE>");   
    writer.println("</TD></TR><TR><TD>");
    chain.doFilter(request, response);
    writer.println("</TD></TR></TABLE>");
    

  4. 这些链接引用不同的 Portlet 窗口状态。要创建 Portlet url 链接,可以使用基础 URL String(根据 URL Addressability 模式引用包含所有所需信息的 Portlet),从而仅忽略变化的窗口状态信息。
    StringBuffer buffer = new StringBuffer();
    buffer.append(servletRequest.getScheme());
    buffer.append("://");
    buffer.append(servletRequest.getServerName());
    buffer.append(":");
    buffer.append(servletRequest.getServerPort());
    buffer.append(servletRequest.getContextPath());
    buffer.append(servletRequest.getServletPath());
    buffer.append("/");
    buffer.append(urlHelper.getPortletWindowId());
    buffer.append("/ver=");
    buffer.append(urlHelper.getVersion());
    String portleturl = buffer.toString();
    

  5. 要首先使用此 WindowFrameFilter 的 plugin.xml 创建一个 JAR 文件,才能看到围绕 Portlet 内容的窗口框架。此 xml 用于定义筛选器的位置和筛选器顺序。对于此示例,筛选器顺序的值必须大于 1000,以便在 DefaultFilter 之后调用,因为窗口框架只能在完成了 HTML 文档转换后创建。
    <?xml version="1.0" encoding="UTF-8"?>
    <?eclipse version="3.0"?>
    <plugin id="portletwindowfilter" name="WS_Server" provider-name="IBM" version="1.0.0">
      <extension point="com.ibm.ws.portletcontainer.portlet-document-filter-config">
        <portlet-document-filter class-name="sample.WindowFrameFilter" order="1200" />
      </extension>
    </plugin>
    

  6. 要部署筛选器,请将筛选器 JAR 文件放入 Application Server 的 lib 目录,并重新启动服务器。
  7. 要访问应用了此筛选器的 WorldClock Portlet,请在浏览器中打开以下 URL:http://localhost:9080/worldclock/StdWorldClock

    可以在图 3 中看到其结果。



    图 3. Portlet 经过筛选,以提供 Portlet 窗口框架
    图 3. Portlet 经过筛选,以提供 Portlet 窗口框架

与 WebSphere Portal 的比较

可以通过 WebSphere Application Server 的 PortletDocumentFilters 对 Portlet 片段进行修改。WebSphere Portal 提供的对应功能是 PortletFilter 概念。

WebSphere Portal 为其 PortletFilter 机制提供了自己的筛选器机制;PortletDocumentFilter 基于 Servlet 筛选器。PortletFilter 嵌入到专用筛选器链中,且要实现 PortletFilter 接口,以便能方便地满足 Portlet 特定的需求。与 PortletDocumentFilter 相比,这些筛选器更灵活;它们并不需要重新启动服务器,因此可以针对每个 Portlet 动态地启用。





回页首


结束语

在本系列文章的这一部分中,我们更为深入地对 WebSphere Application Server 中的 Portlet 容器进行了分析。我们向您介绍了用于帮助创建简单门户框架的聚合功能。然后,我们说明了如何在通过 URL 寻址时修改 Portlet 输出,以及如何定位和访问 Portlet 信息。另外,我们还说明了这些功能与 WebSphere Portal 中的相应功能的比较情况,以及在寻址 Portlet 方面的差异。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章