写点什么

应用 JSF、Ajax 和 Seam 开发 Portlets(1/3)

  • 2008-11-13
  • 本文字数:4087 字

    阅读完需:约 13 分钟

如果你刚开始考虑应用 portal 解决方案,或者想了解把一个新的或现有的 JSF 应用整合进一个 portal 环境有多容易,那么本文绝对值得你仔细研读。

在过去几年中,portals 无论是在企业还是在增强的 portlet 2.0( JSR 286 )规范中都得到了长足发展。新 2.0 版本的 portlets 在聚合不同的应用,并将其呈现在同一个页面的不同窗口方面赋于开发人员很大的自由。此外,它还提供了认证功能,成熟的个性化特性和更好的处理 AJAX 的现成方法。

JSR 301 portlet 桥接规范(portlet bridge specification)的出现,使我们具备了运行 JSF 应用的标准方式,不论 portlets 版本是 1.0 还是 2.0。portlet 桥(bridge)可以支配 portal 的 Action/Render 范式适当地处理 JSF 的生命周期。本教程将主要向你展示配置与开发 JSF portlet 是多么容易的一件事情,同时还会介绍新的 JBoss Portlet Container 2.0 及其一些很酷的新特性。

本文是由三部分组成的系列文章的第一篇。该系列文章从基本的 JSF portlet 和 portal 知识一直讲到 portlet 环境中的 AJAX 和 Seam 的高级用法。

现在准备开始吧!

项目安装

开发工具:

要想成功实践文中的范例就要下载最新版本的 Maven(我用的是 2.0.9 版本)。
安装 Maven 2.0.9+
设置 Maven 二进制版本的环境变量

例子中用到的服务器和二进制版本:

JBoss Portal’s Portlet Container 2.0
JBoss Portlet Bridge Beta3

目前,JBoss Portlet Bridge 是 JSR 301 规范的唯一实现,它允许你运行 JSF、RichFaces 和 Seam 的任意组合。你项目的 Maven 配置可安排下载打包在一起的 JBoss AS 和 JBoss Portlet Container 2.0,如果你想分别下载它们,可以在此处找到这些文件。否则,就给Maven 几分钟让它去自行下载适当的文件。

注意——在当前的2.6.5.SP1 版本的JBoss Portal 中同样可以运行这个portlet ,我在本文中使用了JBoss Portlet Container 2.0,但是桥(bridge)在两者中都能工作。你可通过此处了解令其可在任意版本的JBoss Portal 中运行的配置方法。

下述 Maven 原型(Maven archetype)是创建项目的一种简易方式,可以快速建立并运行一个启始项目(或者模板项目)。一旦你运行了这些命令,就可获得实践本文示例所需的一切文件。

打开一个终端窗口并运行如下指令:

复制代码
mvn archetype:generate -DarchetypeGroupId=org.jboss.portletbridge.archetypes
-DarchetypeArtifactId=1.2-basic
-DarchetypeVersion=1.0.0.B3 -DgroupId=org.whatever.project -DartifactId=myprojectname
-DarchetypeRepository=http://repository.jboss.org/maven2/ -Dversion=1.0.0.B3

现在,找到你的新建项目所在文件目录(如果你使用的跟上面的例子一样,那么目录名就应该是 “myprojectname”),浏览其中刚刚创建的所有文件,你将会看到一个基本 Maven 文件结构,其中带有适用于本文范例的源码。现在你就可以打开最喜欢的 IDE 环境,引入这个 Maven 项目了。

Portlet 桥配置要求

从现在开始的开发过程更像是在 Servlet 世界中开发 JSF 应用,不同之处在于:处理类似单点登录这样的问题;诸如命名空间(namespacing)这样的需要 portletContext 和访问变量的问题;以及 portlet 中像“Help”和“Edit”这样的窗口模式问题。我不想在本文讲述过多 portlet 的细节,但我会提供进行基本开发的必要信息。如果你想了解更多 portlets 的信息,请参考 JSR 168 JSR 286 规范说明。

JBoss Portlet Bridge 比较酷的一点在于它不是一个 portlet,它只是 portlet 和 JSF 之间的媒介。而你的 JSF 应用则是个 portlet,不过除了 WEB-INF 目录下 3 到 4 个额外的 xml 文件和关于 bridge 的 Jar 包外,它的其余部分与你的 Servlet 版本的应用毫无二致。下面几个配置文件是主要区别:

portlet.xml

复制代码
<portlet>
...v <portlet-class>
javax.portlet.faces.GenericFacesPortlet
</portlet-class>
<init-param>
<name>javax.portlet.faces.defaultViewId.view</name>
<value>/home.xhtml</value>
</init-param>
<init-param>
<name>javax.portlet.faces.defaultViewId.edit</name>
<value>/jsf/edit.xhtml</value>
</init-param>
<init-param>
<name>javax.portlet.faces.defaultViewId.help</name>
<value>/jsf/help.xhtml</value>
</init-param>
...
</portlet>

web.xml

复制代码
<context-param>
<param-name>org.ajax4jsf.VIEW_HANDLERS</param-name>
<param-value>
org.jboss.portletbridge.application.FaceletPortletViewHandler
</param-value>
</context-param>
<context-param>
<param-name>javax.portlet.faces.renderPolicy</param-name>
<param-value>
ALWAYS_DELEGATE
</param-value>
</context-param>

faces-config.xml

复制代码
<application>
<view-handler>
org.jboss.portletbridge.application.PortletViewHandler
</view-handler>
<state-manager>org.jboss.portletbridge.application.PortletStateManager</state-manager>
</application> <application></application>

由于上述设置已经应用在你刚刚设定的 Maven 原型中,因此现在我们就可以编译项目,并在 JBoss Portal 上部署它了。

运行 demo 程序

编译新项目,并通过如下两个步骤完成部署:

步骤 1:mvn install cargo:start -Premote-portal -Dpc20

这行命令将会花上几分钟去下载打在一起的 server+portal 包,所以在进行下一步骤之前,请耐心等待直至看到如下内容:

* 注意——在 server 启动前你还会看到一个 PortletException ,这很正常,而且它也是 Portlet Container 2.0 示例 FailDuringInitPortlet 的一部分。

接下来打开另外一个终端窗口,找到 JSF portlet 项目的根目录,并运行:

步骤 2:mvn cargo:deploy -Premote-portal -Dpc20

命令行参数通知 cargo 你正在运行的 portal 版本和 JBoss+Portal 包所在位置。这个例子同样可以运行于遵从 JSR 168 的最新版本 JBoss Portal 2.6.5.SP1 中。如果想了解更多 Maven 命令及相关信息,你可以参考 JBoss Portlet Bridge 文档。要查看已部署的 JSF portlet 情况可访问如下链接: http://localhost:8080/simple-portal/demo/jsr-301.jsp

JSF Portlet 开发

现在让我们来了解将 portlet 和 JSF 联系在一起的技术。

把你的 portlet 视作一个普通的 Web 应用

当把你的应用视作 servlet 端的 Web 应用时,portlet 桥是透明的。作为 portlet 开发人员,一种很好的做法是偶尔仔细检查一下你的应用以确保正在进行的开发没有扩大的趋势,因为它将运行在一个 portal 环境中。要查看此 demo 应用,或者任何已部署的带有桥的应用,可以访问 http://localhost:8080/JSFRIPortlet/home.jsf

命名空间

在 portal 环境中桥可以处理 JSF 的命名空间组合。当你需要在 JSF/xhtml 标记中使用元素 id 时,正常情况下在显示的标记中你所看到的是类似‘form1:myBtn’的代码,而如今在桥命名空间中你所看到的将是象:
jbpns_2fdefault_2fNews_2fStories_2fStoryTemplateWindow12snpbj:_viewRoot:form1:myBtn 这样的标记。

要克服这一点,你可以在你的 Facelets 页中应用下面的表达式,来为你的 javascript 代码预先设定命名空间:
document.getElementById('#{facesContext.externalContext.response.namespace}the_rest_of_JSF_ID');

请注意,因为使用了 portletResponse,所以一旦你试图在 servlet 应用端查看这个页面的时候就会得到一个异常。为避免这种情况的发生,你需要在你的后台 Bean(backing bean)中检查响应的类型,并为 UI 分配一个新的、“安全的”命名空间变量。

preserveActionParams

当你的 web.xml 文件中 preserveActionParams 值被设置为 TRUE 时,桥必须负责维护在 portlet 动作请求期间指派的任意参数,它们被保存在“桥请求域(bridge request scope)”中。当这个属性没有出现或者值为 FALSE 时,只在 portlet 请求作用域维护动作的请求参数。

复制代码
<init-param>
<param-name>javax.portlet.faces.preserveActionParams</param-name>
<param-value>true</param-value>
<init-param>

在你的 Facelets 页面中应用类似 #{request.yourParam}这样的代码可以利用这一设置。

排除桥请求域中的属性

当你的应用在每一次请求上都要使用请求属性而你又不想在扩展的桥请求作用域中管理特殊的属性时,你就必须在你的 faces-config.xml 文件中使用如下的配置了。下面你会看到任何命名空间为 foo.bar 的属性或者是以 foo.baz(通配符)打头的属性都会被从桥请求作用域中排除,这些属性只能用在每一次请求当中:

复制代码
<application>
<application-extension>
<bridge:excluded-attributes>
<bridge:excluded-attribute>foo.bar</bridge:excluded-attribute>
<bridge:excluded-attribute>foo.baz.*</bridge:excluded-attribute>
</bridge:excluded-attributes>
</application-extension>
</application>

或者你可以使用javax.portlet.faces.annotation.ExcludeFromManagedRequestScopej 注解,对你不想包含在请求中的对象类进行注解,也可以达到同样的效果。

结束语

正如你所看到的,JSR 301 规范不仅使得把已存在的 JSF web 应用建立成 portlet 更加容易,而且还提供给开发人员一种管理和处理 JSF 和 portlets 差异的方式。不过,规范目前仍处于频繁地评审和修订阶段。写这篇文章时最新的公开版本是 Early Draft Review 3,但是在 JSR 301 专家组内部,对此修订版本又已经有很多改进了,对桥比较重大的改进是在下一个 JBoss Portlet Bridge 版本(Beta 4)中将会实现的 portlet 模式导航和状态。

如果想了解更多项目信息和桥支持的兼容版本,或者想要参与社区论坛,请访问我们的项目页面 blog

查看英文原文: Developing Portlets using JSF, Ajax, and Seam (Part 1 of 3)


志愿参与 InfoQ 中文站内容建设,请邮件至 editors@cn.infoq.com 。也欢迎大家到 InfoQ 中文站用户讨论组参与我们的线上讨论。

2008-11-13 00:482643
用户头像

发布了 127 篇内容, 共 44.2 次阅读, 收获喜欢 5 次。

关注

评论

发布
暂无评论
发现更多内容

PackML从会到不会——状态机(1)

陈的错题集

标准化 PackML

Python量化数据仓库搭建系列2:Python操作数据库

恒生LIGHT云社区

Python 量化

数仓开发详细剖析

五分钟学大数据

11月日更

并发编程中,你加的锁未必安全

华为云开发者联盟

线程 高并发 并发 线程安全

1 分钟 Serverless 极速抽盲盒,自己部署自己抽!

阿里巴巴云原生

阿里云 Serverless 云原生

16张图解锁Spring的整体脉络

4ye

Java spring 程序员 后端 签约计划第二季

react源码解析3.react源码架构

buchila11

源码 React React Hooks react源码

内存数据库的分布式架构提升之道

鲸品堂

数据库

java开发之DOS命令学习及运行环境配置安装

@零度

java开发学习 DOS命令学习

大厂算法面试之leetcode精讲9.位运算

全栈潇晨

算法 LeetCode

如何使用 Java 代码给图片增加倒影效果

汪子熙

Java API 图片处理 11月日更 Java图片

测试不趁早,“持续测试”搞不好

飞算JavaAI开发助手

DevOps 敏捷开发 自动化测试

前端开发之JavaScript优化

@零度

JavaScript 大前端

阿里云 Serverless 助力企业全面拥抱云原生

阿里巴巴云原生

阿里云 Serverless 云原生 企业

架构实战营模块五作业

孙志强

架构实战营

如何在P4中管理Unreal Engine 代码

龙智—DevSecOps解决方案

版本控制 游戏开发 版本管理 游戏引擎 虚幻引擎

百度商业大规模高性能全息日志检索技术揭秘

百度Geek说

软件架构

大批量更新数据mysql批量更新的四种方法

大数据技术指南

11月日更

KubeMeet 深圳站回顾:应对云原生边缘计算落地挑战

阿里巴巴云原生

阿里云 Kubernetes 云原生 线下活动

react源码解析4.源码目录结构和调试

buchila11

React React Hooks

Elasticsearch云生态下的开源共生之路

大咖说

云计算 elasticsearch 开源

服务API版本控制设计与实践

vivo互联网技术

API 服务器端开发 客户端开发 迭代

应对 Job 场景,Serverless 如何帮助企业便捷上云

阿里巴巴云原生

阿里云 Serverless 云原生 函数 Job

云原生体系下 Serverless 弹性探索与实践

阿里巴巴云原生

阿里云 Serverless 云原生 弹性 SAE

dart系列之:时间你慢点走,我要在dart中抓住你

程序那些事

flutter 架构 dart 程序那些事 11月日更

爱奇艺TFServing负载均衡问题研究及改进实践

爱奇艺技术产品团队

直播预告|数以智用——大数据应用探索与实践

智联卓聘

大数据 数据管理 线上沙龙

大厂算法面试之leetcode精讲10.递归&分治

全栈潇晨

LeetCode 算法面试

Linux学习方法《Linux一学就会》Centos8软件包的管理与安装

侠盗安全

Linux linux运维 运维工程师 云计算架构师

Perforce用户文章转载:每个游戏从业者都应该学学P4

龙智—DevSecOps解决方案

版本控制 游戏开发 版本管理 perforce 游戏厂商

移动计算云分布式数据缓存服务,实现快速可靠的跨区域多活复制

华为云开发者联盟

可用性 云数据缓存 跨区域多活 无冲突复制数据类型CRDT

应用JSF、Ajax和Seam开发Portlets(1/3)_Java_Wesley Hales_InfoQ精选文章