现在的位置: 首页 > 综合 > 正文

WebSphere Portal Portlet API

2013年10月14日 ⁄ 综合 ⁄ 共 21424字 ⁄ 字号 评论关闭

本节提供了 Portlet API 的简要描述。


概述

portlet 是可以提供对基于 Web 的内容、应用程序和其它资源访问的可重用组件。可通过 portlet 访问 Web 页面、web 服务、应用程序和辛迪加内容供给。公司可以创建他们自己的 portlet 或从第三方 portlet 编目中选择 portlet。portlet 是打算被组装成更大的门户网站页面,其中同一 portlet 的多个实例为每个用户显示不同的数据。

从用户的角度来看,portlet 是门户网站站点中提供特定服务或信息(例如,提供日历和新闻)的窗口。从应用程序开发者的角度来看,portlet 是可插入的模块,它们被设计成在门户网站服务器的 portlet 容器中运行。

portlet 容器提供了一个运行时环境,在这个环境中实例化、使用和最终破坏 portlet。portlet 依靠门户网站基础结构来访问用户概要文件信息,参与在窗口和操作事件中,与其它 portlet 通信,访问远程内容,查找凭证,以及存储持久数据。Portlet API 提供了这些功能的标准接口。portlet 容器不是一个类似于 servlet 容器的独立容器。它作为 servlet 容器之上的一个薄层实现,并重用 servlet 容器提供的功能。

IBM 正在与其它公司一同致力于 Portlet API 的标准化,使 portlet 能在实现此规范的门户网站服务器之间协同使用。WebSphere Portal 版本 4.1 中提供的 Portlet API 是迈向 Portlet API 标准化的第一步。要获取有关 portlet 规范的更多信息,请参阅

   http://jcp.org/jsr/detail/168.jsp

Portlet 和 Servlet API

抽象 Portlet 类是 Portlet API 的核心抽象。Portlet 类扩展 Servlet API 的 HTTPServlet。所有 portlet 间接地扩展此抽象类,且从 HttpServlet 继承,如下所示:

...   +--javax.servlet.http.HttpServlet
         |
         +--org.apache.jetspeed.portlet.Portlet
               |
               +--org.apache.jetspeed.portlet.PortletAdapter
                    |
                                        +--com.myCompany.myApplication.myPortlet       

因此,portlet 是特殊类型的 servlet。这种类型的 servlet 的特性使它们能容易地插入并在门户网站服务器中运行。与 servlet 不同,portlet 不能直接发送重定向或错误到浏览器,转发请求,或者写任意的标记到输出流。portlet 容器依赖于 WebSphere Application Server 实现的 J2EE 体系结构。结果是,portlet 按类似于 J2EE Web 应用程序的方式封装,并按类似于 servlet 的方式部署。

一般说来,对 portlet 的管理比 servlet 更为动态。可在不启动和重新启动门户网站服务器的情况下,应用以下更新:

  • 可使用门户网站管理用户界面安装和除去由几个 portlet 组成的 portlet 应用程序。
  • portlet 的设置可由有适当访问权的管理员更改
  • 可使用管理 portlet 动态创建和删除 portlet。例如,一旦管理员创建新的裁剪,裁剪 portlet 就可用于创建新的 portlet 实例。

portlet 容器依赖于 WebSphere Application Server 实现的 J2EE 体系结构。结果是,portlet 按类似于 J2EE Web 应用程序的方式封装在 WAR 文件中,并按类似于 servlet 的方式部署。与其它 servlet 相似,要使用 servlet 部署描述符(web.xml)把 portlet 定义到应用程序服务器。这个文件定义 portlet 的类文件和只读初始化参数。

下图显示部署了其 WAR 文件之后的 portlet。对于门户网站服务器上部署的每个 portlet,它在应用程序服务器上创建一个 servlet 或者 portlet 类实例

portlet 的应用程序服务器和门户网站服务器视图

初始化参数是由 portlet 开发者设置的,并可由 portlet 使用 PortletConfig 对象读取。servlet 部署描述符可以包含多个 Web 应用程序,每个 Web 应用程序由 <servlet> 元素定义。此外,每个 servlet 定义可以指向同一 portlet 类文件,这样可为每个 portlet 类实例使用不同的初始化参数,创建不同的 PortletConfig 对象。要获取更多信息,请参阅 Web 应用程序部署描述符

portlet 部署描述符

除了 servlet 描述符之外,portlet 还必须提供 portlet 部署描述符(portlet.xml)以定义 portlet 对于门户网站服务器的能力。此信息包含特定于特定 portlet 或 portlet 应用程序的配置参数,以及所有 portlet 所提供的一般信息(如 portlet 支持的标记类型)。门户网站服务器使用该信息为 portlet 提供服务。例如,如果 portlet 在 portlet 部署描述符中对帮助和编辑方式注册其支持,则门户网站服务器将呈现图标从而允许用户调用 portlet 的帮助和编辑页面。

以下是带有最少标记的示例 portlet 部署描述符。


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE portlet-app-def PUBLIC "-//IBM//DTD Portlet Application 1.1//EN" "portlet_1.1.dtd">
<portlet-app-def>
  <portlet-app uid="com.myCompany.myPortletApp.54321">
    <portlet-app-name>My portlet application</portlet-app-name>
    <portlet id="Portlet_1" href="WEB-INF/web.xml#Servlet_1">
      <portlet-name>My portlet</portlet-name>
      <supports>
      <markup name="html">
          <view output="fragment"/>
        </markup>
      </supports>
    </portlet>
 </portlet-app>

  <concrete-portlet-app uid="com.myCompany.myConcretePortletApp.54321">
    <portlet-app-name>My concrete portlet application</portlet-app-name>
    <concrete-portlet href="#Portlet_1">
      <portlet-name>My concrete portlet</portlet-name>
        <default-locale>en</default-locale>
         <language locale="en_US">
        <title>My portlet</title>
         </language>
       </concrete-portlet>
    </concrete-portlet-app>
</portlet-app-def>


要获取包含每个标记的描述的详细信息,请参阅部署描述符

portlet 概念

下图显示创建 portlet,在页面上放置 portlet 和用户访问 portlet 时 portlet 的不同变化。注意,前两个步骤涉及使用持久数据,但对于第三个步骤,数据只在会话持续时间期间可用。

portlet 的表现

1  门户网站管理员使用管理界面来部署新的 portlet 应用程序 WAR 文件或安装 portlet 的副本。这两个操作都创建一个具体 portlet,这是由单个 PortletSettings 对象参数化的 portlet。每个 portlet 可能具有多个具体 portlet。PortletSettings 是具有读/写访问权,并是持久的。PortletSettings 包含最初在 portlet 部署描述符中定义的配置参数。

使用具体 portlet 能在不创建另外的 portlet 类实例的情况下,运行许多 portlet 不同配置的实例。在单个 portlet 的生命周期期间,可创建和破坏许多具体 portlet。无明确代表具体 portlet 的对象。可在许多用户之间共享同一个具体 portlet。

2   用户或管理员把 portlet 放到页面上。这创建一个具体 portlet 实例,这是由单个 PortletData 对象参数化的具体 portlet。每个具体 portlet 可能具有多个具体 portlet 实例。PortletData 存储已添加到页面的 portlet 的持久信息。例如,用户可以编辑股票报价 portlet,并可保存股票符号的列表以供公司跟踪。

3    PortletData 的作用域取决于具体 portlet 所在的页面的作用域。

  1. 如果管理员把具体 portlet 放到组页面,则 PortletData 对象包含为用户的组存储的数据。这将为对页面具有查看访问权的用户组保留为真。然而,如果用户对组页面上的 portlet 具有编辑访问权,则为编辑 portlet 的每个用户创建新的具体 portlet 实例。在这种情况下,PortletData 包含编辑 portlet 的每个用户的数据。
  2. 如果具体 portlet 放在用户的页面上,则 PortletData 包含那个用户的数据。

当用户访问包含 portlet 的页面时,会创建一个用户 portlet 实例。当用户登录门户网站时,门户网站服务器会为每个用户的 portlet 创建一个 PortletSession。PortletSession 参数化的具体 portlet 实例称为用户 portlet 实例。每个具体 portlet 实例可能具有多个用户 portlet 实例。

用户 portlet 实例是由单个 PortletSession 参数化的具体 portlet 实例。每个具体 portlet 实例可能具有多个用户 portlet 实例。PortletSession 存储与单次使用 portlet 相关的瞬时信息。

portlet 应用程序

portlet 应用程序提供了封装一组共享相同的上下文的 portlet 的方法。上下文包含所有资源,例如,图像、属性文件和类。所有 portlet 必须封装为 portlet 应用程序的一部分。

具体 portlet 应用程序

具体 portlet 应用程序是由单个 PortletApplicationSettings 对象参数化的 portlet 应用程序。对于每个 portlet 应用程序,可能具有多个具体 portlet 应用程序。PortletApplicationSettings 是具有读/写访问权,并是持久的。无明确代表具体 portlet 应用程序的对象。

从单个 portlet 应用程序派生的两个具体的 portlet 应用程序

具体 portlet 应用程序至少包含一个来自 portlet 应用程序的具体 portlet,但是无需全部包含它们。

portlet 应用程序自己不提供代码,但是形成 portlet 的逻辑组。除了这更多的逻辑收益之外,同一 portlet 应用程序的 portlet 也可交换消息。

portlet 方式

portlet 方式允许 portlet 显示不同的用户界面,这取决于 portlet 所需的任务。portlet 有四种显示方式,其在 portlet 部署描述符中定义。 portlet 容器在 Portlet.Mode 对象中维护 portlet 方式。通过 Portlet API 提供下列方式:

视图
当最初为用户在门户网站页面上构建 portlet 时,它显示在其视图方式下。这是 portlet 的正常操作方式。
帮助
如果由 portlet 支持该方式,则 portlet 对用户提供帮助页面以便获取有关 portlet 的更多信息。
编辑
如果由 portlet 支持该方式,则 portlet 对用户提供页面以便按其本身的需要定制 portlet。例如,portlet 能为用户提供页面来指定其位置以获取当地的天气和事件信息。用户必须登录到门户网站来访问编辑方式。
配置
如果由 portlet 支持该方式,则 portlet 为门户网站管理员提供页面以便对用户或用户组配置 portlet。

Portlet API 为 portlet 提供方法来确定当前或前一个方式。所有 portlet 都必须支持视图方式。portlet 容器为用户提供控件从而使用户在其门户网站页面上能与 portlet 交互。单击其中一个控件能更改 portlet 的方式或状态。下面显示 portlet 在视图方式下的空白标题栏。

视图方式中的 portlet 标题栏

此标题栏显示编辑、帮助、最小化和最大化图标。单击铅笔图标使 portlet 处于编辑方式。

portlet 状态

portlet 状态允许用户更改在门户网站中怎样显示 portlet 窗口。在浏览器中,用户用标题栏中的图标调用这些状态,这与 Windows 应用程序的操作方法是相同的。portlet 状态用布尔值在 PortletWindow.State 对象中维护。

  • 正常当最初在门户网站页面上构建 portlet 时,它以正常状态显示——与其它 portlet 一起排列在页面上。
  • 最大化当最大化 portlet 时,它显示为门户网站的整个主体,替换了其它门户网站的视图。
  • 最小化当最小化 portlet 时,仅显示门户网站页面上的 portlet 标题栏。

Portlet API 为 portlet 提供方法来确定当前状态。

Portlet API 的元素

本节描述 Portlet API 的基本接口、类和方法。下图显示 Portlet API 中许多公共对象的结构图。


1 PortletRequestPortletResponse 由 PortletAdapter 的帮助器方法(例如 doView())传递。


Portlet 类

抽象 Portlet 类是 Portlet API 的核心抽象。所有 portlet 通过扩展抽象类的子类之一(例如 PortletAdapter)来扩展该抽象类,这提供有助于开发者的方法。

portlet 生命周期

portlet 容器在 portlet 的生命周期期间调用抽象 portlet 的以下方法2

init()
门户网站初始化之后,即构造出 portlet 并随后使用 init() 方法初始化。门户网站总是仅实例化 portlet 的单个实例,而且此实例在所有用户之间共享,与 servlet 在应用程序服务器的所有用户之间共享的方式完全相同。
initConcrete()
构造 portlet 之后,在第一次访问该 portlet 之前,具体 portlet 由 PortletSettings 实例化。
service()
要求 portlet 呈现它的内容时,门户网站调用 service() 方法。在 portlet 的生命周期期间,通常会多次调用 service() 方法。对于页面上的每个 portlet,不是按保证的次序调用 service() 方法,甚至可能对于每个请求,以不同的次序调用 service() 方法。
destroyConcrete()
使用 destroyConcrete() 方法从服务除去具体 portlet。当管理员在门户网站服务器上的运行时期间删除具体 portlet 时,可能发生这种情况。
destroy()
门户网站即将终止时,portlet 会取消服务,然后使用 destroy() 方法破坏。最后,portlet 会作为无用信息被收集和终结。

2 这代表所有 portlet 上调用的方法。为实现侦听器的 portlet 调用其它方法。请参阅侦听器生命周期以获取更多信息。

getLastModified()

除了在 portlet 生命周期期间调用的方法外,portlet 容器为每个 portlet 请求调用 getLastModified() 方法。该方法返回 portlet 内容的更改的最后时间(以毫秒计),该时间在当前时间和 1970 年 1 月 1 日午夜之间 UTC(java.lang.System.currentTimeMillis())或为负值(如果时间未知)。要获取有关何时使用 getLastModified() 的更多信息,请参阅刷新 portlet 高速缓存

帮助器类

portlet 不直接扩展抽象 Portlet 类,而是扩展 PortletAdapter 或任何其它帮助器类依次扩展 Portlet。扩展这些类之一,有助于保护 portlet 不被抽象 Portlet 类更改。此外,它保存必须实现所有 Portlet 接口的方法,即使 portlet 不需要全部使用它们。使用 PortletAdapter 类,只需覆盖真正需要的方法。

在它的 service() 方法中,PortletAdapter 类调用对应于 portlet 方式的方法。扩展该类的 portlet 能覆盖 doView()、doEdit() 和 doHelp() 方法,而不必测试该方法或编写特定的 service() 方法。

此外,PortletAdapter 使 portlet 能在具体 portlet 中存储变量。具体 portlet 变量与 Java 实例变量是不同的,因为它们绑定到 portlet 类或非具体 portlet。PortletAdapater 提供 setVariable()、getVariable() 和 removeVariable() 方法和具体 portlet 变量一起使用。

核心对象

以下对象是 portlet 最常用的:

这些对象的每一个是它在 Servlet API 中的副本的扩展。

PortletRequest

PortletRequest 对象通过 login()beginPage()endPage()service() 方法传递给 portlet,为 portlet 提供请求特定的数据并使其能访问以下所列的进一步重要信息。

属性
属性是与请求相关的名称/值对。属性仅能用于请求的作用域。在一个请求期间 portlet 能获取、设置和除去属性。
参数
参数是由客户机发送的名称/值对,它在 URI 查询字符串中作为请求的一部分。通常参数从表单公布。参数用于特定请求的作用域。portlet 能从请求获取却不能设置参数。
客户机
Client 对象封装有关特定请求的用户代理程序的依赖于请求的信息。来自 Client 的信息包含用户代理程序的制造商或客户机支持的标记类型。使用 getClient() 方法从 PortletRequest 抽取 Client。能从 Client 获取以下信息:

用户代理程序
portlet 能获取由用户代理程序发送的字符串来将其本身标识到门户网站。
标记名称
portlet 可以获取表明客户机支持的标记语言的字符串,例如“wml”。
MIME 类型
portlet 能获取表明由客户机支持的 MIME 类型的字符串(如 text/vnd.wap.wml)。如果 portlet 支持多个设备类型,它将获取标记名称而非 MIME 类型。下表显示 MIME 类型和它们相应的标记类型。检索 MIME 类型不区别 HTML 和 cHTML 标记。

MIME 类型 标记类型
Text/html html
Text/vnd.wap.wml wml
Text/html chtml
能力
Capability 对象比标记类型包含更多的详细信息(有关客户机能支持什么),如 HTML、Javascript 或 WML 表的级别。
用户数据
PortletData 对象代表保存到持久存储的具体 portlet 实例的数据。例如,用户能设置 portlet 电子邮件应用程序从而每隔 30 分钟就检查新邮件。在 PortletData 对象中为实例存储该首选项。
会话
PortletSession 代表多个请求的特定用户的瞬时数据。与请求对比,请求在请求完全处理后不保留数据,而会话属性可为不止一个请求记录/保存。
portlet 设置
PortletSettings 对象代表保存到持久存储的具体 portlet 的配置。例如,管理员可以设置 Stock portlet 应该连接到哪个主机和端口以获取实时数据。在 PortletSettings 对象中为具体 portlet 存储该首选项。
方式
Portlet.Mode 提供当前或前一个 portlet 的方式。
PortletWindow
PortletWindow 对象代表当前 portlet 窗口的状态。portlet 能访问该对象来确定当前的 portlet 是要以最大化、最小化还是其正常视图呈现。
ModeModifier
在呈现 portlet 前,可在 PortletAction 中使用该对象把 portlet 方式设置为它的当前、前一个或请求的方式。例如,处于编辑方式的 portlet 可以处理用户操作,并可在返回视图方式之前先使 portlet 返回编辑方式以等待更多的输入。

PortletResponse

响应对象封装从服务器返回到客户机的信息。PortletResponse 通过 beginPage()endPage()service() 方法传递,并可由 portlet 通过使用 Java PrintWriter 用于返回 portlet 输出。响应还包含创建 PortletURI 对象的方法或使用 portlet 的名称空间限制 portlet 标记。

使用下列方法之一来创建 PortletURI:

createURI()
创建指向调用方式为当前方式 portlet 的 PortletURI 对象
createURI(PortletWindow.State state)
创建指向调用方式为当前方式和给定 portlet 窗口状态的 portlet 的 PortletURI 对象。
createReturnURI()
创建 portletURI,指向 portlet 的调用者。例如,createReturnURI() 能用于在编辑方式中创建后退按钮。

每个 portlet 在其本身的唯一名称空间中运行。portlet 使用 encodeNamespace() 方法把属性带至 portlet 输出以避免名称与其它 portlet 冲突。属性能包含参数名称、全局变量或 javascript 函数名。

PortletURI

PortletURI 对象包含指向 portlet 实例的 URI,并能通过添加特定 portlet 的参数或通过附加操作进一步扩展。

操作是特定 portlet 的活动,但在调用 portlet service() 方法之前,它需要以入站请求的结果来执行。例如,当用户在 portlet 编辑方式中输入数据并单击保存按钮时,在下一个标记生成前,portlet 需要处理已公布的数据。这能通过将保存操作添加到代表保存按钮的 URI 来实现。

完整的 URI 可转换为可嵌入到标记中的字符串。

PortletSession

PortletSession 保存 portlet 的具体 portlet 实例的特定用户数据,创建 portlet 用户实例。具体 portlet 实例之间的不同仅在于存储在它们的 PortletData 中的数据。portlet 用户实例之间的不同仅在于存储在它们的 PortletSession 中的瞬时数据。任何持久数据必须使用 PortletData 存储。存储在 portlet 的实例变量中的信息通过读和写访问在所有具体 portlet 实例(甚至所有具体 portlet)之间共享。确保未对用户特定的数据使用实例属性。

另一方面,必须谨慎对待 portlet 把什么添加到会话,特别是如果 portlet 曾运行在群集环境中,该环境是共享数据库序列化会话的地方。任何存储在会话中的东西必须也能序列化。

HttpSession 相似,PortletSession 在匿名页面上不可用。登录期间,将会为页面上的每个 portlet 自动创建 PortletSession。要获取 PortletSession,必须使用 getSession() 方法(在 PortletRequest 可用的)。该方法返回当前会话,或者如果没有当前会话,且给定参数“creat”创建是 true,它将创建一个并返回它。

侦听器

Portlet API 提供了侦听器,它可为 portlet 添加更多的功能。要启用侦听器的功能,portlet 必须实现以下接口之一。

PortletSessionListener

除了存在于每个出现在页面上的 portlet 的具体 portlet 实例之外,portlet 可能还有更细小的颗粒度。PortletSessionListener 使 portlet 能识别用户 portlet 实例的生命周期:

  • login()

    在用户登录到门户网站之后,每个 portlet 为用户创建了会话。具体 portlet 实例和用户会话的组合创建了用户 portlet 实例。用户实例的启动是由门户网站调用 portlet 上的 login() 方法来发信号的。此方法允许 portlet 初始化用户的 porlet 会话实例,例如,以便在会话中存储属性。

  • logout()

    当用户结束与门户网站的会话时,门户网站服务器调用 logout() 方法来通知 portlet 用户的会话实例正在终止。然后,portlet 将清除 portlet 用户实例的任何资源。

PortletPageListener

portlet 没有用于写入从页面上所有 portlet 的输出次序的控制或意识。PortletPageListener 允许 portlet 在页面的开始和结束插入标记。

  • beginPage()

    在每个页面的开始和调用页面上任何 portlet 的任何 service() 方法前,为驻留在页面的每个 portlet 调用 beginPage() 方法。和 service() 方法相似,对于页面上的每个 portlet,不是按保证的次序面调用 beginPage() 方法,甚至可能对于每个请求,以不同的次序调用 beginPage() 方法。该方法允许 portlet 输出对所有 portlet 的 service() 方法可见的 Javascript,或甚至可以设置 cookies 或头。

  • endPage()

    在每个页面的结束和调用页面上所有 portlet 的 service() 方法后,为驻留在页面上的每个 portlet 调用 endPage() 方法。与 service() 方法相似,不是按保证的次序调用 endPage() 方法,甚至可能对于每个请求,以不同的次序调用 endPage() 方法。例如,portlet 可以把需要在页面所有其它元素写好之后发生的 Javascript 插入到页面的结束处。

侦听器生命周期

当实现 PortletSesssionListener 和 PortletPageListener 时,生命周期期间在 portlet 上调用下列方法。

  • init() 非具体 portlet 和 PortletConfig 一起初始化。
  • initConcrete() 具体 portlet 和 PortletSettings 一起初始化。
  • login() 用户 portlet 实例和 PortletSession 一起初始化。
  • beginPage() portlet 可能在每个请求的每个页面开始处呈现输出。
  • service() portlet 可能在每个请求的 portlet 窗口中呈现输出。
  • endPage() portlet 可能在每个请求的每个页面结束处呈现输出。
  • logout() 破坏用户 portlet 实例。
  • destroyConcrete() 破坏具体 portlet。
  • destroy() 破坏非具体 portlet。

PortletTitleListener

如标题栏中显示的,PortletTitleListener 接口用于允许基于条件(例如,用于访问门户网站的设备类型)或用户输入(例如,用户在编辑页面上进行设置的首选项)来更改 portlet 标题。如果没有实现侦听器,portlet 显示 portlet 部署描述符的 <title> 元素(<language> 下)上指定的标题。

PortletSettingsAttributesListener

该接口侦听 PortletSettings 属性的更改,与管理员配置具体 portlet 时相似。

PortletApplicationSettingsAttributesListener

该接口侦听 PortletApplicationSettings 属性的更改,与管理员配置具体 portlet 应用程序时相似。

配置对象

portlet 使用下列对象检索和存储数据,这取决于如何使用数据:

PortletConfig

PortletConfig 将其初始化配置给提供非具体 portlet。配置拥有 portlet 类的信息。该信息对于从 portlet 派生的每个具体 portlet 都生效。

portle 的配置首先从其 servlet 部署描述符读取。该信息由 portlet 开发者定义。配置是只读的,并且 portlet 无法对它更改。

在抽象 Portlet 的 init() 方法中把 PortletConfig 传递给 portlet,并使用 getInitParameters() 将其用于访问特定 portlet 配置参数。PortletConfig 参数是整个非具体 portlet 生命周期可用的名称/值对。非具体 portlet 的参数由 servlet 部署描述符中 <init-param> 标记定义。

PortletSettings

PortletSettings 对象将其动态配置提供给具体 portlet。配置拥有具体 portlet 的信息。该信息对于具体 portlet 的每个具体 portlet 的实例都有效。

具体 portlet 的配置首先从 portlet 部署描述符读取。该配置是只读的并且仅当 portlet 在配置方式下可以由 portlet 来写。该信息通常由门户网站管理员来维护,并且当门户网站服务器运行时可能会被更改。一个请求期间,portlet 能获取、设置和除去属性。要提交更改,必须调用 store() 方法。

PortletSettings 对象可以被 PortletRequest 可用的 getPortletSettings() 方法访问。通常,它用于使用 getAttribute() 来访问特定 portlet 配置参数。属性是整个具体 portlet 生命周期可用的名称/值对。具体 portlet 属性由 portlet 部署描述符中的 <config-param> 标记定义。

PortletApplicationSettings

PortletApplicationSettings 对象将其动态配置提供给具体 portlet 应用程序。配置拥有应用程序中包含的所有具体 portlet 共享的 portlet 应用程序的信息。

具体 portlet 应用程序的配置首先从 portlet 部署描述符读取。该配置是只读的并且仅当 portlet 在配置方式下可以由 portlet 来写。该信息通常由门户网站管理员来维护,并且当门户网站服务器运行时可能会被更改。一个请求期间,应用程序中的 portlet 可以获取、设置和除去属性。要提交更改,必须调用 store() 方法。

PortletApplicationSettings 可以被 PortletSettings 对象可用的 getApplicationSettings() 方法访问。它用于使用 getAttribute() 来访问特定 portlet 配置参数。属性是整个具体 portlet 应用程序生命周期可用的名称/值对。具体 portlet 应用程序属性由 portlet 部署描述符中的 <context-param> 标记定义。

PortletData

PortletData 拥有具体 portlet 实例的数据。页面上每个发生具有一个具体 portlet 实例。PortletData 包含有关具体 portlet 实例的持久信息,而 PortletSession 仅包含用户 portlet 实例的瞬时数据。

页面上 portlet 的每个发生有一个具体 portlet 实例。页面可以由单个用户拥有(个人主页)或单个用户组拥有(组页面)。PortletData 在个人主页上包含特定用户数据,在组页面上包含特定组数据。

PortletData 对象将属性存储为名称/值对。一个请求期间,portlet 能获取、设置和除去属性。要提交更改,必须调用 store() 方法。数据是只读的并且仅当 portlet 在编辑方式下可以由 portlet 来写。

杂项对象

下列对象由 portlet 使用:

PortletContext

PortletContext 接口定义每个 portlet 运行在其中的 portlet 容器的 portlet 视图。PortletContext 还允许 portlet 访问其可用的资源。例如,使用上下文,portlet 可以访问 portlet 日志,访问 portlet 对应用程序中所有 portlet 是公共的上下文参数,获取资源的 URL 引用或访问 portlet 服务

以下描述了有关 PortletContext 的非常重要的详细信息。

InitParameters
参数为 Web 应用程序中所有 portlet 可用的名称/值对。这些定义在 web 部署描述符中 <context-param> 元素下。例如,如果一组 portlet 共享包含门户网站站点管理员电子邮件的名为“Webmaster”的上下文参数,每个 portlet 可能获取那个值并在它们的帮助中提供“mailto”链接。
属性
属性为 web 应用程序中所有 portlet 可用的名称/值对。portlet 能获取、设置和除去属性。上下文的属性存储在单个机器上并且不在群集中分布。
本地化的文本
getText() 方法是 portlet 用来访问给定语言环境中的资源束的。
资源
通过 PortletContext,portlet 才可以装入或包含位于 portlet 应用程序作用域中的资源。可用的方法有 include() 和 getResourceAsStream()。include() 方法通常用于为输出调用 JSP。
消息传递
通过消息传递就使 portlet 和共享数据之间的通信,或发送通知成为可能。通过使用 send() 方法发送消息。要获取更多的信息,请参阅 portlet 消息传递
portlet 服务
PortletService 对象允许 portlet 通过动态的发现使用可插入的服务。
日志
PortletLog 对象提供 portlet 记录信息性、警告或错误消息的能力。日志由 portlet 容器维护。启用或不启用记录日志是由 portlet 容器来判断的。要获取更多的信息,请参阅消息和跟踪记录日志

该对象还可以从 PortletAdapter 类的 getPortletLog() 得到。

PortletWindow

PortletWindow 对象代表封装 portlet 的窗口。例如,在一个 HTML 页面上,portlet 窗口通常可以作为表单元呈现。portlet 窗口能在其各种窗口控件的操作上发送事件,如用户单击最小化或关闭时那样。portlet,能就其当前状态依次询问窗口。例如,portlet 可能不同地呈现其内容,这取决于它的窗口是否为最大化。使用 PortletRequest 对象的 getWindow() 方法,PortletWindow 可用。

User

User 接口包含访问诸如用户全名或用户名的用户属性的方法。

Portlet 事件

portlet 事件包含了关于 portlet 可能需要响应的事件的信息。例如,当用户单击链接或按钮时,将生成操作事件。要接收事件的通知,portlet 必须在 portlet 类中实现事件侦听器。

  • 操作事件:当 HTTP 请求通过与操作关联的 portlet 容器接收时生成(如在用户单击链接时)。
  • 消息事件:当 portlet 应用程序中的另一个 portlet 发送消息时生成。
  • 窗口事件:当用户更改 portlet 窗口的状态时生成。

在生成事件要求的新的内容之前(并且因此 portlet),portlet 容器将所有事件发送到各自的事件侦听器。如果侦听器在处理事件时发现需要生成另一个事件,则那个事件将由 portlet 容器排队,并在 portlet 容器判断的时刻发送。仅保证将它发送并在内容产生阶段前发生。

一旦内容产生阶段开始,将不发送进一步的事件。例如,无法从 beginPage()、service() 和 endPage() 方法中发送消息。结果消息事件将不会被发送和实质上废弃。

直接在 portlet 类中实现事件侦听器。侦听器可以使用 PortletRequestPortletSession 属性从事件和响应访问 PortletRequest

操作事件

当接收与 PortletAction 关联的 HTTP 请求时,发送 ActionEvent 到 portlet。要接收操作事件,portlet 类必须实现 ActionListener 接口和带有 PortletAction 类型的对象。PortletAction 链接到使用 PortletURI 类及其 addAction() 方法引用操作的 URI。ActionEvent 可以用于获取相关联的 PortletActionPortletRequest

通常,PortletAction 与 HTTP 引用或 HTML 表单中的按钮链接。然后所点击的链接的 ActionEvent 把关联的 PortletAction 传送回 portlet,其能依次实现基于用户操作的不同的处理路径。portlet 操作能传送任何信息。然而,它不应该存储请求、响应或会话对象。该信息是操作事件的一部分,并将发送到注册了的侦听器。

以下显示 JSP 如何使用 URI,包括 PortletAction。当用户单击“添加”按钮,一个新的 HTTP 请求被发送到表单的操作 URL。

   <FORM method='POST' action='<%=editBean.getAddURI()%>'>
      Name: <INPUT name='bookmark.name'><br>
      URL: <INPUT name='bookmark.url'><br>
      <INPUT type='submit' name='addButton' value='Add'><br>
   </FORM>

以下显示 ActionListener 如何区分操作。

    public void actionPerformed(ActionEvent event)
   {
      PortletAction _action = event.getAction();
      if (_action instanceof DefaultPortletAction) {
         ...
         DefaultPortletAction action = (DefaultPortletAction)_action;
         if (action.getName().equals("add")) {
         ...

请参阅使用持久性获得代码示例,显示如何为 portlet 添加操作创建 ActionListener

DefaultPortletAction

Portlet API 提供给 DefaultPortletAction 类缺省参数,portlet 可以使用它实现 PortletAction 对象。可以基于 DefaultPortletAction 创建 PortletAction,或使用它来实现您自己的 PortletAction。以下显示如何创建 DefaultPortletAction:

   DefaultPortletAction addAction = new DefaultPortletAction("add");

下列显示如何把 PortletAction 包含到 URI:

   PortletURI addURI = response.createURI();
   DefaultPortletAction addAction = new DefaultPortletAction("add");
   addURI.addAction(addAction);
   

窗口事件

无论何时用户单击其中一个更改窗口状态的控制按钮,如最大化、最小化或恢复,WindowEvent 由 portlet 容器发送。例如,当用户最大化将以其正常状态显示的 portlet 时,可以使用 WindowEvent 显示更多信息。要接收窗口事件,必须在 portlet 类实现 WindowListener 接口。

Portlet API 提供 WindowAdapter 类,该类实现 WindowListener 的空的方法。通过扩展 WindowAdapter,portlet 开发者仅需要实现那些 portlet 所需的回调方法。没有 WindowAdapter,必须实现所有回调方法,即使方法为空。请参阅刷新 portlet 高速缓存以获取 WindowListener 的示例。

消息事件

如果收件人 portlet 是同一个 portlet 应用程序的成员,并且作为正在发送的 portlet 放置在相同的页面上,则消息事件能从一个 portlet 发送到其它 portlet。此外,DefaultPortletMessage 可以跨越 portlet 应用程序边界并被发送到页面的所有 portlet。仅当 portlet 处于 portlet 容器的事件处理周期中时,MessageEvent 才能被活动地发送到其它 portlet,否则将抛出异常。有两种不同类型的消息:

  • 单寻址消息:通过指定 send() 方法上的 portlet 名称,发送到特定 portlet 的消息。
  • 广播消息:发送到页面上所有 portlet 的消息。

当一个 portlet 的更改反映到另一个 portlet 时,消息事件是有用的。必须实现带有 PortletMessage 类型的对象,该对象通过 MessageEvent 传递。接收消息的 portlet 必须实现 MessageListener 接口和带有 PortletMessage 类型的对象。

要获得 portlet 如何能在相互之间发送消息的示例,请参阅 portlet 消息传递

PortletService

为使 portlet 通过动态的发现能使用可插入的服务,Portlet API 提供 PortletService 接口。PortletService 从 PortletContext.getService() 方法访问,查找适当的工厂获得服务,创建服务并将它返回到 portlet。

通过不同供应商可以实现各种服务,例如,SearchService、LocationService、ContentAccessService 或 MailService。Portlet API 提供 ContentAccessService

创建您自己的 portlet 服务

编写 portlet 服务包含四个步骤:

  1. 定义接口
  2. 编写服务实现
  3. 编写服务的工厂
  4. 注册服务

如果要对照现有接口实现您的服务,步骤 1 不是必需的。如果要重用现有的服务工厂,此情况也适用于步骤 3。

定义接口

定义 portlet 服务接口需要与定义任何公用 API 接口相同的严密的注意事项。portlet 服务接口仅必须扩展定义在 org.apache.jetspeed.portlet.service 软件包中的 PortletService 接口,该接口作为标志进行服务,与 Java API 的 Serializable 接口相似。

下面是一个 HelloWorldService 示例接口。


package my.portlet.service;

import org.apache.jetspeed.portlet.service.*;

public interface HelloWorldService extends PortletService
{
    // my service's method
    public String sayIt();
}



编写服务实现

服务实现必须实现 org.apache.jetspeed.portlet.service.spi 软件包的 PortletServiceProvider 接口,这样除了服务接口之外,还可以使用 portlet 服务生命周期方法。例如,init 方法的 PortletServiceConfig 参数允许您访问服务的配置(请参阅注册服务以获取更多的信息)。


package my.portlet.service.impl;

import org.apache.jetspeed.portlet.service.*;
import org.apache.jetspeed.portlet.service.spi.*;

public class HelloWorldServiceImpl implements HelloWorldService, PortletServiceProvider
{

    private String it = null;

    public void destroy()
    {
        // do nothing - no resources in use
    }

    public void init(PortletServiceConfig config)
    {
        it = config.getInitParameter("MY_MESSAGE");

        if (it == null)
            it = "Hello world!!!";
    }

    public String sayIt() 
    {
            return it;
    }
}



编写服务的工厂

通常,不必编写您自己的工厂,因为在 org.apache.jetspeed.portletcontainer.service 软件包中有两个与门户网站服务器一起提供的类属工厂。PortletServiceDefaultFactory 总是返回给定的服务的新实例,PortletServiceCacheFactory 总是返回与给定的服务相同的实例。可以使用这些工厂中的一个而不是作为单个实现服务。工厂必须实现 org.apache.jetspeed.portlet.service.spi 软件包的 PortletServiceFactory 接口。

下面是 HelloWorldService 的工厂类:


package my.portlet.service.factory;

import org.apache.jetspeed.portlet.service.*;
import org.apache.jetspeed.portlet.service.spi.*;

public class HelloWorldServiceFactory implements PortletServiceFactory
{
    PortletServiceProvider psp = null;

    public PortletService createPortletService(Class service, 
                                               Properties serviceProperties,
                                               ServletConfig servletConfig) 
        throws PortletServiceUnavailableException 
    {
        if (psp != null) {
            return psp;
        }
      else { 
            psp = new HelloWorldServiceImpl();

            psp.init(new PortletServiceConfigImpl(
                            service, 
                            serviceProperties, 
                            servletConfig));
            return psp;
        }
    }
}


注册服务

要把服务插入门户网站服务器,相应的类文件必须复制到 was_root/lib/app。然后必须更改 wp_root/app/wps.ear/wps.war/WEB-INF/conf 目录中的 PortletServices.properties 文件:

  1. 把实现作为相应的服务类型注册
  2. 为实现注册工厂
  3. 为实现提供配置参数

# PortletServices.properties

org.apache.jetspeed.portlet.service.default.factory = 
        org.apache.jetspeed.portletcontainer.service.PortletServiceDefaultFactory

...

my.portlet.service.HelloWorldService = my.portlet.service.impl.HelloWorldServiceImpl
my.portlet.service.impl.HelloWorldServiceImpl.factory = my.portlet.service.factory.HelloWorldServiceFactory
my.portlet.service.impl.HelloWorldServiceImpl.MY_MESSAGE = Hello World (properties)!

...



内容访问服务

能通过不同的供应商(例如,SearchService 或 MailService)实现各种服务。通常当必须使用代理时,Portlet API 提供从内部网外的源检索内容的 ContentAccessService。该服务允许 portlet 从远程 web 站点或门户网站 Web 应用程序中的 JSP 和 servlet 访问内容。(相反,PortletContext.include 方法仅能包含 portlet 应用程序的本地 JSP。)

示例:ContentAccessService


import org.apache.jetspeed.portlet.service.ContentAccessService;
.
.
.
ContentAccessService service =
   (ContentAccessService)portletContext.getService(ContentAccessService.class);

//get a URL
URL url = service.getURL("http://www.ibm.com", request, response);

//include the content of a web site into the portlet
service.include("http://www.ibm.com", request, response);

//include a JSP or servlet belonging to the portal web application
service.include("/templates/weather.jsp", request, response);
.
.
.


提示:直接访问因特网资源的缺点是,仅仅简单地将内容拿取并写到 portlet 的输出。这意味着将断开所有与其它页面或图像相关的链接。通过分析内容或使用一些增强的浏览器 portlet 能解决这些问题。

ContentAccessService 还可以打开与远程应用程序的 SSL 连接。除了在 URL 中为 include() 方法指定安全协议(HTTPS)之外,代码与非安全连接的代码相同(请参阅示例:ContentAccessService)。然而,必须如门户网站配置中所描述的来配置门户网站以支持 SSL,请参阅 PortletServices.properties

部署描述符

portlet 应用程序的 WAR 文件必须包含两个描述符文档:Web 应用程序部署描述符和 portlet 部署描述符。Web 应用程序部署描述符中的 servlet 定义必须与 portlet 部署描述符中的 portlet 定义有相同的次序。

Web 应用程序部署描述符

和其它遵守 J2EE 模型的 servlet 一样,portlet 和 Web 应用程序部署描述符(web.xml)一起被封装为 WAR 或 EAR 文件。该描述符在 Web 应用程序中定义每个 portlet 成为 servlet,包含每个 portlet 唯一的

抱歉!评论已关闭.