开发portlet准则的详细介绍
开发portlet准则的详细介绍
本节包含下列主题:
- 模型视图控制器(MVC)设计模式
- Portlet 创建准则
- 标记指南
- 使用 Portlet API 标记
模型视图控制器(MVC)设计模式
Portlet 必须能够支持显示输出到在许多通信设备上运行的多个因特网浏览器。这些浏览器通常需要不同的显示标记语言。较小设备的显示屏幕比较小,通常处理显示标记有更多的限制。
通过以模型视图控制器(MVC)设计模式实现,portlet 可支持多个浏览器和设备类型。此设计包含三个实体:
-
模型,要为 portlet 检索的数据源
Portlet 的模型数据通常是从外部数据源检索并装入 Java 显示 bean,或者到达时就以 XML 文档格式化了。
-
视图,用于显示 portlet 数据的输出机制。
显示视图通常是作为 JSP 或 XSLT 样式表来实现的,使用 Java bean 实现数据模型时通常较多使用前者,进入数据的格式为 XML 文档时,较多使用后者。
-
控制器,它连接选定的视图到数据,并指导 portlet 的操作。
控制器根据目标设备或浏览器选择要显示的视图,然后将数据模型传递给视图。视图抽取特定的显示数据,为浏览器格式化数据,然后将其输出提供给浏览器,作为 portlet 输出的门户网站聚集的一部分。
对于 portlet 开发,MVC 模式有下列特征:
- 取决于客户机支持的标记,portlet 仅负责调用正确的控制器。
- 连接器负责访问内容源。通常,每个内容源类型对应一个连接器,例如,一个连接器用于 POP3 访问,一个用于基于文件的高速缓存。
- 模型表示通过连接器检索的内容。模型是独立于表示的。
- 控制器负责为内容提供适当的标记(HTML、cHTML 或 WML)。
在 MVC 结构中,数据和表示之间存在明显的分离,它会使用一个控制器组件来管理数据(模型)和表示(或视图)之间的交互作用。控制器了解调用应用程序的环境,从数据对象收集要显示的信息,然后使用适用于当前设备的标记语言应用适当的视图来提供数据。
Portlet 创建准则
Portlet API 被设计成给您这样的 portlet 开发者开发 portlet 的最大灵活性。通过应用一些准则,可最大限度确保优化 portlet 的性能。如果使用 Servlet API 开发过 servlet,您会发现一些准则非常类似于创建 Portlet 的准则。
实例和类变量
最重要的规则是限制在 portlet 中使用实例或类变量。在 WebSphere Portal 中,仅例示 portlet 类的单个实例。即便不同的用户在他们的页面上使用相同的 portlet,还是由相同的 portlet 对象实例来生成标记。因此,每个 portlet 实例会被当作一个单体来对待。这暗示不应该使用实例或类变量来存储 portlet 调用之间的任何状态或其它信息。作为单体,portlet 的每个实例变量有效地成为具有类似作用域的类变量,在每个用户的 portlet 上下文中多次访问变量时,可能会出现问题。最好是通过将实例或类变量的使用限制为只读的值来避免这些问题。否则就只能牺牲重入或线程安全性。
此规则的一个例外是您可以使用实例变量。值不会更改的变量可安全地存储在实例变量中。例如,初始化 portlet 时,可在 portlet 中设置它的配置。因为对于不同的用户或调用之间的配置不会更改,所以可以将它存储在实例变量中。
访问 Portal Server
WebSphere Portal 是基于一个称为 Jetspeed 的开放源项目。然而,WebSphere Portal 包含许多不可用于 Jetspeed 中的新的功能部件和功能,因此无法保证两个产品提供的对象和接口之间的二进制兼容性。通常,不应该写尝试访问 WebSphere Portal 的内部组件的 portlet 或门户网站扩展,因为这些扩展或 portlet 可能会降低门户网站的性能和操作。
portlet 效率和性能
WebSphere Portal 使用相同的 portlet 实例来为不同的用户生成不同的页面标记。对执行这些任务的线程数量有一个限制。实现 portlet 让它尽快完成其工作是必须的,这样才能优化整个页面的响应时间。
应该考虑的优化是:
- 在 portlet 方法的处理中限制使用同步的方法或同步的代码块。
-
限制复杂字符串操作的使用。这包含:
- 当可能时,使用带视图 bean 的 JSP 而不是 XSL。当 JSP 比 Java 对象快得多且实例化较少的中间 Java 对象时,XSL 样式表会导致许多临时 Java 对象例示。
- 考虑使用 StringBuffer 来替换临时 String 对象。一般而言,这些在处理字符串时更有效,并且一般也不用实例化其它临时的 String 对象。
- 确定日志级别是否在将消息或跟踪信息写到日志前启用。请参阅消息和跟踪记录日志以获取更多信息。
- 限制使用长时间运行的循环。
- 在 JSP 中,减少空白和使用不可转换的 JSP 注释格式(<%----%>),而不要使用 HTML 注释格式(<!---->)。
- 最小化 Java 对象例示。
portlet 输出的一般提示
写 portlet 标记的目的之一是提供一致、清晰和完整的用户界面。 Portal Server 页面使用由门户网站管理员定义的外观和主题显示。主题表示门户网站的整个外观和感受,包括颜色和字体。外观表示在独个的 portlet 周围呈现的边框。WebSphere Portal 与一些预定义的外观和主题一起安装。
要让 portlet 与组织的门户网站或用户的定制门户网站集成起来,它们应该生成调用 portlet 的类属样式类的标记,而不是使用标记或属性来指定颜色、字体或其它可视的元素。要获取更多有关这些样式类的信息,请参阅定制外观和感受
Portlet 只被允许提供标记片段,随后这些片段会被 portlet 框架组装成一个完整的页面。例如,portlet 在门户网站页面上以 HTML 表单元(<td>)的上下文提供。因此,确保排除所有页面级别标记,如 <html>、<head>、<body>、<link>、<title>、<meta>、<base>、和 <wml>。对于标记,建议使用一个验证工具,如 W3C HTML 验证服务或标记编辑器中的工具,如 WebSphere Studio。请参阅标记指南以获取有关 HTML、WML 和 cHTML 标记片段的特定信息。
资源 URI 应该是编码的名称空间,其允许门户网站提供到有关受保护的、不受保护的和特定语言环境的资源位置的资源的直接路径。还应该编码命名的元素(表单字段、JavaScript 变量等)来避免与其它门户网站页面上的元素或其它页面上的 portlet 冲突。请参阅 PortletURI 以获取有关编码的常规信息,并参阅使用 JSP 生成标记以获取如何编码 JSP 中的输入字段的名称的示例。
只要可能,请提供对一种以上标记(HTML、WML 和 cHTML)类型的支持。这意味着从 Client 对象到标记测试,需要使用 getMarkupName() 方法。还必须在 portlet 部署描述符中表明 portlet 所支持的标记类型。
要准备转换 portlet,确保使用 PortletContext 的 getText() 方法,从特性文件检索所有字符串,而不是在 portlet 中硬编码。允许在某些语言的 portlet 用户界面中进行字符串扩展。
写 portlet 的标记时,考虑 portlet 将如何被残疾人访问。例如,视力有缺陷的人可能无法分辨某些颜色,或需要阅读器的辅助来访问 portlet 的内容。可以从应用特殊技术中心(CAST)或 W3C Web 可访问性倡议中找到更多关于可访问性准则的信息。IBM 在 http://www-3.ibm.com/able/accessweb.html 中提供 Web 可访问性的准则。
标记指南
本节提供关于使用 HTML、WML 和 cHTML 标记片段的信息。因为 HTML、WML 及 cHTML 代码段被嵌入到其它代码段,所以请确保它们是完整的,不包含开放标记,并且只包含有效的 HTML、WML 或 cHTML。例如,这可帮助防止 portlet 的 HTML 代码损坏门户网站聚集的 HTML 代码。要获取其它信息,请参阅门户网站输出的一般提示。
精简 HTML(cHTML)
- 使用标准 cHTML。要获取关于与 i-mode 兼容的 HTML 的信息,请参阅 http://www.nttdocomo.com/i/tagindex.html。
- 假设设计 portlet 时它可以单独显示,或可同其它 portlet 一起显示。
- 密切注意未终止的和多余的标记;带有未正确终止的标记的页面行为是无法确定的。
-
仅使用可包含到主体的元素;不要使用
<head>
或<body>
标记。要获取应避免的标记列表,请参阅标记片段的一般提示。 - 避免冗长、复杂的 cHTML,因为 portlet 可能会同其它对象共享页面。
- 避免过多地使用图像,不要对图像使用对齐和定位参数。
-
不要为用作
<a>
标记中引用的电话号码使用超过 24 个符号长的字符串。 - 不要使用超过 200 个字节长的 URL。
HTML
- 使用标准 HTML。要获取官方的 HTML 规范,请参阅 http://www.w3.org。
- 密切注意未终止的和多余的标记;带有未正确终止的标记的页面行为是无法确定的。
- 仅使用可在 HTML 表单元中正确输出的元素。例如,框架在插入表时不会出现。
- 不要使用嵌套很深的表,因为它们会降低 Netscape 浏览器上的性能。
- 避免冗长、复杂的 HTML。Portlet 会与其它 portlet 共享页面,每个 portlet 生成的内容越多,浏览器在可显示内容之前需要做的也越多。
- 使用 Portal Server 的样式表。如果硬编码字体和颜色,当用户更改页面样式设置时,portlet 可能会错位。要获取在门户网站中使用 CSS 的信息,请参阅更改外观和感受。
- 使用 CSS API 格式化文本。这样确保即便将来修改样式表,portlet 也能正常工作。
- 避免使用 CSS 进行绝对定位,因为这样无法确保 portlet 在特定位置显示。
- 保持 portlet 内容简洁。不要尝试通过小的 portlet 获得和显示全屏幕的内容。
- 不要在 portlet 中创建固定宽度的 HTML 表,因为这样无法确定 portlet 的列的宽度。
- 避免长的未分行文本;结果类似于使用固定宽度的表时发生的情况。
- 检查调整页面大小时 portlet 的行为,确保 portlet 能使用不同的浏览器大校
- 检查更改缺省浏览器字体时 portlet 的行为;portlet 应该能无缝地处理这些情况。
- 不要绘制 portlet 条幅,如标题栏,因为门户网站聚集会提供它们。
- 确保 portlet 提供的任何 Javascript 不干扰门户网站页面、浏览器窗口或页面上其它 portlet 的特性。此外,请在产生 JavaScript 的 JSP 中使用 <portletAPI:encodeNamespace value="function" /> 来防止 Javascript 函数和变量名与门户网站页面上其它的 portlet 冲突。要获取更多信息,请参阅使用 Portlet API 标记,以获取更多信息。
WML
- 使用标准的 WML。要获取信息,请参阅 http://www.wapforum.org。
- 当设计 portlet 时,假设它可以单独显示,或者可同其它 portlet 一起显示。
- 密切注意未终止的和多余的标记;带有未正确终止的标记的页面行为是无法确定的。
- 仅使用可包含在卡片(可能会加上 portlet 和元素)中的元素,并且不要创建单独的卡片。
- 不要设置卡片标题。
- 不要使用模板。
- 避免使用冗长、复杂的 WML,因为缓冲区长度可能受到用户代理程序的限制,且 portlet 可能会与其它 portlet 共享页面。
- 避免过多地使用图像。使用图像时,定义有意义的 alt 名称,因为对于不支持图像的设备,或是无法取图像时,这是必需的。如果可能,定义 localsrc。
- 不要使用本征事件,因为这些事件(如 oneventforward 和 oneventbackward)仅由聚集级别添加。
- 避免使用定时器。
- 仅在需要时才使用用户触发的事件,并总是明确地定义标签和名称参数。请将 portlet 的唯一标识用作名称前缀,否则一个页面上的不同 portlet 之间可能会产生冲突。为标签使用有意义的名称。
- 不要在 portlet 中创建固定宽度的 WML 表或图像。
- 避免使用长的、不环绕的未分行文本,这样可帮助防止不必需的滚动。
使用 Portlet API 标记
此节描述 portlet 容器识别的标记。portlet 容器提供 portlet JSP 中使用的标记。要使得这些标记可用于 JSP,在 JSP 的开始处必需下列伪指令:
<%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %>
- <portletAPI:if attribute="value>
-
通过该标记的属性,可以检查几个条件。如果条件为 true,标记的内容写到页面。否则,跳过该内容。可以评估多个条件。对于被写的标记内容,所有条件必须评估为 true。另外,每个参数可以包含由逗号或分号分隔的多个值。对于评估为 true 的条件,列表中仅一个值需要为 true。
至少包含下列属性中的一个:
- mode = [Portlet.Mode]
- 评估 portlet 的当前方式。例如,如果用户以编辑方式放置 portlet,mode="Edit" 为 true。
- previousMode = [Portlet.Mode]
- 评估 portlet 的前一个方式。例如,将 portlet 从查看方式转到编辑方式后,previousMode="View" 为 true。
- state = [PortletWindow.State]
- 评估 portlet 的状态。例如,用户单击 portlet 的最小化图标后,state="Minimized" 为 true。
- markup = [string]
- 评估客户机支持的标记语言。例如,如果客户机支持 WML,markup="wml" 为 true。
- mimetype = [string]
- 评估客户机支持的 MIME 类型。例如,如果客户机支持 HTML,mimetype="test/html" 为 true。
- capability = [Capability]
- 评估客户机的能力。例如,如果客户机支持级联样式表,capability="HTML_CSS" 为 true。
在下列示例中,portlet 必须是查看方式,并且对于要呈现的图像 portlet 状态必须是正常或最大化的:
<portletAPI:if mode="View" state="Normal,Maximized"> <img src="images/results.gif"> </portletAPI:if>
- <portletAPI:log text="text" level="level">
-
在 portlet 日志中写字符串。
- text = [string]
- 表明 portlet 日志中记录的消息或跟踪字符串。 必需此属性。
- level = [ERROR | WARN | INFO | DEBUG]
- 表明要记录的消息级别。请参阅消息和跟踪记录日志,以获取更多有关编写的日志信息。此参数是可选的;如果未指定级别,ERROR 是缺省值。
<portletAPI:log text="这是错误消息!"/>
- <portletAPI:text bundle="properties_file" key="string">
-
写本地化的字符串到输出流。当未找到资源束时,开始和结束标记之间的内容被写到输出流。
- bundle = [string]
- 指定资源束。必需此参数。
- key = [string]
- 资源束中查找到的键。必需此参数。
在下列示例中,welcome_message 参数的值是从 portlet 的 stockportlet.properties 文件检索的。
<portletAPI:text bundle="nls.stockportlet" key="welcome_message"> 欢迎! </portletAPI:text>
- <portletAPI:bidi is="rtl|ltr">
-
该标记用于支持双向语言文本。双向语言指从右到左或从下向上读龋属性 is 是必需的。
-
<wps:bidi is="rtl">
仅当文本是双向时写标记内容。 -
<wps:bidi is="ltr">
仅当文本非双向时写标记内容。
-
<wps:bidi is="rtl">
- <portletAPI:dataLoop>
-
通过当前具体 portlet 实例的
PortletData
中的所有属性循环。使用 <dataAttribute> 标记获取 dataLoop 开始和结束标记之间的属性。- pattern = string
- 可眩定义应该循环哪些属性的正则表达式。
请参阅 dataAttribute,以获取如何使用此标记的示例。
- <portletAPI:dataAttribute>
-
返回一个或多个
PortletData
属性的值。该属性可以由名称参数指定。也可以在 <dataLoop> 标记内使用此标记来检索所有属性或来自PortletData
的属性的子集。- name = string
- 可眩表明属性名称。
下列示例通过
PortletData
属性循环,仅返回有名称以 stock.user. 开始的值您的股票 portlet 的用户设置:<br> <portletAPI:dataLoop pattern="stock.user.*."> <portletAPI:dataAttribute/><br> </portletAPI:dataLoop> 股票 portlet 的一个特定用户设置:<br> <portletAPI:dataAttribute name="stock.user.quotes-count"/><br>
- <portletAPI:settingsLoop>
-
通过当前具体 portlet 的
PortletSettings
中的所有属性循环。使用 <settingsAttribute> 标记获取开始和结束标记之间的属性。- pattern = string
- 定义应该循环哪些属性的正则表达式。
请参阅 settingsAttribute,以获取如何使用此标记的示例。
- <portletAPI:settingsAttribute>
-
返回一个或多个
PortletSettings
属性的值。该属性可以由名称参数指定。也可以在 settingsLoop 标记内使用此标记来检索所有属性或来自PortletSettings
的属性的子集。- name = string
- 可眩表明属性名称。
下列示例通过
PortletSettings
属性循环,仅返回有名称以 stock.config. 开始的值.您的股票 portlet 的配置设置:<br> <portletAPI:settingsLoop pattern="stock.config.*."> <portletAPI:settingsAttribute/><br> </portletAPI:settingsLoop> 股票 portlet 的一个特定配置设置:<br> <portletAPI:settingsAttribute name="stock.config.hostname"/><br>
- <portletAPI:CreateReturnURI>
-
创建指向 portlet 的调用者的 URI。可以通过在
CreateReturnURI
开始和结束标记之间包含URIParameter
或 URIAction 来传递 URI 中的参数或操作。下列示例创建 URI 来提供返回用户到 portlet 的前一个方式或状态的链接。
<a href="<portletAPI:CreateReturnURI/>"> <portletAPI:text bundle="nls.my_portlet" key="back_label"> 上一个 </portletAPI:text> </a>
要获取传递具有此标记的参数或操作的示例,请参阅 URIParameter 和 URIAction。
- <createURI>
-
创建指向具有给定参数的当前 portlet 的 URI。可以通过在 createURI 开始和结束标记之间包含
URIParameter
或URIAction
来传递 URI 中的参数或操作。- state = [PortletWindow.State]
- 可眩表明 portlet 的状态。例如,state="Maximize" 创建最大化 portlet 的链接的 URI。如果未指定状态,URI 指向 portlet 的当前状态。
请参阅 URIParameter 和 URIAction。
- <URIParameter>
-
添加参数到
createURI
和CreateReturnURI
标记的 URI。- name = string
- 必需。要添加的参数的名称。
- value = string
- 必需。要添加的参数的值。
在下列示例中,参数 showQuote 和值 IBM 被添加到 URI。
<portletAPI:createURI state="Maximized"> <portletAPI:URIParameter name="showQuote" value="IBM"/> </portletAPI:createURI>
- <URIAction>
-
添加缺省操作到
createURI
和createReturnURI
标记的 URI。portlet 必须提供操作侦听器来处理事件。- name = string
- 必需。要添加的参数的名称。
<portletAPI:createURI> <portletAPI:URIAction name="Add" /> </portletAPI:createURI>
- <portletAPI:encodeNamespace name="string">
-
映射给定字符串值到此 portlet 的名称空间。为 portlet 输出中的命名元素(例如,表单字段或 JavaScript 变量)使用此标记,来唯一地将元素与此具体 portlet 实例关联起来,并避免与门户网站页面上的其它元素或页面上的其它 portlet 的名称冲突。
下列参数名称不可用于没有名称空间编码的 portlet JSP,因为它们是 WPS 框架保留的:
- 以点‘.’开始的名称
- 以下划线‘_’开始的名称
- name = string
- 必需。指定要映射到 portlet 的名称空间的值。
在下列示例中,编码具有名称‘email’的文本字段以确保门户网站页面上的唯一性。
<input border="0" type="text" name="<portletAPI:encodeNamespace name='email' />">
- <portletAPI:init>
-
提供下列 JSP 可以用于访问 portlet API 的相应对象的变量:
- portletRequest
- portletResponse
- portletConfig
使用 init 标记后,JSP 调用 portletResponse 的 encodeNamespace() 方法。
<portletAPI:init/> <%=portletResponse.encodeNamespace("test")%>