这里我们主要以4.0的版本为主,虽然还只是rc1版,但相信正式版应该很快就出来了。
一、portal服务器下载和运行环境
首先访问liferay的官方网站http://www.liferay.com下载portal服务器,我们可以选择它的tomcat集成版下载,这样可以省去一些麻烦。
然后启动bin目录下的statup.bat就启动了tomcat服务,然后通过http://localhost:8080访问就可以,默认的用户名和密码是 test@liferay.com/test。
登录以后可以通过左方面的连接进入相关的操作:
“我的帐户”里可以进行个人信息,欢迎信息,语言等基本信息的设置。
“我的地方”可以分别进行个人,公开,gust,cms,suport等环境的设置,其实就相当于几个不同的虚拟站点。
针对“我的地方“的每个站点可以进行”页设置“,即站点页面和级次的设置
”增加内容“则是对当前所在的页面进行内容的添加或改变页面模版(但目前感觉它的范本设置还存在问题),如果要删除的话直接点击每个portlet的删除按钮就可以了。
另外在我的私人空间首页,即登录后默认的首页里,在”管理者“的portlet里我们可以进行相应的设置,像企业里可以改变站点的语言,banner图片等基本信息,portlets里可以进行目前的所有portlet的管理。
这个里面基本上都是一些设置的熟悉和使用,相信每个地方都试一试就会有所了解了。
二、简单的开发自己的portlet
做portlet开发通常首先也要建立一个独立的工程(避免和系统的混在一起不便于管理)。建立工程的时候不管是用jbuilder还是eclipse,和我们建立普通的web工程并没有什么不同。测试的例子以前网上有一篇介绍3.6.1的开发的写的很不错,我只是指出其中的一些不同和做一些补充,避免大家在多花去一些不必要的时间,我也是多花了几个小时才找出来的。
1、portlet程序编写
其中HelloWorldPortlet和HelloJSPPortlet 是两个独立的portlet测试,只不过前面一个类似servlet直接输出,而后者使用了jsp页面的显示。
package com.lyj.portal;
import java.io.IOException;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
public class HelloWorldPortlet extends GenericPortlet {
public void doView(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
res.setContentType("text/html");
res.getWriter().println("HelloWorld liuyujun test one! 中文测试一");
}
public void doEdit(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
res.setContentType("text/html");
res.getWriter().println("HelloWorld liuyujun test two! 中文测试二");
}
}
package com.lyj.portal;
import java.io.IOException;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.PortletPreferences;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
public class HelloJSPPortlet extends GenericPortlet {
public void doView(RenderRequest req, RenderResponse res) throws
IOException, PortletException {
res.setContentType("text/html");
String jspName = getPortletConfig().getInitParameter("view-jsp");
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(
jspName);
rd.include(req, res);
}
public void doEdit(RenderRequest req, RenderResponse res) throws
IOException, PortletException {
res.setContentType("text/html");
String jspName = getPortletConfig().getInitParameter("edit-jsp");
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(
jspName);
rd.include(req, res);
}
}
2、我们在工程的web的根目录下再增加HelloJSPPortlet需要用到的两个jsp文件
view.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<table cellpadding="8" cellspacing="0" width="100%">
<tr>
<td>
<font class="Portlet-font" style="font-size: x-small;">
This is a <b>Sample JSP Portlet</b> used in viewing model。 Use this as a quick
wayy to include JSPs。 view 成功
</td>
</tr>
</table>
edit.jsp
<%@ page language="java" contentType="text/html;charset=GBK"%>
<table cellpadding="8" cellspacing="0" width="100%">
<tr>
<td>
<font class="Portlet-font" style="font-size: x-small;">
This is a <b>Sample JSP Portlet</b> used in viewing model。 Use this as a quick
wayy to include JSPs。edit 万岁
</td>
</tr>
</table>
注意橙色背景的内容一定要加上,不然会有中文乱码问题
3、web.xml配置
<?xml version="1.0"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="TestPortal">
<display-name>TestPortal</display-name>
<context-param>
<param-name>company_id</param-name>
<param-value>liferay.com</param-value>
</context-param>
<listener>
<listener-class>com.liferay.portal.shared.servlet.PortletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>HelloWorldPortlet</servlet-name>
<servlet-class>com.liferay.portal.servlet.PortletServlet</servlet-class>
<init-param>
<param-name>portlet-class</param-name>
<param-value>com.lyj.portal.HelloWorldPortlet</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldPortlet</servlet-name>
<url-pattern>/HelloWorldPortlet/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>HelloJSPPortlet</servlet-name>
<servlet-class>com.liferay.portal.servlet.PortletServlet</servlet-class>
<init-param>
<param-name>Portlet-class</param-name>
<param-value>com.lyj.portal.HelloJSPPortlet</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloJSPPortlet</servlet-name>
<url-pattern>/HelloJSPPortlet/*</url-pattern>
</servlet-mapping>
<taglib>
<taglib-uri>http://java.sun.com/portlet</taglib-uri>
<taglib-location>/WEB-INF/tld/liferay-portlet.tld</taglib-location>
</taglib>
</web-app>
其中红色字体和蓝色字体的内容,如果以前使用3.6.1的一定要注意,蓝色部分以前是不需要加的,但是现在是必须的,如果不加的话,在portal管理列表里能列出我们开发的portlet,但在添加内容时无法找到我们自己的portlet。红色字体的部分相对原来多了shared,也就是它的类包进行了一定的调整,注意一下就可以了。
4、另外增加WEB-INF下增加portlet的私有配置文件
portlet.xml
<?xml version="1.0"?>
<portlet-app xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
<portlet>
<portlet-name>HelloWorldPortlet</portlet-name>
<display-name>HelloWorldPortlet</display-name>
<portlet-class>com.lyj.portal.HelloWorldPortlet</portlet-class>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>edit</portlet-mode>
</supports>
<portlet-info>
<title>HelloWorldPortlet</title>
<short-title>HelloWorldPortlet</short-title>
<keywords>HelloWorldPortlet</keywords>
</portlet-info>
<portlet-preferences>
<preference>
<name>portlet-title</name>
<value></value>
</preference>
<preference>
<name>show-portlet-borders</name>
<value>true</value>
</preference>
</portlet-preferences>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
<portlet>
<portlet-name>HelloJSPPortlet</portlet-name>
<display-name>HelloJSPPortlet</display-name>
<portlet-class>com.lyj.portal.HelloJSPPortlet</portlet-class>
<init-param>
<name>view-jsp</name>
<value>/view.jsp</value>
</init-param>
<init-param>
<name>edit-jsp</name>
<value>/edit.jsp</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>edit</portlet-mode>
</supports>
<portlet-info>
<title>HelloJSPPortlet</title>
<short-title>HelloJSPPortlet</short-title>
<keywords>HelloJSPPortlet</keywords>
</portlet-info>
<security-role-ref>
<role-name>guest</role-name>
</security-role-ref>
<security-role-ref>
<role-name>power user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
</portlet-app>
liferay-portlet.xml
<?xml version="1.0"?>
<!DOCTYPE liferay-portlet-app PUBLIC "-//Liferay//DTD Portlet Application 3.5.0//EN" "http://www.liferay.com/dtd/liferay-portlet-app_3_5_0.dtd">
<liferay-portlet-app>
<portlet>
<portlet-name>HelloWorldPortlet</portlet-name>
<struts-path>HelloWorldPortlet</struts-path>
<use-default-template>true</use-default-template>
<instanceable>true</instanceable>
</portlet>
<portlet>
<portlet-name>HelloJSPPortlet</portlet-name>
<struts-path>HelloJSPPortlet</struts-path>
<use-default-template>true</use-default-template>
<instanceable>true</instanceable>
</portlet>
<role-mapper>
<role-name>administrator</role-name>
<role-link>Administrator</role-link>
</role-mapper>
<role-mapper>
<role-name>guest</role-name>
<role-link>Guest</role-link>
</role-mapper>
<role-mapper>
<role-name>power user</role-name>
<role-link>Power User</role-link>
</role-mapper>
<role-mapper>
<role-name>user</role-name>
<role-link>User</role-link>
</role-mapper>
</liferay-portlet-app>
liferay-display.xml
<?xml version="1.0"?>
<!DOCTYPE display PUBLIC "-//Liferay//DTD Display 3.5.0//EN" "http://www.liferay.com/dtd/liferay-display_3_5_0.dtd">
<display>
<category name="category.test">
<portlet id="HelloWorldPortlet"/>
<portlet id="HelloJSPPortlet"/>
</category>
</display>
5、在WEB-INF下新建一个tld目录,把 tomcat/liferay/WEB-INF/tld/liferay-portlet.tld 复制过来就可以了
6、编译完成后,像我们正常的发布web的方式发布就可以了,比如修改tomcat的配置文件,直接用一个虚拟目录TestPortal指向我们工程的web目录;或者把我们的web目录打包成TestPortal.war放到tomcat的webapps目录下就可以了。重新启动tomcat,登录后,我们会在portlet管理中发现增加了HelloWorldPortlet,HelloJSPPortlet两个portlet,在增加内容的时候在弹出的内容页面 测试(test)中多了上述的两个portlet。并且可以增加到我们的页面中看看效果吧。
JSR168中定义了Portal的实现规范和接口,并对理想的Portlet进行了详细的规划和描述。
它的特点在于生产者将消费者所需要的信息通过WSRP返回给消费者,这些信息是相对标记片断,例如HTML、XHTML等,可以直接嵌入用户的页面中,而不用像Web Service一样开发用户端接口。
实现这个规范,Portal可以跟各式各样的数据源打交道,彻底终结信息孤岛的窘境。
什么是Portal
Portal是基于Web的,以“应用整合”和“消除信息孤岛”为最终目的,提供单点登录、内容聚合、个性化门户定制等功能的综合信息系统。
完整的Portal通常由Portal服务器、Portlet容器、Portlet构成。
Portal 服务器Portal服务器是容纳Portlet容器,支持Portlet呈现的普通或者特殊Web服务器。Portal服务器通常会提供个性化设置、单点登录、内容聚合、信息发布、权限管理等功能,支持各种信息数据来源,并将这些数据信息放在网页中组合而成,提供个性化的内容定制,不同权限的浏览者能够浏览不同的信息内容。通常,Portal提供以下功能:
单点登录:Portal通常采用ACL、SSL、LDAP等业界标准的安全技术,提供对所有现有应用系统的安全集成,只需在Portal的唯一入口上登录一次,就可以访问所有应用系统和数据。对于安全性要求较高的应用系统,如电子商务平台、交易系统等,通过扩展接口传递用户身份信息,如数字证书信息、数字签名信息等,进行二次身份认证,保证单点登陆的安全性。
权限控制:系统采用LDAP对用户资源进行统一的管理,同时提供二次开发接口,可以与其他应用系统的用户管理模块对接,并能随相关业务系统实时更新访问权限。通过完善的授权机制及存取控制,用户访问权限控制到字段级别,确保用户只能访问具有权限的应用系统及相关信息。
内容管理: 实现应用系统之间实时交换信息。采用多种缓存机制,保证内容交换的性能和准确性。采用基于XML的Rich Site Summary (RSS)标准,迅速在各应用系统之间传播最新变化。
信息发布: 实现信息门户内容的动态维护。动态网站系统可与OA协同办公系统、知识管理系统等集成,网站信息须经OA系统的审批流程流转通过后或知识管理平台设置具有外部共享权限后才可正式发布,真正实现内外信息发布的同步。
文件管理: 系统实现无缝集成多种数据源,包括:数据库、文档(Office文档、PDF、AutoCAD、甚至ZIP文档)、Web网页、FTP站点等,并对数据按业务要求和职务特点加以分析整理,通过统一Web界面主动推送(Push)至用户的门户桌面,帮助用户做出及时、正确的决策。
Portlet容器Portlet容器提供Portlet执行的环境,包含很多Portlet并管理它们的生命周期,保存Portlet的定制信息。
一个Portal容器接收到来自Portal的请求后,接着将这个请求传递给存在Portal容器的Portlet 执行。Portlet容器没有义务去组合Portlet 产生的信息內容,这个工作必须由Portal来处理。Portal和 Portal容器可以放在一起视为同一个系统的组件,或者分开成为两个独立的组件。
Portlet容器是普通Web Servlet容器的扩展,所以一个Portlet容器可以构建于一个已经存在的Servlet容器或者可能实现全部Web Servlet容器的全部功能。无论Portlet容器怎么实现,它的运行环境总是假定它支持Servlet2.3规范。
通常,Portlet容器扩展自普通的Servlet容器
Portlet与Servlet的关系Portlet被定义成为一个新的组件,具有新的明确的界面与行为。为了尽可能与现有的 Servlet 结合达到重复使用的目的,Portlet 的规范利用了 Servlet 的规范,许多观念都很相似的,结合 Portlet、Servlet 及 Jsp 在同一个网站系统中,我们称为Portlet 应用 。在同一个 Portlet 应用 中,他们将分享同一个类加载器(ClassLoader),上下文(Context) 及 Session。
①、Portlet 和 Servlet 的相似之处
@ Portlet 也是 Java 技术的 web 组件
@ Portlet 也是有特定的 container 在管理
@ Portlet 可以动态产生各种内容
@ Portlet 的生命周期由 container 所管理
@ Portlet 和客户端的互动是通过 request/response 的机制
②、Portlet 和 Servlet 也有一些不同
@ Portlet 只产生 markup 信息片段,不是完整的网页文件。而 Portal 会将所有的 Portlet markup 信息片段放到一个完整的 Portal 网页。
@ Portlet 不会和 URL 有直接的关系
@ 客户端必须通过 portal 系统才能和 Portlet 互动
@ Portlet 有一些定义好的 request 处理,action request 以及 render request。
@ Portlet 默认定义 Portlet modes 及窗口状态可以指出在网页中该 Portlet 的哪个功能正在执行及现在的 状态。
@ Portlet 可以在同一个 portal 网页之中存在多个。
③、Portlet 有一些附加的功能是 Servlet 所没有的
@ Portlet 能够存取及储存永久配置文件及定制资料。
@ Portlet 可以存取使用者数据
@ Portlet 具有 URL 的重写功能在文件中去动态建立连结,允许 portal server 不用去知道如何在网页的片 段之中建立连结及动作。
@ Portlet 可以储存临时性的数据在 Portlet session 之中,拥有两个不同的范围:
application-wide scope 及 Portlet private scope 。
④、Portlet 不具有一些功能, 但是 Servlet 却有提供
@ Servlet 具有设置输出的文字编码( character set encoding)方式
@ Servlet可以设置 HTTP 输出的 header
@ Servlet才能够接收客户对于 portal 发出的 URL 请求
Portlet的生命周期
Portlet的生命周期一个Portlet有着良好的生命周期管理,定义了怎样装载,实例化和初始化,怎样响应来自客户端的请求及怎样送出服务。这个Portlet生命周期由Portlet接口的init,processAction,render和destroy方法来表达。
载入和实例化:Portlet容器负责载入和实例化Portlet。当Portlet容器运行Portlet应用或者延迟到Portlet需要服务使用者的请求时,Portlet就会被载入并实例化。载入Portlet类后,Portlet类随即被实例化。
初始化:Portlet类实例化后,Portlet容器还需要初始化Portlet。以调用Portlet去响应客户端的请求。Portlet容器呼叫Portlet接口中的init方法初始化Portlet。扩展自PortletConfig的类可以取出定义在部署描述文件中的初始化参数,以及Resource Bundle。
初始化异常:在 Portlet初始化期间,Portlet可能会丟出 UnavailableException 或 PortletException 异常。此时,Portlet容器不能把 Portlet置入已启动的服务,并且 Portlet容器必需释放这个 Portlet。 destory方法不能被呼叫,因为初始化被认为执行失败。发生 失败后,Portlet容器会尝试着重新实例化及初始化 Portlet。这个异常处理的规则是:由一个UnavailableException 指定一个不能执行的最小时间,当此异常发生时,Portlet容器必需等到指定时间过去后才产生并且初始化一个新的 Portlet。
在初始化过程中所丟出的 Runtime Exception异常,被当作 PortletException 来处理。
重要的基类:GenericPortlet像Servlet一样,编写的Portlet也必须直接或者间接的扩展基类GenericPortlet,这个是由JCP针对Portal提出的JSR168规范定义的。只要扩展自规范的GenericPortlet,所有的Portlet都可以在支持JSR168规范的Portal服务器上运行。
GenericPortlet统一定义了可供Portal容器识别和调用的方法,包括:
public Init():初始化;
public Init(PortletConfig) :初始化;
public getInitParameter(String):取得在Portlet.xml中定义的初始化参数;
public getInitParameterNames():取得在Portlet.xml中定义的全部初始化参数;
public getPortletConfig():取得包含初始化参数的配置对象PortletConfig实例;
public getPortletContext():取得Portlet上下文;
public getPortletName():取得在Portlet.xml中定义的Portlet名称。
public getResourceBundle(Locale) :取得Portlet国际化的Resource Bundle;
protected getTitle(RenderRequest) :取得Portlet的标题;
protected doView(RenderRequest,RenderResponse) :Portlet浏览模式的处理方法;
protected doEdit(RenderRequest,RenderResponse) :Portlet编辑模式的处理方法;
protected doHelp(RenderRequest,RenderResponse) :Portlet帮助模式的处理方法;
protected doDispatch(RenderRequest,RenderResponse) :Portlet行为分发;
protected processAction(RenderRequest,RenderResponse) :Portlet处理Action Request的方法;
protected render(RenderRequest,RenderResponse):Portal处理Render Request的方法;
public destroy():Portlet销毁,终止其生命周期。
在Portlet Portal运行的时候,doView、doEdit、doHelp三个方法分别被调用,用以生成Portlet标记。同样也可以调用Servlet生成Portlet标记,或者不调用JSP或者Servlet,直接在方法中得到PrintWriter然后用最简单的pw.println()打印出内容。这个过程类似Servlet.