在这个系列文章的第一篇和第二篇中,我解释了什么是portlet bridge?以及如何在一个基本的JSF 和基于RichFaces(Ajax)的portlet 中安装和使用它,和当前能支持运行JBoss Portlet Bridge 的portal 服务器的主要区别。最后这篇文章将集中讲述Seam portlet 的开发,和最新发布的 JBoss Portlet Bridge Beta 4 版本的所有特性和优势。对于不太熟悉 portlets 的读者来说,仔细阅读前面两篇文章会有助于更好的理解本文。
现在让我们先从 Seam portlet 的开发入手。
安装 Seam Portlet
开发工具:
要仿照本文示例进行开发,就需要下载最新版本的 Maven(我用的是 2.0.9 版本)。
安装 Maven 2.0.9+
在机器上设置Maven binaries 的path 环境变量
创建项目:
不同的 Maven 原型(archetype)对应可以产生不同种类的 bridge。直接从命令行运行如下代码,可创建你的 Seam portlet 项目:
mvn archetype:generate -DarchetypeGroupId=org.jboss.portletbridge.archetypes -DarchetypeArtifactId=seam-basic -DarchetypeVersion=1.0.0.B4 -DgroupId=org.my.project -DartifactId=seamproject -DarchetypeRepository=http://repository.jboss.org/maven2/ -Dversion=1.0.0.B4
该特定原型是模块化的,这意味着通过其产生的项目将由几个子项目构成。这样做的好处是源码、资源和配置之间的界限更加清晰,维护也更方便。上述命令将产生三个目录,其中,‘web’目录中包含标记文件、图片和 WEB-INF xml 配置文件;‘ejb’目录中包含所有 Seam EJB3 源码,以及任何跟持久化和 ejb 部署相关的 xml 配置文件信息;最后是‘ear’目录,它主要用来集合项目信息构建 ear 文件。
如果你是用上面提到的原型(archetype)命令创建的项目,那么现在你就会有一个‘seamproject’目录。现在到该目录下并运行如下命令:
mvn install
这个命令将会帮助你下载本地 Maven 库中缺少的任何组件,并编译和构建 ear 文件。
运行和部署 portlet:
既然你已经有一个可部署的 ear 文件,那么再利用下面的命令就可以轻松的将 portlet 部署到最新版本的 JBoss Portal 上(已绑定到 JBoss 应用服务器)了。如果你已经自己下载或创建了本地安装包,就可在 bridge 文档中找到使用自定义配置的说明了。
现在转到{seamproject}/ear 目录下运行如下命令:
mvn cargo:start -Premote-portal-Dportal-2.7.0.B1
该命令将花上一段时间(视你的网络情况而定)来下载最新版本的 JBoss Application Server 和 JBoss Portal(软件均位于 SourceForge.net 网站上)。在继续下一步骤之前你应该能看到与上文画面相似的日志记录。* 注意:你也许还会看到日志记录中不断滚屏的 WSRP 信息,不用担心,这同样是证明你已准备就绪的标志。
现在来部署你的 Seam 项目 ear 文件。新打开一个终端窗口,转到目录{seamproject}/ear 下,运行如下命令:
mvn cargo:deploy-Premote-portal -Dportal-2.7.0.B1
当你在服务器日志中看到 ear 文件已部署成功时,访问链接 http://localhost:8080/portal/portal/default/seamproject ,会看到如下页面:
现在我们已经准备好一个要开发 Seam portlet 了。当然,应用程序到底怎么写是由开发人员来决定的事情。但是这会帮你摆脱那些琐碎的配置问题,轻松的开始工作。
配置
将 JSF portlet 转换为一个典型的 Seam 应用,只需要少量的配置工作即可完成。下面的配置文件代码省略了前面文章(第一部分和第二部分)已经提到过的配置信息。如果想了解详细内容,请参照bridge 文档的配置部分。
web.xml
------------------
下面的这段配置通常是任何 Seam 应用中都会有的内容,并且不会因为 portlet 环境而有所不同:
<listener> <listener-class> org.jboss.seam.servlet.SeamListener </listener-class> </listener> <servlet> <servlet-name>Seam Resource Servlet</servlet-name> <servlet-class> org.jboss.seam.servlet.SeamResourceServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>Seam Resource Servlet</servlet-name> <url-pattern>/seam/resource/*</url-pattern> </servlet-mapping> <filter> <filter-name>Seam Filter</filter-name> <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class> </filter> <filter-mapping> <filter-name>Seam Filter</filter-name> <servlet-name>Faces Servlet</servlet-name> <dispatcher>FORWARD</dispatcher> <dispatcher>REQUEST</dispatcher> <dispatcher>INCLUDE</dspatcher> </filter-mapping>
配置 ExceptionHandler 上下文参数,可允许 bridge 应用现成的异常处理器去解决基于 Seam 的异常。如果愿意的话,你也完全可以应用自己的实现:
<context-param> <param-name>org.jboss.portletbridge.ExceptionHandler</param-name> <param-value> org.jboss.portletbridge.SeamExceptionHandlerImpl </param-value> </context-param>
Bridgelet 是针对 portlet bridge 扩展(extension)的名称。portlet bridge 社区一直在积极的开发一些扩展以增强或集中 JBoss Portal、Seam 和 Richfaces 三者的特性,例如,PortalIdentity(SSO)seam 组件可允许你把 jar 文件放在你的 classpath 上,这样你立刻就会有一个可用于 Seam 和 Portal 之间的 SSO 了。你也可以在 Maven pom 中将这个扩展配置成一个依赖(象下面将看到的那样)。
如果你对 Bridgelet 有什么建议,或者有意参与 JBoss Portlet Bridge 的开发工作,那么我们期待你积极加入我们的论坛并提交 Jira tasks 。
Seam 应用和 JBoss Portal 之间的单点登录问题
开发人员可以把 Seam Booking Demo 用做一个开发和测试的 portlet 参考程序。如果想了解和实践 SSO Bridgelet,你可以从此地址 http://anonsvn.jboss.org/repos/portletbridge/tags/1.0.0.B4/examples/seam/booking/ 下载源代码,然后运行与此篇文章上面刚刚讲过的完全相同的 maven 部署命令(或者是下面将要讲到的简短版本)来部署和运行该程序。
简短版本是:
转到{SeamBooking}根目录下,运行如下命令:
mvn install
然后再转到{SeamBooking}/ear 目录下,运行:
mvn cargo:start -Premote-portal-Dportal-2.7.0.B1
现在再来部署你的 Seam 项目 ear 文件。新打开一个终端窗口,在{SeamBooking}/ear 目录下运行如下命令:
mvn cargo:deploy-Premote-portal -Dportal-2.7.0.B1
一旦你部署完成并运行 demo 后,就可以访问链接 http://localhost:8080/portal/portal/default/SeamBooking 继续下面的步骤了。点击“注册新用户(Register New User)",新建一个用户并用其登录系统:
登录之后你将会看到酒店搜索页面,还有与当前登录角色对应的所有功能。但是,如果你看向屏幕右上角,你会发现登录到 Seam 应用和你的 JBoss Portal 用户 / 管理员账户一点关系都没有:
这就是我们需要 SSO Bridgelet 的理由,它允许通过 Seam 身份认证模块来验证 JBoss Portal 用户名。现在让我们来尝试一下:
令服务器依然保持运行状态,在进行部署的那个终端窗口中,返回到上一级目录,也就是{SeamBooking}/ 根目录下运行如下命令:
mvn install -Psso
接下来再转到{SeamBooking}/ear 目录下运行如下命令:
mvn cargo:deploy-Premote-portal -Dportal-2.7.0.B1
通过上述命令我们将 SSO jar 包嵌入进了应用,并重新部署了一次 ear 文件。
现在,让我们回到 http://localhost:8080/portal/portal/default/SeamBooking 上的 portlet。这次我们登录到 portal 而不是 Seam 应用。点击页面右上方的 portal login 进行登录,用户名和密码都是‘admin’。
如果这是一个现实中的应用,我们会对 UI 做一点调整,把 Seam 应用的登录表单隐藏起来。同时因为 SSO 的存在,我们可以调整网站其它基于角色的内容。但是,正如我前面所说,这是从最原始状态的 Seam booking demo 出发做最小改动能达到的效果,只是一个参考。
登录到 JBoss Portal 后,在你的 Seam 和 Portal UI 上你将会看到如下内容:
在解决了 Portal 和你的 Seam 应用之间的身份认证问题后,应用的创建就变得容易些了。如果你的 Seam portlet 是基于 Maven 创建的,那么还需要你做的就只有在 pom.xml 文件中添加如下代码了:
<dependency> <groupId>org.jboss.portletbridge.extensions.seam</groupId> <artifactId>PortalIdentity</artifactId> <version>1.0.0.B4</version> </dependency>
或者你也可以把 PoralIdentity.jar 文件放到应用程序 WEB-INF/lib 目录下就行了,不再需要做别的配置了。
JBoss Portlet Bridge Beta4 概述
既然这是本系列文章的最后一篇,那么在最后一部分我将介绍 9 月 11 日刚刚发布的 JBoss Portlet Bridge Beta 4 版本的新特性。
支持 PortletMode 变化
一个 PortletMode 代表了应用中一个不同的展现路径(render path),有三种标准的模式:view、edit 和 help。bridge 的 ExternalContext.encodeActionURL 可以辨认查询字符串参数 javax.portlet.faces.PortletMode,并用这个参数值在底层 portlet actionURL 或响应上设置 portlet 模式。 一旦处理完就要把这个参数从查询字符串中去掉。下述导航规则将会在 portlet 的 edit 模式下呈现 viewId 为\edit.jspx 的页面:
<navigation-rule> <from-view-id>/register.jspx</from-view-id> <navigation-case> <from-outcome>edit</from-outcome> <to-view-id>/edit.jspx?javax.portlet.faces.PortletMode=edit</to-view-id> </navigation-case> </navigation-rule>
导航至一个模式的最终 viewId
缺省地,一个模式的改变将从模式的默认视图(不带状态)开始。对于一个普通的 portlet 模式,在其返回到进入另一模式之前的那个模式时(例如:view->edit->view),它将会跳转到这个模式(离开之前)的最终视图(和状态)。bridge 能够对必要信息进行清楚的编码,以便有需要返回到前一个模式时,它可以定位到适当的视图,并恢复到应有的状态。开发人员可以使用由 bridge 维护的 session 属性,以便从一个模式导航回其前一个模式的最终位置和状态。同样,开发人员需要描述一个动态导航:“从视图 X 返回到模式 Y 的最终视图”。这可以用由 EL 表达式简单地表示如下:
<navigation-rule> <from-view-id>/edit.jspx*</from-view-id> <navigation-case> <from-outcome>view</from-outcome> <to-view-id>#{sessionScope['javax.portlet.faces.viewIdHistory.view']}</to-view-id> </navigation-case> </navigation-rule>
Portlet 开发人员需要注意的问题
根据 bridge 实现,当用到这些 session 范围的属性值、或者任何可能包含查询字符串参数的 viewIds 时,最好在验证规则目标(rule target)时使用通配符语法。例如,上面的<to-view-id>
表达式返回的是一个表单的 viewId(/viewId?javax.portlet.faces.PortletMode=view&....
)。其不含通配符,因此当该新视图发生页面跳转时,导航规则就无法解析了,因为它找不到任何可与之完全匹配的对象。
而上面的edit.jspx <from-view-id>
包含了通配符,导航规则就可用查询串(<to-view-id> /edit.jspx?javax.portlet.faces.PortletMode=edit </to-view-id>
)来和它匹配。强烈建议开发人员都使用这种通配符以确保程序可以在各种 bridge 实现中正常执行。
处理 Portlet 中的 Ajax 错误
默认的,错误是由处理 Ajax 请求的标准 servlet 页面来解决。要在 portlet 内部处理错误,就要用到下面的 JavaScript 代码:
<script type="text/javascript"> A4J.AJAX.onError = function(req,status,message){ window.alert("Custom onError handler "+message); } A4J.AJAX.onExpired = function(loc,expiredMsg){ if(window.confirm("Custom onExpired handler "+expiredMsg+" for a location: "+loc)){ return loc; } else { return false; } } </script>
结论
正如前面所说,portlet bridge 社区从项目早期测试阶段就已经开始发布补丁和其它形式的帮助来促进其发展。虽然项目的核心是 JSR-301 规范,然而整合 Seam、 Richfaces、Portal 和 Bridgelets 以及其它辅助性的加强功能是具有无限潜能和意义的。已经有些开发人员为项目的发展贡献了他们的力量,在此我们对所有这些提供过补丁、增强构件以及在论坛上积极回答问题的人们表示衷心的感谢。
最后,这是一个基于社区的项目,提供帮助和反馈的开发人员越多,我们的新产品发布的越快,其功能也就更强,代码也更完善。预计 GA 版本会在 09 年初发布。
在论坛上提供反馈非常有用,我们也很欢迎。如果你想要了解更多关于JBoss Portlet Bridge 项目的信息可以访问我们的项目和文档页面 。
相关阅读:
使用JSF、Ajax 和Seam 开发Portlets(1/3)使用JSF、Ajax 和Seam 开发Portlets(2/3)
志愿参与InfoQ 中文站内容建设,请邮件至 editors@cn.infoq.com 。也欢迎大家到 InfoQ 中文站用户讨论组参与我们的线上讨论。
评论