http://blog.csdn.net/yuanxz/category/100084.aspx
从最宏观的角度来说,portal归根结底是一个内容聚集的平台。典型的场景是这样:一个企业(或者政府部门)拥有这个那个的业务系统,譬如网上注册、网上年检、新闻发布、咨询公告、外汇牌价、天气预报……这堆东西怎么给用户集中展现?怎么让用户定制自己想看到的界面?怎么实现单点登录?这是portal要解决的问题。各个application提供业务能力,portal提供一个统一的look and feel。所以portlet和servlet绝对不是竞争的关系,portlet的功能是“聚集+展现”,应该尽量回避具体于业务的逻辑。
举个例子。工商局的portal可能是这样:普通用户可以定制几个信息发布类的portlet,例如新闻、公告、外汇牌价和天气预报,这些portlet从后面的application那里获得RSS feed,再根据用户选择的skin显示出来;企业用户登录之后,有一个portlet可以看到自己的年检进度(也是通过RSS获得信息),再点一个链接就进入年检系统,并且已经携带了登录信息;工商局内部用户登录以后,就有几个portlet显示待办事宜、学习文件等等(还是RSS),同样是点一个链接进入年检系统直接处理一个待审企业。
IBM Websphere Portal好象就是用JetSpeed为基础做的,所以API都一样。JSR 168定义的接口和JetSpeed现在的接口也差不多。JSR 168没有定义portlet之间的事件模型,我感觉这块也是很有必要的,因为有时portlet也需要直接提供一些简单的交互性。譬如说,“文件浏览”portlet也许可以直接把文件摘要显示出来,领导看个大概齐就在后面点一下“同意”了事,这时“待办事宜”portlet里面就应该把这个文件的链接去掉。
1.Portal用例
读者可以在下面三个网站上注册自己的用户,体会Portal的功能。
http://my.msn.com
http://my.yahoo.com
http://my.liferay.com
My MSN的功能最灵活强大,用户可以任意拖放操作栏目(column)和内容版块(content)的位置和个数。
My Liferay只能选择固定的栏目(column)布局,但可以在本栏目(column)内移动内容版块(content)的位置。
My Yahoo只能选择固定的栏目(column)布局,而且不能移动内容版块(content)的位置。
Portal的结构分为三层。
(1) Page
(2) Column,或者称为Pane
(3) Content,或者称为Portlet
我们来看看Portal的整个操作流程。
(1) 每个Column的下方都有一个[Add Content]按钮,让用户选择加入自己喜欢的内容。
从这里,我们知道,Portal系统里面有一个公用的Common Portlet Repository,供用户选用。
JSR168 Portlet规范里面定义了Portlet Deployment Discriptor。Common Portlet Repository以这个Portlet Deployment Discriptor的格式存放。
开源项目JetSpeed的XReg文件用来存放Common Portlet Repository的定义。
(2) 加入Content之后,用户的Page和Column里面就多了这个Content。下次用户登陆的时候,就会看到自己订制的Portal版面。
从这里,可以看出,Portal系统会纪录用户的个人Portal配置信息 – User Portal Config。
开源项目JetSpeed的PSML文件用来存放User Portal Config的定义。
------- 综上。
Add Content的整个流程为:
Common Portlet Repository --> Add Content --> Personal Portal Config
Display Portal的整个流程为:
从Personal Portal Config读取用户配置的Portlet ID --> 根据Portlet ID,从Common Portlet Repository查找详细的Portlet定义 --> 根据这个详细的Portlet定义显示这个Portlet。
2.Portal实现
我们考虑如何用Java来实现Portal。
2.1 Dynamic Include
首先,我们采用最简单的思路,我们用100个JSP文件(1.jsp, 2.jsp, 3.jsp, … 100.jsp等),代表100个Portlet。
用户页面MyPage.jsp包含用户选定的多个Portlet。
现在,假设用户选取的Portlet为1.jsp, 3.jsp, 7.jsp等3个Portlet,那么我们如何在MyPage.jsp中显示这些Portlet?最直观的做法是,用jsp:include。比如:
<table>
<tr><td>
<jsp:include page=”1.jsp” />
</td></tr>
<tr><td>
<jsp:include page=”3.jsp” />
</td></tr>
<tr><td>
<jsp:include page=”7.jsp” />
</td></tr>
</table>
由于<jsp:include>只能指定固定的jsp文件名,不能动态指定jsp文件名。我们需要把<jsp:include>翻译为Java code – RequestDispatcher.include();
下面我们换成这种写法。
| java代码: |
|
<table> <tr><td> <% request.getRequestDispatcher(”1.jsp”).include(request, response); /> </td></tr> <tr><td> <% request.getRequestDispatcher(”3.jsp”).include(request, response); /> </td></tr> <tr><td> <% request.getRequestDispatcher(”7.jsp”).include(request, response); /> </td></tr> </table> |
| java代码: |
|
<% String[] fileNames = {“1.jsp”, “3.jsp”, “7.jsp”}; %> <table> <% for(int i = 0; i < fileNames.length; i++) { String fileName = fileName s[i]; %> <tr><td> <% request.getRequestDispatcher(fileName).include(request, response); /> </td></tr> <% } // end for %> </table> |
| java代码: |
|
<% String[] fileNames = (String[])session.getAttribute(“portlets.config”); %> <table> <% for(int i = 0; i < fileNames.length; i++) { String fileName = fileNames[i]; %> <tr><td> <% request.getRequestDispatcher(fileName).include(request, response); /> </td></tr> <% } // end for %> </table> |
| java代码: |
|
interface Portlet { void render(request, response); }; MyPage.jsp如下: <% String[] portletClassNames = (String[])session.getAttribute(“portlets.config”); %> <table> <% for(int i = 0; i < portletClassNames.length; i++) { String className = portletClassNames[i]; Portlet portlet = (Portlet)Class.forName(className).newInstance(); %> <tr><td> <% portlet. render (request, response); /> </td></tr> <% } // end for %> </table> Portlet类的示例代码如下: public class Portlet7{ public void render(request, response){ request.getRequestDispatcher(“7.jsp”).include(request, response); } }; |