作者 Andrew Lorek
05/30/2006
这篇文章介绍了如何将工作于门户以外的现有 Web 应用程序转换为自适型 Portlet,以便用于 AquaLogic User Interaction。 文章指出了在使用 Java Server Faces 或 Struts 等现有 Web 应用程序框架时遇到的一些困难,并介绍了一个克服这些困难的工具:Java Portlet 工具包。 文章还简要介绍了 Java Portlet 工具包随附的 PortletBean 和特定于门户的 JSP 标记等工具。
自从 Java Servlet 和 Java Server Pages (JSF) 规范面世起,人们就不断尝试简化 Java Web 应用程序的编写、配置和定制。 大多数应用程序采用 "Model 2" 结构,在这种结构中,请求由一个负责控制的 Servlet 发送给各种 JSP 页面,显示和更改数据随 JavaBean 被发送给 Servlet 请求和会话。 这种属于 “模型-视图-控制器”模式的结构,大大简化了 Java Web 应用程序的开发。 许多 Web 应用程序框架,如 Struts 和 Java Server Faces,通过允许开发者将请求的路由、JavaBean 管理、验证及其他常见的 Web 应用程序任务作为框架的一部分进行配置,而不是生硬地将这些功能编写为 JSP 或 Java 类,从而进一步简化了 Web 应用程序开发。
Struts 及 JSF 等框架在执行处理请求、验证及导航等方面可以很好地适应独立的 Web 应用程序,开发者可以腾出更多精力关注应用程序所需的业务逻辑。 不幸的是,由于它们对表单提交的依赖性和以重定向管理应用程序导航的方式,使得它们在结构上并不适合在门户应用程序中使用。 另外,大多数框架都难于适应多 Portlet 环境(在这种环境中,同一 Web 应用程序的多个实例可以作为 Portlet 出现在一个页面上),因为它们不具备在一个 Web 应用程序的范围以外唯一识别页面元素的功能。
所以我们希望有一种理想的解决办法,在不更改任何应用程序代码或配置文件的情况下,实现对基于 Struts、JSF 或任何 JSP/Servlet 的应用程序的转换,使它们既可以用于 Portlet 又可以作为独立的 Web 应用程序使用。 幸运的是,Plumtree Java Portlet Tools 库可以帮助开发者完成这种任务。 另外,该库为 EDK 功能提供了 JavaBean 包装器。 EDK 是一组应用程序库,开发者可以使用它来访问嵌在请求 header 部分的 Portlet 信息,以及执行远程服务任务,例如利用门户应用程序的协作及搜索等功能访问数据。 通过 Java Portlet Toolkit EDK 包装器 Bean,开发者可以使用 JSP 2.0 表达式语言 get 和 set Portlet 的属性、设置和性能。 最后,它还包括一组定制标记,这些标记简化了对自适型 Portlet 技术(例如,原地刷新和 PCC 事件处理等)的访问,允许开发者在不必编写任何 JavaScript 的情况下执行复杂的 DHTML 操作。
要阅读本文,读者最好熟悉 Java、Java Servlets、JSP 和 JSP 标记库技术。 希望单纯地将 Java 应用程序转换为自适型 Portlet 的开发者可以直接阅读 Servlet 过滤器和 PTPortletFilter一节,而跳过讨论 Java Portlet 工具库的其他功能的部分。 希望全面地掌握自适型 Portlet 技术的开发者应该阅读整篇文章。
Java Servlet 2.3 规范包括一个名为 Filter 的新类。 过滤器(Filters) 是在 Java Servlet 应用程序的 web.xml
文件中进行配置的,它可以在将 Servlet 的请求和响应发送给 JSP 和 Servlet 类之前和之后执行截取和更改。 Java Portlet 工具提供了一个特殊的 Servlet 过滤器,称为PTPortletFilter,它用于从 Web 应用程序截取 HTML 发送内容,并将其重写,以便在 Pulmtree Portlet 中包括这些内容。 这一重写将执行以下类型的操作:
onload
事件处理程序。 声明 PTPortletFilter 的方式是,向 Web 应用程序的 web.xml
配置文件添加以下 XML:
<filter>
<filter-name>Adaptive Portlet Filter</filter-name>
<filter-class>com.plumtree.remote.filter.PTPortletFilter</filter-class>
<init-param>
<param-name>filter.config.file</param-name>
<param-value>C:\portlettools\apps\carstore\conf\custom-filter.xml</param-value>
</init-param>
<init-param>
<param-name>filter.log.file</param-name>
<param-value>C:\portlettools\apps\carstore\logs\jpt.log</param-value>
</init-param>
<init-param>
<param-name>filter.log.level</param-name>
<param-value>debug</param-value>
</init-param>
<init-param>
<param-name>jsxml.version</param-name>
<param-value>177643</param-value>
</init-param>
<init-param>
<param-name>portal.imageserver.alternate</param-name>
<param-value>https://plumtree/imageserver</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Adaptive Portlet Filter</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
过滤器所有的初始化参数都是可选的,如果不想记录过滤器日志或执行某些定制操作,则不添加过滤器类及 URL 映射即可。 对于更复杂的门户配置,您可能需要添加一些图像服务器或日志的初始化参数。 PTPortletFilter 使用下面描述的方式识别初始化参数:
参数 | 描述 | 缺省 |
filter.config.file | 指向一个 XML 文件,该文件定义了 PTPortletFilter 可以在 Web 应用程序的响应 HTML 中执行的嵌入操作树。 Java Portlet 工具过滤器提供了一个样例 filter.xml 文件,用于测试 JSF 应用程序。 这个样例文件适用于大多数 Java Web 应用程序框架,而且它是可配置的,还允许开发者根据需要添加新的 HTML 重写操作。 附录 A:PTPortletFilter Configuration XML 深入描述了如何定制这个 XML 文件。 只有在对过滤器进行定制的时候才指定这个参数。 | 默认的 filter.xml 文件位于 portlet-tools.jar 中。 |
filter.log.file | 这个参数指向过滤器记录日志信息的文件的绝对路径。 | stdout |
filter.log.level | 过滤器执行记录的级别。 可能的值:debug、info、warning、severe、error 和 off。 | warning |
jsxml.version | Plumtree JSXML JavaScript 组件的版本,该组件使在 Plumtree 门户上实现原地刷新成为可能。 这个值是指 Web 应用程序将使用的首选 JSXML JavaScript 库的版本。 JSXML 是基于 G6 脚本框架的 AJAX 框架。 | JSXML 的最新版本 |
portal.imageserver.alternate | 在包含 JSXML JavaScript 组件时,开发者可以使用指定的 URL 连接到图像服务器。 如果门户具有阻止 Web 应用程序直接访问图像服务器的安全限制,则此参数是必需的。 | – |
content.type | 设置 HTTP 响应的内容类型 | text/html;charset=UTF-8 |
character.encoding | 设置 HTTP 响应使用的字符集。 | utf-8 |
关于 PTPortletFilter 如何重写响应 HTML 的示例,请参考一个简单的提交按钮:
<form id="myform" action="next.jsp">
<input type="submit" name="action" value="Submit"
onchange="alert('Saving info...')">
...
</form>
在不更改任何内容的情况下,这个按钮将提交门户上的整个页面,并且只返回具有单击按钮事件的 Portlet 的内容,导致 Portlet 接管门户页面的所有内容。 同样是提交按钮,PTPortletFilter 重写标记使其使用原地刷新:
<form id="myform_203"
action="http://host/portal/server.pt/gateway/PTARGS_0_16_203_0_0_43/http%3B/app/next.jsp">
<input type="button" name="action" value="Submit"
onchange="alert('Saving info...');
postback_203(document.getElementById('myform_203'),
document.getElementById('pt-portlet-java-203'),
{'action':'Submit'});">
...
</form>
其中,指向 Web 应用程序资源(同时用于刷新当前页面)的超级链接将被重写,以便执行原地刷新。 例如,对以下链接执行原地刷新:
<a href="next.jsp">Link in this window</a>
<a href="next.jsp" target="new">Link in another window</a>
<a href="http://www.plumtree.com">Link to another site</a>
只有第一个链接会在门户上出现问题 比如上面的表单示例,单击这个链接会导致 Portlet 接管整个门户页面的所有内容。 只有这个链接被重写,以执行原地刷新请求。
<a onclick="linkback_203('http://host/portal/server.pt/gateway/PTARGS_0_16_203_0_0_43/http%3B/app/next.jsp',
document.getElementById('pt-portlet-java-203'); return false;"
href="#">Link in this window</a>
<a href="http://host/portal/server.pt/gateway/PTARGS_0_16_203_0_0_43/http%3B/app/next.jsp"
target="new">Link in another window</a>
<a href="http://www.plumtree.com">Link to another site</a>
最后,在 Web 应用程序中任何以编程方式提交表单的 JavaScript 都被重写,以执行原地刷新。 任何引用表单的 JavaScript 都被重写,以使用追加了 Portlet ID 的唯一 ID 引用表单。
当 Web 应用程序被视作孤立的 Web 应用程序而不是 Portlet 中的远程 Web 服务时,PTPortletFilter 将被禁用。 如果 Web 应用程序中的一个页面由门户的网关匆匆处理以及在 Portlet 的内部显示,PTPortletFilter 将在不更改任何内容的情况下显示 Web 应用程序的 HTML 内容。