Portlet开发指南


Portlet 开发指南 1 Portlet 开发指南 Portlet 开发指南 2  目录 Portlet 开发指南............................................................................................................................... 1 第一章节 入门介绍 ......................................................................................................................... 7 一、 Portlet 简介 ............................................................................................................... 8 什么是 Portal .................................................................................................................... 9 什么是 Portlet ................................................................................................................... 9 什么是 Portlet 容器 .......................................................................................................... 9 三者关系 ......................................................................................................................... 10 版本兼容性 ..................................................................................................................... 10 JSR286 的主要新特性 .................................................................................................... 10 与 J2EE 的版本对应 ....................................................................................................... 10 二、 Portlet 与 servlet 的关系 ........................................................................................ 11 Portlet 与 servlet/jsp 中的桥梁 ...................................................................................... 12 用 servlet 生命周期事件 ................................................................................................ 12 Servlet 容器与 Portlet 容器之间的关系........................................................................ 12 三、 开发环境搭建 ......................................................................................................... 13 IBM WebSphere Portal 环境搭建 ................................................................................... 13 Apache Pluto Portal 环境搭建 ........................................................................................ 24 快速入门 ......................................................................................................................... 29 第二章节 独有概念 ....................................................................................................................... 36 四、 Portlet 概念 ............................................................................................................. 37 Portlet 定义 ..................................................................................................................... 37 Portlet 是 Portal 页面中的一个区域 ............................................................................. 37 Portlet 和 Web 框架 ....................................................................................................... 38 五、 Portlet URLs ............................................................................................................. 39 BaseURL 接口 ................................................................................................................. 39 包含 Portlet Mode 和 Window State 信息 ................................................................... 40 Portlet URL 安全性 ......................................................................................................... 40 总结 ................................................................................................................................. 40 六、 Portlet Modes .......................................................................................................... 42 查看 Portlet Mode ......................................................................................................... 42 编辑 Portlet Mode ......................................................................................................... 42 帮助 Portlet Mode ......................................................................................................... 42 自定义 Portlet Modes ................................................................................................... 42 受支持的 Portlet Modes................................................................................................ 43 七、 Window States ........................................................................................................ 44 正常 Window State ........................................................................................................ 44 最大化 Window State .................................................................................................... 44 最小化 Window State .................................................................................................... 44 Portlet 开发指南 3 自定义 Window States .................................................................................................. 44 支持的 Window State .................................................................................................... 44 八、 Portlet Preferences .................................................................................................. 45 PortletPreferences 接口 ................................................................................................ 45 Preference Attributes 范围 ............................................................................................ 45 Preference Attributes 定义 ............................................................................................ 46 第三章节 基础概念 ....................................................................................................................... 47 九、 Portlet 生命周期接口 ............................................................................................. 48 Portlet 实例的数量 ........................................................................................................ 48 Portlet 生命周期............................................................................................................. 48 Portlet 的个性化 ............................................................................................................ 49 Request 请求处理 ........................................................................................................... 50 总结 ................................................................................................................................. 54 十、 Portlet Config .......................................................................................................... 55 初始化参数 ..................................................................................................................... 55 Portlet Resource Bundle .................................................................................................. 55 默认事件命名空间 ......................................................................................................... 56 公告展现参数 ................................................................................................................. 56 发布事件 ......................................................................................................................... 56 处理事件 ......................................................................................................................... 56 支持的国际化 ................................................................................................................. 56 支持的运行时选项 ......................................................................................................... 56 总结 ................................................................................................................................. 57 十一、 Portlet Context ................................................................................................ 58 Portlet Context 范围 ....................................................................................................... 58 Portlet Context 功能 ...................................................................................................... 58 与 Servlet Context 关系 ................................................................................................. 58 总结 ................................................................................................................................. 59 十二、 Portlet Requests .............................................................................................. 60 PortletRequest 接口 ...................................................................................................... 60 ClientDataRequest 接口 ................................................................................................. 64 ActionRequest 接口 ....................................................................................................... 64 ResourceRequest 接口 .................................................................................................. 64 EventRequest 接口 ........................................................................................................ 65 RenderRequest 接口 ...................................................................................................... 65 Request 对象的时间范围 .............................................................................................. 65 总结 ................................................................................................................................. 65 十三、 Portlet Response ............................................................................................. 66 PortletResponse 接口 .................................................................................................... 66 StateAwareResponse 接口 ............................................................................................ 68 ActionResponse 接口 ..................................................................................................... 68 EventResponse 接口 ...................................................................................................... 68 MimeResponse 接口 ...................................................................................................... 69 RenderResponse 接口 ................................................................................................... 69 Portlet 开发指南 4 ResourceResponse 接口 ................................................................................................ 70 Response 对象的时间范围 ........................................................................................... 70 十四、 Sessions ........................................................................................................... 71 创建 Session .................................................................................................................... 71 Session 范围 ................................................................................................................... 71 Session 中设置属性 ........................................................................................................ 71 与 Web Application HttpSession 关系 ............................................................................ 71 写入 Portlet Session ........................................................................................................ 72 Session Timeouts............................................................................................................. 73 最后访问时间 ................................................................................................................. 73 重要的 Session 语义 ..................................................................................................... 73 总结 ................................................................................................................................. 73 十五、 请求分发给 Servlets 和 JSPs ....................................................................... 74 获取 PortletRequestDispatcher ..................................................................................... 74 使用 Dispatcher .............................................................................................................. 74 Include 方法 ................................................................................................................... 74 forward 方法 .................................................................................................................. 75 Servlet filters ................................................................................................................... 76 改变默认的 Included Forwarded Session 范围 ............................................................ 76 总结 ................................................................................................................................. 76 十六、 Portlet 标签库 ................................................................................................ 77 defineObjects 标签 ........................................................................................................ 77 actionURL 标签 .............................................................................................................. 79 renderURL 标签 ............................................................................................................. 79 resourceURL 标签 ........................................................................................................... 80 namespace 标签 ............................................................................................................. 81 param 标签 ..................................................................................................................... 81 总结 ................................................................................................................................. 81 十七、 Portlet 应用 .................................................................................................... 82 与 Web Applications 的关系 .......................................................................................... 82 与 PortletContext 的关系 ............................................................................................... 82 Portlet Application 中的元素 ......................................................................................... 82 目录结构 ......................................................................................................................... 82 Portlet Application Classloader ....................................................................................... 82 Portlet Application 存档文件 ........................................................................................ 82 Portlet application 部署描述符 ..................................................................................... 83 更新 Portlet Application ................................................................................................. 83 十八、 打包和部署描述符 ......................................................................................... 84 Portlet 和部署描述符 ..................................................................................................... 84 打包 ................................................................................................................................. 84 Portlet 部署描述符元素 ................................................................................................. 84 处理 Portlet 部署描述符规则 ....................................................................................... 85 Portlet.xml 中唯一的值 .................................................................................................. 85 第四章节 高级特性 ....................................................................................................................... 86 Portlet 开发指南 5 十九、 资源服务 ......................................................................................................... 87 ResourceServingPortlet 接口 ......................................................................................... 87 访问 Render 参数、 Portlet Mode、 Window State ................................................. 88 访问 Request 和 Response Headers ............................................................................. 88 获取 HTTP 方法 ............................................................................................................ 89 访问 Resource ID ............................................................................................................ 89 Resource URLs ................................................................................................................. 89 Generic Portlet 支持 ...................................................................................................... 89 Ajax 请求 ......................................................................................................................... 89 二十、 Portlet 协作 ..................................................................................................... 91 Public Render Parameters ............................................................................................... 91 Portlet Events .................................................................................................................. 92 Events 传送复杂对象 ..................................................................................................... 96 总结 ................................................................................................................................. 96 二十一、 Portlet Filter .................................................................................................... 98 什么是 Portlet filter ....................................................................................................... 98 主要概念 ......................................................................................................................... 99 总结 ............................................................................................................................... 101 第五章节 可选概念 ..................................................................................................................... 102 二十二、 缓存 ............................................................................................................... 103 缓存过期 ....................................................................................................................... 103 验证缓存 ....................................................................................................................... 103 总结 ............................................................................................................................... 104 二十三、 用户信息 ....................................................................................................... 105 定义用户属性 ............................................................................................................... 105 访问用户属性 ............................................................................................................... 105 重要注意事项 ............................................................................................................... 106 总结 ............................................................................................................................... 106 二十四、 安全性 ........................................................................................................... 107 介绍 ............................................................................................................................... 107 角色 ............................................................................................................................... 107 安全性代码开发 ........................................................................................................... 107 总结 ............................................................................................................................... 107 二十五、 Portal Context ................................................................................................ 108 二十六、 Portlet 容器运行时 ...................................................................................... 109 动态修改 Portlet 标题 .................................................................................................. 109 二十七、 使用注释的方法 ........................................................................................... 111 GenericPortlet Render Handling ................................................................................... 111 二十八、 Setting next possible Portlet Modes ............................................................. 112 二十九、 Struts2 开发 Portlet 实例 ............................................................................. 113 三十、 Spring mvc 开发 Portlet 实例 ....................................................................... 114 三十一、 附录 ............................................................................................................... 115 修改记录 ....................................................................................................................... 115 名词解释 ....................................................................................................................... 115 Portlet 开发指南 6 疑问 ............................................................................................................................... 116 Portlet 开发指南 7 第一章节 入门介绍 入门介绍主要包括 Portlet 开发中三个基本概念(Portlet、Portlet 容器、Portal)的介绍, Portlet 与 servlet 的关系,以及搭建开发环境,并进行部署。 Portlet 开发指南 8 一、 Portlet 简介 Portlet 与 servlet 一样,都是 JSR 的规范 api 定义,不同的 Portlet 还比较“年轻”,目前 版本还只到 2.0,而 servlet 规范已经相当成熟,发布了多个版本。如果不是十分准确的说, Portlet 只是另一种开发 web 程序的 api,从这个方面说,开发 Portlet 并没有什么神秘的地方, 但是之所以有 Portlet 这个规范,Portlet 适用的场景肯定与 servlet 是不同的,比如开发 Portlet 不但要与 Portlet 容器打交道,还要与 Portal 打交道。读者在学习 Portlet 开发的过程中,可 以不时的用 servlet 的概念与 Portlet 相比较,比较两者的异同,可以达到事半功倍的效果。 刚才说到 Portlet 规范已经出到 2.0,分别是 JSR168,JSR286。JSR 168 目前在业界受到广 泛支持,目前我们开发的大部分代码都是基于 JSR168 的,JSR168 规范支持基本的开发方式, 虽然提供的功能比较少,但是已经基本可以满足日常需要。JSR168 发布三年之后,大多数 支持 Java Portlet Specification V1。0 的门户产品都提供一些附加扩展,以支持更高级的用例, 这些附加的扩展造成了各个门户产品的标准不统一,彼此间的交互协作成了不可避免的问题。 为了更好地规范 Portlet 开发,以适应业界发展,并提供适应于最高级别用例的标准解决方 案,从而为这些高级功能提供互操作性,在 2005 年 11 月开始了 Java Portlet Specification V2.0(称为 JSR 286)的开发,在 2008 年 1 月 Java Portlet Specification V2.0 目前已经正式发 布。JSR 286 规范兼容了 JSR 168,并完善了 JSR 168 的部分功能,并提供了诸多 JSR 168 所 没有的新特性,例如资源服务、事件、Portlet 过滤器、共享呈现参数及 Portlet 窗口等。与 V1。0 类似,V2.0 也将基于 J2EE 1.4,因此可让 Portlet 使用 J2EE 1.4 增强(如 JSP 2.0)。 下面是该新规范的一些主要功能及特性: 1. 资源服务:一种新的通过 Portlet 呈现资源的方式。 2. 事件:通过发送事件和接收事件来实现 Portlet 之间的通信。 3. Portlet 过滤器:与 servlet 过滤器类似,根据 Portlet 请求和响应动态的呈现内容 的变换。存在以下四种类型的 Portlet 过滤器: o Action 过滤器 o Render 过滤器 o Resource 过滤器 o Event 过滤器 4. 共享呈现参数:除了 Portlet 私有的呈现参数之外,新增了可以在 Portlet 之间共享 的呈现参数。 5. Portlet 窗口:提供 Portlet 窗口 ID 供 Portlet 使用 要讲解 Portlet,首先要明确三个概念:Portal、Portlet、Portlet 容器。Portlet 与 Portlet 容器的关系可以比较 servlet 与 servlet 容器的关系,两者是完全一致的,开发者按照 Portlet 规范开发 Portlet,部署在中间件提供商(ibm、oracle、apache)提供的 Portlet 容器中运行, 比较难理解的是 Portal,首先 Portal 是一个 JEE 的 application,Portal 负责提供页面给客户, 其次 Portal 里面的内容是 Portlet 生成出来的。一般的过程是,用户通过 web 客户端向 Portal 发起 http 请求,Portal 解析这些请求,把请求“下发”给 Portlet 容器,Portlet 容器来调用 Portlet,由 Portlet 产生输出返回给 Portlet 容器,Portlet 容器再把输出返回给 Portal,Portal 负责把这些Portlet的输出聚集起来,把内容返回给web客户端。下面来具体描述一下Portal、 Portlet、Portlet 容器三个概念。 Portlet 开发指南 9 什么是 Portal Portlet 规范中是这样定义 Portal 的: A Portal is a web based application that –commonly- provides personalization 、 authentication、content aggregation from different sources and hosts the presentation layer of Information Systems。 Portal 是一个基于 web 的提供个性化、登录授权、从不同的数据源聚集内容基于展现层 的信息系统。具体到 J2EE 领域,Portal 大多数情况是一个符合 J2EE 标准的 ear 包工程。 什么是 Portlet 规范中式这样定义 Portlet 的: A Portlet is an application that provides a specific piece of content (information or service) to be included as part of a Portal page。 It is managed by a Portlet container、 that processes requests and generates dynamic content 一个Portlet是一个基于java技术的被Portlet容器管理的web组建,它可以处理requests、 生成动态的内容输出,一个 Portlet 负责提供 Portal 页面中的某个特定部位的展现内容。 与 servlet 同样,Portlet 的生命周期是被 Portlet 容器来管理的。Portlet 生成的内容也可 以称作 fragment,这些多个 Portlet 生成的多个 fragment 会被 Portal 聚集(aggregate)在一 起展现。不同用户看到的 Portlet 可能不同,这依赖于不同用户对使用 Portlet 的配置。 什么是 Portlet 容器 规范中式这样定义 Portlet 容器的: A Portlet container runs Portlets and provides them with the required runtime environment。 A Portlet container contains Portlets and manages their lifecycle。 It also provides persistent storage for Portlet preferences。 A Portlet container receives requests from the Portal to execute requests on the Portlets hosted by it。 Portlet 容器提供 Portlet 生命周期环境,管理 Portlet 的生命周期,还提供 Portlet preferences 的持久化支持,Portlet 从 Portal 接受请求,然后分发给运行其上的 Portlet。 Portlet 不负责聚集 Portlet 生成的内容,这是 Portal 责任。根据中间件厂商的实现方式 Portlet 容器与 Portal 可以放在一个 application 中实现,也可以放在两个不同的 application 中 实现。 Portlet 开发指南 10 三者关系 下面是以一个用户使用 web 客户端来与 Portal 交互的用力,描述 Portlet、Portlet 容器、 Portal 三者关系、责任: 1. web 客户端通过 http 来对 Portal 发起 request 请求 2. request 请求被 Portal 就收到 3. Portal 分析这个请求是否需要与 Portlet 进行交互 4. 如果需要,则 Portal 通知 Portlet 容器调用 Portlet 处理交互 5. Portal 通过 Portlet 容器得到 Portlet 返回的 fragments 6. Portal 聚集 Portlet 产生的 fragments,生成最终的页面,返回给 web 客户端 版本兼容性 JSR286 规范是向后兼容的,所以所有基于 JSR168 写的代码生成的 war 都可以在 JSR286 容器里面运行。不过下面罗列出一些特例,这些特例会在具体章节说明。 1. RenderResponse。setContentType 已经不再需要在 getWriter 或者 getOutputstream 之前调用了,已经不会产生 IllegalStateException 2. 对于在 Portlet 工程中嵌入 servlet、jsp 调用 getProtocol,JSR168 中返回时 null,JSR286 中返回时 HTTP/1.1 JSR286 的主要新特性 JSR286 对 JSR168 是向后兼容的,JSR286 主要增加了如下新特性:  事件 Events,可以是 Portlet 可以接受、发送事件  公共展现参数 public render parameters,容许 Portlet 之间共享参数  资源服务 resource serving ,提供 Portlet 服务资源的能力  Portlet 拦截器 Portlet filter,容许在 Portlet 的 request、response 之间建立拦 截器 与 J2EE 的版本对应 J2EE servlet jsp JSR168 1.3 2.3 1.2 JSR286 1.4 2.4 2.0 Portlet 开发指南 11 二、 Portlet 与 servlet 的关系 Servlet 规范中是这样定义的: A servlet is a Java technology based web component、 managed by a container、 that generates dynamic content。 Like other Java-based components、 servlets are platform independent Java classes that are compiled to platform neutral bytecode that can be loaded dynamically into and run by a Java enabled web server。 Containers、 sometimes called servlet engines、 are web server extensions that provide servlet functionality。 Servlets interact with web clients via a request/response paradigm implemented by the servlet container。 中文翻译是:servlet 是基于 java 技术的 web 组件,被 servlet 容器管理,生成动态内容。 Servlet 通过 servlet 容器与 web 客户端展开 request、response 交互。 其实很难说出 Portlet 与 servelt 之间的关系,从某个层面说 Portlet 与 servlet 之间没有任 何关系,但是从另一个层面来说又有个千丝万缕的关系,所以这里只是做一些技术上的比较。 Portlets 与 servlets 的相同点:  都是基于 java 技术的 web 组件  都被专门的容器管理  都生成动态内容  生命周期都被容器管理  都是与 web 客户端通过 request/response 的方式交互 Portlets 与 servlets 的不同点:  Portlet 只生成内容片断,Portal 来负责把这些片断聚集在一个页面中。  Portlet 不能直接映射成一个 URL  Web 客户端同 Portlet 交互需要通过 Portal application  Portlets 有多种 request,比如: action request、render request、event request、 resource rquest  Portlets 定义了 Portlet modes 和 window states  同一个 Portlets 可以存在多次在同一个 Portal 页面 Portlet 提供的附加功能但是 servlet 没有提供  Portlets 可以持久化存储和访问数据  Portlets 可以访问用户的信息  Portlets 具有生成 URL 功能,可以让 Portal 来生成访问 Portlet 的链接和请求  Portlets 可以在 session 的两个范围中存储数据,application-wide scope 和 the Portlet private scope  Portlet 之间可以互相接受、发送事件 Portlets 不具备的 servlet 提供的功能  在 render response 中设置字符编码  直接通过 URL 访问 虽然 render 不能设置字符编码,但是 JSR286 中新提供的 serveResource 方法具有完全的 response 控制功能。 就是由于上述的不同,才定义了这个新的 web 组件规范。Portlet 重用了很多 servlet 中 基础的、重要的概念,比如部署方式、类加载、生命周期管理、session 管理、request 分发。 Portlet 开发指南 12 Portlet application 包括 servlet、jsp、Portlet、静态文件、图片等内容,在同一个 Portlet 应用中的 Portlet、servlet、jsp 共享类加载、应用上下文、session。 Portlet 与 servlet/jsp 中的桥梁 Portlet 可以利用 servlet、jsp 生成内容,一个 Portlet 可以使用 request 分发调用 servlet、 jsp,就像一个 servlet 可以调用 servlet、jsp。当一个 servlet 被 Portlet 调用,servlet 的 request 基于 Portlet 的 request,servlet 的 response 基于 Portlet 的 response。比如:  在 Portlet 中 request 设置的属性,Portlet include 调用的 servlet 可以获得。  Portlet 和此 Portlet include 的 servlet、jsp 共享一个输出流。  使在 Portlet 中 session 设置的属性,servlet 可以获得。 用 servlet 生命周期事件 Portlet 中的 PortletContext 、PortletSession 与 servlet 中的 SevletContext、HttpSession 是 有关联关系的,所有这对 servlet 生命周期的 listener 同样对 Portlet 有效。下面的 servlet 中 的 listener 对 Portlet 同样有效:  javax.servlet.ServletContextListener  javax.servlet.ServletContextAttributeListener  javax.servlet.http.HttpSessionActivationListener  javax.servlet.http.HttpSessionAttributeListener  javax.servlet.http.HttpSessionBindingListener  javax.servlet.ServletRequestListener Servlet 容器与 Portlet 容器之间的关系 Portlet 的容器是 servlet 容器的扩展,根据中间件厂商的实现方式 Portlet 容器可以单独 实现也可以基于 servlet 扩展。 Portlet 开发指南 13 三、 开发环境搭建 本文涉及两套开发环境,一个是商业上最成功的 IBM Portal 的开发环境,一个是开源界 Apache 旗下的 Pluto。开发环境有分为开发工具(IDE)、 Portal server 的搭建。 IBM WebSphere Portal 环境搭建 本文使用的是 WebSphere Portal 版本是 6.1.5,开发工具是 RAD 7.5 安装 Portal Server 请参考 Portal 安装手册,待补充。 安装开发工具 RAD 请参考 RAD 安装手册,待补充。 配置 RAD RAD 是一个 Eclipse 的插件扩展,开发习惯和 Eclipse 非常像。需要配置的地方也是普通 使用 eclipse 开发需要配置的地方。 配置 Portal Server 1. 新建服务器 首先需要配置一个 server,这块与配置 tomcat 基本上没啥区别。 Portlet 开发指南 14 Portlet 开发指南 15 Portlet 开发指南 16 配置首选项 1. 去掉验证 Portlet 开发指南 17 2. 文本文件编码 文本文件编码一律统一使用 UTF-8 格式 CSS、HTML、JSP 也使用 UTF-8 格式 Portlet 开发指南 18 Portlet 开发指南 19 Portlet 开发指南 20 Portlet 开发指南 21 Portlet 开发指南 22 3. 缺省包 缺省包使用 :com。Portalguide Portlet 开发指南 23 4. 添加用户库 如果开发 Portlet 需要设置用户库,可以添加 Portlet 开发指南 24 Apache Pluto Portal 环境搭建 Apache Pluto Portal 支持 JSR286,定位是简单容器实现,并不适合在生产环境下使用。 目前 Pluto 的版本是 2.0。2,开发环境可以使用 eclipse 比如 eclipse-jee-helios-SR1-win32 版 本,也可以是 RAD,本文使用了 RAD,因为这样同事开发 IBM、Apache Portal 的时候比较方 便。 安装 Portal Server 1. 下载 Pluto 2.0 binary distribution 2. 解压缩 zip 文件 3. 设置 CATALINA_HOME 环境变量 4. 通过 startup。bat 启动 Apache Pluto 门户 5. 通过 http://192。168。0。198:8080/pluto/Portal 访问门户 6. 修改 pluto-2.0。2\webapps\pluto\WEB-INF\themes\pluto-default-theme。jsp、添加 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> 解决中文乱码问题 7. 通过 tomcat/tomcat 登陆 Portlet 开发指南 25 配置 RAD 配置首选项的设置于 IBM WebSphere Portal 环境是一样的,主要区别是新建 server,Pluto 使 用的 server 就是 Apache Tomcat Version 6。0。26,所以这里我新建的 server 使用 tomcat6 Portlet 开发指南 26 Portlet 开发指南 27 新建好 Portal 服务之后还需要设置一下 tomcat 的模块部署方式。 Portlet 开发指南 28 Portlet 开发指南 29 快速入门 首相给出两个例子,一个是最简单的 hello world,另一个是增删改查,如果现在还不能 理解,没有关系以后的章节会具体讲解。因为这里开发的 Portlet 是符合 JSR168、JSR286 规 范的,所以可以同时在 WebSphere Portal、Pluto Portal 中运行,但是在开发 IDE 中由于开发 工程需要设定不同的配置,所以还是有些不同的,这里采用的方式是首先在 IDE 中开发适合 WebSphere Portal 的工程,通过 RAD 可以直接部署到 WebSphere Portal,如果要部署到 Pluto Portal 可以通过工程打成 war 包,然后把 war 包稍加修改部署到 Pluto Portal 中。 HelloPortlet 新建 Portlet Portlet 开发指南 30 Portlet 开发指南 31 Portlet 开发指南 32 Portlet 开发指南 33 部署 Portlet 开发指南 34 CRUDPortlet CrudPortlet 主要实现增删改查功能,具体请见代码实现,后续章节会讲解 在 Pluto Portlet 中部署 在 Pluto Portal 中部署唯一的区别是要在 web.xml 中添加 Portlet 的定义,比如: PG03FirstPortlet org。apache。pluto。container。driver。PortletServlet Portlet-name PG03FirstPortlet 1 Portlet 开发指南 35 PG03FirstPortlet /PlutoInvoker/PG03FirstPortlet 以 helloPortlet 为例整个过程如下 1. 使用 RAD 导出 war 包 PG03FirstPortlet。war 2. 修改 web.xml,添加 Portlet 定义 3. 把 war 包部署在 Pluto Portal 中,因为 Pluto Portal 就是 tomcat,所以可以直接把 PG03FirstPortlet。war 拷贝到 webapp 目录下面。 4. 登陆 Pluto Portal,添加测试页面,在测试页面中添加 PG03FirstPortlet。 CRUDPortlet 部署过程如下 5. 使用 RAD 导出 war 包 ContactsPortlet。war 6. 修改 web.xml,添加 Portlet 定义,添加数据源定义 7. 在 META-INF 中添加 context。xml 8. 把 war 包部署在 Pluto Portal 中,因为 Pluto Portal 就是 tomcat,所以可以直接把 ContactsPortlet。war 拷贝到 webapp 目录下面。 9. 在 pluto-2.0。2\lib 中添加 jstl、jdbc 的 jar 包。 10. 登陆 Pluto Portal,添加测试页面,在测试页面中添加 ContactsPortlet Portlet 开发指南 36 第二章节 独有概念 本章介绍 Portlet 独有的一些概念,比如 Portlet url、Portlet mode、window state、 preferences 等。 Portlet 开发指南 37 四、 Portlet 概念 Portlet 定义 Portlet 提供了面向服务(SOA)的界面(User Interface),而且规范定了 events、 application sessions、 public render parameters 等特性来提供组件之间的交互的能力。Portal 提供整体页 面,Portlet 提供页面中一个区域,Portal 负责把 Portlet 组合起来。值得注意的是规范都是针 对 Portlet 和 Portlet 容器的,并没有定义门户的实现方式。 Portlet 是 Portal 页面中的一个区域 Portlet 负责生成一个个的页面片断,Portal 负责把这些片断聚集起来,Portal 还可以添 加一些 title control buttons 元素。下图是一个页面的示意图,可以看到这个页面中共包括四 个 Portlet。 请记住上图只是一个 Portal 实现的例子,可能存在其他的实现方式,这里要强调的是 Portal 中除了能聚集 Portlet 还能有其他页面片断。 Portlet 开发指南 38 Portal 页面的生成 Portlet 是运行在 Portlet 容器中的,Portlet 容器服务通过 Portlet 来生成内容,通常情况 下,Portlet 容器把生成的内容返给 Portal,Portal 负责把生成的内容组合到一个页面,之后 把页面发送给客户端(比如 web 客户端)。整个流程如下图: Portal 页面请求 Portal 的请求顺序大概是这样的,客户端访问 Portal 页面,Portal 会分析出需要处理 request 的 Portlet 列表,Portal 通过 Portlet 容器调用 Portlet,Portlet 处理请求,之后通过 Portlet 容器返回内容,Portal 把 Portlet 产生的内容片断聚集起来返回给客户端。 Portlet 和 Web 框架 Portlet 规范本身就提供了一套清晰的请求处理流程,使用 processAction 和 processEvent 处理提交请求,使用 render 和 serveResource 处理展现请求。Portlet 和 web 框架(比如 spring mvc、struts)可以配合使用,具体后续分析。 Portlet 开发指南 39 五、 Portlet URLs 由于 Portlet 不像 servlet 有便准确定的 URL 对应,但是浏览器最终还是需要通过 URL 来 访问 Portlet 的。所有 Portlet 要提供生成 Portlet URL 的功能。这些通过 Portlet 容器为每个 Portlet 生成的可以请求相应 Portlet 的 URL 就叫做 Portlet URL。 PortletAPI 中定义了 PortletURL 和 ResourceURL 两个接口,Portlet 容器生成的必须是 PortletURL 或者 ResourceURL 接口对 应的对象。Portlet 使用 PortletResponse 接口 的 createActionURL、 createRenderURL, createResourceURL 三个方法来生成 Portlet URL。 Render URL 必须是幂等的,也就意味着不能在 render 方法中作修改状态、做后台数据 的工作,需要特别注意,不能把 render URL 用在 form 中,否则容器将不会把 form 中的参数 传输给 Portlet。 BaseURL 接口 BaseURL 接口提供了所有 Portlet URL 的公共功能,它有两个子接口 PortletURL 和 ResourceURL。可以通过 PortletResponse 对象调用 createActionURL、 createRenderURL、 createResourceURL 来 生 成 PortletURL 和 ResourceURL 对象。BaseURL 对 象 可 以 调 用 setParameter 和 setParameters 来添加设置参数。Portlet 可以调用 BaseURL 的 setProperty、 Portlet 开发指南 40 addProperty 方法来设置属性。 PrintWriter writer=response.getWriter(); PortletURL URL = response.createRenderURL(); URL.setParameter("customer"、"foo.com"); URL.setParameter("show"、"summary"); Writer.print("Summary"); 包含 Portlet Mode 和 Window State 信息 可以调用 PortletURL 的 setWindowState 和 setPortletMode 来设置 state、mode。 PrintWriter writer=response.getWriter(); PortletURL actionURL = response.createActionURL(); actionURL.setParameter("paymentMethod"、"creditCardInProfile"); actionURL.setWindowState(WindowState.MAXIMIZED); writer.print("
"); writer.print(""); writer.print("
"); Portlet URL 安全性 可以调用 PortletURL 的 setSecure 来设置 Portlet 安全性,如果没有调用 setSecure,默认 Portlet 使用安全性策略与 Portal 一致。 总结 本章介绍了 Portlet URL 的使用方法,请注意在 Portlet 中用代码生成 URL 的方式可以被 在 jsp 中直接使用标签来代替。 对于使用 JSR 168 API 的 URL 生成,Portlet 始终必须在将 URL 对象写入到标记中之 前,使用 PortletURL.toString() 方法将其转换为字符串。由于 WebSphere Portal 中的 URL 的 丰富性质和长度不叫长,此字符串转换会负面影响创建大量 URL 的 Portlet 的性能。 JSR 286 添加了 write() 方法,允许您将 URL 对象直接流向响应写出程序,从而避免创 建临时字符串对象。应该使用此方法来写出 URL。与 toString() 方法不同,此方法还自动提 Portlet 开发指南 41 供 XML 和 HTML 规范所要求的 URL 的正确 XML 转义。类似的注意事项同样适用于 jsp 中的 Portlet URL 标记:直接写出 URL 的标记语法优先于在临时字符串变量中存储生成的 URL 的标记语法。 Portlet 开发指南 42 六、 Portlet Modes Portlet 的 modes 用来指定访问的 render 方式,默认情况下 Portlet 有三种 modes,分别 是 view,edit,help,与其对应默认有三个调用方法分别是 doview,doedit,deohelp。一般 情况下 Portal 会对用户访问 view,edit,help 的权限做一些限制,比如可以让所有用户访问 view,help mode,但是只有特殊权限的用户可以访问 edit modes。用户可以直接通过门户来 修改当前 Portlet 的 mode,门户提供的此功能是根据不同厂商而定的,当然也可以通过编程 的方式调用标准的 api 来修改修改当前 Portlet 的 mode。 查看 Portlet Mode view mode 通过名字就可以理解,是用来 Portlet 日常展现的 modes,Portlet 必须具有此 mode。Portlet 在 view mode 的时候后台访问的是 doView 方法,开发者通过重载 GenericPortlet 抽象类的 doView 方法来自定义此 Portlet 的 view mode 展现内容。 编辑 Portlet Mode 一般来说 edit mode 用来设置用户的个性化设置,可以通过 preferences 来设置,一般来 说不是所有用户都具备使用 edit mode 的权限。Edit 是一个可选的 modes。Portlet 在 edit mode 的时候后台访问的是 doEdit 方法,开发者通过重载 GenericPortlet 抽象类的 doEdit 方法来自 定义此 Portlet 的 edit mode 展现内容。 帮助 Portlet Mode Help mode 是用来提供 Portlet 的帮助信息的 mode,help 同样也是一个可选的 mode。 Portlet 在 help mode 的时候后台访问的是 doHelp 方法,开发者通过重载 GenericPortlet 抽象 类的 doHelp 方法来自定义此 Portlet 的 help mode 展现内容。 自定义 Portlet Modes 除了默认提供的三个 mode,可以也可以自己来定义 mode,比如 ibm 的 Portal 中就自 己定义了两种 mode(config、edit_defaults)。 首先需要在 Portlet.xml 进行定义。 Portlet 开发指南 43 config edit_defaults 之后要重写请求分发的 doDispatch 方法 protected void doDispatch(RenderRequest request、 RenderResponse response) throws PortletException、 IOException { if (!WindowState。MINIMIZED。equals(request。getWindowState())){ PortletMode mode = request。getPortletMode(); if (CUSTOM_CONFIG_MODE。equals(mode)) { doCustomConfigure(request、 response); return; } else if (CUSTOM_EDIT_DEFAULTS_MODE。equals(mode)) { doCustomEditDefaults(request、 response); return; } } super。doDispatch(request、 response); } 受支持的 Portlet Modes 每个 Portlet 必须定义它们支持的 mode 类型,portlet.xml 中定义,如下图: text/html view edit help config edit_defaults Portlet 开发指南 44 七、 Window States Portlet state 主要定义了某个 Portlet 占所在 Portal 页面的大小,Portlet 默认共有三种 state, 分别是 normal、maximized、minimized,normal 代表正常大小,maximized 代表最大化, minimized 代表最小化。 正常 Window State 正常状态下,Portal 会按照正常的设定大小来展现。Portlet 会与其他 portlet 共享此 portal 页面,共同在 portal 页面中展现内容。 最大化 Window State 最大化情况下,Portal 会在整个页面只展现这一个 Portlet,或者用大部分页面来展现这 个 Portlet,这取决有 Portal 的实现。 最小化 Window State 最小化情况下 Portal 页面中只展现 Portlet 的 title,不展现具体内容。 自定义 Window States 客户可以自定义 window 的状态,比如一半大小,不过对于笔者开来,这样通常意义不 大,很少有这样的需求 支持的 Window State 如果没有特殊定义,所有 portlet 默认是支持 normal、maximized、minimized 这三种 window state。 Portlet 开发指南 45 八、 Portlet Preferences Portlet 通过配置功能来提供个性化的内容展现,配置信息必须有一个持久化的机制, JSR168 规范中规定了这个机制,并提供 Portlet preferences 来作为具体调用的方式。值得说 明的是,Portlet preferences 只是用来提供 Portlet 配置信息的持久化功能,并不能用来替代 数据库。 PortletPreferences 接口 Portlet 使用 PortletPreferences 接口来调用 preferences,Portlet 可以在处理请求的时候 访问 PortletPreferences,但是只能在 processAction、 processEvent 和 serveResource 方法中 修改 Preferences、这点需要注意,不能在 render 中修改 Preferences,否则可能造成 Preferences 的混乱。Preferences 中保存的对象只能是 String,也可以设置为 null。 PortletPreferences 接口中提供如下方法  getNames  getValue  setValue  getValues  setValues  getMap  isReadOnly  reset  store 具体使用方式见下面代码 PortletPreferences prefs = request.getPreferences(); try { prefs.setValue(TEST_KEY,request.getParameter(CONFIG_TEXT)); prefs.store(); } catch( ReadOnlyException roe ) { } catch( ValidatorException ve ) { } Preference Attributes 范围 Preference Attributes 也有范围得概念,但是规范中并没有对这块定义的特别明确,究 其原因是因为各个门户的实现厂商会利用 preference 的概念来对门户的个性化提供支持,但 是实现的理论基础可能不一样,所以这块没有特别进行明确清楚。 Portlet 开发指南 46 Preference Attributes 定义 Preference 可以预先在 Portlet.xml 里面定义作为出事值,可以在定义是设置此属性是否 为只读。下面是一个例子: ... PreferredStockSymbols FOO XYZ true quotesFeedURL http://www.foomarket.com/quotes Portlet 开发指南 47 第三章节 基础概念 本章节主要描述 Portlet 开发中最重要、基础的概念,比如 Portlet config、context、request、 response、session 等。 Portlet 开发指南 48 九、 Portlet 生命周期接口 Portlet 规范中共有三个接口定义了 Portlet 的生命周期,分别是 Portlet、EventPortlet 和 ResourceServingPortlet 接口。Portlet 接口是 Portlet API 中的主要点和关键点。所有 Portlet 直 接或者间接的实现这个接口。Portlet 可以选择性的实现 EventPortlet 和 ResourceServingPortlet 接口来实现附加的功能。GenericPortlet 类实现了 Portlet、EventPortlet 和 ResourceServingPortlet 三个接口,并且提供了一些实用的默认实现。开发者可以直接继承 GenericPortlet 类来方便开发 Portlet。 Portlet 实例的数量 Portlet 部署描述符中(Portlet.xml)中定义了 Portlet 容器怎么创建 Portlet 实例。默认情 况下,Portlet 不是在分布式环境中,Portlet 容器必须实例化和使用唯一的一个 Portlet 实例 对象。如果是在分布式环境中每个 jvm 维护一个 Portlet 实例对象。不过这些都是对 Portlet 容器实现厂商的规定,开发者一般不用过多关注。 Portlet 生命周期 和 servlet 一样,Portlet 容器管理着 Portlet 的生命周期,Portlet 生命周期定义了 Portlet 怎么被加载、实例化、初始化,怎么接受客户端发过来的 request,怎么销毁。Portlet 生命 周期通过 Portlet 接口中的 init、 processAction、render 和 destroy 几个方法来实现。当然 EventPortlet 和 ResourceServingPortlet 接口中定义了附加的一些方法。 加载和实例化 Portlet 容器负责加载和实例化 Portlet。加载和实例化可以发生在 Portlet 刚部署时,亦 可以延时到有请求要访问这个 Portlet。Portlet 容器加载 Portlet 的类加载器要与 servlet 容器 加载 servlet 的类加载器一致。当 Portlet 容器加载好 Portlet 后就会实例化这个 Portlet。 初始化 当 Portlet 被实例化之后,Portlet 容器必须先初始化这个 Portlet 才能让请求访问这个 Portlet。Portlet 容器调用 Portlet 接口的 init 方法初始化 Portlet。这里很像 servlet 的方式, 在 Portlet 接口的 init 方法中可以调用 PortletConfig 接口的对象,通过 PortletConfig 的实例可 Portlet 开发指南 49 以访问 Portlet.xml 中的一些初始化参数和 ResourceBundle。和 servlet 一样可以通过 PortletConfig 访问 PortletContext 接口的对象,PortletContext 是用来保存上下问信息的。 PortletConfig 和 PortletContext 介绍请见后续章节。 在初始化的过程中,Portlet 对象可能会抛出 UnavailableException 或者 PortletException 异常,此时 Portlet 容器必须不能把此 Portlet 对象作为可接受请求状态,必须释放此 Portlet 对象。destory 方法也不能调用,因为并没有初始化成功。Portlet 容器可以在失败之后重新 尝试实例化和初始化此 Portlet 对象。 开发者不能通过在Portlet中添加静态变量和静态方法的方式来达到初始化资源的目的, 在 init 被调用之前,不应该使用其他方式来初始化资源,所以最佳实践是在 init 方法中初始 化这些资源。 结束服务 Portlet 容器没有必要一直加载这 Portlet 的实例,这要看中间件实现厂商的决定。当 Portlet 容器决定暂时停掉某个 Portlet 的服务的时候,它会调用 destory 方法,开发者可以在 desyory 方法中作一些释放资源和保存必要信息。例如 Portlet 容器可以在决定减少服务器内 容资源或者 app server 停止的时候来调用这个方法,什么时间、什么策略来调用主要看中间 件实现厂商的决定。当 Portlet 容器调用 destory 之前,它会让目前还在执行的线程执行完成, 当然为了避免永远等待下去,Portlet 容器也会有相应的策略来结束这种等待。一旦 destory 方法被调用,Portlet 就不能再接受任何请求,如果容器想重启启动这个 Portlet,就要重复之 前的加载、实例化、初始化过程。如果在在调用 destory 的过程中出现了 RuntimeException, Portlet 容器必须保证 Portlet 可以正常毁灭。当 Portlet 被毁灭掉之后,Portlet 对应的对象就 会被释放,等待垃圾收集。 Portlet 的个性化 Portlet model 利用轻量级的模式提供所有请求的访问,这保证了 Portlet 实例尽可能的 少并且对大量用户访问提供了可扩展性。为了区别不能级别的个性化,Portlet 规范中定义了 Portlet entity 和 Portlet window。 Portlet 定义 和 Portlet Entity Portlet.xml 对 Portlet 的定义中可以包括一组带有默认值的 preferences,这组 preferences 用来创建 preferences 对象。在运行时,当 Portlet 被 request 请求的时候,Portlet 自身会与 一组preferences相关联。这些与特定的preferences绑定的Portlet产生的结果被定义成Portlet Entity。Portlet Entity 概念是抽象的,并没有一个具体的对象(页面片断)与之相关联。这些 preferences 一般定义在 Portlet.xml 里面,Portlet 中的行为和内容一般会与这些 preferences 相关联,当然 Portal 和 Portlet 容器也提供了途径在运行时读取、增加和修改这些 preferences。 首选项对象的操作、管理与配置和 Portlet 窗口的创建是通过 Portal 或 Portlet 容器的实 Portlet 开发指南 50 现来进行。该实现也可以提供其它高级特征,如首选项对象的分线管理或首选项属性的级联 变更。 Portlet Window 相对于 Portal 这个具体的概念,Portlet 对用户来说还是比较抽象化的。Portal 中会包含 一个到多个 Portlet window(页面片断),在 Portal 页面中的每个 Portlet,我们叫做一个 Portlet window。Portlet entity 通常会对应多个 Portlet window,比如普通用户可以通过 Portlet entity 的一个 Portlet window 来查看信息,管理员可以通过这个 Portlet entity 的赢一个 Portlet window 来修改 preferences 来达到管理此 Portlet entity 的目的。 没有 Portlet window 对 应 一 个 唯 一 的 ID ,此 window ID 可以通过 PortletRequest.getWindowID()来获得。 Request 请求处理 当 Portlet 对象被初始化的时候,Portlet 对象就可以处理 Portlet 容器发过来的 request 请求了。Portlet 接口定义了两个方法来处理请求,分别是 processAction 方法和 render 方法。 Portlet 还 可 以 通 过 实现 EventPortlet 或者 ResourceServingPortlet 接口, 从 而 通 过 processEvent 和 serveResource 方法来处理请求。 当 Portlet 容器调用 Portlet 的 processAction 方法的时候,Portlet request 对象被封装成 一个 action request,然后发送给 processAction 方法。作为这个 action 处理的结果,这个 Portlet 可能发布一些 Portlet event,这时候另外的 Portlet 的 processEvent 会被调用,在 processEvent 方法中会有一个 event request 对象包含着事件请求。 当 Portlet 容器调用 Portlet 的 render 方法的时候,Portlet request 对象被封装成一个 render request 对象。 当 Portlet 容器调用 Portlet 的 serveResource 方法的时候,Portlet request 对象被封装成 一个 resource request 对象。 通常情况下 Portlet 的请求是 URL 触发的,这些有 Portlet 生成的 URL 叫做 Portlet URL。 Portlet URL 分为三类 action URLs、 render URLs 和 resource URLs。 假设这种场景,一个 Portal 页面中有 n 个 Portlet(n>1),那么一个 Portlet action 请求会 触发一个 antion 请求、0-m 个 event 请求,n 个 render 请求。一个 render 请求,会触发 n 个 render 请求。一个 resource 请求,会触发一个 resource 请求。 如果是一个 process 请求,那个 Portlet 容器必须先调用这个 Portlet 的 process action 方 法。等待 process 方法完成之后才能调用 event 方法。等 event 方法调用完成之后再调用这 个页面中所有 Portlet 的 render 方法,除非某个 Portlet 定义了缓存。值得注意的是 render 方法的调用时没有特定顺序的。 如果是一个 render 请求,Portlet 容器调用页面中所有 Portlet 的 render 方法,除非某个 Portlet 定义了缓存。值得注意的是 render 方法的调用时没有特定顺序的。 如果是一个 resource 请求,Portlet 容器调用页面中所有 Portlet 的 serveResource 方法, 除非某个 Portlet 定义了缓存。 Portlet 开发指南 51 如果 Portlet 中定了缓存,Portal 可以按照策略不调用 Portlet 的 render、serveResource 请求。 之前也说过如果某个 Portlet 一段时间没有被请求,可能被 Portlet 容器给销毁掉。 Action Request 一般情况下 action Request 请求用来修改数据库、Portlet preferences 等信息。 processAction 方法有两个参数 ActionRequest 和 ActionResponse。 ActionRequest 提供了获得 action 参数、window state、Portlet mode,Portal context、Portlet session、Portlet preferences 的途径。 当处理 action 请求的时候,Portlet 可以指示 Portlet 容器 redirect 到一个 URL。通过在 processAction 中调用 redirect 方法,这时与 servlet 进行页面的 redirect 达到的效果一样。 可以通过 ActionResponse 对象来改变 window 状态、Portlet 模式,要修改 Portlet 模式, 前提是当前用户有这个权限来进入到相关的 Portlet 模式。 可以在处理 action 请求的时候调用 ActionResponse 对象来设置 render 参数。 Portlet 可以把一个 action 请求委派给 servlet 处理。 Portlet 可以通过 ActionResponse 的 setEvent 方法来发布事件。 Event Request 一般情况下 event 用来在不同 Portlet 之间进行协作。 Portlet 开发指南 52 EventPortlet 接口的 processEvent 方法有两个参数 EventRequest 和 EventResponse。 可以从 EventRequest 中得到 event payload、window state、Portlet mode、render parameters、Portal context、Portlet session 、Portlet preferences。 Portlet 可以在通过 EventResponse 来更改 window 状态、Portlet 模式,要修改 Portlet 模式,前提是当前用户有这个权限来进入到相关的 Portlet 模式。 可以在 event 请求的时候调用 EventResponse 对象来设置 render 参数。 Portlet 可以把一个 event 请求委派给 servlet 处理。 Portlet 可以通过 EventResponse 的 setEvent 方法来发布事件。 Render Request 一般情况下 render 请求用来产生展现内容。 Portlet 接口的 render 方法有两个参数 RenderRequest 和 RenderResponse。 可以从 RenderRequest 得到请求参数、window state、 Portlet mode、 render parameters、 Portal context、Portlet session、Portlet preferences。 Portlet 可以通过本身的 renderResponse 来产生内容,或者委托给 servlet\jsp。 Render 请求不应该触发任何的状态的改变,也就是说 render 请求时幂等的。 Resource Request Resource request 是为了服务资源和内容片断,可以通过实现 ResourceServingPortlet 接 口来做此工作。 ResourceServingPortlet 接 口 的 serveResource 方法有两个参 ResourceRequest 和 ResourceResponse。 可以从 ResourceRequest 得到请求参数、window state、 Portlet mode、 render parameters、 Portal context、 Portlet session 、 Portlet preferences 数据。 Portlet 可以通过本身的 serveResource 来产生内容,或者委托给 servlet\jsp。 GenericPortlet GenericPortlet 是一个抽象类,它实现了 Portlet、EventPortlet、ResourceServingPortlet 三个接口,所以它提供了为 events、resource 和 render 请求提供服务的能力,我们开发的 时候一般继承 GenericPortlet 类。 Action Dispatching GenericPortlet 中的 processAction 来处理分发,也可以使用注解的方式。 Portlet 开发指南 53 Event Dispatching GenericPortlet 中的 processEvent 来处理分发,也可以使用注解的方式。 Resource Serving Dispatching GenericPortlet 中的 serveTesource 来处理分发,也可以使用注解的方式。 Rendering Dispatching GenericPortlet 中的 render 来处理分发,也可以使用注解的方式。不过一般情况下 render 方法会根据 Portlet state 把请求分发给  doView 用来处理 VIEW 请求  doEdit 用来处理 EDIT 请求  doHelp 用来处理 HELP 请求 并行执行的请求 由于Portlet容器处理Portlet请求的时候是并行的,所以Portlet开发者必须处理话Portlet 的并行问题。 请求处理异常 在处理 Portlet 请 求 的 时 候 可 能 会 抛 PortletException 、 PortletSecurityException 、 UnavailableException。 线程安全 与 servlet 一样,在实现 Portlet 是要注意线程安全的问题。 Portlet 开发指南 54 总结 Portlet 规范中共有三个接口定义了 Portlet 的生命周期,分别是 Portlet、EventPortlet 和 ResourceServingPortlet 接口。 通过实现这三个接口,共有四个方法来分别处理四种不同的请求,分别是 render(Portlet 接口定义)方法来处理 render 请求,processAction(Portlet 接口定义)方法来处理 action 请求,processEvent(EventPortlet 接口中定义)方法来处理 event 请求,serveResource (ResourceServingPortlet 接口中定义)方法来处理 resource 请求。 GenericPortlet 中实现了 Portlet、EventPortlet 和 ResourceServingPortlet 三个接口,并且 提供了一些默认方法的实现。可以通过直接继承抽象类 GenericPortlet 来达到简化开发的目 的。 Portlet 的生命周期与 servlet 生命周期有很多可比性,Portlet 容器管理着 Portlet 的生命 周期,Portlet 生命周期定义了 Portlet 怎么被加载、实例化、初始化,怎么接受客户端发过 来的 request,怎么销毁。 Portlet 开发指南 55 十、 Portlet Config Portletconfig 对象提供了 Portlet 初始化时需要使用的信息,Portletconfig 还提供了访问 Portlet context、default event namespace、public render parameter names、resource bundle 的 途径。这些信息都是在 Portlet.xml 中定义。 初始化参数 可以通过 PortletConfig 接口的 getInitParameterNames 和 getInitParameter 方法从 Portlet.xml 中获取初始化参数,代码如下: String initPara = this.getInitParameter("Portlet286.initpara"); Log.info(initPara); Enumeration initParas = getInitParameterNames(); while (initParas.hasMoreElements()) { initPara = initParas.nextElement().toString(); log.info(getInitParameter(initPara)); } log.info(this.getInitParameterNames().toString()); Portlet Resource Bundle 可以在 Portlet.xml 或者在资源文件里面定义 Portlet 标题、关键字等信息,这些信息用 来在 Portlet 展现的时候渲染 Portlet 的 title。比如在 portle。xml 里面,代码如下: PLT6ResourceBundlePortlet PLT6ResourceBundlePortlet PLT6ResourceBundlePortlet 当然也可以在 resource-bundle 里面定义,代码如下: Com.Portlet286.plt6Portlet.nl.PLT6ResourceBundlePortletResource 我们一般建议在资源文件中定义,这样可以很好的适应国际化的需要。 Portlet 开发指南 56 在 GenericPortlet 类中定义的 render 方法使用 PortletConfig 对象引用的 ResourceBundle 对象来设置 Portlet 的 title 默认事件命名空间 可以通过 PortletConfig 接口的 getDefaultNamespace 方法从 Portlet.xml 中获取默认的命 名空间,在 events 和 public render parameters 中需要命名空间。 公告展现参数 可以通过 PortletConfig 接口的 getPublicRenderParameterNames 方法从 Portlet.xml 中获取 到此 Portlet 支持的 public render parameter。 发布事件 可以通过 PortletConfig 接口的 getPublishingEventQNames 方法从 Portlet.xml 中获取到此 Portlet 支持的 publish event。 处理事件 使用 PortletConfig 接口的 getProcessingEventQNames 方法从 Portlet.xml 中获取到此 Portlet 支持的 Process event。 支持的国际化 使用 PortletConfig 接口的 getSupportedLocales 方法从 Portlet.xml 中获取到此 Portlet 支 持的 local(国际化)。 支持的运行时选项 使用 PortletConfig 接口的 getContainerRuntimeOptions 方法从 Portlet.xml 中获取到此 Portlet 支持的 Portlet 容器运行时。 容器运行时选项允许 Portlet 从门户和 Portlet 容器请求特定的运行时行为。 Portlet 开发指南 57 总结 Portletconfig 对象提供了 Portlet 初始化时需要使用的信息,Portletconfig 还提供了访问 Portlet context、default event namespace、public render parameter names、resource bundle 的 途径。这些信息都是在 Portlet.xml 中定义。 Portlet 开发指南 58 十一、 Portlet Context Portlet context 与 servlet context 在概念上是一致的,都是用来存储、获取 Portlet 全局 context 的对象。 Portlet Context 范围 Portlet 容器中每一个实例化的 Portlet 都只有一个 PortletContext 对象实例,如果部署在 分布式环境中没没有 jvm 都会有一个 PortletContext 对象实例。 Portlet Context 功能 Portletcontext 的作用与 servletcontext 一致,Portletcontext 在所在 Portlet 的实例是全局 的,用户可以通过调用api来从Portletcontext存放属性和取回属性,也可以通过Portletcontext 来初始化一些参数,获取一个到 servlet 和 jsp 的分发器(dispatcher)。 与 Servlet Context 关系 一个 Portlet application 是普通的 web application 的扩展版本,所以 Portlet application 同 样具有 servlet context,可以说 Portletcontext 的实现上使用了大量 servlet context 的功能, 但是需要强调的是两个对象是完全不同的两个对象。 Context 范围的初始化参数,对 Portlet context 和 servlet context 来说都是一样的,都是 在 web.xml 中定义,而且 Portlet context 和 servlet context 中的属性是共享的。Portlet context 必须提供访问 servlet context 中资源的方法。Portlet context 必须与 servlet context 具有同样 的临时目录。Portlet context 必须与 servlet context 对于虚拟主机和重新加载策略具有同样行 为和功能。 Portlet context 与 servlet context 有同样的方法  getAttribute  getAttributeNames  getInitParameter  getInitParameterNames  getMimeType  getRealPath  getResource  getResourcePaths  getResourceAsStream  log  removeAttribute Portlet 开发指南 59  setAttribute 总结 Portlet context 的概念与 servle tcontext 的概念基本一致,而且可以 Portlet context 和 servlet context 之间是可以共享属性的。 Portlet 开发指南 60 十二、 Portlet Requests PortletRequest 封装了所有客户端的请求信息,比如请求 parameters、request content data、 Portlet mode、 window state 等等。Portlet 可以通过 processAction、 processEvent、 serveResource、 render 方法来获取 PortletRequest 对象。 PortletRequest 接口 与 processAction、 processEvent、 serveResource、 render 四个方法相对应,共有四个 具体的 request 对象供处理请求的方法使用,分别是 ActionRequest、EventRequest、 ResourceRequest、RenderRequest。PortletRequest 接口定义了所有 request 接口的公共功能。 ClientDataquest 提供了 ActionRequest 和 ResourceRequest 的公共功能。Request 各个接口的 类图请见下图: Request 参数 PortletRequest 接口可以通过如下方法获取参数  getParameter  getParameterNames Portlet 开发指南 61  getParameterValues  getParameterMap  getPublicParameterMap  getPrivateParameterMap Form 表单和查询参数 如果使用 form 表单进行提交,form 最好是 post 方式。 Action 和 Event 请求参数 在 action、event 方法中接受到得参数不能传递到之后需要执行的 render 里面,在 action 方法中接受到的参数也不会传递到接下来执行的 event 方法中。如果确实需要在 render 中使 用参数,需要在 action、event 的 response 调用 setRenderParameter 或者 setRenderParameters 方法。 Render 请求参数 如果有多个 Portlet 在一个页面中,从客户的 web 客户端中触发了多次请求,如果其中 一次的请求不是针对某个 Portlet,那么这个 Portlet 接受到的 render 请求获取的参数与这个 Portlet 前一次接受到的请求时获取的参数是一样的。 如果一个 Portlet 接受到一个事件,是因为在同一个页面中的针对其他 Portlet 产生的(即 其他 Portlet 发起事件),那么这个 Portlet 接受到的 render 请求获取的参数与这个 Portlet 前 一次接受到的请求时获取的参数是一样的。 如果一个 Portlet 接受到一个 render 请求,是因为之前的 action、event 请求产生的,那 么这个这个 render 请求的参数是在 action、event 中设置的。 如果一个 Portlet 接受的 render 请求就是因为一个针对此 Portlet 的 render 请求,那么接 受到的参数就是 Portlet URL 中设置的参数。 总之,Portal 提供修改 Portlet mode 和 window state 的方法,URL 也是 Portal 负责生成, URL 触发的 render 请求中的参数是会被保存的。Portlet 不能收到其他 Portlet 的参数。Portlet 如果收到一个 action、event 请求 render 参数就会自动清除。 Resource 请求参数 Resource 请求参数是通过 resource URL 中传递过来的。 Portlet 开发指南 62 Public Render 参数 为了和在同一个 Portlet application 或者跨 Portlet application 中 Portlet 之间可以进行协 作,Portlet 可以在 Portlet.xml 中声明 public render parameters,public render parameters 在 processAction、 processEvent、 render、 serveResource 都可以获得和修改。 Portlet 容 器 只 能 把 public render 参 数 发 送 给 在 Portlet.xml 中 定 义 了 “supported-public-render-parameter“的 Portlet。 如果 Portlet 系统删除掉某个 public render 参数,可以使用 StateAwareResponse 接口或 者 PortletURL 接口的 removePublicRenderParameter 方法。 Portlet 获取私有和公共的参数用的都是 getParameter 方法,但是获取参数 Map 是使用 的方法是分开的,分别是 getPrivateParameterMap 和 getPublicParameterMap。 额外 Request 参数 Portal、Portlet 容器可以额外定义一些参数来支持本身 Portal 应用的运转(以 javax.Portlet 开头),但是这些参数对 Portlet 来说是不可见的。 Request 属性 Request 属性不能在 action、resource、event 和 render 请求中共享。属性可以用来在 Portlet 和 servlet 中共享信息,在 PortletRequest 接口中有如下操作属性的方法:  getAttribute  getAttributeNames  setAttribute  removeAttribute 以 javax.Portlet.开头的属性名称是被保留的,开发者请不要使用。 Request 属性中获取用户信息 Portlet 可以通过 PortletRequest.USER_INFO 属性访问用户信息。 Request Properties 可以通过 PortletRequest 接口的如下方法访问一些 properties,这些 properties 是 Portal、 Portlet 容器的一些特定的 properties,或者有可能是 http header 中的信息。  getProperty Portlet 开发指南 63  getProperties  getPropertyNames cookie 可以通过 PortletRequest 接口的 getCookies 方法来获取 cookie 信息。 Request Context Path 可以通过 PortletRequest 接口的 getContextPath 方法来获取上下文路径 安全相关信息 可以通过 PortletRequest 接口的这些方法访问一些用户信息  getAuthType  getRemoteUser  getUserPrincipal  isUserInRole  isSecure Response Content 类型 Portlet 可以通过 getResponseContentType 来获取放回类型。 Portlet 支持多种 content types,默认情况下返回类型是 String 国际化 可以通过 PortletRequest 接口的 getLocale 方法来获取此 Portlet 的方言。 Portlet Mode 可以通过 PortletRequest 接口的 getPortletMode 方法来获取此 Portlet 的 mode。 Portlet 开发指南 64 Window State 可以通过 PortletRequest 接口的 getWindowState 方法来获取此 Portlet 的 state。 访问 Portlet Window ID 可以通过 PortletRequest 接口的 getWindowID 方法来获取此 Portlet 的 WindowID。 ClientDataRequest 接口 ClientDataRequest 接口继承 PortletRequest 接口, 提 供 ActionRequest 和 ResourceRequest 接口的一些公共功能。ClientDataRequest 主要提供的功能是获取 http 请求 信息,比如输入流。 接受上传数据 当有 post 表单把数 据 流 上 传 到 了 服 务 器 时,ClientDataRequest 接口可 通 过 getPortletInputStream 和 getReader 来获取数据流。 为了管理上传到服务器的数据流,ClientDataRequest 接口提供了如下的方法。  getContentType  getCharacterEncoding  setCharacterEncoding  getContentLength setCharacterEncoding 方法只在 getReader 之前设置时,起到设置字符流的作用。 ActionRequest 接口 ActionRequest 接口继承 ClientDataRequest 接口,目前 ActionRequest 没有提供额外什么 功能。 ResourceRequest 接口 ResourceRequest 接口继承 ClientDataRequest 接口。ResourceRequest 接口还提供了 Portlet 开发指南 65 getResourceID 方法来获取 ResourceID。 EventRequest 接口 EventRequest 接口继承 PortletRequest 接口,EventRequest 还提供了 getEvent 功能 RenderRequest 接口 RenderRequest 接口继承 PortletRequest 接口,目前 RenderRequest 没有提供额外什么 功能。 Request 对象的时间范围 每个 request 对象都在一个特定的 processAction、processEvent、 serveResource 、render 方法调用中有效,request 对象只有在特定的范围内才有效。 总结 PortletRequest 封装了所有客户端的请求信息,比如请求 parameters、request content data、 Portlet mode、 window state 等等。Portlet 可以通过 processAction、 processEvent、 serveResource、 render 方法来获取 PortletRequest 对象。与 processAction、 processEvent、 serveResource、 render 四个方法相对应,共有四个具体的 request 对象供处理请求的方法使 用,分别是 ActionRequest、EventRequest、ResourceRequest、RenderRequest。PortletRequest 接口定义了所有 request 接口的公共功能。ClientDataquest 提供了 ActionRequest 和 ResourceRequest 的公共功能。 Portlet 开发指南 66 十三、 Portlet Response PortletResponse 封装了所有 Portlet 返回给 Portlet container 的信息(重定向、 Portlet mode 改变、 标题、 内容等等),Portal 使用这些信息来组装呈现给客户端的内容。在 processAction、 processEvent、 serveResource 和 render 方法中可以获取 response 方法。 PortletResponse 接口 PortletResponse 接口定义了 ActionResponse、 EventResponse、 ResourceResponse 和 RenderResponse 接口的公共方法(功能)。与 processAction、 processEvent、 serveResource、 render 四个方法相对应,共有四个具体的 response 对象供处理请求的方法使用,分别是 ActionResponse 、 EventResponse 、 ResourceResponse 和 RenderResponse 。 StateAwareResponse 接口继承 PortletResponse 接口,是 ActionResponse 和 EventResponse 接口的父接口。MimeResponse 接口继承 PortletResponse 接口 ,是 RenderResponse 和 ResourceResponse 接口的父接口。类图请见下图: Response Properties 可以使用 PortletResponse 接口的下面两个方法来设置属性  setProperty Portlet 开发指南 67  addProperty PortletResponse 中设置 properties 会被作为 Portal 的 http header 被传递给客户端。如果 希望这些 properties 被设置成功,那么必须在 response 提交之前被调用,否则将被忽略。 Portlet 设置的 header 不一定会在 Portal application 中保存,有可能出于安全原因 Portal application 会做一些限制,或者 Portlet 设置的 header 被其他 Portlet 所覆盖。 URLs 编码 Portlet 中需要引用 Portlet application 中的 servlets、 JSPs、 图片 和其他静态文件。有 些 Portal、Portlet 容器的实现要求对这些 URL 进行 encode,因为有可能 Portal 需要在这些 URL 中添加一些额外信息。如果对于某些 Portal、Portlet 容器来说 encode 是没有必要的,那 么 encode 返回的内容是没有变化的。 Resources 的 URL 如果没有被 encode,那么 Resources URL 是不能被保证可以被正常访 问。 Namespacing 可以使用 PortletResponse 接口 getNamespace 的方法来返回此 Portlet 的命名空间,一般 来说 namespace 用来在 Portal 页面中唯一定义此 Portlet 中的 dom 元素,这样 js 就可以准确 的定位到 Portlet 中的元素了。 设定 Cookies 可以通过 PortletResponse 接口 addProperty 方法添加 javax.servlet.http.Cookie 的 key 值 来添加 cookie。 JSR 286 添加了用于针对 Portlet 请求和响应读取和写入 Cookie 属性的 API 方法,但 是门户实现可以自由决定有关如何存储和处理这些 Cooie 的细节。WebSphere Portal 直接 将 Cookie 属性转换为实际的 HTTP Cookie。如果您不显式指定 CooKie 路径,则会将其缺 省设置为门户的 URL 上下文,因此后续的门户请求可以正确地接收回 Cookie,但是相同服 务器上的其他 Web 应用程序则不能。 Cookie 不在某个命名空间中,因此可以在 Portlet 之间共享,如果需要的话,还可以与 其他 Web 应用程序共享。因此 Cookie 提供了 Portlet 之间的替代协作机制,这在某些情 况下可能非常有用。由某个 Portlet 设置的新 Cookie 对相同客户端请求的后续生命周期阶 段中的所有 Portlet 可见,除非客户端决定丢弃它们,否则在后续请求中也可见。 WebSphere Portal V6.1 目前不支持在呈现阶段中设置 Cookie。当客户端响应已经在呈 现阶段中提交时,这些 Cookie 未传输到客户端,从而在后续的请求中丢失。 Portlet 开发指南 68 StateAwareResponse 接口 StateAwareResponse 接 口 继 承 PortletResponse 接口,是 ActionResponse 和 EventResponse 接口的父接口。StateAwareResponse 接口提供了设置 render parameters、 Portlet mode、 window state 的功能。 Render Parameters 使用 StateAwareResponse 接口的 setRenderParameter 、setRenderParameters 方法来设 置 render 参数。与 Portlet 在 URL 中产生的 render 参数一样,如果没有一个新的请求(比如 processaction,processevent,render)来再次请求这个 Portlet,这些参数将一直存在。 可以通过 removePublicRenderParameter 方法来删除公共参数。 修改 Portlet Modes 和 Window State 使用 StateAwareResponse 接口的 setPortletMode 方法来修改 mode 使用 StateAwareResponse 接口的 setWindowState 方法来修改 state 发布 Events 使用 StateAwareResponse 接口的 setEvent 方法来发布事件 ActionResponse 接口 ActionResponse 接口继承 StateAwareResponse 接口,这个接口还提供了 redirect 到其它 URL 的 sendRedirect 方法。 sendRedirect 方法可以让 Portal 跳转到另一个 URL。如果在 sendRedirect 方法之前调用 setPortletMode,setWindowState,removePublicRenderParameter,setRenderParameter 或者 setRenderParameters 方法,则会抛出 IllegalStateException 异常。也就是说在 redirect 之前不 要修改 Portlet 的属性状态信息。 EventResponse 接口 EventResponse 接口继承 StateAwareResponse 接口 Portlet 开发指南 69 MimeResponse 接口 MimeResponse 接 口 继 承 PortletResponse 接口 ,是 RenderResponse 和 ResourceResponse 接口的父接口。MimeResponse 接口提供生成输出内容的功能。 返回内容类型 一般情况用如下方法来设置返回内容类型, setContentType 必须在获取输出的 getWriter 或者 getPortletOutputStream 方法之前调用,否则会被忽略掉。 Response.setContentType(request.getResponseContentType()); Output Stream 和 Writer 对象 可以使用 Output Stream 和 Writer 来生成输出内容,Output Stream 用来生成二进制内容, Writer 用来生成字符文本内容。 Buffering 为了输出更加有效 Portlet 可以提供(非必须)buffer 功能。一般情况,Portlet 默认会启 用 buffer,然后容许 Portlet 在运行时设置一些参数,比如:  getBufferSize  setBufferSize  isCommitted  reset  resetBuffer  flushBuffer RenderResponse 接口 RenderResponse 接口继承 MimeResponse 接口。这个接口可以设置 Portlet 的 title Portlet 开发指南 70 ResourceResponse 接口 ResourceResponse 接口继承 MimeResponse 接口。这个接口可以为客户端直接产生内容, 而不用经过 Portlet 容器的封装处理。 Response 对象的时间范围 每个 response 对象都在一个特定的 processAction、processEvent、 serveResource 、render 方法调用中有效,response 对象只有在特定的范围内才有效。 Portlet 开发指南 71 十四、 Sessions Portlet 中的 session 与 servlet 中的 session 概念和作用上基本一致,都是为了保存一个 用户的信息,使之可以在多次操作中共享信息。有很多种方法来达到服务端跟踪客户的状态:  HTTP Cookies  SSL Sessions  URL rewriting 开发者可以方便的通过 PortletSession 来获取到当前的用户信息,而不用实际关心服务 端(容器)是怎么跟踪用户状态的。 创建 Session 在同一个 Portlet application 中的多个 Portlet 必须使用同一个 session。 Session 范围 在不同的 Portlet application 中的 Portlet 不能共享 session。 Session 中设置属性 Portletsession 定义了 APPLICATION_SCOPE 和 PORTLET_SCOPE 两 个 范 围 , APPLICATION_SCOPE 代表这个 Portlet war 中的所有 Portlet 共享的范围,PORTLET_SCOPE 代表 单独的这个 Portlet windows 的范围。 通过 HttpSessionBindingListener 可以知道 session 中何时保存了属性何时删除了属性。 PortletSessionUtil 工具类中提供了方法确定 PortletSession 中对象的范围,如果对象保存在 PORTLET_SCOPE 范围内,PortletSessionUtil 工具类的 decodeAttributeName 方法可以检索 属性名称,开发者可以通过 PortletSessionUtil 工具类来在 servlet 中处理 PORTLET_SCOPE 范围 内保存的属性。 与 Web Application HttpSession 关系 之前强调过一个 Portlet 的 application 同样也是一个 web application。一个 Portlet application 中可能包含 jsp 和 servlet。Portlets、 servlets 、 JSPs 可以通过 session 共享信息 (数据)。注意这里面说的 session 对象可能和 servlet 中定义不是同一个对象,但是 Portlets、 servlets 、 JSPs 从 session 中获取信息(数据)的方法是一致的。 Portlet container 必须保证所有保存在 PortletSession 中的属性在 httpsession 中同样可以 Portlet 开发指南 72 获取到。比如 Portlet 保存在 PortletSession 中 APPLICATION_SCOP 范围里的数据,jsp、servlet 通过 httpsession 也能获取到,PortletSessionjsp、servlet 保存在 HttpSession 中数据,Portlet 通过 HttpSession 在 APPLICATION_SCOP 范围内也能获取的到。 HttpSession 方法映射 HttpSession 与 PortletSession 方法必须对应,例如:  getCreationTime  getId  getLastAccessedTime  getMaxInactiveInterval  invalidate  isNew  setMaxInactiveInterval  getAttribute  setAttribute  removeAttribute  getAttributeNames getAttribute、setAttribute、removeAttribute 和 getAttributeNames 方法在 HttpSession 接 口和 PortletSession 接口中具有同样的功能,符合下列规则:  PortletSession 中在在 APPLICATION_SCOP 范围的属性与 HttpSession 中的 属性具有同样的名称。  PortletSession 中在在 PORTLET_SCOPE 范围的属性,HttpSession 中的属性名 称有一定的前戳。 写入 Portlet Session 可以在 action、event、render 中处理 session,但是在 render 中处理 session 会遇到一些 问题。 action 和 process event 中写入 session 存在这并发问题 Render 中写入 session 规范中并没有规定不可以在 render 中修改 session 的值,但是基于一般上的概念,render Portlet 开发指南 73 是只用来展现内容而并不是用来提供、修改什么内容,一般意义上 render 方法是可以重复 调用而结果是一样的(幂等)。所以在调用 render 时并不建议修改 session 数据。 保留的 HttpSession Attribute 名称 在 session 中属性名称以 javax。Portlet 为开头是为 Portlet 容器供应商保留的。Portlet 容器供应商使用此开头的属性来实现一些特定的功能,Portlet 开发者不应该使用此开头的 session 属性。 Session Timeouts Portlet 中的 session timeout 与 servlet 中的 session timeout 一样。 最后访问时间 Portlet 中的最后访问时间与 servlet 中的最后访问时间一样。 重要的 Session 语义 Portlet 中的 session 语义与 servlet 中的 session 语义一样。 总结 Portlet 开发指南 74 十五、 请求分发给 Servlets 和 JSPs Portlet 可以把生成内容、逻辑处理等工作委托给 servlet、jsp 来做。一般来说 Portlet 来 做 mvc 中的控制器,jsp 用来做展现。PortletRequestDispatcher 接口提供了分发委托的能力。 获取 PortletRequestDispatcher 可以通过 PortletContext 的两个方法获得 PortletRequestDispatcher  getRequestDispatcher  getNamedDispatcher 一般通过 getRequestDispatcher 来获取 PortletRequestDispatcher 在 Dispatcher 中添加查询参数 可以通过以“/”开头的字符串获得一个 PortletRequestDispatcher 对象,可以在 URL 中 添加参数。 String path = "/raisons.jsp?orderno=5"; PortletRequestDispatcher rd = context.getRequestDispatcher(path); Rd.include(renderRequest, renderResponse); 使用 Dispatcher 上面给出的例子是调用 PortletRequestDispatcher 的 include 方法,也可以调用 forward。 Portlet 容器必须保证调用 PortletRequestDispatcher 的线程和 servlet、jsp 的线程是同一个线 程。 Include 方法 在 Portlet 的生命周期中所有方法中都可以调用 PortletRequestDispatcher 接口的 include 方法,而且可以调用多次。被 include 的 servlet、jsp 将接收到一个受限版的 HttpServletRequest 和 HttpServletResponse 对象。被 Portlet include 的 servlet、jsp 不能再调用 RequestDispatcher 的 forward 方法,否则会发生不可预知的问题。Render 方法 include 的 servlet、jsp 必须调用 get 请求。 Portlet 开发指南 75 Included Request 参数 被 include 的 servlet、jsp 可以通过访问如下属性得到一些信息  javax.servlet.include.request_uri  javax.servlet.include.context_path  javax.servlet.include.servlet_path  javax.servlet.include.path_info  javax.servlet.include.query_string Included Request 属性 被 Portlet include 的 servlet、jsp 除了标准的 servlet 规范中的属性,还可以通过访问如 下属性得到一些信息 范围 属性 类型 所有 javax.Portlet.config javax.Portlet.PortletConfig processAction javax.Portlet.request javax.Portlet.ActionRequest javax.Portlet.response javax.Portlet.ActionResponse processEvent javax.Portlet.request javax.Portlet.EventRequest javax.Portlet.response javax.Portlet.EventResponse render javax.Portlet.request javax.Portlet.RenderRequest javax.Portlet.response javax.Portlet.RenderResponse serveResource javax.Portlet.request javax.Portlet.ResourceRequest javax.Portlet.response javax.Portlet.ResourceResponse forward 方法 只有 Portlet 中还没有输出提交到 response 时才可以调用 forward 方法。cookies, properties, Portlet mode, window state, render parameters 和 Portlet title 这些信息必须在 forward 之前进行调用。在 forward 返回之前,Portlet 容器不可以提交、关闭 response 内容。 在 Portlet forward 到的 servlet 中,可以使用 ServletRequest 获得 RequestDispatcher 对象, 但不能通过 ServletContext 对象获得。 Forwarded Request 参数 被 forward 的 servlet、jsp 可以通过访问如下属性得到一些信息  javax.servlet.include.request_uri Portlet 开发指南 76  javax.servlet.include.context_path  javax.servlet.include.servlet_path  javax.servlet.include.path_info  javax.servlet.include.query_string Servlet filters Servlet filter 可以拦截 Portlet 中 include、forword 的 servlet、jsp。 改变默认的 Included Forwarded Session 范围 默认情况下 include 、forward 的 servlet、jsp 与 Portlet 对应的 session 范围是 application, 可以通过在 Portlet.xml 中设置运行时参数来改变为 Portlet 范围。但是现在还不能确认都有 哪些容器提供了这个特性。 总结 Portlet 开发指南 77 十六、 Portlet 标签库 Portlet tag 可以让 jsp 方便的访问 request、 比如 RenderRequest 或者 ResourceRequest 和 response、 比如 ActionResponse 或者 RenderResponse。也可以用来生成 Portlet URLs。 Portlet 容器负责提供标签库的实现,开发者使用 Portlet tag 需要在 jsp 页面中包含如下 内容: <%@ taglib uri=”http://java。sun。com/Portlet_2_0” prefix=”Portlet”%> 当然为了规范的向后兼容性,也可以在 jsp 页面中包含如下,这样 jsp 就只能使用 JSR168 中定义的“对象” <%@ taglib uri=”http://java。sun。com/Portlet” prefix=”Portlet” %> defineObjects 标签 defineObjects 标签负责定义 jsp 中使用的对象,所以基本所有 jsp 中都会有 defineObjects 标签的定义,例如下面的写法: 有了上面定义,jsp 中有了很多有用的对象,具体包括如下对象:  如果是 render 方法 include 的 jsp,必须有 RenderRequest renderRequest、RenderResponse renderResponse 对象  如果是 serveResource 方法 include 的 jsp,必须有 ResourceRequest resourceRequest、 ResourceResponse resourceResponse 对象  如果是 processAction 方法 include 的 jsp,必须有 ActionRequest actionRequest、 ActionResponse actionResponse 对象  如果是 processEvent 方法 include 的 jsp , 必 须 有 EventRequest eventRequest 、 EventResponse eventResponse 对象  PortletConfig PortletConfig 对象  PortletSession PortletSession,不产生新的 session,如果还没有 session 创建就返回空  Map PortletSessionScope、返回的是 PortletSession。getAttributeMap()  PortletPreferences PortletPreferences 对象  Map PortletPreferencesValues、,返回的是 PortletPreferences。getMap()  其实这些对象就是放在 servletRequest 中属性中的对象。 下面是一些例子: <% out.println("renderRequest : " + renderRequest); Portlet 开发指南 78 out.println(""); out.println(".。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("renderResponse : " + renderResponse); out.println(""); out.println("。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("PortletConfig : " + PortletConfig); out.println(""); out.println("。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("PortletSession : " + PortletSession); out.println(""); out.println("。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。"); out.println("PortletPreferences : " + PortletPreferences); %> 输出内容是: renderRequest : com 。 ibm 。 ws 。 Portletcontainer 。 core 。 impl 。 RenderRequestImpl@d700d7 wrapping com 。 ibm 。 wps 。 engine 。 PortalRequestWrapper@53435343 wrapping com 。 ibm 。 wps 。 engine 。 ExtendedLocaleRequest@532d532d wrapping com。ibm。ws。webcontainer。srt。 SRTServletRequest@73e573e5 。。。。。。。。。。。。。。。。。。。。。。。。。 。。。。。。。 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 renderResponse : com。ibm。ws。Portletcontainer。core。impl。RenderResponseImpl@10e010e wrapping com 。 ibm 。 wps 。 engine 。 HttpServletResponseWrapperOnWriter@7fb17fb1 wrapping com 。 ibm 。 wps 。 engine。HttpServletResponseWrapperOnWriter@7a107a10 wrapping com。ibm。 wps。engine。HttpServletResponseWrapperOnWriter@72fa72fa wrapping com。 ibm。wps。engine。HttpServletResponseWrapperOnWriter@71a671a6 wrapping com。ibm。wps。engine。PortalResponseWrapper@54b354b3 wrapping com。ibm。 ws 。 webcontainer 。 srt 。 SRTServletResponse@74577457 。。。。。。。。。。。。。。。。。。。。。。。。 。。。。。。。。 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 PortletConfig : com 。 ibm 。 wps 。 pe 。 pc 。 waspc 。 core 。 impl 。 PortletConfigWrapper@4ec04ec 。。。。。。。。。。。。。。。。。。。。。。。。 。。。。。。。。 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 PortletSession : com 。 ibm 。 ws 。 Portletcontainer 。 core 。 impl 。 PortletSessionImpl@94a094a 。。。。。。。。。。。。。。。。。。。。。。。。。 。。。。。。。 。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 PortletPreferences : PortletWindowIdentifier[7_8000CB1A00OM10IMKFFMF820G1、 /。PGTagPortlet、 PGTagPortlet] - PortletPrefences : {} Portlet 开发指南 79 再次提醒,Jsp 要想用这些对象必须在 jsp 中写标签。 actionURL 标签 actionURL 标签生成一个指向此 Portlet 的 processAction 方法的 URL,在 actionURL 标签 中可以放入 param 标签来设置参数 actionURL 中可以定义一些属性,这些属性不是必须的。 1. windowState, 2. PortletMode 3. var 4. secure 5. copyCurrentRenderParameters 6. escapeXml 7. name
">
上面的例子创建了一个指向 processAction 的 URL,这个 URL 可以使 Portlet 进入编辑模 式、最大化此 Portlet。 renderURL 标签 renderURL 标签生成一个指向此 Portlet render 方法的 URL,在 renderURL 标签中可以放 入 param 标签来设置参数 renderURL 中可以定义一些属性,这些属性不是必须的。 1. windowState, 2. PortletMode 3. var 4. secure Portlet 开发指南 80 5. copyCurrentRenderParameters 6. escapeXml 7. name
上面的例子创建了一个指向 render 的 URL,这个 URL 可以使 Portlet 进入查看模式、使 Portlet 变为正常大小。 resourceURL 标签 resourceURL 标签生成一个指向此 Portlet serveSesource 方法的 URL,在 resourceURL 标 签中可以放入 param 标签来设置参数 resourceURL 中可以定义一些属性,这些属性不是必须的。 1. var 2. secure 3. id 4. cacheability 上面的例子创建了一个指向 serveResource 的 URL,这个 URL 指向的是 icons/mypict。 gif 这个图片。是因为 GeneralPortlet 中默认的 serveResource 如下 public void serveResource(ResourceRequest request 、 ResourceResponse response) throws PortletException、 IOException { if (request。getResourceID() != null) { PortletRequestDispatcher rd = getPortletConfig() 。 getPortletContext() 。 getRequestDispatcher( request。getResourceID()); if (rd != null) rd。forward(request、 response); } } Portlet 开发指南 81 namespace 标签 namespace 生成一个和 PortletResponse。getNamespace 方法返回一样的唯一字符串,这 个字符串主要功能是在一个 Portal 页面中有很多个相同的 Portlet 的时候用来唯一确定一些 dom 元素 doFoo()”>Foo param 标签 param 标签用来定义 actionURL、renderURL、resourceURL 标签的参数,前边的例子中已 经有介绍。 总结 Portlet 中的标签主要作用是方便开发者使用各种 Portlet 的对象,如果不使用标签也能 使用代码的方式打到同样的目的,但是代码会看上去比较凌乱。在 Portlet 中同样也可以使 用 JSTL 等标签。 Portlet 开发指南 82 十七、 Portlet 应用 一个 Portlet application 就是一个普通定义 web application。在 Portlet application 中包括 Portlet 、Portlet.xml 、servlet、jsp、html、classes、其他资源。 与 Web Applications 的关系 除了 Portlet 之外的所有 Portlet application 中的组件(servlet、jsp、html)都是运行在 servlet 容器之中的。Portlet 容器的实现一般来说是基于 servlet 容器。 与 PortletContext 的关系 Portlet 容器必须确保 PortletContext 对象与 Portlet application 是一对一对应关系的。如 果 Portlet application 是分布式部署的,Portlet 容器必须为每个 JVM 创建一个 PortletContext 实例对象。 Portlet Application 中的元素 Portlet application 中包括 web application 中的所有元素(servlet、jsp、html)和 Portlet 独有的元素(Portlet.xml)。 目录结构 Portlet application 与 web application 的目录结构基本一致,Portlet application 还多包涵 一个 Portlet.xml 文件 Portlet Application Classloader Portlet 容器与 servlet 容器必须使用同一个 classloader。 Portlet Application 存档文件 Portlet application 与 web application 一致,部署包形式是 war 包。 Portlet 开发指南 83 Portlet application 部署描述符 除了 web application 标准的 web.xml 部署描述符之外,Portlet application 还有一个 Portlet.xml 部署描述符。Portlet.xml 的作用是描述 Portlet 容器、Portlet。 更新 Portlet Application Portlet 容器可以更新一个 Portlet application 而不用重启 Portlet 容器 Portlet 开发指南 84 十八、 打包和部署描述符 Portlet.xml 部署描述为应用开发者、应用分发者、应用部署者之间定义了各种元素和配 置信息。 每个 Portlet application 都需要一个 Portlet.xml、一个 web.xml 来定义 Portlet application 的各种配置,web.xml 用来定义 web application,Portlet.xml 来专门定义 Portlet。Portlet 分 为两个版本(JSR168、JSR286), JSR286 版本的 Portlet.xml 必须兼容于 JSR168 的 Portlet.xml。 Portlet 和部署描述符 在 Portlet 规范中,web 资源(servlet、jsp、html)和 Portlet 有清晰的区别。Web.xml 部署描述符是不可以扩展的,所有的 web 资源(servlet、jsp、html)都在 web.xml 中定义。 所有的 Portlet 和 Portlet 相关的设置都在 Portlet.xml 中定义。 打包 和 servlet 一样,Portlet application 中的所有 web 资源(servlet、jsp、html)、 Portlet、 Portlet.xml、web.xml 都要打包成 war 包。 版本信息 在 META-INF/MANIFEST。MF 文件中用 Implementation 来定义版本信息 例如 Implementation-Title: myPortletApplication Implementation-Version: 1。1。2 Implementation-Vendor: SunMicrosystems。 Inc Portlet 部署描述符元素 Portlet.xml 包括两块内容 Portlet Application 定义和 Portlet 定义。 Portlet 开发指南 85 处理 Portlet 部署描述符规则 下面是一些对于 Portlet 部署描述符通用的规则 1. Portlet 容器会忽略所有 Portlet.xml 中的空格 2. Portlet容器会检查war包是否是一个合格的Portlet war,包括是否包含Portlet.xml、 web.xml、Portlet 容器被建议根据 dtd、xml schema 来检查 Portlet.xml、web.xml 的 格式是否正确。 Portlet.xml 中唯一的值 下面的值必须在 Portlet application 范围内唯一  Portlet  custom-Portlet-mode  custom-window-state  user-attribute中的  event-definition中的  public-render-parameter中的  filter 下面的值必须在 Portlet 范围内唯一  init-param  supports  preference  security-role-ref Portlet 国际化支持 Portlet 用来来定义支持的国际化 Portlet 开发指南 86 第四章节 高级特性 高级特性部分主要包括事件模型、filter 等内容 Portlet 开发指南 87 十九、 资源服务 Portlet 可以生成两种 resource 链接 1. 直接引用同一个 Portlet application 中的一些静态资源,使用 PortletResponse。 encodeURL()方法来 encode。这些请求并不会具有上下文信息,所以比较适合引用静态 资源。 2. Resource URL,这样的请求会调用 Portlet 的 serveResource 方法,这些请求具有上 下文信息,资源 URL 包含当前 Portlet 的瞬时状态(Portlet 模式、窗口状态和呈 现参数),但不能为此状态设置新值。 资源服务为您提供了对 HTTP 协议的所有方面的完全控制。WebSphere Portal 将您在资 源响应上指定的所有响应属性作为 HTTP 标头写出,因此您可以控制所提供的内容的语言、 内容类型和其他信息。另一面在于,与普通页面请求相反,门户不为响应提供任何缺省标头 信息;所有信息都必须在资源服务过程中显式地进行设置。 ResourceServingPortlet 接口 通过调用 ResourceServingPortlet 接口的 serveResource() 方法, Portlet 不仅可以通过 控制门户访问而对资源进行保护,并且 Portlet 容器不会呈现任何除 serveResource() 方法 返回的内容之外的附加输出。这样,用户由于可以直接通过操作响应对象而被赋予了更多的 控制权限,并且没有额外门户请求的开销,减轻了门户服务的负载。而 Portal 服务器此时 只是充当了一个代理服务器的作用。 Portlet 开发指南 88 访问 Render 参数、 Portlet Mode、 Window State 可以通过 ResourceRequest 来获取 Render 参数、 Portlet Mode、 Window State PortletMode mode=request。getPortletMode(); System。out。println("PortletMode : "+mode); System。out。println("WindowState : "+request。getWindowState()); System。out。println("WindowID : "+request。getWindowID()); System。out。println("Preferences : "+request。getPreferences()); 访问 Request 和 Response Headers 由于 Portlet 容器、Portal 不会在 request 中添加任何额外内容,也不会再 response 中附 加输出,所有 resource 可以完全获取 request 和控制 response。Portlet 可以像所有处理方法 一样通过 getProperty 或者 getProperties,使用 resource 访问 http header。同样 resource 也 可以通过 setProperty 或者 addProperty 设置 http header。值得注意的是,设置 http header Portlet 开发指南 89 要在产生输出之前,否则会被 Portlet 容器忽略。 获取 HTTP 方法 可以通过 ResourceRequest 接口的 getMethod 方法来获取 http 方法,比如 GET、 POST 、 PUT 访问 Resource ID 可以通过 ResourceRequest 接口的 getResourceID 方法来获取 resource ID 方法,当调用了 setResourceID 方法后 getResourceID 返回的是 setResourceID 中设置的参数,如果没有调用过 setResourceID,则返回 null。 Resource URLs Resource URL 中的参数不能与 render 的参数共享 Generic Portlet 支持 Generic Portlet 中提供了默认的 serveResource 实现,默认情况下会 forward 到 resourceid 指向的资源。 public void serveResource(ResourceRequest request、 ResourceResponse response) throws PortletException、 IOException { if (request。getResourceID() != null) { PortletRequestDispatcher rd = getPortletConfig()。getPortletContext()。 getRequestDispatcher( request。getResourceID()); if (rd != null) rd。forward(request、 response); } } Ajax 请求 Render 和 serveResource 都可以接受到 ajax 请求,两个方法使用的场景不一样,render Portlet 开发指南 90 可以用来修改 Portlet 的 state、window mode 等信息,serveResource 一般提供一些返回信息 的片段,比如 json、xml 等。 Portlet 开发指南 91 二十、 Portlet 协作 为了提供协作的能力规范引入了如下特性: 1. 在 application session 范围,同一个 application 中的 Portlet 可以共享 session 信息。 2. Public render parameter 可以共享 render 信息 3. Event 可以让 Portlet 之间发送、接受事件 Public Render Parameters 本章将介绍共享呈现参数和事件。 请注意 Portlet 规范中并没有定义怎么把两个 Portlet 中连线,具体实现(配置)方式需 要参考具体的 Portal application。 Public Render Parameters 共享呈现参数,顾名思义,就是指 Portlet 之间共享参数,每一个 Portlet 对该参数的 修改都能够直接被另外支持该参数 Portlet 所获得。 Public render pararmeter 用来共享 render 信息,比如,在页面中有两个 Portlet,一个用 来展现用户所在城市的天气,一个用来展现用户所在城市的地图,我定义了一个共享呈现参 数来表示用户所在城市,那么如果客户在天气 Portlet 中选择了一个城市,地图 Portlet 可以 通过 public render pararmeter 来获取用户所在城市,从而展现城市地图。从而实现了不同 Portlet 之间的协作。 除了 Portlet 事件以外,公共呈现参数代表 Portlet 之间的协作方法。尽管两种机制都 允许在 Portlet 之间交换信息,但它们在几个方面存在差异。 正如在本文的第一部分所指出的,从编程的角度看,公共呈现参数的处理几乎与普通(私 有)呈现参数的处理完全相同:Portlet 可以使用 JSR 168 为私有呈现参数引入的相同 API 方法来设置和读取此参数。共享呈现参数与 JSR 168 中已经有私有呈现参数的区别就在于, 私有呈现参数只为 Portlet 内部使用,而共享呈现参数则为多个 Portlet 之间通信协作而设 置。共享呈现参数与事件相比的优势就在于避免了事件处理过程调用的繁琐。从程序员的角 度看,重要的区别在于,公共呈现参数是在 Portlet.xml 部署描述符中声明的。 声明 对共享呈现参数的使用声明包括两个部分,对共享呈现参数定义的声明和支持共享呈现 参数的 Portlet 声明。 1. 共享呈现参数定义声明:对于共享呈现参数定义的声明必须在 Portlet.xml 部署文 件中使用 关键字,该元素与 元素并列为 的分支。 publicrenderparameter publicrenderparameter 2. 支持共享呈现参数 Portlet 声明:对于支持共享呈现参数的 Portlet 的声明需要在 Portlet 开发指南 92 Portlet.xml 中 元素中使用 关键字 publicrenderparameter 使用 与非共享呈现参数的使用方法相同,共享呈现参数可以通过 ActionResponse 的 setRenderParameter("标识","值") 方法设定,并通过 RenderRequest 的 getParameter("标识 ") 来获得。 response 。 setRenderParameter("publicrenderparameter", request 。 getParameter(FORM_TEXT)); <%=request。getParameter("publicrenderparameter") %> Portlet Events JSR 286 定义的事件模型是一种松耦合的代理事件模型。在此模型中,Portlet 定义可以 接收以及在 Portlet 部署描述符中公布的事件。在运行时,门户管理员(或业务用户)可以 将不同的 Portlet 连接在一起。 事件可以让Portlet接收到调用(从而修改Portlet的状态等信息),而不是客户端触发的, 是事件触发的。 Portlet 事件服务并不是一个可信任消息服务(例如 JMS)的替代。很多情况下 Portlet 事件并不能总是保证能够传送到目的地。因此 Portlet 必须能够在部分或即使所有事件都不 能正确接收的情况下仍然能够工作。 另外,有的时候 Portlet 为了响应某一个事件,也会向另外的 Portlet 发布新的事件, 这样就形成了事件的衍生代。这在一定程度上可能造成事件的死锁,JSR 286 本身没有对衍 生代做出限制,但是很多 Portlet 容器会定义事件的最大衍生代以防止死锁的发生。读者在 开发相关应用时请注意其本身的限制。 EventPortlet 接口 为了可以接受到事件,Portlet必须实现EventPortlet接口,Portlet容器会调用processEvent 方法来处理接收到的事件 Portlet 开发指南 93 Event 声明 对于一个事件的声明包括三个部分,分别是事件的定义声明、事件的发布载体声明也就 是发布该事件的 Portlet 声明、事件接收载体的 Portlet 声明。 1. 事件定义声明:我们需要在 Portlet.xml 中使用 元素对事件进行 声明,并且该元素与 元素并列作为 的子元素 http://PGEventPortlet/ com。Portalguide。simpleevent java。lang。String com。Portalguide。complesevent com。Portalguide。pgeventPortlet。SampleComplexEvent 对于一个事件的声明有两点需要注意:事件的名称和值的类型。对于事件名称,JSR 286 既可以为事件定义默认的命名空间,其作用域为所有未声明 QName 的事件;也可以为事 件单独定义自己的 QName。对于 QName 和命名空间的理解,请读者参考 XML 规范的相 关文档,本文不做详细介绍。对于事件值的类型,既可以是简单的 Java 对象,例如 Integer, String 等,也可以是预先定义的 Java 复杂对象,但是前提是该对象必须实现 Serializable 接 口。上面的代码是默认命名空间的声明,下面的代码是自定义命名空间的声明方式 event-with-simple-value java。lang。Integer event-with-qname com。ibm。JSR286。。TestEventBean 2. 事件发布载体声明:事件的发布载体声明需要在 Portlet.xml 的 元素中 Portlet 开发指南 94 用 关键字。对应事件声明格式,事件发布载体 Portlet 声明亦有默认命名空间和自定义命名空间以及简单对象和复杂对象的情况,见示例: ComplexEventSenderPortlet ComplexEventSenderPortlet ComplexEventSenderPortlet com。Portalguide。pgeventPortlet。 ComplexEventSenderPortlet com。Portalguide。complesevent 3. 事件接收载体声明与事件发布载体声明类似,事件的接收载体声明需要在 Portlet.xml 的 元素中用 关键字。 SimpleEventReceiverPortlet SimpleEventReceiverPortlet SimpleEventReceiverPortlet com。Portalguide。pgeventPortlet。SimpleEventReceiverPortlet com。Portalguide。simpleevent 发送 Events JSR 286 事件传播机制描述每当某个 Portlet 发布了事件时的自动化 Portlet 交互。 Portlet 生命周期的事件阶段不允许任何类型的客户端用户交互。 我们可以在希望发布事件的 Portlet 的 processAction() 方 法 里 , 通 过 调 用 ActionResponse 的 setEvent() 进行事件发布,setEvent() 方法的输入参数为事件的名称和对 应的值,这些参数必须与我们前面在 Portlet.xml 中的事件声明一致。 //Initialize the fields in the class as per your requirement java。lang。String sampleObject = new java。lang。String("test event"); response。setEvent("com。Portalguide。simpleevent", sampleObject); Portlet 开发指南 95 Event 处理 事件的接收 Portlet 必须实现 javax。Portlet。EventPortlet 接口,事件的接收处理则在 该接口包含 processEvent() 方法中进行,JSR 286 定义该方法提供了两个输入参数: EventRequest 和 EventResponse,我们可以通过调用 EventRequest 实例的 getEvent() 方法 来获得当前事件,该方法返回一个事件对象的实例,该实例封装了事件的唯一标识和对应的 值。获得事件对象后,我们也可以通过 getQNames() 方法或者 getName() 获得事件的 名称。两种获得事件方法的区别是 getQNames() 可以得到事件的全称标识,而 getName() 只是取得本地标识名。而取得事件的值则可以通过事件的 getValue() 方法获得。 Event sampleEvent = request。getEvent(); if(sampleEvent。getName()。toString()。equals("com。Portalguide。simpleevent")) { Object sampleProcessObject = sampleEvent。getValue(); System。out。println(sampleProcessObject); } GenericPortlet support 在 JSR 168 Portlet 的开发中,开发者通常继承抽象类 javax。Portlet。GenericPortlet 来 实现自己的 Portlet 逻辑代码。 同 JSR 168 相比, JSR 286 的 GenericPortlet 增加了 javax。 Portlet。EventPortlet 和 javax。Portlet。ResourceServingPortlet 接口的实现,从而增加了事 件处理和资源服务的功能。 在 GenericPortlet 中添加了默认的 processEvent 实现,所以默认情况下 processEvent 只 是把 eventRequest 作为参数传递(response。setRenderParameters(request);) public void processEvent(EventRequest request, EventResponse response) throws PortletException, IOException { String eventName = request。getEvent()。getQName()。toString(); try { // check for exact match Method eventMethod = processEventHandlingMethodsMap。get(eventName); if (eventMethod != null) { eventMethod。invoke(this, request, response); return; Portlet 开发指南 96 } else { // Search for the longest possible matching wildcard annotation int endPos = eventName。indexOf('}'); int dotPos = eventName。lastIndexOf('。'); while (dotPos > endPos) { String wildcardLookup = eventName。substring(0, dotPos + 1); eventMethod = processEventHandlingMethodsMap 。 get(wildcardLookup); if (eventMethod != null) { eventMethod。invoke(this, request, response); return; } if (dotPos == 0) { break; } dotPos = eventName。lastIndexOf('。', dotPos - 1); } } } catch (Exception e) { throw new PortletException(e); } // if no event processing method was found just keep render params response。setRenderParameters(request); } Events 传送复杂对象 JSR 286 规范允许 Portlet 作为事件有效负载发送和接收复杂 Java 对象,前提是这些有 效负载是 Java 和 JAXB XML 可序列化的。这种许可允许跨类加载器甚至事件服务器传输复 杂对象,例如在与遵循 Web Services for Remote Portlets (WSRP) 2.0 协议的远程 Portlet 通 信的时候。WebSphere Portal 6。1 支持 WSRP 2.0,并允许本地和远程 Portlet 之间的完全 互操作性和事件传播。 总结 正如我们从前面的讨论中看到的,可以将公共呈现参数视为对 Portlet 事件的较轻量级 的通信替代方法。下面的列表将各自的功能进行了对比,以帮助您决定哪一种机制更适合您 Portlet 开发指南 97 的用例。 公共呈现参数具有以下特性:  它们通常不需要显式的编码,而是只需在 Portlet.xml 部署描述符中进行声明。  它们仅限于简单字符串值。  它们不需要显式的管理来设置协作。  它们不会随着共享信息的 Portlet 数量的增长而导致性能开销。  它们通过 URL 更改进行更新,例如跳转到某个书签。  可以在门户主题和皮肤中编码的链接中对它们进行设置。  可以在使用特定于产品的 API 创建的链接上对它们进行设置,这样的链接从一个 Portlet 指向不同页面上的另一个 Portlet。 Portlet 事件具有以下特性:  需要显式的 Portlet 代码来发送和接收它们。  它们可以包含复杂信息。  它们允许通过在 Portlet 之间设置不同类型的连接(页面内或跨页面,公共或私有) 实现细粒度的控制。  它们可以触发具有不同信息的级联更新。例如,Portlet A 可以将事件 X 发送到 Portlet B,后者又将不同的事件 Y 发送到 Portlet C。  它们随着通信链接数量的增长而导致增加处理开销。  它们必须由某个显式的用户交互(通常是通过单击 Portlet 中的某个操作链接)发 起,并且不能在第一次跳转到某个页面时将它们用于设置协作视图。 两种机制都允许您将数据交互与某个页面切换耦合在一起。对于事件,正如前面所解释 的,您可以定义页面切换跨页面连接。对于公共呈现参数,您可以在一个 Portlet 中使用特 定于产品的 API 生成指向不同页面上的另一个 Portlet 的链接,并为该目标设置公共呈现 参数。 当然,您甚至可以组合使用两种技术;例如,您可以在 Portlet 中声明一个设置呈现参 数的处理事件,同时将此参数设置为公共参数,以便能够通过两种方式接收信息。 此讨论应该有助于您确定哪一种功能更适合给定的用例。根据一般经验,应该在可使用 公共呈现参数的场合使用公共呈现参数,并对呈现参数不足够的较复杂情况使用 Portlet 事 件。 Portlet 开发指南 98 二十一、 Portlet Filter Portlet 过滤器是 JSR 286 提供的有一个非常重要的新特性。事实上,在 JSR 286 之前, 就已经有很多厂商(包括 IBM)自定义扩展了 JSR 168,提供了过滤器功能。由此可见,Portlet 过滤器的重要性。为了避免各种厂商不同 Portlet 过滤器的不兼容性,JCP(Java Community Process)对 JSR 286 定义了标准的过滤器实现。 什么是 Portlet filter 与 Servlet 相似,Portlet 过滤器可以使用户改变一个 request 和修改一个 response。 Filter 不是一个 Portlet,它不能产生一个 response,它能够在一个 request 到达 Portlet 之 前预处理 request,也可以在离开 Portlet 时处理 response。换句话说,过滤器其实是一个 “Portlet chaining”(Portlet 链)。它能够实现的功能包括: 1. 在 Portlet 被调用之前截获; 2. 在 Portlet 被调用之前检查 servlet request; 3. 根据需要修改 request 头和 request 数据; 4. 根据需要修改 response 头和 response 数据; 5. 在 Portlet 被调用之后截获; 事实上,从宏观功能的角度看来,Portlet 过滤器和 Servlet 过滤器是很相似的。这是 因为二者都可以声明性地嵌入,从而截获并修改请求和响应。但是理解它们之间存在着很大 的不同是非常重要的。在一定程度上,它们之间的差异是与 Servlet 和 Portlet 之间的差异 相联系的:Servlet 过滤器是一个门户级过滤器,它可以修改由一些小的部分(来自页面上 所有 Portlet 的响应)集合而成的整个门户页面;而 Portlet 过滤器只能用于那些小的部分。 Servlet 过滤器(如果已经安装的话)是接收和修改客户端请求的第一个组件,同时也是修 改对客户端的响应的最后一个组件。 另外一点需要注意的是,Servlet 过滤器比 Portlet 过滤器的优先级别要高,容器将首 先进行 Servlet 过滤,其次是 Portlet 过滤。一个过滤器链包含一个或多个过滤器。在一个 过滤器完成处理之后,新的请求和响应将传送到链上的下一个过滤器;链上的最后一个过滤 器调用目标资源(Servlet 或 Portlet)。 Portlet 开发指南 99 主要概念 Portlet 过滤器可以放置在 V2.0 规范提供的任何生命周期方法调用的前面或者后面 (processAction、processEvent、render、serveResource),而且还支持这些生命周期方法使 用包装的请求和响应。与 Servlet 过滤器类似,Portlet 过滤器需要在 Portlet.xml 部署描述 符中进行定义,不同的是,servlet 只有一个 service()的请求处理方法,因此 servlet 只有一种 类型的过滤器。而 Portlet 却有四种请求处理方法,于是有四种类型的过滤器,包括 1. Action 过滤器 2. Render 过滤器 3. Resource 过滤器 4. Event 过滤器 下面我们来介绍四种过滤器的工作原理。 JSR 286 为四种过滤器分别定义了一个接口类,这四个接口类都继承 PortletFilter 类, 并分别添加了各自 doFilter() 方法。关于这几个类之间的关系,请见下图 四种过滤器分别对 Portlet 的四个方法进行拦截。用户自定义的过滤器必须实现相应的 过滤器接口,通过其 doFilter() 方法来实现相应的动作 Portlet 开发指南 100 Filter 生命周期 JSR 286 为 Portlet 过滤器提供了接口类 PortletFilter,该接口提供了两个方法。 1. void init(FilterConfig config) 容器调用一次这个方法来准备用于服务的过滤器。对象 filterConfig 使得过滤器能够 访问配置参数以及对门户上下文的引用。 2. void destroy() 这个方法是在将过滤器从服务移除之后调用的。这个方法使得过滤器能够清除任何 存放的资源。 Filter 首先需要使用 init 方法进行初始化,如果符合 filter 的条件,Portlet 容器就会调用 相应 filter 的 doFilter 方法,doFilter 方法更加不同的拦截的方法会有不同的参数对象  ActionRequest 和 ActionResponse for processAction 调用  EventRequest 和 EventResponse for processEvent调用  RenderRequest 和 RenderResponse for render调用  ResourceRequest 和 ResourceResponse for serveResource调用 Filter 环境 和 servlet filter 一样,也可以在定义 Portlet filter 的时候定义一些初始化参数,然后通过 FilterConfig 来获取 在 Portlet Application 中配置 Filters 可以 Portlet.xml 中配置 filter AllPortletFilter com。Portalguide。filter。TestAllPhaseFilter ACTION_PHASE EVENT_PHASE RENDER_PHASE RESOURCE_PHASE AllPortletFilter PGFilterPortlet Portlet 开发指南 101 总结 关于 Portlet 过滤器有几点需要声明的是:  对于一个 Portlet 过滤器的声明亦包括两部分,过滤器的定义声明以及过滤器的映 射声明。  一个 Portlet 过滤器可以为多个 Portlet 服务,而且 一个 Portlet 可以同时有多个 Portlet 过滤器。  一个 Portlet 过滤器可以有多个生命周期阶段,当然前提是该 Portlet 过滤器实现 了相应过滤器接口。 Portlet 开发指南 102 第五章节 可选概念 此章介绍一些可选的、非必须的概念,读者可以视情况选读,主要包括缓存、获取用户 信息、安全性。 Portlet 开发指南 103 二十二、 缓存 缓存内容可以帮助减少 Portal 的响应时间和 application server 的压力。Portlet 规范定义 了一套基于过期的针对具体每个 Portlet 的缓存机制。 如果当一个非 action、event 请求,而这时恰好 Portlet 容器还缓存着数据,那么 Portlet 容器就不会调用,而是直接返回缓存的数据。如果是一个 action、event 请求,则 Portlet 容 器会删除目前此 Portlet 的缓存,然后调用 action、event 请求。 缓存过期 可以在 Portlet.xml 中定义 cache 的时间(秒)以及方式(private、public)。如下图中定 义的 Portlet 缓存过期未 300 秒,并且不能在不同用户之间共享。 。。。 300 private 。。。 Portlet 可以使用编程的方式修改缓存的时间和方式,方法是为 RenderResponse 或者 ResourceResponse 设置 EXPIRATION_CACHE 和 CACHE_SCOPE 属性。或者在 MimeResponse 中调用 getCacheControl 方法获取 CacheControl 对象,然后调用 CacheControl 对象的 setExpirationTime 和 setScope 方法。 Portlet 必须在输出内容之前设置缓存时间、方式,否则会被 Portlet 容器忽略。 如果 expiration-cache 是-1 则永不过期,如果是 0 则代表立即过期,如果方式是 private 的则缓存只能在同一个用户中共享,如果方式是 public 的则缓存可以在不同用户中共享。 Private 方式是默认的方式。 验证缓存 作为缓存过期机制的扩展,Portlet 规范提供了验证缓存。验证缓存可以让 Portlet 放回 一些标记。 Portlet 可以通过 CacheControl 在 RenderResponse 或者 ResourceResponse 中设置 ETAG。下面是一个例子 protected void doView (RenderRequest request, RenderResponse response) throws PortletException, java。io。IOException { „ Portlet 开发指南 104 if ( request。getETag() != null ) { // validation request if ( markupIsStillValid(request。getETag()) ) { // markup is still valid response。getCacheControl()。setExpirationTime(30); response。getCacheControl()。setUseCachedContent(true); return; } } // create new content with new validation tag response。getCacheControl()。setETag(someID); response。getCacheControl()。setExpirationTime(60); PortletRequestDispatcher rd = getPortletContext()。getPortletRequestDispatcher(“jsp/view。jsp”); rd。include(request, response); } 总结 缓存内容可以帮助减少 Portal 的响应时间和 application server 的压力。Portlet 缓存使用 的一个典型场景是当 Portal 页面中的 Portlet 大部分只是做内容展现,而这些页面的访问量 还特别的大,这是就可以通过 Portlet 缓存机制来提高性能。 Portlet 开发指南 105 二十三、 用户信息 通常 Portlet 可以提供个性化的内容,这是 Portlet 一般需要获得登陆此 Portal 的用户信 息,比如用户名、email 登陆。Portlet 容器提供了一套机制来使开发者获取这些用户信息。 定义用户属性 Portlet.xml 中可以定义用户的信息,如下面的代码 User Given Name user。name。given User Last Name user。name。family User eMail user。home-info。online。email Company Organization user。business-info。postal。organization Portlet 容器会按照 Portlet.xml 中的定义来进行用户信息映射。 访问用户属性 开发者可以通过代码的方式获取用户信息,如下面代码 Map userInfo = (Map) request。getAttribute(PortletRequest。USER_INFO); String givenName = (userInfo!=null) ? (String) userInfo。get(PortletRequest。P3PUserInfos。USER_NAME_GIVEN) : “”; String lastName = (userInfo!=null)(String) userInfo。get(PortletRequest。P3PUserInfos。USER_NAME_FAMILY) : “”; Portlet 开发指南 106 重要注意事项 Portlet 规范之前并没有 java 中并没有定义标准的用户信息的获取方式,在 Portlet 规范 中定义 Portlet 中定义了用户信息的访问。如果 java 标准中定义了获取用户信息的方法, Portlet 规范中的获取机制就没有必要存在,使用标准的就可以了。 总结 Portlet 中定义了一些获取用户信息的方式。 Portlet 开发指南 107 二十四、 安全性 介绍 和 servlet 一样,也可以在 Portlet application 中定义安全性。 角色 Portlet 规范中定义的角色与 servlet 规范中的一致。 安全性代码开发 可以通过如下几个方法获取安全性用户信息  getRemoteUser  isUserInRole  getUserPrincipal 可以在 Portlet.xml 中定义用户和角色的映射关系 。。。 。。。 FOO manager 。。。 。。。 总结 Portlet 开发指南 108 二十五、 Portal Context PortalContext 接口提供了 Portal application 的 各 种 信 息 , 可以通过 Portlet 的 getPortalContext 方法来获取 PortalContext 对象。 PortalContext 对象可以通过 getPortalInfo 方法获得 Portal 的制造商、版本等信息基本信 息 , 通 过 getProperty 和 getPropertyNames 获得 Portal 的 属 性 信 息 , 通 过 getSupportedPortletModes 获得 Portal 支持的 Portlet mode,通过 getSupportedWindowStates 获得 Portal 支持的 windowstate。 Portlet 开发指南 109 二十六、 Portlet 容器运行时 Portlet 可以在 Portlet.xml 中定义 Portlet application 级别和具体某个 Portlet 级别的运行 时选项。Portlet application 级别的运行时选项对所有 Portlet 都有效,具体某个 Portlet 级别 的运行时参数只对所定义的 Portlet 有效,并且可以覆盖 Portlet application 级别的运行时选 项。 可以通过 PortletContext 接口的 getContainerRuntimeOptions 方法来获取运行时参数 Enumeration containerRuntime = this.getPortletContext().getContainerRuntimeOptions(); while (containerRuntime.hasMoreElements()) { log.info(containerRuntime.nextElement().toString()); } 一般情况来说这些运行时参数是为了版本兼容性、container 的个性化设置,但是这些 个性化的设置一般是不为推荐的。所有一般情况不需要设置。 WebSphere Portal V6.1 支持以下容器运行时选项:  Javax.Portlet.escapeXml(由 JSR 286 定义),用于避免 JSP 标记生成的 URL 的缺省 XML 转义。  Javax.Portlet.actionScopedRequestAttributes(由 JSR 286 定义),用于跨请求边界保 留 Portlet 请求属性。  Com.ibm.Portal.public.session(特定于产品),用于指示某个 Portlet 需要会话才能正 确操作。它请求门户在每当包含该 Portlet 的页面被访问时,即使不存在任何用户 登录,也要创建会话 Cookie。 有些代码不是非常适合 Portlet 规范的概念,但是仍然应该在 WebSphere Portal 中受 到支持,上述所有这些运行时选项就表示此类代码的变通办法。在频繁使用的门户上,使用 后两个运行时选项还会导致性能下降。因此,应该尽量避免使用这些运行时选项,并且最好 以使得这些选项变得不必要的方式编写代码。 动态修改 Portlet 标题 读者会发现我在示例 2 中定义的 CONFIG_TITLE 这个变量始终没有用到,其实是为了实 现 Portlet 标题栏文字的自设定而放置的。 WebSphere Portal6 中 Portlet 标题栏文字的修改比较怪异,本来按照 JSR168 中所规定的,只 要使用 RenderResponse.setTitle(String title)函数就可以设置标题了,而且我用这个方法在 pluto-1.1.4 中测试通过,但在 WebSphere Portal 中却怎么调都不行,看了 IBM 网站上的一篇 文章《Tip: Changing a Portlet title at run time in WebSphere Portal V6》才有点明白,似乎是 IBM 为了访问效率考虑,所以在 WebSphere Portal 中调用 RenderResponse.setTitle 只是修改了 com.ibm.Portal.Portlet.Constants.DYNAMIC_TITLE 这个值,然后还需要在皮肤中使用 DOM,并 读取该值才能显示。 Portlet 开发指南 110 下面是实现步骤。在示例 2 的代码中进行修改实现。 (1)修改皮肤。 复制 IBM 皮肤文件夹,重命名为 IBM_DT,修改其中的 control.jsp。 找到其中如下一段代码 为其添加 span 或者 div 标签,用于修改时的定位,修改为 然后在 control.jsp 文件的最下方,添加如下代码用于修改标题栏文字。 如此,皮肤就修改完成了。 (2)修改 PortletExamplePortletView.jsp,在其中添加一行代码。 renderResponse.setTitle(prefs.getValue(PortletExamplePortlet.CONFIG_TITLE, "ConfigTitle")); (3)转入 Portal 中查看显示效果。 安装该皮肤,并且设置要修改标题的 Portlet 都要使用该皮肤。 为了演示此种方式可以同时在一个页面中给多个 Portlet 设置不同的标题文字,我们可以再 复制一个 PortletExample Portlet,命名为 PortletExample2,然后将其也添加到测试页面上。 然后给这两个 Portlet 配置不同的参数,如下图,可以看到,两个 Portlet 的标题是不同的, 显示内容、高度等也都不同。 这种方式修改的只是 View 视图时的标题,如果我们进入配置模式,会发现标题栏还是原来 的名字。 RenderResponse.setTitle(String title)函数也可以在 PortletExamplePortlet.java 中的 doView、 doEdit 等函数中调用,显示结果与直接在 jsp 中调用相同,留待读者自己尝试 Portlet 开发指南 111 二十七、 使用注释的方法 GenericPortlet Render Handling 可以通过@RenderMode 这种方式来定义与 view、edit、help mode 对应的方法,但是笔 者觉得没有什么必要,用默认的方法名称就成了。 Portlet 开发指南 112 二十八、 Setting next possible Portlet Modes Portlet 开发指南 113 二十九、 Struts2 开发 Portlet 实例 我们在开发 Servlet 应用时,习惯于将数据存放在 request 作用域中,通过页面的跳转 将数据呈现到 jsp 视图页面。但是,这种做法在 Portlet 开发中是不可行的。与 servlet 的 生命周期有所不同,Portlet 存在操作响应阶段和呈现阶段。 在 Portlet 操作响应阶段存放 在 request 作用域的变量,在呈现阶段就会失效。在原有 API 上解决这个问题既费时又不 优雅,而 Struts 2 对 Portlet 的支持将能够很好的解决这些问题。 Portlet 开发指南 114 三十、 Spring mvc 开发 Portlet 实例 Portlet 与 Servlet 生命周期最主要的区别在于 Portlet 的请求分为两个明显的阶段:行 动阶段和呈现阶段。行动阶段只执行一次是由于“后台”有改变或者行动发生,例如修改数 据库操作。呈现阶段是每次显示被刷新,然后产生显示结果给用户。这里的关键点是在单个 全生命周期的请求,行动阶段只被执行一次,但是呈现阶段可能执行多次。这样就使修改您 系统的持久状态的活动和产生显示给用户的活动有一个清晰的分离。 Portlet 两个阶段是 JSR-168 规范的一个功能强大的特性。例如,动态搜索显示结果可以 在显示修改而不需要用户重新运行搜索功能。很多其它的 Portlet mvc 框架努力对开发人员 隐蔽两个阶段使 Portlet 的开发尽可能像开发传统的 servlet 应用那样-我们认为这种方式减少 使用 Portlet 的一个重要好处。所以 Spring 的 Portlet mvc 框架是始终保留两个分离的阶段。 这种方式的主要的表现是 servlet mvc 的版本的类有一个方法处理请求,Portlet mvc 版 本的类有两个方法处理请求:一个是行动阶段和一个呈现阶段。例如,servlet 版本的 AbstractController 有一个 handleRequestInternal(。。 )方法;Portlet 版本的 AbstractController 有 handleActionRequestInternal(。。 )和 handleRenderRequestInternal(。。 )方法。 Portlet 开发指南 115 三十一、 附录 修改记录 版本号 修改日期 描述 0.1 2010/12/12 正式开始编写 0.2 2010/12/22 草稿第一次完成 0.3 2010/12/29 整理文档总体结构、分为五章,完善了部分章节(缓存、用 户信息、安全性、Portlets 协作、Portlet Filter)内容 0.31 2010/12/30 完善资源管理章节 0.32 2010/12/31 完善部署章节 0.33 2011/01/03 完善 session、Portlet context、Portlet config、Portlet 生命周期 接口章节 0.34 2011/01/04 完善 request、response 章节 0.4 2011/01/07 草稿第一次完善完毕、附带代码完成 名词解释 名词 解释 Portlet 一个 Portlet 是一个基于 java 技术的被 Portlet 容器管理的 web 组建,它可 以处理 requests、生成动态的内容输出,一个 Portlet 负责提供 Portal 页 面中的某个特定部位的展现内容 Portal Portal 是一个基于 web 的提供个性化、登录授权、从不同的数据源聚集内 容基于展现层的信息系统。 Portlet 容器 Portlet 容器提供 Portlet 生命周期环境,管理 Portlet 的生命周期,还提供 Portlet preferences 的持久化支持,Portlet 从 Portal 接受请求,然后分发给 运行其上的 Portlet。 fragment 指 Portlet 生成的内容片断 aggregate 指 Portal 把 Portlet 生成的组合在一起集中展现 Portlet window Portlet 窗口 Portlet Entity Portlet 实体 preferences 首选项 Web application Web 应用 Portlet application Portlet 应用 Portlet 开发指南 116 Resource service 资源服务 Public render parameter 共享呈现参数 Event Portlet 事件 Portlet filter Portlet 拦截器 Tag 标签,可以在 Portlet 的 jsp 里面使用的标签。 疑问 标签库 1 怎么在 action、event 中 include jsp
还剩115页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享pdf获得金币 ] 34 人已下载

下载pdf

pdf贡献者

lshfantasy

贡献于2011-06-28

下载需要 20 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf