将 WorldClock portlet 从 IBM Portlet API 转换到 JSR 168 portlet API

本文介绍如何将 IBM WebSphere Portal 的 Portlet 从 IBM Portlet API 迁移到遵循 JSR168 标准的 API。通过实际案例 WorldClock Portlet 的迁移过程,展示了两种 API 在导入声明、主要方法、部署描述符等方面的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文说明了如何将一个为 IBM WebSphere Portal 专用 Portlet API 开发的 portlet 转换为使用 JSR 168 标准 portlet API 的 portlet。它描述了在执行这样的转换时存在的主要问题。如果您需要将一个 portlet 从 IBM Portlet API 转换到 JSR 168 API,本文为您提供了一个非常好的模型。

引言

Java™ Portlet 规范(JSR 168)定义了本地的 portlet 如何接入到门户。我们需要这个标准的 portlet API,因为在过去这几年中,不同的门户供应商定义了不同的 API,但是它们没有一个是可以互操作的。创建这个标准的 API 是由 IBM 和 Sun 在 Java Community Process 内部共同努力实现的。该规范使本地 portlet 和门户之间可以实现互操作,提供给 portlet 开发人员一个简单的编程模型,提供了同其他 Java 技术的移植性和互操作性,并通过 J2EE 技术利用和调整了 portlet API。

在创建 JSR 168 以前,IBM 已经在 WebSphere Portal 里面提供了一个专有的 API。然而,随着 JSR 168 的出现,我们推荐 portlet 开发人员使用新的标准的 portlet API。将使用 IBM Portlet API 的 portlet 转换为使用 JSR 168 API,需要做几个方面的转换。在 portlet 描述符、JSP 和它们的标签以及主要的 portlet 方法上两者有很大的不同。它们有不同的方法参数和操作流,并且需要重新编写一些功能,因为两者之间的 API 并没有一一对应的关系。

本文描述了如何转换 WorldClock portlet,该 portlet 用 IBM 的 WebSphere Portal 开发,要将其从 IBM Portlet API 转换到 JSR 168 API。这个例子包括了当执行这样的 portlet 转换,并且将其应用到 WebSphere Portal version 5 及以上版本时应该注意的主要问题。请注意这里显示的代码片断没必要符合最佳实践;该转换的目的只不过是用最小的努力来转换 portlet。

对比 IBM WebSphere Portlet API 与 JSR 168 API

IBM Portlet API 和 JSR 168 API 在主要方面是相似的。IBM Portlet API 在功能上要丰富一些,因为它已经定义了好几年并且一直在加强。这就意味着将使用 IBM portlet API 的 portlet 转换到 JSR API 的 portlet 时,会出现一些困难,因为 JSR 168 API 可能并不支持原始 portlet 所支持的所有功能。现在 JSR 168 API 正在添加更多的功能,因此,到时困难将会越来越少。不过 IBM 为 JSR 168 portlet API 提供了扩展,以提供至少与传统的 IBM portlet API 相同的功能。

两个 API 之间主要的相似点和不同点概括如下。如果想要了解关于 portlet API 不同点更加详细的描述,参阅 比较 JSR 168 Java Portlet 规范和 IBM Portlet API

相似的 API 概念不同的 API 概念
  • Portlet Modes: View、Help、Edit、(Configure)
  • Window States:Normal、Minimized、Maximized
  • Portlet 生命周期和请求处理:Init、handle requests、destroy
  • URL 编码
  • 包含 Servlet/JSP
  • Portlet 应用程序打包
  • 基于过期的缓存
  • Portlet Session
  • 请求和响应对象对于 IBM 的 portlet API 的 action 和 render 阶段是相同的,但是对于 JSR portlet API 来说却不同。
  • Portlet 可能在 action 阶段的请求中存储属性,并且在 render 时重新得到它们。使用 JSR 168 Portlet API 是不能做到这一点的。
  • Portlet Application 实体
  • Portlet Entities

WorldClock portlet

用来做转换范例的 WorldClock portlet 是一个简单的 portlet,实现了简单的功能,因此是转换的一个良好范例。该 portlet 允许用户设定他们的本地时区,在该时区内查看当前时间。用户同样可以在单独的时区内快速的搜索当前本地时间。该 portlet 依赖运行 WebSphere Portal 的服务器提供的时间来进行计算。


图1. 范例 WorldClock Portlet
范例 WorldClock Portlet 




回页首


如何转换 WorldClock Portlet

接下来的步骤描述了 WorldClock portlet 从 IBM Portlet API 向 JSR 168 API 一步步转换。为了对转换前后的代码不同有一个总体了解,我们提供了两种 WorldClock portlet 的范例源代码。该转换步骤分成以下四个部分。

每个部分都提供了原始 portlet 和转换后的 portlet 的代码对比。大多数例子同样链接到代码的完整范例,让您可以在 portlet 里面合适的方法上下文中查看代码。

常见 portlet 转换问题

当将 portlet 从 IBM Portlet API 转换到 JSR 168 API 时需要执行一些常见的步骤。这些步骤包含对 import 声明的更改和方法的重构和重命名。

IBM Portlet APIJSR 168 API
import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlet.event.*;
import org.apache.jetspeed.portlets.*;

import javax.portlet.*;

引入的 IBM Portlet API 包包含了完整功能的 portlet 所需的所有接口和实现类。在 JSR 168 API 的包 javax.portlet.*; 中,这些必须的接口和类已经被打包在一起,例如,包含 portlet 的 action 请求和响应、rander 请求和响应、配置和其他所需的接口。参考 WebSphere Portal 5.0 的 Portlet API Javadoc 和 JSR 168 Portlet 规范 API,了解包内容的完整列表。

IBM Portlet APIJSR 168 API
public class WorldClockController 
    extends PortletAdapter
    implements ActionListener

public class WorldClockController 
    extends GenericPortlet

IBM Portlet API 的 PortletAdapter 提供了 Portlet 接口的默认实现。 ActionListener 接口是 Portlet 接口的一个补充。如果 portlet 中的对象想要获取 action 事件,除了 Portlet 接口以外还必须实现这个接口。

对于 JSR 168 portlet, GenericPortlet 类提供了对 Portlet 接口的默认实现。它提供了抽象子类来创建 portlet。 GenericPortlet 类允许您实现 processAction 方法,该方法处理 action 处理,其在 IBM portlet API 的 ActionListener 接口中提供。

这些代码是 WorldClock portlet 的 构造器的一部分。

 

IBM Portlet APIJSR 168 API
public void init(PortletConfig portletConfig) 
     throws UnavailableException

public void init(PortletConfig portletConfig) 
     throws PortletException, 
             UnavailableException

在 JSR 168 API 和 IBM Portlet API 规范中,  init 方法都可以抛出  UnavailableException 异常。然而,在 JSR 168 情况下,当它不能成功执行其操作时,同样可以抛出通用异常  PortletException

 

 

IBM Portlet APIJSR 168 API
public void doView (PortletRequest request, 
          PortletResponse response) 
          throws PortletException, IOException

public void doView (RenderRequest request,
          RenderResponse response)
          throws PortletException, IOException

在 IBM Portlet API 里面,render 请求和响应与 action 请求和响应是相同的。然而 JSR 168 API 在下面的 action 是否需要 portlet 内容的 re-rerdering 或者 action 处理上是有区别的。仅仅 render 请求和响应在 JSR 168 API portlet 的  doView 方法里面作为参数传递。

 

IBM 专有的 portlet API 并没有遵照 Model-View-Controller(MVC)模式。在 portlet 的 render 阶段期间,它的状态依旧可以改变。在 JSR 168 portlet API 中这是不正确的,它通过不同的请求(render 和 action )来采取不同的方式,不管 portlet 的状态是可以修改,还是 portlet 的内容正在被显示。JSR 168 种特定 portlet API 的 doView 方法表现 MVC 模式的 view 组件。Portlet 的内容可能提供到促使调用的 actionPerformed 方法的 action URL。Portlet 的状态只能通过 action 请求在该方法中更改。这部分表现 MVC 模式的 controller 部分。

这是 WorldClock portlet 的 doView 方法的一部分。

 

IBM Portlet APIJSR 168 API
public void actionPerformed(ActionEvent anEvent) 
     throws PortletException 
{
      DefaultPortletAction pAction = 
             (DefaultPortletAction)anEvent.getAction();
      String action = pAction.getName();
      PortletRequest request = anEvent.getRequest();
}

public void processAction(ActionRequest request, 
          ActionResponse response)
          throws PortletException
{          
     String action = request.getParameter(PARAMETER_NAME);
}

IBM Portlet API 定义 action 处理通过  ActionListener 接口及其实现类来单独进行。每个 action 处理的标准实现已经在 JSR 168 的  GenericPortlet 类中提供。因为 JSR 168 API 对待 action 请求响应和 render 请求响应是不同的,  processAction 方法接收  ActionRequest 和  ActionResponse 对象作为参数。

 

下面这段代码是 WorldClock portlet 的 actionPerformed 方法的一部分。

portlet 转换详细问题

这些是在将 portlet 从 IBM Portlet API 转换到 JSR 168 API 时的一些详细步骤。对于这些改变,您需要对这两种 API 有比较深的了解。这些在转换 WorldClock portlet 时所需的详细步骤将在本节中进行描述。

 

IBM Portlet APIJSR 168 API
import org.apache.jetspeed.portlet.PortletData;
 PortletData data = request.getData();
 data.setAttribute(name, value);
 data.getAttribute(name);
 data.removeAttribute(name);

import javax.portlet.PortletPreferences;
PortletPreferences data = request.getPreferences();
data.setValue(name, value);
data.getValue(name, default_value);
data.reset(name);

IBM Portlet API 通过  PortletSettings 对象提供了关于 portlet 的基本配置信息,然而每个 portlet 实例的个性信息是在  PortletData 对象中提供。在 JSR 168 API 里面,这些信息仅仅通过一个叫做 PortletPreferences 的对象提供。当使用 preference 属性代替 portlet 设置或者 portlet 数据时,需要考虑两个主要的不同点:

 

  • PortletPreferences 的 preference 属性允许空值。因此,如果没有设定值的话是否通过指定一个返回的默认值,JSR 168 API 是区别对待的。
  • PortletPreferences 的 reset 方法移除或重置 preference 值为可用的预定义的值。IBM Portlet API 通过 PortletData 对象的 remove 方法来实现这一功能。

下面是 WorldClock portlet 的 doView 方法的一部分。

 

IBM 特定 APIJSR 168 API
getPortletConfig().getContext().include
      ("/WEB-INF/worldclock/WorldClockView.jsp", request, response);

PortletRequestDispatcher dispatcher = getPortletConfig().
      getPortletContext().getRequestDispatcher
      ("/worldclock/html/WorldClockView.jsp");
dispatcher.include(request, response);

 

在 IBM Portlet API 里面,在 PortletContext 中通过直接使用 include 方法包含了一个外部资源。在 JSR 168 API 中, PortletRequestDispatcher 对象是由 PortletContext 来提供;然后使用该对象的include 方法来包含资源。

点击 这里获取 WorldClock portlet 实现的代码范例。

 

IBM Portlet APIJSR 168 API
org.apache.jetspeed.portlet.PortletURI
PortletURI quick_uri = response.createURI();
PortletAction quickAction = new DefaultPortletAction(QUICK_LOOKUP);
quick_uri.addAction(quickAction);

javax.portlet.PortletURL
PortletURL quick_uri = response.createActionURL();
quick_uri.setParameter(COMMAND, QUICK_LOOKUP);

Unified Resource Locator(URL)的生成在两种 API 中是不同的。在 IBM Portlet API 中创建一个 URL 来调用 action 事件,指定 action 将要发生的  PortletAction 对象需要创建和扩展。使用 JSR 168 API,  createActionURL 方法直接返回调用 action 方法的 URL。为了指定 action,必须设置一个参数。

 

下面是 WorldClock portlet 的 doEdit 方法的部分代码。

 

IBM Portlet APIJSR 168 API
request.setModeModifier(Portlet.ModeModifier.CURRENT);

response.setPortletMode(PortletMode.VIEW);

IBM Portlet API 允许通过指定 portlet 请求的  ModeModifier 来在事件处理中定义下一个 portlet 模式。使用 JSR 168 API,aciton 响应的  setPortletMode 方法用来更改到任何 portlet 模式。当在两种 portlet API 的转换期间,请记住 IBM Portlet API 的  createReturnURI 方法将 portlet 模式改回该 portlet 的上一个模式(通常将它从 EDIT 改为 VIEW 模式)。为了在 JSR 168 中具备相同的行为, createReturnURI 调用需要由  RenderResponse.createActionURL 来代替。在该方法中调用  processAction,该 portlet 的 VIEW 模式可以明确的设定在 action 响应中。

 

 

IBM Portlet APIJSR 168 API
portletConfig.getContext().getLog().
     debug("WorldClockController(init): entering init()...");

log("WorldClockController(init): entering init()...");

IBM Portlet API 和 JSR 168 API 都提供了通过  PortletContext 访问日志工具。然而,JSR 168 Portlet API 在 portlet 上下文本身提供了  log 方法,而不是使用  PortletContext.getLog 方法返回的 PortletLog

 

部署描述符差异

Portlet 部署描述符( portlet.xml)用来描述 web 存档中打包的 portlet;除了 web 存档中必须存在的使其有效的 web 部署描述符( web.xml)之外,还必须提供这个部署描述符。JSR 168 Portlet API 没有使用 web.xml 来存储 portlet 信息。因此 JSR 168 Portlet 应用程序的 web.xml 文件可能是空的。

这里有一些将 portlet 部署描述符从 IBM 特定 Portlet API 转换为 JSR 168 API 时需要执行的详细步骤。对于这些更改需要对两种 portlet 描述符有较深的理解。因为 portlet 部署描述符用非常不同的结构提供关于 portlet 的信息,这里仅列出 WorldClock portlet 的 portlet.xml 文件中呈现的一些不同之处。

 

IBM Portlet APIJSR 168 API
<!DOCTYPE portlet-app-def 
    PUBLIC "-//IBM//DTD Portlet Application 1.1//EN" 
    "portlet_1.1.dtd">
<portlet-app-def>
<portlet-app> ... </portlet-app>
<concrete-portlet-app> ... </concrete-portlet-app>
</portlet-app-def>

<portlet-app xmlns=
    "http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" 
version="v1.0" id="worldclock_app_id" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation=
    "http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd 
http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
</portlet-app>

文件  portlet.xml 描述了一个 portlet 应用程序,如同 IBM portlet Document Type Definition(DTD)或者 JSR 168 portlet XML Schema Definition(XSD)中描述的那样。IBM Portlet API 将一个 portlet 应用程序的定义划分为一个  portlet-app 以及一个  concrete-portlet-app,然而 JSR 168 API 仅仅定义了一个  portlet-app。因此转换  portlet.xml 的第一个步骤是更改 portlet 应用程序标签,包含到 portlet 部署描述符的 XML Schema 定义的引用。

 

每个 portlet 通过 portlet 应用程序里面的 <portlet> 标签来定义;这在两种 API 中是相同的。

 

IBM Portlet APIJSR 168 API
<servlet-class> ... </servlet-class>

<portlet-class> ... </portlet-class>

在 IBM Portlet API 中,portlet 的完整类名是在  web.xml 文件中,通过和 servlet 一样的方式来指定。然而 JSR 168 API portlet 是它们自己的组件,并不是特殊的 servlet,该 portlet 的完整类名是在 portlet.xml 中的  <portlet-class> 标签中指定的。

 

 

IBM Portlet APIJSR 168 API
<supports>
<markup name="html">
<view output="fragment"/>
<edit output="fragment"/>
<config output="fragment"/>
</markup>
                
</supports>

<supports>
<mime-type name="html">
<portlet-mode>view</portlet-mode>
<portlet-mode>edit</portlet-mode>
<portlet-mode>config</portlet-mode>   
</mime-type>
</supports>

由 portlet 支持的该 portlet 模式是在  <supports> 块中指定的。IBM Portlet API 通过  <markup> 标签来指定支持的标记语言;JSR 168 API 使用  <mime-type> 标签。该 portlet 模式中由 IBM 专有模式标签(例如,<view>,<edit>,<help>)定义的模式需要更改为 JSR 168 API 的  <portlet-mode> 标签。因为在 JSR 168 API 中还定义了 configure 模式作为一个选项,在  <custom-portlet-mode> 标签的  <portlet-mode> 标签中也必须定义这个 portlet 模式。

 

 

IBM Portlet APIJSR 168 API
<concrete-portlet> ... 
<title> ... </title>
<title-short> ... </title-short>
... </concrete-portlet>

<portlet-info>
<title> ... </title>
<short-title> ... </short-title>
</portlet-info>

对于使用 IBM Portlet API 的 portlet,每个具体的 portlet 都定义了标题。由于 JSR Portlet API 并没有使用具体 portlet 相同的概念,每个 portlet 的信息都定义在 portlet 定义内部的  <portlet-info>标签中。为了根据区域来支持不同的设置,该信息可以使用 JSR 168 特殊的关键字(例如,  javax.portlet.title,  javax.portlet.short-title 以及  javax.portlet.keywords)在一个资源包文件中指定。这些资源包必须在每个 portlet 定义的  <resource-bundle> 标签中指定。

 

JSP 差异

两个版本的 WorldClock portlet 都包含四个 JSP 文件,用来显示内容。

 

BidiInclude.jspBidiInclude JSP 使对 BIDI 的支持更加容易。该 JSP 中定义的变量补充了 <bidi> 标签的内容。
WorldClockEdit.jspWorldClockEdit JSP 用来修改 WorldClock portlet 并且更改其设置或者首选项。
WorldClockHelp.jspWorldClockHelp JSP 呈现一个 JSP 来显示 WorldClock portlet 的帮助页面。
WorldClockView.jspWorldClockView JSP 用来显示 WorldClock portlet 的内容。

 

在 IBM 和标准 WorldClock portlet 之间,它们的 JSP 文件有一些不同。WorldClock portlet 使用的 JSP 文件,BidiInclude.jsp、WorldClockEdit.jsp 以及 WorldClockView.jsp 使用 Portlet API 指定的 JSP 标签。Portlet 标签库使 portlet 中包含的 JSP 文件可以直接访问 portlet 特定的元素,诸如 portlet 请求和响应。它同样允许 JSP 去访问 portlet 功能比如 portlet URL 的创建。在 JSP 里面,标签元素始终都是通过它定义的前缀来引用的(例如,portletAPI)。

JSP 通过以下的方式引用 IBM 特定的 portlet 标签:

<%@ taglib uri="/WEB-INF/tld/portlet.tld" prefix="portletAPI" %>

.

JSR JSP 像这样来引用标签库:

<%@ taglib uri="http://java.sun.com/portlet" prefix="portletExt" %> 

WebSphere Portal 提供了额外的标签来供 JSR 168 portlet 中使用。为了使这些标签能够在 JSP 中使用,需要添加以下的指令:

<%@ taglib uri="/WEB-INF/tld/ibm-portlet-ext.tld" prefix="portletExt"%>

<portletExt/> 通过以下方式使用:

<portletExt:bidi dir="rtl|ltr" locale="
        locale" />
      

dir: 指明语言中的文本的正常方向。

  • 对于 dir="rtl",仅仅当客户端的区域属于双向语言时,标签内容才能写入。
  • 对于 dir="ltr",仅仅当客户端的区域不属于双向语言时,标签内容才能写入。

locale: 仅仅当语言属于 LocalizerService.properties 中定义的双向语言时,标签内容才能写入。

在 IBM WorldClock portlet 中已经提到的 JSP 使用了下面这些标签元素:

 

init实现该标签功能的类创建了可以在 JSP 中使用的以下四个变量:
  • portletRequest
  • portletResponse
  • portletConfig
相应的 JSR 168 API 指定的 portlet 标签是 <defineObjects>
encodeNamespace实现该标签功能的类将给定的字符串值映射到这个 portlet 的命名空间。标签参数: 
  • name (强制) - 该值可以映射到 portlet 命名空间
JSR 168 API 中指定的一个类似的标签是 <namespace>
text(不赞成)实现该标签功能的类向输出流中写入一个局部字符串。当没有发现资源包文件时,在 start 和 end 标签之间的文本将写入到输出流中。标签的参数是: 
  • bundle (强制) - 资源包名
  • key (强制) - 资源包中要发现的关键字
目前,没有相应的反映这一功能的 JSTL JSP 标签可用。
bidi实现该标签功能的类支持双向语言的文本。除了当显示从左向右的文本字符串(例如,URL、代码范例或者目录和文件名)时,双向语言一般都是从右相左读。 
目前,没有相应的反映这一功能的 JSTL JSP 标签可用,但是提供了一个 IBM 扩展,如上所示。 
encodeURI实现该标签功能的类创建 PortletResponse 对象,并且执行 encodeURI 方法。 
以下 JSR 168 API 指定 portlet 标签提供了相同的行为: <actionURL> and <renderURL> .

 

以下的标签元素已经在 JSR 168 WorldClock portlet 的 JSP 中提到:

 

defineObjectsdefineObjects 标签必须在 JSP 中定义以下的变量:
  • renderRequest
  • renderResponse
  • portletConfig

这些变量必须引用存储在 JSP 的请求对象中的相同的 JSR 168 API 对象。使用 defineObjects 标签的 JSP 可能在整个页面的代码段中使用这些变量。 下面是 defineObjects tag 标签使用的一个范例:

	
%<portlet:defineObjects/%>
%<%=renderResponse.setTitle("my portlet title")%%>

在使用 defineObjects 标签以后,JSP 调用 RenderResponse 的 setTitle 方法来设定 portlet 的标题。

actionURL该 portlet 的 actionURL 标签创建 URL ,并且必须指向当前的 portlet,必须用支持的参数来触发 action 请求。通过在actionURL start 和 end 标签之间包含 param 标签,参数可以添加到 URL 中。下面是为这个标签定义的非必须的属性:
  • windowState (类型: String,非必须) -- 标明了当该链接执行后 portlet 应该具有的窗口状态。
  • portletMode (类型: String,非必须) -- 标明了当这个链接执行后,如果没有发现错误,portlet 应该具备的 portlet 模式。
  • var (类型: String,非必须) -- 用于 action URL 的输出范围变量的名字。
  • secure (类型: String,非必须) -- 指明作为结果的 URL 是否应该是一个安全的连接(如果该值设置为“true”)或者一个不安全的连接(如果该值设置为“false”)。
renderURL该 portlet 的 renderURL 标签创建一个 URL,该 URL 必须指向当前的 portlet,并且必须触发使用支持参数的 render 请求。参数可以通过在 renderURL start 和 end 标签之间包含 param 标签来添加。正如 actionURL 标签中列出的那样,这个标签也同样定义了相同的非必须属性。
namespace这个标签为当前的 portlet 产生一个唯一的值。该标签应该用于 portlet 输出中指定的元素(例如 JavaScript 方法和变量)。该命名空间确保给定的名字唯一的与这个 portlet 联系在一起,并且避免同该 portlet 页面或者该页面其他 portlet 上的其他元素发生冲突。
param这个标签定义了一个参数,可以添加到 actionURL 或者 renderURL 中。 param 标签不能包含任何主体内容。为这个标签定义了以下必须的属性:
  • name (类型: String,必须) - 添加到该 URL 的参数名。如果名字为 null 或者空,不会执行任何 action。
  • value (类型:String,必须) - 添加到该 URL 的参数值。如果值为 null,将作为空值处理。

 

对于标准 portlet 标签的更多的参考,请参考 The JSR 168 Portlet Specification

范例 Standard WorldClockEdit JSP 代码片断

<%@ page session="false" buffer="none"%>
<%@ page import="java.util.*,javax.portlet.*,com.ibm.wps.portlets.worldclock.WorldClockController" %>
        
<%@ taglib uri="http://java.sun.com/portlet" prefix="portletAPI" %> 
<portletAPI:defineObjects/>
<portletAPI:actionURL var="saveURI">
   <portletAPI:param name="<%=WorldClockController.COMMAND%>" value="<%=WorldClockController.SAVE%>"/>
</portletAPI:actionURL>

......
<!-- build table for edit screen -->
        <form name="WORLD_CLOCK_EDIT" action="<%=saveURI%>" method="POST">
   .....
   <table >
      <tr>
         <td>
            <label for="local_time_zone"><%= 
                   WorldClockController.getText ("text.local_time_zone", renderRequest.getLocale ()) %></label>
         </td>
      </tr>
      <tr>
         <td>
            <%--  on the next line width is for Netscape, style is for IE --%>
            <select id="local_time_zone" name="LocalTimeZone" size="1">
            <%
               int selPos = -1;
               String localTimezone = (String)renderRequest.getAttribute("localTimezone");
               if (localTimezone != null) {
                 try {
                   selPos = Integer.parseInt(localTimezone);
                 }
                 catch (NumberFormatException ex) {
                 }
               }
               Vector timezoneVector = (Vector)renderRequest.getAttribute("timezoneVector");
               for (int i=0; i < timezoneVector.size(); i++) {
                  String id = (String)timezoneVector.elementAt(i);
                  // exclude default selection
                  if ( selPos != i ) {
             %>
                    <option value="<%= i%>"><%= id %></option>
             <%
                  }
                  else {
             %>
                    <option selected value="<%= i%><%= id %></option>
             <%
                  }
               }
             %>
             </select>
         </td>
      </tr>
   </table>
	
   .....
 	
</form>
 	
      





回页首


WorldClock portlet 源代码

本节比较了用 IBM Portlet API 编写的 WorldClock portlet 源代码,和转换后的 JSR 168 Portlet API 的 portlet 源代码,突出显示的代码指明了转换上下文中的改变。

使用 IBM Portlet API 的 WorldClock portlet 构造器使用 JSR 168 API 的 WorldClock portlet 构造器
// Java libraries
import java.util.*;
import java.io.*;
import java.text.*;
// Portlet API classes
              import org.apache.jetspeed.portlet.*;
import org.apache.jetspeed.portlet.event.*;
import org.apache.jetspeed.portlets.*;
import com.ibm.wps.portlets.*;
/**
 * The WorldClockController class controls the 
 *  content display and portlet configuration
 *  behavior of the world timezone clock.
 */
public class WorldClockController 
	
              extends PortletAdapter 
		implements ActionListener
{
    .....
}
            

// Java libraries
import java.util.*;
import java.io.*;
// Portlet API classes
              import javax.portlet.*;
/**
 * The WorldClockController class controls the 
 * content display and portlet configuration
 *  behavior of the world timezone clock.
 */
public class WorldClockController 
	
              extends GenericPortlet
		
{
    .....
}
            

返回文章

 

使用 IBM Portlet API 的 WorldClock portlet doView 方法使用 JSR 168 API 的 WorldClock portlet doView 方法
/**
* View functionality. Pass the format information 
*  to the JSP for display of local and
*  other time zone times.
*/
public void doView (
                PortletRequest request,
	PortletResponse response) 
	  throws PortletException, IOException
{
  
                PortletData data = request.getData();
  .....
  // include JSP for extended search
  
                getPortletConfig().getContext().
     include("/WEB-INF/worldclock/WorldClockView.jsp", 
         request, response);
    ....
}
              

/**
* View functionality. Pass the format information 
*  to the JSP for display of local and
*  other time zone times.
*/
public void doView (
                RenderRequest request,
	RenderResponse response) 
	   throws PortletException, IOException
{
  
                PortletPreferences data = request.getPreferences();	
  .....
			    
  // include JSP for extended search
  
                PortletRequestDispatcher dispatcher = getPortletConfig().
      getPortletContext().getRequestDispatcher
        ("/worldclock/html/WorldClockView.jsp");
  dispatcher.include(request, response);
  ....
}
              

返回文章

 

 

使用 IBM Portlet API 的 WorldClock portlet doEdit 方法使用 JSR 168 API 的 WorldClock portlet doEdit 方法
 /**
* Edit functionality. 
* Allow the user to adjust the local time and 
* time zone. They can also pick the other time 
* zones in the world to display in view mode.
*/
public void doEdit (
                PortletRequest request,
	PortletResponse response) 
	   throws PortletException, IOException
{
  .....
  // include JSP for extended search
  
                getPortletConfig().getContext().include
      ("/WEB-INF/worldclock/WorldClockEdit.jsp",
       request, response);
  ....
} 

		
/**
* Edit functionality. 
* Allow the user to adjust the local time and 
* time zone. They can also pick the other time 
* zones in the world to display in view mode.
*/
public void doEdit (
                RenderRequest request,
	RenderResponse response) 
	  throws PortletException, IOException
{
  .....
  // include JSP for extended search
  
                PortletRequestDispatcher dispatcher = 
      getPortletConfig().getPortletContext().
       getRequestDispatcher
         ("/worldclock/html/WorldClockEdit.jsp");
   dispatcher.include(request, response);
   ....
}
              

返回文章

 

 

使用 IBM Portlet API 的WorldClock portlet doHelp 方法使用 JSR 168 API 的 WorldClock portlet doHelp 方法
 
/**
* Help functionality. 
* The help JSP of the portlet is displayed.
*/
public void doHelp ( PortletRequest request,
	PortletResponse response) 
       throws PortletException, IOException
{
    // include JSP for extended search
    
                getPortletConfig().getContext()include
        ("/WEB-INF/worldclock/WorldClockHelp.jsp",
         request, response);
}
              

	
/**
* Help functionality. 
* The help JSP of the portlet is displayed.
*/
public void doHelp (
                RenderRequest request,
	RenderResponse response) 
	   throws PortletException, IOException
{
    // include JSP for extended search
    
                PortletRequestDispatcher dispatcher = 
        getPortletConfig().getPortletContext().
         getRequestDispatcher
           ("/worldclock/html/WorldClockHelp.jsp");
    dispatcher.include(request, response);
}
              

返回文章

 

 

使用 IBM Portlet API 的 WorldClock portlet actionPerformed 方法使用 JSR 168 API 的 WorldClock portlet actionPerformed 方法
 
/**
* Implements the save action for the portlet's 
* edit mode. The action is executed as part of 
* the submit URI before doView gets control. The
*  parameters that have been set by the user in the
*  edit form are retrieved from the request and 
* written to the portlet database through PortletData.
*/
                public void actionPerformed(ActionEvent anEvent) 
	throws PortletException
{
  
                DefaultPortletAction pAction = 
      (DefaultPortletAction)anEvent.getAction();
  String action = pAction.getName();
  PortletRequest request = anEvent.getRequest();
  .....
  // save parameters to the user's config data
  PortletData data = request.getData();
  .....
  // go back to edit view
  
                request.setModeModifier(Portlet.ModeModifier.CURRENT);
  ....
}
              

	
/**
* Implements the save action for the portlet's 
* edit mode. The action is executed as part of 
* the submit URI before doView gets control. The
*  parameters that have been set by the user in the
*  edit form are retrieved from the request and 
* written to the portlet database through PortletData.
*/
                public void processAction(ActionRequest request, 
	ActionResponse response) throws PortletException
{
  
                String action = request.getParameter(COMMAND);
  .....
  // save parameters to the user's config data
  
                PortletPreferences data = request.getPreferences();
  ....
   
}
              

返回文章

 





回页首


结束语

本文示范了一个简单的方法,将用 IBM Portlet API 开发的 portlet 转换为遵循 JSR 168 的 portlet。虽然没有包括两种 API 之间的所有不同,但这个转换的例子涉及了这种转换的一些通常的问题,并没有涵盖 JSR 168 portlet 编程模型的最佳实践。这个例子使开发人员能够更好的理解两种 API 的主要不同,以及如何改变功能性,将使用一种 API 的 portlet 转换到另一种。

资源下载链接为: https://pan.quark.cn/s/22ca96b7bd39 在当今的软件开发领域,自动化构建与发布是提升开发效率和项目质量的关键环节。Jenkins Pipeline作为一种强大的自动化工具,能够有效助力Java项目的快速构建、测试及部署。本文将详细介绍如何利用Jenkins Pipeline实现Java项目的自动化构建与发布。 Jenkins Pipeline简介 Jenkins Pipeline是运行在Jenkins上的一套工作流框架,它将原本分散在单个或多个节点上独立运行的任务串联起来,实现复杂流程的编排与可视化。它是Jenkins 2.X的核心特性之一,推动了Jenkins从持续集成(CI)向持续交付(CD)及DevOps的转变。 创建Pipeline项目 要使用Jenkins Pipeline自动化构建发布Java项目,首先需要创建Pipeline项目。具体步骤如下: 登录Jenkins,点击“新建项”,选择“Pipeline”。 输入项目名称和描述,点击“确定”。 在Pipeline脚本中定义项目字典、发版脚本和预发布脚本。 编写Pipeline脚本 Pipeline脚本是Jenkins Pipeline的核心,用于定义自动化构建和发布的流程。以下是一个简单的Pipeline脚本示例: 在上述脚本中,定义了四个阶段:Checkout、Build、Push package和Deploy/Rollback。每个阶段都可以根据实际需求进行配置和调整。 通过Jenkins Pipeline自动化构建发布Java项目,可以显著提升开发效率和项目质量。借助Pipeline,我们能够轻松实现自动化构建、测试和部署,从而提高项目的整体质量和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值