Terry.Li-彬

虚其心,可解天下之问;专其心,可治天下之学;静其心,可悟天下之理;恒其心,可成天下之业。

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  143 随笔 :: 344 文章 :: 130 评论 :: 0 Trackbacks
OpenDoc版权说明:
本文档版权归原作者所有。
在免费、且无任何附加条件的前提下,可在网络媒体中自由传播。
如需部分或者全文引用,请事先征求作者意见。
如果本文对您有些许帮助,表达谢意的最好方式,是将您发现的问题和文档改进意见及时反馈给作者。当然,倘若有时间和能力,能为技术群体无偿贡献自己的所学为最好的回馈。



随着信息化建设的深入,Portal 门户已经成为新型办公环境的一个重要组成部分。 Portal所提供的单点登录、权限控制、个性化定制、内容集成、文件管理等独特的功能, 已经大大占据公众的眼球,并在信息集成和消除信息孤岛方面发挥了重要的左右。
随着Portal技术的成熟,以MyNestcape、MyYahoo、MSN-Space等为代表大型网站也较多的采用Portal架构来实现个性化的内容聚合和定制,以实现灵活的扩展的服务策略。
Liferay Portal作为一个开源的Portal项目,利用Hibernate、Struts、Spring等开源框架,实现了JCP JSR168规范中提出的Portal功能,在开源Portal系统中有比较典型的代表性。
本 文从Liferay Portal的架构入手,详细讲解Portal的用户策略、内容布局、桌面和品质的要素,引导读者完成Liferay Portal初步的二次开发,在Liferay Portal上定制自己的Portlet。Liferay Portal程序框架和源码分析不在本文的讨论范围。
目录
第一部分 Liferay Portal 架构解析
第一章  Liferay Portal
第一节  Portal规范
1.1.1  JSR168
1.1.2  WSRP
第二节  什么是Portal
1.2.1  Portal 服务器
1.2.2  Portlet容器
第三节  什么是Portlet
1.3.1  Portlet
1.3.2  Portlet与Servlet的关系
1.3.3  Portlet的生命周期
第四节  Liferay Portal工作原理
1.4.1  Portlet 样式以及窗口状态
1.4.2  Portal页面
第二章Liferay Portal的使用
第一节  Liferay Portal安装
第二节  Liferay Portal的用户策略
2.2.1  定义用户
2.2.2  添加用户
2.2.3  修改用户
2.2.4  定义用户组
2.2.5  新增、重命名用户组
2.2.6  修改用户组
2.2.7  定义角色
2.2.8  新增、重命名角色
2.2.9  修改用户组角色
2.2.10  定义Portlet的角色
第三节  Liferay Portal内容和布局
2.3.1  什么是布局
2.3.2  什么是内容
2.3.3  内容布局与Portlet的关系
2.3.4  选择内容和布局
第四节  Liferay Portal的桌面
2.4.1  什么是桌面
2.4.2  定义个性化的桌面
第五节  Liferay Portal的品质
2.5.1  什么是品质 30
2.5.2  品质和Portlet、Portal的关系
2.5.3  定义个性化的品质
第六节  Liferay Portal的部署描述文件
2.6.1  web.xml
2.6.2  portlet.xml
2.6.3  liferay-Portlet.xml
2.6.4  liferay-display.xml
2.6.5  liferay-layout-templates.xml
2.6.7  liferay-look-and-feel。xml
第二部分 Liferay Portal 二次开发
第三章 开发自己的Portlet
第一节  重要的基类:GenericPortlet
第二节  Portlet标签
3.2.1  defineObjects标签
3.2.2  renderURL标签
3.2.3  actionURL标签
3.2.4  param标签
3.2.5  namespace标签
第三节  Portal的对象
3.3.1  Request对象
3.3.2  Response对象
3.3.3  PortletConfig对象
3.3.4  Session对象
3.3.5  Preference对象
第四节  编写自己的Portlet类
3.4.1  开发环境
3.4.2  准备工作
3.4.3  HelloWorldPortlet
3.4.4  HelloJSPPortlet
第五节  修改Web部署描述文件
第六节  创建Liferay Portal部署描述文件
第三部分 Liferay Portal部署
第四章 部署自己的Portlet
第一节  手动部署
第二节  Ant自动部署
第三节  加入Liferay Portal自有列表
第四节  普通Java Web应用转化为Portlet应用
第四部分 附录
第五章 相关资源
第一节 资源网站
第二节  示例
第六章 参考资料
后序

第一部分 Liferay Portal 架构解析
本部分主要内容
Portal 服务器  Portal 容器  Portlet
第一章  Liferay Portal
作为一个开源Portal产品,Liferay Portal提供对多个独立系统的内容集成,帮助多个组织实现更有效的合作。与其他商业的Portal产品相比,Liferay Portal有着一系列的优良特性,而且不需要付费。
第一节  Portal规范
随着Portal的兴起,越来越多的公司开始涉足Portal产品开发,并组建各自的Portal组件和基于其的产品,比如IBM、BEA、MicroSoft、SAP、Apache等。各个厂商的接口互不兼容,给软件开发商以及开发人员带来诸多不便。
1.1.1  JSR168
为 此,JCP组织发布了JSR168(Java Specification Request),Portlet Specification V1.0,用来提供不同的Portal和Portlet之间的互通性。只要开发的Portlet遵循JSR168,则就可以在所有遵循JSR168的 Portal上部署运行。
JSR168中定义了Portal的实现规范和接口,并对理想的Portlet进行了详细的规划和描述。
1.1.2  WSRP
WSRP 是OASIS Web Service for Remote Portlet的缩写。WSRP是Web Service的一种新的商业应用,一种新的标准,主要用来简化Portal对于各种资源或者程序整合的复杂度,可以避免编程带来的整合麻烦和问题。而且 Portal管理员可以从海量的WSRP服务中选择需要的功能用以整合到目前所用的Portal中。它有三种角色:
①、生产者  提供Portlet
②、消费者  使用Portlet
③、终端用户  最终用户
它的特点在于生产者将消费者所需要的信息通过WSRP返回给消费者,这些信息是相对标记片断,例如HTML、XHTML等,可以直接嵌入用户的页面中,而不用像Web Service一样开发用户端接口。
实现这个规范,Portal可以跟各式各样的数据源打交道,彻底终结信息孤岛的窘境。
第二节  什么是Portal
Portal是基于Web的,以“应用整合”和“消除信息孤岛”为最终目的,提供单点登录、内容聚合、个性化门户定制等功能的综合信息系统。
完整的Portal通常由Portal服务器、Portlet容器、Portlet构成。
1.2.1  Portal 服务器
Portal 服务器是容纳Portlet容器,支持Portlet呈现的普通或者特殊Web服务器。Portal服务器通常会提供个性化设置、单点登录、内容聚合、信 息发布、权限管理等功能,支持各种信息数据来源,并将这些数据信息放在网页中组合而成,提供个性化的内容定制,不同权限的浏览者能够浏览不同的信息内容。 通常,Portal提供以下功能:
单点登录:Portal通常采用ACL、SSL、LDAP等业界标准的安全技术,提供对所有现有应用系统的安全 集成,只需在Portal的唯一入口上登录一次,就可以访问所有应用系统和数据。对于安全性要求较高的应用系统,如电子商务平台、交易系统等,通过扩展接 口传递用户身份信息,如数字证书信息、数字签名信息等,进行二次身份认证,保证单点登陆的安全性。
权限控制:系统采用LDAP对用户资源进行统一的管理,同时提供二次开发接口,可以与其他应用系统的用户管理模块对接,并能随相关业务系统实时更新访问权限。通过完善的授权机制及存取控制,用户访问权限控制到字段级别,确保用户只能访问具有权限的应用系统及相关信息。
内容管理: 实现应用系统之间实时交换信息。采用多种缓存机制,保证内容交换的性能和准确性。采用基于XML的Rich Site Summary (RSS)标准,迅速在各应用系统之间传播最新变化。
信息发布: 实现信息门户内容的动态维护。动态网站系统可与OA协同办公系统、知识管理系统等集成,网站信息须经OA系统的审批流程流转通过后或知识管理平台设置具有外部共享权限后才可正式发布,真正实现内外信息发布的同步。
文 件管理: 系统实现无缝集成多种数据源,包括:数据库、文档(Office文档、PDF、AutoCAD、甚至ZIP文档)、Web网页、FTP站点等,并对数据按 业务要求和职务特点加以分析整理,通过统一Web界面主动推送(Push)至用户的门户桌面,帮助用户做出及时、正确的决策。
1.2.2  Portlet容器
Portlet容器提供Portlet执行的环境,包含很多Portlet并管理它们的生命周期,保存Portlet的定制信息。
一 个Portal容器接收到来自Portal的请求后,接着将这个请求传递给存在Portal容器的Portlet 执行。Portlet容器没有义务去组合Portlet 产生的信息內容,这个工作必须由Portal来处理。Portal和 Portal容器可以放在一起视为同一个系统的组件,或者分开成为两个独立的组件。
Portlet容器是普通Web Servlet容器的扩展,所以一个Portlet容器可以构建于一个已经存在的Servlet容器或者可能实现全部Web Servlet容器的全部功能。无论Portlet容器怎么实现,它的运行环境总是假定它支持Servlet2.3规范。
通常,Portlet容器扩展自普通的Servlet容器。

第三节  什么是Portlet
Portlet是Portal中最重要的 组件,负责在Portal中呈现信息内容,有相应的生命周期。通过自定义Portlet,用户很容易定义个性化的Portal页面。Portlet由 Portlet容器负责管理、处理请求并返回动态页面,可以作为Portal的可即插即用的界面组件。
1.3.1  Portlet
一个Portlet是以Java技术为技术的Web组件,由Portlet容器所管理,专门处理客户的 信息请求以及产生各种动态的信息内容。Portlet 为可插式的客户界面组件,提供呈现层成为一个信息系统。
这 些由Portlet产生的内容也被称为片段,而片段是具有一些规则的标记( HTML、XHTML、WML ),而且可以和其他的片段组合而成一个复杂的文件。一个或多个 Portlet 的内容聚合而成为一个 Portal 网页。而 Portlet 的生命周期是被 Portlet 容器所管理控制的。
客户端和Portlet的互动是由Portal通过典型的请求/响应方式实现,正常来说,客 户会和Portlet所产生的内容互动,举例来说,根据下一步的连接或者是确认送出的表单,结果 Portal将会接收到Portlet的动作,将这个处理状况转向到目标Portlet。这些Portlet 内容的产生可能会因为不同的使用者而有不同的变化,完全是根据客户对于这个Portlet的设置。
1.3.2  Portlet与Servlet的关系
Portlet 被定义成为一个新的组件,具有新的明确的界面与行为。为了尽可能与现有的 Servlet 结合达到重复使用的目的,Portlet 的规范利用了 Servlet 的规范,许多观念都很相似的,结合 Portlet、Servlet 及 Jsp 在同一个网站系统中,我们称为Portlet 应用 。在同一个 Portlet 应用 中,他们将分享同一个类加载器(ClassLoader),上下文(Context) 及 Session。
①、Portlet 和 Servlet 的相似之处
@ Portlet 也是 Java 技术的 web 组件
@ Portlet 也是有特定的 container 在管理
@ Portlet 可以动态产生各种内容
@ Portlet 的生命周期由 container 所管理
@ Portlet 和客户端的互动是通过 request/response 的机制
②、Portlet 和 Servlet 也有一些不同
@ Portlet 只产生 markup 信息片段,不是完整的网页文件。而 Portal 会将所有的 Portlet markup 信息片段放到一个完整的 Portal 网页。
@ Portlet 不会和 URL 有直接的关系
@ 客户端必须通过 portal 系统才能和 Portlet 互动
@ Portlet 有一些定义好的 request 处理,action request 以及 render request。
@ Portlet 默认定义 Portlet modes 及窗口状态可以指出在网页中该 Portlet 的哪个功能正在执行及现在的 状态。
@ Portlet 可以在同一个 portal 网页之中存在多个。
③、Portlet 有一些附加的功能是 Servlet 所没有的
@ Portlet 能够存取及储存永久配置文件及定制资料。
@ Portlet 可以存取使用者数据
@ Portlet 具有 URL 的重写功能在文件中去动态建立连结,允许 portal server 不用去知道如何在网页的片 段之中建立连结及动作。
@ Portlet 可以储存临时性的数据在 Portlet session 之中,拥有两个不同的范围 :
application-wide scope 及 Portlet private scope 。
④、Portlet 不具有一些功能, 但是 Servlet 却有提供
@ Servlet 具有设置输出的文字编码( character set encoding)方式
@ Servlet可以设置 HTTP 输出的 header
@ Servlet才能够接收客户对于 portal 发出的 URL 请求
1.3.3  Portlet的生命周期
一个Portlet有着良好的生命周期管理,定义了怎样装载,实例化和初始化,怎样响应来自客户端的请求及怎样送出服务。这个Portlet生命周期由Portlet接口的init,processAction,render和destroy方法来表达。
载入和实例化:Portlet容器负责载入和实例化Portlet。当Portlet容器运行Portlet应用或者延迟到Portlet需要服务使用者的请求时,Portlet就会被载入并实例化。载入Portlet类后,Portlet类随即被实例化。
初 始化:Portlet类实例化后,Portlet容器还需要初始化Portlet。以调用Portlet去响应客户端的请求。Portlet容器呼叫 Portlet接口中的init方法初始化Portlet。扩展自PortletConfig的类可以取出定义在部署描述文件中的初始化参数,以及 Resource Bundle。
初始化异常:在 Portlet初始化期间,Portlet可能会丟出 UnavailableException 或 PortletException 异常。此时,Portlet容器不能把 Portlet置入已启动的服务,并且 Portlet容器必需释放这个 Portlet。 destory方法不能被呼叫,因为初始化被认为执行失败。发生 失败后,Portlet容器会尝试着重新实例化及初始化 Portlet。这个异常处理的规则是:由一个UnavailableException 指定一个不能执行的最小时间,当此异常发生时,Portlet容器必需等到指定时间过去后才产生并且初始化一个新的 Portlet。
在初始化过程中所丟出的 Runtime Exception异常,被当作 PortletException 来处理。
第四节  Liferay Portal工作原理
Portal系统根据需要由一个或者多个Portal页面组成,每个Portal页面包含零个或者多个的Portlet。每个Portlet呈现自己的信息内容,以此实现内容聚合。通过定义每个Portlet的可用权限,实现个性化的桌面信息定制。

1.4.1  Portlet 样式以及窗口状态

图1.4.1-1

图1.4.1-2
JCP 组织提出的JSR168规范定义了Portlet的实现标准。每个Portlet对外表现为一个小窗口,有自己的默认样式和窗口状态。如上图, Portlet有自己的标题,浏览状态下支持编辑、关闭、上移、下移、最大化、最小化功能,编辑状态下支持返回和关闭功能。从各种数据来源提取的信息以 Portlet内容的形式呈现在Portal中。
Portlet样式指出 Portlet正处于什么模式,Portlet通常会根据所处的模式而执行不同的工作并产生不同的内容。
Portlet模式让 Portlet决定它该显示什么内容和执行什么动作。调用一个 Portlet的时候,Portlet 容器会提供一个 Portlet模式给那个 Portlet。当在处理一个请求动作时,Portlet 的模式是可以用程序来改变的。
JSR168规范定义了三个Portlet模式: 浏览、编辑和帮助,Liferay Portal支持其中的全部三个模式。同时Portal是可以根据使用者的角色,来决定是要提供(显示)哪几个 Portlet 模式给使用者操作。
例如,匿名使用者可以操作浏览和帮助等 Portlet 模式的内容, 而只有授权过的使用者可以操作编辑这个 Portlet 模式所提供的内容或动作。
在浏览这个Portlet模式里,所被期望要提供的功能是产生标记语言来表现此时 Portlet的状态。 举例来说, Portlet的 浏览 模式可以包含一个或多个画面让使用者可以浏览与互动, 或是一些不需要与使用者互动的静态内容。
在编辑这个Portlet模式里, Portlet 需要提供内容和逻辑来让使用者定制 Portlet 的行为。典型的说, 编辑模式的 Portlet 会设定或更新 Portlet 的参数设定值。
在帮助这个模式里,Portlet应该提供有关这个 Portlet的帮助信息。这个帮助信息可以是有关这个 Portlet的简单且条理清楚的视窗说明或是详细的说明整个来龙去脉。所有的Portlet并不需要都提供帮助这个模式。
一 个 Portlet可以根据窗口状态来决定在一个页面里该占多少空间。 当调用一个 Portlet时, Portlet容器 需要告诉该 Portlet目前的窗口状态。 此时 Portlet可以根据窗口状态来决定它该对多少信息作处理。 在处理请求的过程中, Portlet可以通过程序的方式来改变窗口状态。
1.4.2  Portal页面

图1.4.2-1
每个Portal 页面包含零个或者多个Portlet小窗口,构成一个完整的信息呈现页面。Portal在启动之后根据Portlet配置文件等信息,给Portlet的 标题等属性赋值,赋予Portlet编辑、关闭等各种控制按钮,使Portlet成为一个标准的Portlet窗口。Portlet合并这些 Portlet窗口,组成一个完整的文档,即Portal页面。每个Portlet都处于相应的布局当中,呈现事先定义的内容,表现Portal公共的品 质。而且Portlet可以在不同的布局之间切换。Portlet响应客户端的请求,并将请求提交到相应的URL进行逻辑处理。
Portlet开发完毕之后,部署到Portal服务器,由Portal服务器负责组织、权限控制和呈现。Portal页面创建过程如下:
Portlet 在 Portlet容器内执行,Portlet容器接收 Portlet产生的内容。通常 Portlet容器将这些内容提交给 Portlet服务器,Portlet服务器依照这些内容建立Portal页面,然后将它传给客户端呈现。具体流程如下图:
Portlet 在 Portlet容器内执行,Portlet容器接收 Portlet产生的内容。通常 Portlet容器将这些内容提交给 Portlet服务器,Portlet服务器依照这些内容建立Portal页面,然后将它传给客户端呈现。具体流程如下图:
Portal页面的请求过程如下:
使 用者经由客户端设备(例如浏览器)存取 Portal,Portal 根据接收到的请求决定哪些 Portlet 需要被执行以满足需求。Portal 通过Portlet容器呼叫 Portlet,然后由 Portlet产生的片段建立Portal页面,再传回客户端呈现给使用者。具体流程如下图:
第二章Liferay Portal的使用
Liferay Portal分为Professional 和 Enterprise两个版本。
Liferay Portal支持多个应用服务器和Servlet容器。Liferay Portal Ent版本需要一个健壮的J2EE服务器,而Pro版本只要一个普通的Servlet服务器就可以运行。如果需要运行EJB,建议使用Pro版本。两个版 本的源码和应用接口都是一样的。
默认的,Pro版本分别集成Tomcat / Jetty / Resin作为Web服务器,采用Struts作为Web框架,实现轻量级的系统架构。Enterprise集成JBoss作为Web服务器,采用Spring作为Web框架,兼顾EJB。
Liferay Portal默认集成HSQL数据库,来持久化保存用户自定义的数据。通过修改集成在Liferay Portal的Tomcat的部署描述文件,用户可以更改数据源。Liferay Portal官方网站提供了数据库表的生成脚本。
下面以Pro版本(Tomcat服务器)为例,讲述Liferay Portal的用户策略、内容布局、桌面和品质。
第一节  Liferay Portal安装
由于Liferay Portal Pro版本集成了Tomcat服务器V5,所以只要把应用包下载解压就可以直接运行。
1、 从 http://www.iferay.om/web/guest/downloads/portal_pro 下载Pro版本zip包, 解压到目录{PORTAL_HOME}, 目录结构相对普通的Tomcat增加了Liferay文件夹。Liferay是默认的Web应用。
2、正确安装JDK1.4或者JDK1.5,并在环境变量里面正确配置JAVA_HOME变量。

图2.1-1
3、从命令行启动{PORTAL_HOME}/bin/startup.bat,启动Liferay Portal。
4、在浏览器地址栏输入http://localhost ,访问Portal首页。
5、用Login为test@liferay.com密码为test的用户登录Portal系统,得到的是一个Demo的首页。
如果启动呈现异常,请查看Tomcat控制台查找原因。
Liferay Portal启动之后,HSQL数据库自动启动。
登录系统后,点击右上角“My Account”链接,在“Display”选项卡中将Language改为“Chinese(China)”,以便中文化Portal界面。
第二节  Liferay Portal的用户策略
Liferay Portal通过定义严谨的用户策略、灵活的可个性化定制的内容和布局以及丰富可定制的品质策略,实现灵活的可定制的产品理念。
Liferay Portal采用用户-用户组-角色-Portlet的关联方式来实现用户权限的管理。用户录属于用户组(也可以单独存在),该用户组具有某种(多种)角 色,角色分配给用户组,也可以直接分配给用户。而操作某个Portlet 需要具有其指定的角色。下面通过实例操作,来了解和体验一下Liferay Portal的用户管理策略。
2.2.1  定义用户
Liferay Portal的用户管理在系统管理的Portlet中。缺省只有系统管理员才能使用。登录Portal后,可以在默认的桌面上找到“系统管理” Portlet。如果没有,从页面底部的选择框中选择“系统管理”添加上。也可以通过右上角“CMS”桌面的“内容和布局”页面找到管理入口。
从“系统管理”Portlet中选择“用户”项,进入用户管理界面。
2.2.2  添加用户
图2.2.1-2所示页面右边为“新增用户”列, 填入你所要增加的用户名称,姓氏,用户标识(可自动生成),邮件地址,密码(可自动生成)等。可以修改该用户所具有的用户组和角色信息(也可创建之后再修 改)。用户标识必须是系统唯一的,所以请确保你所输入的用户标识与已有的不冲突。
点击“新增用户”,我们成功增加一位用户标示为“educhina”的用户,如图2.2.1-2所示。左侧列表中新增一项“educhina eamoi”。然后我们就可修改这位用户的用户组,角色,个人档案等信息了。
2.2.3  修改用户
选择用户列表中一项,然后点击底部的三个编辑按钮,就可以分别编辑该用户的用户组、角色、档案等信息了。
此处我们选择用户“educhina eamoi”,然后选择“编辑档案”,出现档案编辑页面。如图2.2.3-3所示。填写你想要修改的信息,点击对应的“更新”按钮即可完成修改。需要注意的是整个档案页面分成几个部分,需要分别修改更新。
选 择用户“educhina eamoi”,然后选择“编辑角色”,进入角色编辑页面,如图2.2.3-4所示。左侧列表框为当前该用户所具有的角色,右侧列表为所有可用的角色。要赋 给用户新角色,则从右侧选择一项或多项,通过中间的转移按钮,从右侧添加至左侧。要删减用户角色,则从左侧移至右侧。最后点击底部的“更新”即可。更新完 页面会自动返回。
编辑用户组的操作同上。
2.2.4  定义用户组
用户组是对具有相同角色的用户的聚合。只要把用户需要的角色赋给用户组,则该用户组内所有的用户就都具备了该角色,具有该角色所有的权限,这样子就简化了用户权限管理。
用户组还有一个共用首页面的概念,是该用户组所有用户共享的页面。这些用户可以看到一个内容布局一致的页面,用以在用户组中共享信息。
从系统管理中选择[用户组]项,进入用户组定义页面。如图2.2.4-1所示:

图2.2.4-1
2.2.5  新增、重命名用户组
图中左侧为用户组列表,右侧为新增,和重命名。
在新增部分直接添入用户组名称,点击“新增用户组”即可。
选择列表中一个用户组,然后在右侧下方添入要修改的新组名,点击“更新”既可。
“友好的URL”为该用户组的共用首页面设置URL。
2.2.6  修改用户组
对于用户组我们可以修改它的角色,所包含的用户和该用户组的共用首页面。
选择用户组列表中一项,然后点击底部的“编辑角色”,进入用户组角色编辑页面,如图2.2.6-1所示。页面左侧为用户组当前已具备的角色,右侧为所有可用角色。添加删除操作同[2.2.3修改用户]。更新完会自动返回用户组列表页面。

图2.2.6-1

选择用户组列表中一项,然后点击底部的“编辑用户”,进入用户组用户编辑页面,如图2.2.6-2所示。页面左侧为用户组 当前包含的用户,右侧为所有用户。添加删除操作同[2.2.3修改用户]。更新完会自动返回用户组列表页面。

图2.2.6-2

选择用户组列表中一项,然后点击底部的“编辑页面”,进入用户组首页编辑页面,如图2.2.6-3所示。
首先增加一个新页。在“处理子页”一栏,填入新页的名字,选择类型,点击“新增页面”,左侧树状列表中会增添一个以新页名字为标题的新项。
然后为新页设置布局。点击左侧列表中的新页,右侧出现布局编辑页面,如图2.2.6-4所示。详细设置布局的操作可参考所述。

图2.2.6-4
2.2.7  定义角色
角色是对用户身份的一种定义。不同的角色具有不同的权限。被赋予这种角色的用户自然就获得了该角色的权限。
从系统管理中选择[角色]项,进入角色定义页面。如图2.2.7-1所示。

图2.2.7-1
2.2.8  新增、重命名角色
图中左侧为角色列表,右侧为新增,和重命名。
在新增部分输入角色名称,点击“新增角色”即可新增一个角色。
选择列表中一个角色,然后在右侧下方对应栏位填入新角色名,点击“重命名角色”即可重命名该角色。
2.2.9  修改用户组角色
对于角色,我们可以修改它的用户组和用户。该操作可以通过修改用户组和用户的角色来完成。
选择角色列表中一项,然后点击底部的“编辑用户组”,进入角色的用户组编辑页面,如图2.2.9-1所示。页面左侧为已具备当前角色的用户组,右侧为所有用户组。添加删除操作同[2.2.3修改用户]。更新后自动返回角色列表页面。
选择角色列表中一项,然后点击底部的“编辑用户”,进入角色的用户编辑页面,如图2.2.9-2所示。页面左侧为已具备当前角色的用户,右侧为所有用户。添加删除操作同[2.2.3修改用户]。更新后自动返回角色列表页面。

图2.2.9-2

2.2.10  定义Portlet的角色
通过为Portlet设置必需的角色,我们实现了用户与Portlet的关联。只有当用户或所属的用户组具有Portlet所必需的角色,他才能操作该Portlet。
从系统管理中选择[Portlet]项,进入Portlet定制页面。如图2.2.10-1所示。页面中显示了目前系统中可用的Portlet列表,列表中显示了Portlet目前的状态和必需的角色。

图2.2.10-1

选择一个Portlet,点击“编辑”进入Portlet定制页面,如图2.2.10-2所示。页面左侧为Portlet必需的角色,右侧为所有角色。添加删除操作同[2.2.3修改用户]。

图2.2.10 - 2
第三节  Liferay Portal内容和布局
Portlet 容器采用布局来对包含的Portlet进行管理并呈现,不同的布局决定了不同的Portlet呈现效果。每个加入到Portal服务器的Portlet必 须属于某个布局,才能够被使用者所看到。内容则是Portlet对外呈现的信息片断,是Portlet的核心。两者都是Portal的重要组成部分。 Liferay Portal采用开源框架Struts的Tiles来管理内容和布局。
2.3.1  什么是布局
布局,即Layout,也可以称为布局管理器,是Portlet容器管理Portlet的一个重要工具。一个布局,在生成的Portal页面中,呈现出单行多列或者多行多列的效果。而Portlet就内嵌在某一列中。
在Liferay Portal中,将列分为宽栏和窄栏。通常,宽栏占据页面2/3的宽度,窄栏占据页面1/3的宽度。每个Portlet在部署的时候都必须在部署描述符文件中指定Portlet是被部署在宽栏或者窄栏当中,默认是部署在宽栏中。

图 2.3.1-1
Liferay Portal采用tpl文件来定义布局,这些tpl文件存储在{PORTAL_HOME} /liferay/html/layouttpl文件夹中。在tpl文件中,规定每个列的宽度。当Portlet加入到列中时,取得当前列的宽度,然后根 据这个宽度确定Portlet窗口的显示宽度。tpl文件采用标准的HTML代码和Liferay Portal自定义的标签来定义布局。如下图:

图2.3.1-2
只要把定义的tpl文件路径加入到部署描述文件中,Liferay Portal在启动的时候就可以自动载入,供系统调用。如下图:
Liferay Portal默认的布局允许有一列、二列、三列的布局。二次开发的时候可以定义自己的布局文件。
在每个列的底部,有一个下拉列表框,列出本列可用的所有Portlet。列表框旁边的“添加”按钮,则可以将选中的按钮添加到列中显示。

图2.3.1-4

图2.3.1-5

图2.3.1-6
2.3.2  什么是内容
内容具体指Portlet显示出来的标记片断,称为Portlet内容。通常,当Portlet窗口处于浏览或者编辑状态的时候,就会表现相应的Portlet内容。内容在开发Portlet的时候确定。
Portlet对各种来源的数据进行加工和逻辑处理,最后输出为一些规则的标记(HTML、XHTML、WML),最后在Portlet容器中形成Portlet窗口,供Portal组合成为Portal页面。
内容是Portlet的信息主体,它形成的表单、链接等同时接受使用者的信息请求或者数据提交,并将系统对使用者请求的响应呈现在客户端。下图为以日历为内容的Portlet。

图2.3.2-1
2.3.3  内容布局与Portlet的关系
通 过定义布局,对Portlet进行有效管理,是Liferay Portal容器组织Portlet的有效方式。在相同的列中,Portlet可以很容易的调整位置。当列中的Portlet数量超过一个的时候,通过 Portlet右上角的“上移”和“下移”按钮,可以调整相邻Portlet的上下位置。当Portlet的内容较长的时候,可以把Portlet部署到 宽栏中,占据更大的屏幕空间,以有效的显示数据。相应的,如果Portlet内容较少时,可以把Portlet部署到窄栏中。

图2.3.3-1
每个Portlet在定义的时候,可以在部署描述文件中定义Portlet所属的类(Category),每个类可用的布局,这些定义也可以启动Portal之后在“内容与布局”选项卡中修改。
在“修改布局”子选项卡中可以修改的包括桌面的标识,如果是单行两列的布局,还可以调整宽栏和窄栏的位置。如下图:利用Liferay Portal提供的工具,可以很方便的修改布局内容和它被显示在Portal页面的什么地方。
在“处理孩子”子选项卡中,可以定义每个Portal页面的子页面,形成页面树。根节点的子页面会平行的出现在桌面上。如下图:

图2.3.3-4
Portal 是大量信息和系统的集成。Portlet内容往往来源与集成的各个系统。Portlet面向的用户通常也是复杂的。除了在用户策略中合理定义 Portlet的用户策略外,也可以对Portlet内容进行过滤,针对相应的用户显示适当的信息。当然,这种方法没有定义用户策略那样来得直观。
2.3.4  选择内容和布局
Liferay Portal内置了数个Portlet应用,包括系统管理、日历、书签等等。目前,Liferay Portal支持单行单列、单行两列、单行三列的布局显示,可以在相应桌面的“内容和布局”中选择。
每个默认的Portlet则来自于各个数据源的既有数据,或者对该数据的重新加工处理。通过定义Portlet所属类别和相应的用户策略,成功实现Portlet的合理显示。
Liferay Portal提供了基于Web的工具,可以很方便的在几种默认的布局之间切换。
①、登录系统后,选择桌面当中的“内容和布局”,进入布局管理页面。
②、选中桌面的第一级节点,然后在“列数”中选择需要的列数。
③、点击底部的“更新页”按钮,提交选择。布局修改生效。返回桌面。
可以看到,单行单列的布局默认是一个宽栏;单行两列的布局默认是一个宽栏和一个窄栏;单行三列的布局默认是三个窄栏。
第四节  Liferay Portal的桌面
2.4.1  什么是桌面
定义个性化的桌面是Portal的标准功能之一。用户可以把任何允许的Portlet添加到桌面上,构建符合自己需求的信息集合。
桌面是用户定义的Portlet的集合,也是Portlet内容的最终呈现媒介之一,可以是一个Portal页面,或者是一个Portal页面集合,里面包含一个或者多个的Portlet。每个桌面通常用一个或者多个布局来管理桌面上的Portlet。
Portlet 在部署之前,会在部署描述文件中定义该Portlet可用的用户组和角色。在定义了用户所属的用户组和角色之后,就可以在桌面下方的添加列表中看到该用户 可用的所有Portlet。用户可以把任何符合该用户角色权限的Portlet添加到相应的布局中。这些Portlet和桌面的定制信息会被Portal 服务器持久化保存。

图2.4.1-1
Portal启动之后,根据定制的Portlet和桌面信息,搜索并实例化Portlet,构建Portal页面,把Portlet内容显示在用户定制的桌面上。
2.4.2  定义个性化的桌面
在 完成用户策略、Portlet定义之后,登录Liferay Portal,就可以进行个性化桌面的定制了。用户登录进入到相应的桌面后,在相应的布局列底部可以看到可用的全部Portlet列表。选中某个 Portlet,点击“添加”按钮,将选中的Portlet添加到列中。对已经添加到列中的全部Portlet,可以通过点击Portlet窗口右上角的 “上移”、 “下移”按钮,调整Portlet窗口的位置。也可以点击Portlet窗口右上角的“最大化” 、“最小化”按钮,改变窗口的状态。定制完毕的桌面效果如下图:
第五节  Liferay Portal的品质
Liferay Portal支持个性化的皮肤和外观设计,并将此作为品质单独管理。
2.5.1  什么是品质
品质是Liferay Portal的外观,包括题材和色彩设计两个部分。题材主要影响Portlet窗口的样式和Portal的整体效果,包括Portlet边框格式、功能按钮、Portal页面效果等等。色彩设计主要影响Portal的CSS样式效果。
Liferay Portal默认定义了多种题材效果和色彩设计效果。使用者可以在“品质”选项卡中很容易的选择自己满意的品质。
2.5.2  品质和Portlet、Portal的关系
品质跟Portlet和Portal的呈现效果有很大的关系。通常应该根据Portlet内容选择适当的品质即题材和色彩设计。
题材对Portal的影响主要体现在背景和整体风格上面,以及Portlet和其他功能菜单的布局位置。色彩设计主要影响Portal的字体大小以及颜色等效果。
题材主要控制Portlet生成的窗口的样式效果,包括边框效果、标题样式等等。色彩主要控制Portlet窗口的字体效果,包括字体大小、字体颜色等等。
选择合适的题材和色彩设计对于Portal页面的整体呈现效果有明显的影响。如下图:
  
图2.5.2-1 采用不同的色彩设计得到的Portal页面
 
图2.5.2-2 采用不同的题材效果得到的Portal页面
2.5.3  定义个性化的品质
用户登录Portal系统之后,点击功能菜单上的“品质”,进入品质定制页面。选择适当的题材和色彩设计,相应的品质效果立即生效。
返回桌面查看品质效果。
使用者可以在二次开发的时候定义自己的品质,只要按照规范,在部署描述文件中定义可用的品质,Liferay Portal就可以自动调用。如下图:第六节  Liferay Portal的部署描述文件
跟所有的Web应 用一样,Liferay Portal采用多个XML部署描述文件,来初始化部署信息,规范操作模式,比如Portlet的初始化信息、可用的Portlet列表、Portlet 所属角色和用户组等等。通过这些部署描述文件,Liferay Portal可以在启动的时候自动加载Portlet,根据需要生成所需的Portlet页面。普通的Web应用,也可以很方便的转换成可部署的 Portlet。这种实现也是JSR168所规定的。
2.6.1  web.xml
web.xml是所有Java Web应用的部署描述文件。其正式的规范由http://java.sun.com/dtd/web-app_2_3.dtd 定义。
与其他普通Web应用相比,Liferay Portal的Portlet 应用还需要在web.xml中增加如下内容:
a、监听器:

这个要求web 服务器监听所有跟Portlet有关的请求信息,并将监听到的内容交给Liferay Portal的Portlet容器处理。
b、Portlet Servlet映射:

其 中,servlet-name为部署的servlet名称;init-param中定义自己的Portlet类,这个param-name要跟 portlet.xml、liferay-portlet.xml、liferay-display.xml中的portlet-name节点值一致。
c、标签库映射:

定义了这个标签库映射,在JSP文件中才可以使用诸如<portlet:defineObjects />在内的一些特定的Portlet标签。
如果在应用中有用到其他的元素,可以按照web.xml规范加入到相应的位置当中。
Liferay Portal默认的liferay应用,由于使用了Struts、Hibernate、Spring在内的多个开源框架,所以{PORTAL_HOME}/liferay/WEB-INF/web.xml文件会相对复杂些。
在自定义的Portlet,可以使用getPortletConfig().getInitParameter(“ ”)和getPortletConfig().getParameterNames(“”)两个方法来取得在web.xml中定义的参数。
2.6.2  portlet.xml
portlet.xml 用来定义Portlet的诸如部署名称、初始化参数、支持模式、resource bundle等普通的初始化信息,包括:portlet-name、display-name、portlet-class、init-param、 expiration-cathe、supports、portlet-info、security-role-ref等等。其正式的规范请参考: http://java.sun.com/xml/ns/Portlet/Portlet-app_1_0.xsd 。根目录为portlet-webapp。
portlet-name:Portlet的规范名称,在Portlet应用中必须唯一,主要用在Portlet部署和映射中。
display-name:供部署工具调用的Portlet简称,在Portlet应用中必须唯一。
portlet-class:Portlet对应的类,这个类必须直接或者间接的继承javax.Portlet.GenericPortlet。
init-param:初始化参数,有成对的<name>和<value>子元素。通常定义Portlet相应模式下可用的JSP页面。
expiration-cathe:定义Portlet加载允许最长的过期时间,以秒为单位。-1代表用不过期。
supports:定义Portlet支持的模式。所有的Portlet都必须支持浏览模式。
其他的元素含义请参照:http://java.sun.com/xml/ns/Portlet/Portlet-app_1_0.xsd
当Web 应用中有多个的Portlet时,可以统一的在Portlet。xml中定义一组的<portlet>元素。
2.6.3  liferay-Portlet.xml
定义Portlet默认可用的用户组、默认模板、是否支持多个实例等,规范由http://www.liferay.com/dtd/liferay-Portlet-app_3_5_0.dtd 定义。
liferay -portlet.xml主要包含单独或者成组的<portlet>、<role-mapper>。其中,< portlet>下包含<portlet-name>、<struts-path>、<use-default- template>、<instanceable>等子元素,<portlet-name>在应用中必须唯一,且要跟 portlet.xml相同;<role-mapper>下包含成对的<role-name>、<role- link>子元素。具体的元素含义请查看上述dtd定义。

2.6.4  liferay-display.xml
定义 Portlet默认的所属类别。Liferay Portal对Portlet实行按类别管理和划分用户权限。正如我们在用户策略中提到的,可以制定某个类别可用的用户组、用户和角色,方便权限控制。 Liferay-display.xml规范由http://www.liferay.com/dtd/liferay- display_3_5_0.dtd 定义。
Liferay-display.xml中,<display>下成组的<category>描述了可用的类别,其中portlet元素的id必须与liferay-portlet.xml的portlet-name保持一致,且在应用中唯一。

2.6.5  liferay-layout-templates.xml
定 义Portal可用的布局。正如我们在布局与品质中提到的那样,Portal采用tpl文件来规划桌面的布局。liferay-layout- templates。xml采用成组的layout-template来构建一个可用的布局列表。此xml的规范由http: //www.liferay.com/dtd/liferay-layout-templates_3_6_0.dtd 来定义。
本文采用Liferay Portal默认的布局,暂时不需要定义自己的布局,故不准备深入讨论。读者有兴趣可以自己查看相关资料。

2.6.7  liferay-look-and-feel。xml
定 义Portal可用品质的模板、图片、样式表等等,定义完毕后,Portal可以通过“布局与品质”管理工具来进行品质的切换。Liferay-look -and-feel.xml规范由http://www.liferay.com/dtd/liferay-look-and- feel_3_5_0.dtd 定义。
本文采用Liferay Portal默认的品质,不准备对品质的自定义深入探讨。有兴趣的读者可以查看相关资料。
第二部分 Liferay Portal 二次开发
本部分主要内容
GenericPortlet 自定义Portlet类 部署描述文件
第三章 开发自己的Portlet
在 了解了Liferay Portal的基础架构,初步体会Liferay Portal良好的个性化定制之后,本章将开始Liferay Portal二次开发之旅,讲述并扩展Portlet的超类GenericPortlet,创建或者修改部署描述文件,构建属于自己的Portlet。
第一节  重要的基类:GenericPortlet
像Servlet 一样,编写的Portlet也必须直接或者间接的扩展基类GenericPortlet,这个是由JCP针对Portal提出的JSR168规范定义的。 只要扩展自规范的GenericPortlet,所有的Portlet都可以在支持JSR168规范的Portal服务器上运行。
GenericPortlet统一定义了可供Portal容器识别和调用的方法,包括:
public Init():初始化;
public Init(PortletConfig) :初始化;
public getInitParameter(String):取得在Portlet。xml中定义的初始化参数;
public getInitParameterNames():取得在Portlet。xml中定义的全部初始化参数;
public getPortletConfig():取得包含初始化参数的配置对象PortletConfig实例;
public getPortletContext():取得Portlet上下文;
public getPortletName():取得在Portlet。xml中定义的Portlet名称。
public getResourceBundle(Locale) :取得Portlet国际化的Resource Bundle;
protected getTitle(RenderRequest) :取得Portlet的标题;
protected doView(RenderRequest,RenderResponse) :Portlet浏览模式的处理方法;
protected doEdit(RenderRequest,RenderResponse) :Portlet编辑模式的处理方法;
protected doHelp(RenderRequest,RenderResponse) :Portlet帮助模式的处理方法;
protected doDispatch(RenderRequest,RenderResponse) :Portlet行为分发;
protected processAction(RenderRequest,RenderResponse) :Portlet处理Action Request的方法;
protected render(RenderRequest,RenderResponse):Portal处理Render Request的方法;
public destroy():Portlet销毁,终止其生命周期。
在Portlet Portal运行的时候,doView、doEdit、doHelp三个方法分别被调用,用以生成Portlet标记。同样也可以调用Servlet生成 Portlet标记,或者不调用JSP或者Servlet,直接在方法中得到PrintWriter然后用最简单的pw.println()打印出内容。 这个过程类似Servlet,如下:
PrintWriter pw = renderResponse.getWriter();
pw.println(“Hello,world!”);
与Servlet类似,可以使用getInitParamter(String s)得到配置文件中Portlet的初始值,只不过Servlet在web.xml中,而Portlet在portlet.xml中。
portlet.xml:
<init-param>
<name>jspView</name>
<value>/jsp/view。jsp</value>
</init-param>
针对如上portlet.xml中的初始化信息,可以采用如下的调用方式:
SimplePortlet.java:
String jspName = getPortletConfig()。getInitParameter("jspView");

第二节  Portlet标签
跟Servlet一样,Portlet也自 定义了很多灵活的标签。通过这些标签,可以调用Portlet内部的参数比如renderResponse、renderRequest、 PortletConfig等,在JSP中跟Portlet通信。当然,在使用之前,除了要在web。xml中声明标签库外,还要在JSP的头部声明标签 库调用:<%@ taglib uri="http://java。sun。com/Portlet" prefix="Portlet" %>
3.2.1  defineObjects标签
在使用Portlet典型标签之前,要见声明<portlet:defineObjects/>,这样才可以使用其他的标签。defineObjects中间不允许定义任何属性和包含任何内容。
3.2.2  renderURL标签
属性 值类型 对应值
windowState String minimized
normal
maximized。

PortletMode String view, edit , help
var String
secure
String true
false

创建一个当前RenderURL,当访问它时将使Portlet窗口变为最大化状态,模式变为浏览。<portlet:param/>子元素会在生成的RenderURL中增加number、page两个参数和值。
3.2.3  actionURL标签
属性 值类型 对应值
windowState String minimized
normal
maximized。

portletMode String view, edit , help
var String
secure
String true
false
<portlet:actionURL windowState="normal" PortletMode="edit">
<portlet:param name="action" value="login"/>
</portlet:actionURL>
创建一个当前ActionURL,当访问它时将使Portlet窗口变为正常状态,模式变为编辑。<Portlet:param/>子元素会在生成的ActionURL中增加action参数和值。
renderURL和actionURL两个标签在诸如生成form表单的action等方面特别有用。
3.2.4  param标签
属性 值类型
name String
用在renderURL和actionURL标签内部,用来在生成的URL中增加参数和值。param标签不运行body内容存在。
3.2.5  namespace标签
为目前的Portlet产生一个唯一的Value,防止与其他Portlet或者Portal上面的Value冲突。
上述标签的具体属性及其约束,请参阅{PORTAL_HOME}/liferay/WEB-INF/tld/liferay-portlet.tld 。
第三节  Portal的对象
JSR168 给Portal定义了几个特别的对象,用来操作Portal特有的信息。这些对象跟Servlet的对象有点类似,又有点不同。这些对象都封装在 {PORTAL_HOME}/common/lib/ext/portlet.jar包中,具体支持实现要视Portal服务器而定。
3.3.1  Request对象
Portlet 中的Request与Servlet的Request一样接受客户端发送的请求,但是与Servlet不同,Portlet的Request分为 Action Request及Render Request两种类型,因此Portlet接口中定义了两种方法用来处理不同的Request。分别是processAction (ActionRequest request,ActionResponse response) 和render(RenderRequest request,RenderResponse response),分别用以处理Action Request和Render Request。某种意义上来讲,render方法类似Servlet中的service方法,doView,doEdit,doHelp方法又类似 doGet,doPost方法。
①、RenderRequest和ActionRequest
PortletRequest分为 RenderRequest和ActionRequest两种,分别由renderURL和actionURL来触发。renderURL是 actionURL的一种优化。Portlet的开发过程中尽量使用renderURL而避免actionURL。actionURL适用于有确实的 Action(行为)的情况下。比如说,表单form提交后Persistent状态的改变、session的改变、perference的修改等等。 renderURL通常用来处理Portlet的导航。举个例子:
使用actionURL:
<%
PortletURL pu = renderResponse.createActionURL();
pu.setParameter("ACTION","LOGIN");
<form name="usrform" method="post" action="<%=pu.toString()%>">
%>
说明:表单提交最好使用Post方法而不是Get方法,因为某些Portal服务器可能会将内部状态编码到URL的Query字符串中。
使用renderURL:
<%
PortletURL pu=renderResponse.createRenderURL();
Pu.setParameter("PAGE",Number);
%>
<a href="<%=pu%>">下一页</a>
②、renderURL和actionURL的处理方式
当客户端请求是由一个renderURL触发的时候,Portal服务器会调用该Portal页面所有Portlet的render方法。
而当客户端请求是由一个actionURL触发的时候,Portal服务器会先按用该页面所有Portlet的processAction方法再调用render方法。所以,要明确自己到底使用那种URL来出发客户端请求。
③、RenderRequest和ActionRequest的parameter参数作用范围
当客户端请求由一个actionRequest触发时,所有parameter参数的取得都必须在processAction方法中进行。比如:
public void processAction(ActionRequest req,ActionResponse res){
String str = req.getParameter("ACTION");
//response.setRenderParameter("ACTION",action);
}

public void doView(ActionRequest req,ActionResponse res){
String str = req.getParameter("ACTION");
}
如 上processAction方法中,getParameter方法将能成功得到表单中的参数ACTION所对应的值,因为我们知道,当目标 Portlet的processAction方法运行完后,Portlet Container将调用Portal页面中所有Portlet的render方法.但是实际上doView方法中使用getParameter不会得到 任何值.但是如果把processAction方法中注释了的一行解除注释的话,你就可以在doView方法中的得到参数ACTION对应的值. 这说明action request的参数,render方法中不可以直接取到.必须使用了setRenderParameter方法,再次传递一次.
3.3.2  Response对象
与Request对象一样, Response对象也有两种:RenderResponse和ActionResponse,分别用来封装对应的RenderRequest和 ActionRequest的返回信息,比如重定向、窗口状态、Portlet模式等。他们两者的父类PortletResponse拥有 serPorperty和getPorperty两个方法,用来传递信息给Portal容器。
ActionResponse主要用来处理以下功能:
a、 重定向
b、 改变窗口状态、Portlet模式
c、 传递parameter参数到RenderRequest中去
RenderResponse主要用来提供以下功能:
a、 设置ContentType
b、 得到OutputStream和Writer对象,用来输出页面内容
c、 Buffering缓冲
d、 设定Portlet的标题,但是必须在Portlet输出前调用,否则将被忽略
3.3.3  PortletConfig对象
和ServletConfig对象类似,PortletConfig对象提供对Portlet初始化信息以及PortletContext对象存取的方法。
和ServletConfig对象不同的是,PortletConfig对象提供对Portlet的标题等资源的I18N支持,可以通过设定不同的Resource Bundle文件以提供多种语言支持。
3.3.4  Session对象
由于容器不同,Portal的Session对象与Servlet的Session对象略有不同。
由于Portlet处于Portal服务器的缘故,Portlet的Session分为Application Scope和Portlet Scope。两者的区别在于:
①、Application Scope范围的Session中保存的对象,对于同一个Portlet应用范围内的所有Portlet都是可用的。
②、Portlet Scope范围的Session中保存的对象,只对本Portlet可用,其他Portlet即使在同一个应用中,也不可用。
但是对于Portlet应用来说,可以通过HttpSession来访问。毕竟Portlet应用也是Web应用。在使用Session对象的时候,最好能明确指出使用的是那个Scope范围的Session。比如:
<portlet:actionURL windowState="NORMAL" PortletMode="view" var="pu1">
<portlet:param name="ACTION" value="ApplicationScope"/>
</portlet:actionURL>

<portlet:actionURL windowState="NORMAL" PortletMode="view" var="pu2">
<portlet:param name="ACTION" value="PortletScope"/>
</portlet:actionURL>
这个JSP创建了两个ActionURL,分别产生了两种PortletSession对象。
PortletSession ps = req.getPortletSession();
if(ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE)!=null){
app=ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE).
toString();
}
if(ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE)!=null){
Portlet=ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE).
toString();
}
以上代码根据需要取得不同Scope范围的Session对象值。
同一个应用下,可以直接通过ServletSession取得PortletSession。APPLICATION_SCOPE范围下的Session对象值。
HttpSession se = request.getSession();
if(se.getAttribute("PortletSession.AS")!=null){
app=se.getAttribute("PortletSession.AS");
}
3.3.5  Preference对象
Preference对象被设计用来实现用户的个性化设置,可以帮助用户对Portlet进行符合用户需求的显示定制和行为定制,可以替代部分的数据库功能。需要指出的是,Preference对象只是用来存取简单的配置信息,并不能完全替代数据库应用。
Preference对象对于配置信息采用键-值的形式存取,用户可以将需要的信息暂时保存在Preference中。
PortletPreference p= req.getPortletPreferences();
p.setValue("educhina.username","educhina");
p.store();
Preference对象用来存取用户的个性化信息,所以不同用户的Preference对象不能共享,这点跟Session不同。
可以在Portlet.xml中配置Preference信息,如下:
<Portlet-preferences>
  <preference>
    <name>educhina。username</name>
    <value>educhina</value>
    <read-only>true</read-only>
  </preference>
</Portlet-preferences>
另外,还可以配套使用PreferencesValidator对象,对Portlet的Preference在存储之前进行验证,以确保Preference的正确性。
具体规范可以参照http://java.sun.com/xml/ns/Portlet/Portlet-app_1_0.xsd 的<complexType name="preferenceType">部分。
第四节  编写自己的Portlet类
Liferay Portal内部集成了78个Portlet,包括直接用PrintWriter输出的、调用JSP输出的、调用Servlet输出的,数据来源有直接从 数据库取得的、通过Web Service取得的等等。这里,我们只讲述直接用PrintWriter输出的和调用JSP输出的,目的在于讲述如何编写自己的Portlet类。其他 的与此类似,不赘述。
3.4.1  开发环境
IDE:Eclipse V3.0.1
JDK:V1.4.2_06
ANT:V1.6.2
Tomcat:V5.0(集成在Liferay Portal中)
Liferay Portal:liferay-portal-pro-3.6.0-tomcat
3.4.2  准备工作
①、安装JDK V1.4.2_06,在系统环境变量中增加变量JAVA_HOME,指向JDK安装目录。
②、安装ANT,在系统环境变量中增加变量ANT_HOME,指向ANT安装目录。
③、下载并启动Eclipse V3.0.1.
④、下载并解压缩liferay-portal-pro-3.6.0-tomcat.zip到某一文件夹,该文件夹即为{PORTAL_HOME}。
⑤、 在Eclipse中新建一个Java项目,命名为TestPortal,路径为D:"TestPortal,将{PORTAL_HOME}"common "ext"portlet.jar以外部jar的形式添加到库中。下文中,D:"TestPortal将以{APP_HOME}代称。在 {APP_HOME}下创建文件夹webapp、deploy、bak。项目缺省输出文件夹为{APP_HOME}"webapp"WEB-INF" classes 。
⑥、在{APP_HOME}"webapp"WEB-INF目录下创建web.xml,内容如下:
<?xml version="1。0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc。//DTD Web Application 2。3//EN" "http://java。sun。com/dtd/web-app_2_3。dtd">
<web-app>
<display-name>TestPortal</display-name>
</web-app>
⑦、在{APP_HOME}"webapp"WEB-INF下创建tld文件夹,将{PORTAL_HOME}"liferay"WEB-INF"tld/liferay-portlet.tld拷贝到创建的tld文件夹下,备用。
⑧、新建一个Java包com.educhina.portal 。
3.4.3  HelloWorldPortlet
HelloWorldPortlet 类计划用单纯的PrintWriter输出Portlet标记片断。在包com.educhina.portal下新建Java类 HelloWorldPortlet,这个类必须扩展自javax.Portlet.GenericPortlet类。设计让 HelloWorldPortlet支持浏览和编辑两种模式,所以HelloWorldPortlet重写doView和doEdit方法。简单的代码如 下:
package com.educhina.portal;
import java.io.IOException;
import javax.Portlet.GenericPortlet;
import javax.Portlet.PortletException;
import javax.Portlet.RenderRequest;
import javax.Portle.RenderResponse;

public class HelloWorldPortlet extends GenericPortlet{
public void doView(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
res.setContentType("text/html");
res.getWriter().println("HelloWorld!");
}
public void doEdit(RenderRequest req,RenderResponse res)
throws IOException,PortletException {
res.setContentType("text/html");
res.getWriter().println("HelloWorld!");
}
}
doView和doEidt方法从RenderRequest取得PrintWriter对象,直接输出一个String字符“HelloWorld!”。这个String字符将作为HelloWorldPortlet的片断内容。
3.4.4  HelloJSPPortlet
HelloJSPPortlet 类计划调用外部JSP输出。同样的,HelloJSPPortlet也要扩展自GenericPortlet类。HelloJSPPortlet调用 getPortletConfig().getInitParameter("..")方法,取得在Portlet。xml中配置的view-jsp和 edit-jsp参数值,以此确定JSP页面的具体位置。然后调用PortletRequestDispatcher的include方法,将JSP页面 加载到RenderResponse。代码如下:
package com.educhina.portal;

import java.io.IOException;
import javax.Portlet.GenericPortlet;
import javax.Portlet.PortletException;
import javax.Portlet.PortletRequestDispatcher;
import javax.Portlet.RenderRequest;
import javax.Portlet.RenderResponse;

public class HelloJSPPortlet extends GenericPortlet{
public void doView(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
res.setContentType("text/html");
String jspName = getPortletConfig().getInitParameter("view-jsp");
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(jspName);
rd.include(req,res);
}
public void doEdit(RenderRequest req,RenderResponse res)
throws IOException,PortletException {
res.setContentType("text/html");
String jspName = getPortletConfig().getInitParameter("edit-jsp");
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(jspName);
rd.include(req,res);
}
}
在{APP_HOME}/webapp目录下创建view.jsp和edit.jsp,view.jsp代码如下,edit.jsp类似:
<table cellpadding="8" cellspacing="0" width="100%">
<tr>
<td>
<font class="Portlet-font" style="font-size: x-small;">
This is a <b>Sample JSP Portlet</b> used in viewing model。 Use this as a quick way to include JSPs。
</font>
</td>
</tr>
</table>
JSP 文件不能包含关于HTML的<head>、<body>、<html>的信息,只能包含原来位于< body></body>内部的HTML内容。那些<head>、<body>、<html>信 息由Portal页面来提供。
只有在JSP页面中使用<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>和<portlet:defineObjects/>,JSP页面才可以直接操作Portlet的一些变量,比如: renderResponse、renderRequest、portletConfig。
第五节  修改Web部署描述文件
正如2.6.1所指出的那样,要保证 Portlet能够在Liferay Portal成功部署,必须对web.xml进行必要的修改,添加Portlet监听器、Servlet映射、Portlet标签库。在先前 web.xml的<display>节点下增加如下内容:
<listener>
<listener-class>com.liferay.portal.servlet.PortletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>HelloWorldPortlet</servlet-name>
<servlet-class>com.liferay.portal.servlet.PortletServlet</servlet-class>
<init-param>
<param-name>Portlet-class</param-name>
<param-value>com.educhina.portal.HelloWorldPortlet</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldPortlet</servlet-name>
<url-pattern>/HelloWorldPortlet/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>HelloJSPPortlet</servlet-name>
<servlet-class>com.liferay.portal.servlet.PortletServlet</servlet-class>
<init-param>
<param-name>Portlet-class</param-name>
<param-value>com.educhina.portal.HelloJSPPortlet</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloJSPPortlet</servlet-name>
<url-pattern>/HelloJSPPortlet/*</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>http://java.sun.com/Portlet</taglib-uri>
<taglib-location>/WEB-INF/tld/liferay-Portlet.tld</taglib-location>
</taglib>
其 中,<listener>节点是增加一个监听器,以便Liferay Portal监听所有针对Portlet的操作。<servlet>以及<servlet-mapping>是将上述两个 Portlet类加入Servlet容器中。Portlet类实质上也是Servlet。<tablib>是将Liferay Portal标签库加入列表中,以便JSP调用。
第六节  创建Liferay Portal部署描述文件
修改完web.xml之后,还要创建2.6所说的三个Portlet部署描述文件:portlet.xml、liferay-portlet.xml、liferay-display.xml。
①、portlet.xml
portlet.xml 定义Portlet的初始化信息。这里,我们在portlet.xml中增加两个Portlet节点,分别代表HelloWorldPortlet和 HelloJSPPortlet。其中,HelloWorldPortlet支持PringWriter输出,HelloJSPPortlet支持JSP 输出;两者都支持浏览和编辑两种模式。HelloJSPPortlet需要定义两个init参数,告诉系统JSP文件的位置。
<portlet>
<portlet-name>HelloWorldPortlet</portlet-name>
<display-name>HelloWorldPortlet</display-name>
<portlet-class>com.educhina.portal.HelloWorldPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<supports>
<mime-type>text/html</mime-type>
<Portlet-mode>edit</Portlet-mode>
</supports>
<portlet-info>
<title>HelloWorldPortlet</title>
<short-title>HelloWorldPortlet</short-title>
<keywords>HelloWorldPortlet</keywords>
</portlet-info>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
<portlet>
<portlet-name>HelloJSPPortlet</portlet-name>
<display-name>HelloJSPPortlet</display-name>
<portlet-class>com。Educhina.portal.HelloJSPPortlet</portlet-class>
<init-param>
<name>view-jsp</name>
<value>/view。jsp</value>
</init-param>
<init-param>
<name>edit-jsp</name>
<value>/edit。jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<supports>
<mime-type>text/html</mime-type>
<Portlet-mode>edit</Portlet-mode>
</supports>
<portlet-info>
<title>HelloJSPPortlet</title>
<short-title>HelloJSPPortlet</short-title>
<keywords>HelloJSPPortlet</keywords>
</portlet-info>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
②、liferay-Portlet.xml
Liferay-Portlet.xml主要定义Portlet的模板、实例总数、是否允许重复定义等。同样的,我们增加了两个<Portlet>节点,代表HelloWorldPortlet和HelloJSPPortlet。
<?xml version="1。0"?>
<!DOCTYPE liferay-Portlet-app PUBLIC "-//Liferay//DTD Portlet Application 3。5。0//EN" "http://www。liferay。com/dtd/liferay-Portlet-app_3_5_0。dtd">
<liferay-portlet-app>
<portlet>
<Portlet-name>HelloWorldPortlet</Portlet-name>
<struts-path>HelloWorldPortlet</struts-path>
<use-default-template>true</use-default-template>
<instanceable>true</instanceable>
</portlet>
<portlet>
<Portlet-name>HelloJSPPortlet</Portlet-name>
<struts-path>HelloJSPPortlet</struts-path>
<use-default-template>true</use-default-template>
<instanceable>true</instanceable>
</portlet>
<role-mapper>
<role-name>administrator</role-name>
<role-link>Administrator</role-link>
</role-mapper>
<role-mapper>
<role-name>guest</role-name>
<role-link>Guest</role-link>
</role-mapper>
<role-mapper>
<role-name>power-user</role-name>
<role-link>Power User</role-link>
</role-mapper>
<role-mapper>
<role-name>user</role-name>
<role-link>User</role-link>
</role-mapper>
</liferay-portlet-app>
③、liferay-display.xml
liferay-display.xml定义Portlet所属类别。Liferay Portal默认定义了一个category.test类别,这里,我们将HelloWorldPortlet和HelloJSPPortlet归属到category.test。
<?xml version="1。0"?>
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 3。5。0//EN" "http://www。liferay。com/dtd/liferay-display_3_5_0。dtd">
<display>
<category name="category。test">
<Portlet id="HelloWorldPortlet" />
<Portlet id="HelloJSPPortlet" />
</category>
</display>
至此,一个简单的Portlet就开发完成了。接下来,我们把它部署到Liferay Portal上。
第三部分 Liferay Portal部署
本部分主要内容
Portlet部署  ANT  管理Portlet
第四章 部署自己的Portlet
Liferay Portal跟Tomcat5.0集成在一起,从本质上讲,liferay-portal-pro-3.6.0-tomcat.zip是一个Tomcat 压缩包,只是其中将liferay作为默认应用,并将跟Portlet有关的操作都交给liferay应用处理而已。因此,Liferay Portal支持所有针对Tomcat5.0的部署方式,包括:手动部署、Ant部署,并且支持热部署。
第一节  手动部署
手动部署可以采用拷贝文件夹、war部署、编写部署文件三种方式:
①、 拷贝文件夹:与单纯的Tomcat一样,我们可以将{APP_HOME}"webapp目录拷贝到{PORTAL_HOME}"webapps"下,该 webapp目录名为TestPortal。启动Liferay Portal(双击{PORTAL_HOME}"bin"startup。bat)即可。
②、war部署:或者将{APP_HOME}" webapp打包成TestPortal.war,拷贝war到{PORTAL_HOME}"webapps"下,启动Liferay Portal,让Tomcat自动解压。在命令行模式下切换到{APP_HOME}"webapp目录,执行 jar cvf TestPortal.war * 。
③、编写部署文件:
{PORTAL_HOME}"conf"Catalina"localhost目录下,创建TestPortal.xml文件,内容如下:
<Context path="/TestPortal" docBase="D:"TestPortal"webapp" debug="0" reloadable="true" crossContext="true">
</Context>
部署成功后,登录Liferay Portal,可以在桌面底部的下拉列表中看到HelloWorldPortlet和HelloJSPPortlet两个Portlet。将它们添加到桌面中。
第二节  Ant自动部署
确保之前已经安装Apache Ant,并正确添加ANT_HOME到系统环境变量。
①、拷贝之前打包的TestPortlet.war到{APP_HOME}/deploy目录;
②、 从http://prdownloads。sourceforge。net/lportal/Portlet-deployer-3。6。0。xml 下载Portlet-deployer-3.6.0.xml 到{APP_HOME}"deploy,改名为build。xml以便Ant自动加载;
③、确保JDK1.4.2和Ant 1.6安装成功,并配置到系统环境变量;
④、确保Tomcat或者其他服务器已经正确安装,或者Liferay Portal正常安装。
编 辑build.xml,使其只想你的应用服务器或者Servlet容器。比如,如果你安装JBoss+Jetty到/opt/liferay目录,那么编 辑build.xml,确保只有JBoss+Jetty部分没有被注释,修改app.server属性为/opt/liferay。
Build.xml默认是开启JBoss+Jetty部分,本文采用的是Tomcat集成包,所以将JBoss+Jetty部分注释掉,开始Tomcat部分。修改app.server.dir属性,指向{PORTAL_HOME}。如下图:
⑤、 命令行切换到到{APP_HOME}/deploy目录,执行 ant deploy ,系统会自动将TestPortal。war解压,必要时修改web.xml、portlet.xml等部署文件,将解压后的TestPortal文件夹 拷贝到{PORTAL_HOME}"webapps目录下。
启动Liferay Portal之前,建议先确认修改后的web.xml、portlet.xml等部署文件是否正确。
第三节  加入Liferay Portal自有列表
之 前我们提到过,Liferay Portal集成了78个默认的Portlet应用。这些应用都通过{PORTAL_HOME}"liferay"WEB-INF"目录下的 portlet.xml、liferay-portlet.xml、liferay-display。xml描述。我们只要更改这些描述文件,就可以将我 们自己的应用加入到Liferay Portal的Portlet列表中了,效果跟手动部署和Ant自动部署一样。
①、拷贝{APP_HOME}"webapp目录的内容到{PORTAL_HOME}"liferay"html"Portlet目录下,更改文件夹名称为TestPortal。
②、将TestPortal"WEB-INF"classes文件夹剪切到{PORTAL_HOME}"liferay"WEB-INF目录下。
③、 将TestPortal"WEB-INF"web。xml中<servlet>、<servlet-mapping>的内容合并 到{PORTAL_HOME}"liferay"WEB-INF"web.xml中。删除TestPortal"WEB-INF"web.xml。
④、 将TestPortal"WEB-INF"Portlet.xml中关于HelloWorldPortlet和HelloJSPPortlet的< portlet>的内容合并到{PORTAL_HOME}"liferay"WEB-INF"portlet.xml中。删除TestPortal "WEB-INF" portlet.xml。
⑤、将TestPortal"WEB-INF"liferay-portlet.xml中关于 HelloWorldPortlet和HelloJSPPortlet的<portlet>的内容合并到{PORTAL_HOME}" liferay"WEB-INF"liferay-portlet.xml中。删除TestPortal"WEB-INF"liferay- portlet.xml。
⑥、将TestPortal"WEB-INF"liferay-display.xml中关于 HelloWorldPortlet和HelloJSPPortlet的<portlet>的内容合并到{PORTAL_HOME}" liferay"WEB-INF"liferay- display.xml中。删除TestPortal"WEB-INF" liferay- display.xml。
这个方法比较复杂,而且不容易扩展和调试,通常不建议采用。
第四节  普通Java Web应用转化为Portlet应用
随 着开发的深入,我们希望能够将原来的Java Web应用迁移到Liferay Portal,构建真正的企业门户。Liferay Portal灵活的二次开发机制,允许用户将各种各样的内容集成到Portal平台上来,消除信息孤岛。将一个Java Web应用转化为Portlet应用的步骤如下:
①、撰写扩展自GenericPortlet的Portlet和JSP页面。这个Portlet可以使用PrintWriter输出或者调用JSP页面输出方式。通常,如果Java Web应用是采用MVC三层模式,那么只需要更改View层就可以了。
②、修改web.xml,增加2。6。1所述的Portlet监听器和Portlet标签库,增加针对上步骤所写的servlet和servlet映射。
<servlet>
<servlet-name>yourPortlet</servlet-name>
<servlet-class>com.liferay.portal.servlet.PortletServlet</servlet-class>
<init-param>
<param-name>Portlet-class</param-name>
<param-value>full.name.of.yourPortlet</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>yourPortlet</servlet-name>
<url-pattern>/yourPortlet/*</url-pattern>
</servlet-mapping>
③、创建portlet.xml,增加相应的Portlet定义信息,规范参考2.6.2。
④、创建liferay-portlet.xml,增加相应的Portlet定义信息,规范参考2.6.3。
⑤、创建liferay-display.xml,增加相应的Portlet类别定义信息,规范参考2.6.4。
⑥、 拷贝portlet.jar和liferay-Portlet.tld到当前应用。其中,portlet.jar是Portlet API包,作用类似servlet-api.jar,位于{PORTAL_HOME}"common"lib"ext"liferay- portlet.tld是Liferay Portal提供的Portlet标签库。
⑦、选择适当的部署方式,将修改后的Java Web应用部署到Portlet平台上。
第四部分 附录
本部分主要内容
资源网站 Portlet范例 参考资料 后序
第五章 相关资源
作为一个开源的门户产品,Liferay Portal已经比较成熟,有比较齐全的文档。随着应用的深入,开源免费的中文化文档也在陆续出现。
第一节 资源网站
Liferay Portal 官方网站:http://www.liferay.com 
Liferay Portal 中文网站:http://www.liferay.cn 
Liferay Portal 论坛:http://forums.liferay.com 
Tracker : http://support.liferay.com 
邮件列表:http://sourceforge.net/mailarchive/forum.php?forum=lportal-development 
JavaLobby专题:http://www.javalobby.org/articles/liferay/
OSQS专题:http://cstsolaris.cst.nait.ab.ca/ist410/gerry/liferay/index.jsp 
Leonardsoko1专题:http://www.leonardsokol.com/liferay/
Developer专题:http://www.developer.com/java/web/article.php/10935_3372881_1
第二节  示例
Liferay Portal随程序包提供了丰富的documentation,其中的Portlet Examples对Portal内置的Hello World、IFrame、Calendar、Message Boards、Mail五个Portlet进行了比较详细的解说。启动Liferay Portal后,浏览这里:
http://localhost/web/guest/documentation/development/Portlet
另 外,Liferay Portal还在官方网站上提供了Sample Layout Template、Sample Portlet、Sample Themes供下载。其中,Sample Portlet包括Sample JSP Portlet、Sample Struts Portlet、Sample JSF SUN Portlet、Sample JSF MyFaces Portlet。浏览这里:
http://localhost/web/guest/downloads/sample_Portlet


第六章 参考资料
①、文档
《JSR168 PORLET标准手册汉化整理》 作者:Jini等
《Portlet应用开发(JSR168)》 作者:Terry Lee
《(原创翻译)Liferay-Portal架构》                   作者:eamoi
②、网站
http://www.liferay.com
http://www.liferay.cn

后序
研 究Liferay Portal属于半路出家。从开始到本文完成,俩月有余。作为一个开源的Portal产品,Liferay的确值得称许,虽然还有不少bug。在本文截稿 的时候,Liferay Portal V3.6.1已经发版,新版本在拖拉Portlet、Spring远程传输和布局热部署方面有比较大的提升。本文不会就此终结,暂称V1.0,作为前段工 作的总结。本文的用户策略部分参考了同事Kevin的文档,特此感谢。
PS:写文章真的很费脑筋。

(完)


posted on 2008-03-02 10:49 礼物 阅读(3637) 评论(0)  编辑  收藏 所属分类: Liferay