开发环境:WinXP+SP2,RAD 7.0.0.3
测试环境:Win2003+SP2,WebSphere Portal6
示例1:在Portlet编辑页面中添加用户登录界面,在视图页面中显示用户名和密码。
1. 启动RAD。
2. 新建Portlet项目。
选择“文件-》新建-》Portlet项目”。
将项目命名为PortletExample,选择“创建portlet”,RAD就会自动在项目中添加一portlet。由于是要部署在Portal6上的,目标运行时设置为“WebSphere Portal V6.0 stub”。Portlet API选择“JSR 168 Portlet”,我们要开发的就是它嘛,如果还是“IBM Portlet”,搞不好哪天就被IBM自己抛弃了
Portlet类型选择“基本Portlet”,RAD就会创建一示例portlet,我们只需在其上做一些修改即可。其它都接受默认即可。
将所有的视图都勾上。
取消“将操作侦听器添加至portlet以处理操作请求”,我们暂时不会涉及到该方面内容。然后“完成”即可。
项目建立完成后我们就可以看见如图所示的项目文件列表。
WebContent下包含了项目的jsp文件,五个jsp文件分别对应五种视图。
3.编写代码。
(1)在PortletExamplePortlet.java中定义三变量EDIT_USERNAME、EDIT_PASSWORD和EDIT_CANCEL。EDIT_CANCEL用于处理按钮的取消事件。
public
static
final
String
EDIT_USERNAME
=
"PortletExamplePortletEditUsername"
;
public
static
final
String
EDIT_PASSWORD
=
"PortletExamplePortletEditPassword"
;
public
static
final
String
EDIT_CANCEL
=
"PortletExamplePortletEditCancel"
;
(2)编辑PortletExamplePortlet.java,处理EDIT_SUBMIT和EDIT_CANCEL按钮事件,在函数processAction中针对编辑视图的提交请求和取消进行处理,将username和password两值存入到PortletPreferences中。
if
( request.getParameter(
EDIT_SUBMIT
) !=
null
) {
PortletPreferences prefs = request.getPreferences();
try
{
prefs.setValue(
EDIT_USERNAME
,request.getParameter(
EDIT_USERNAME
));
prefs.setValue(
EDIT_PASSWORD
,request.getParameter(
EDIT_PASSWORD
));
prefs.store();
}
catch( ReadOnlyException roe ) {
}
catch( ValidatorException ve ) {
}
response.setPortletMode(PortletMode.
VIEW
);
}
if
( request.getParameter(
EDIT_CANCEL
) !=
null
) {
response.setPortletMode(PortletMode.
VIEW
);
}
使用response.setPortletMode(PortletMode.VIEW);语句决定提交后将转向的视图。
(3)编辑PortletExamplePortletEdit.jsp,删除RAD自动生成的代码,设计用户名和密码提交页面。
<%@
page
session
=
"false"
contentType
=
"text/html"
pageEncoding
=
"GB18030"
import
=
"javax.portlet.*,portletexample.*"
%>
<%@
taglib
uri
=
"http://java.sun.com/portlet"
prefix
=
"portlet"
%>
<
portlet:defineObjects
/>
<%
PortletPreferences prefs = renderRequest.getPreferences();
if
(prefs !=
null
) {
String username = prefs.getValue(PortletExamplePortlet.EDIT_USERNAME, ""
);
String password = prefs.getValue(PortletExamplePortlet.EDIT_PASSWORD, ""
);
%>
<
FORM
ACTION
=
"<portlet:actionURL/>"METHOD="POST">
Username:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.EDIT_USERNAME%>"VALUE="<%=username%>"TYPE="text"><BR>
Password:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.EDIT_PASSWORD%>"VALUE="<%=password%>"TYPE="password"><BR>
<
INPUT
NAME
=
"<%=PortletExamplePortlet.EDIT_SUBMIT%>"TYPE="submit" value="Save">
<
INPUT
NAME
=
"<%=PortletExamplePortlet.EDIT_CANCEL%>"TYPE="submit" value="Cancel">
</
FORM
>
<%
}
else
{
%>
Error: PortletPreferences is null.
<%
}
%>
注意标签<portlet:defineObjects/>,在页面中添加它后才可调用PortletConfig、RenderRequest、RenderResponse这几个对象。
(4)编辑PortletExamplePortletView.jsp,在页面上输出用户名和密码值。
<%@
page
session
=
"false"
contentType
=
"text/html"
pageEncoding
=
"GB18030"
import
=
"javax.portlet.*,portletexample.*"
%>
<%@
taglib
uri
=
"http://java.sun.com/portlet"
prefix
=
"portlet"
%>
<
portlet:defineObjects
/>
<%
PortletPreferences prefs = renderRequest.getPreferences();
if
(prefs !=
null
) {
String username = prefs.getValue(PortletExamplePortlet.EDIT_USERNAME, ""
);
String password = prefs.getValue(PortletExamplePortlet.EDIT_PASSWORD, ""
);
%>
<
P
>
<%=
PortletExamplePortlet.EDIT_USERNAME
%>
:
<%=
username
%>
</
P
>
<
P
>
<%=
PortletExamplePortlet.EDIT_PASSWORD
%>
:
<%=
password
%>
</
P
>
<%
}
else
{
%>
Error: PortletPreferences is null.
<%
}
%>
4.全部修改完成后保存,导出WAR安装包。
指定导出位置。
5.在Portal6上安装,新建一测试页面将该Portlet添加到页面上。
初始运行界面如图,由于最初用户名和密码都为空,所以显示的也都是空的。
点击右上角小三角打开portlet菜单,点击个性化,即进入编辑模式,输入用户名密码然后保存。
此时页面转往视图模式,显示刚才设置的用户名和密码值。
如在个性化设置中点击取消,则所做改动无效,直接转回视图模式。
至此,第一个Portlet示例就开发完成了。
读者可以试着实现在配置模式中完成相同功能。
===========================================================================================
第二个示例:在Portlet配置页面中添加设置界面,在视图页面中显示用户设定的网页链接,同时可以控制该网页的宽度和高度。
在第一个示例项目中添加代码实现本示例。
(1)在PortletExamplePortlet.java中定义变量。
public
static
final
String
CONFIG_TITLE
=
"PortletExamplePortletConfigTitle"
;
public
static
final
String
CONFIG_URL
=
"PortletExamplePortletConfigUrl"
;
public
static
final
String
CONFIG_WIDTH
=
"PortletExamplePortletConfigWidth"
;
public
static
final
String
CONFIG_HEIGHT
=
"PortletExamplePortletConfigHeight"
;
public
static
final
String
CONFIG_MAXWIDTH
=
"PortletExamplePortletConfigMaxWidth"
;
public
static
final
String
CONFIG_MAXHEIGHT
=
"PortletExamplePortletConfigMaxHeight"
;
public
static
final
String
CONFIG_CANCEL
=
"PortletExamplePortletConfigCancel"
;
(2)编辑PortletExamplePortlet.java,处理CONFIG_SUBMIT和CONFIG_CANCEL按钮事件,在函数processAction中针对配置视图的提交和取消进行处理,将各参数值存入到PortletPreferences中。
if
( request.getParameter(
CONFIG_SUBMIT
) !=
null
) {
PortletPreferences prefs = request.getPreferences();
try
{
prefs.setValue(
CONFIG_TITLE
,request.getParameter(
CONFIG_TITLE
));
prefs.setValue(
CONFIG_URL
,request.getParameter(
CONFIG_URL
));
prefs.setValue(
CONFIG_WIDTH
,request.getParameter(
CONFIG_WIDTH
));
prefs.setValue(
CONFIG_HEIGHT
,request.getParameter(
CONFIG_HEIGHT
));
prefs.setValue(
CONFIG_MAXWIDTH
,request.getParameter(
CONFIG_MAXWIDTH
));
prefs.setValue(
CONFIG_MAXHEIGHT
,request.getParameter(
CONFIG_MAXHEIGHT
));
prefs.store();
}
catch
( ReadOnlyException roe ) {
}
catch( ValidatorException ve ) {
}
response.setPortletMode(PortletMode.
VIEW
);
}
if
( request.getParameter(
CONFIG_CANCEL
) !=
null
) {
response.setPortletMode(PortletMode.
VIEW
);
}
(3)编辑PortletExamplePortletConfig.jsp,删除RAD自动生成的代码,设计参数提交页面。
<%@
page
session
=
"false"
contentType
=
"text/html"
pageEncoding
=
"GB18030"
import
=
"javax.portlet.*,portletexample.*"
%>
<%@
taglib
uri
=
"http://java.sun.com/portlet"
prefix
=
"portlet"
%>
<
portlet:defineObjects
/>
<%
PortletPreferences prefs = renderRequest.getPreferences();
if
(prefs !=
null
) {
String title = prefs.getValue(PortletExamplePortlet.CONFIG_TITLE,
"ConfigTitle"
);
String url = prefs.getValue(PortletExamplePortlet.CONFIG_URL,
"http://www.csdn.net"
);
String width = prefs.getValue(PortletExamplePortlet.CONFIG_WIDTH,
"50%"
);
String height = prefs.getValue(PortletExamplePortlet.CONFIG_HEIGHT,
"400"
);
String maxwidth = prefs.getValue(PortletExamplePortlet.CONFIG_MAXWIDTH,
"100%"
);
String maxheight = prefs.getValue(PortletExamplePortlet.CONFIG_MAXHEIGHT,
"800"
);
%>
<
FORM
ACTION
=
"<portlet:actionURL/>"METHOD="POST">
Title:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_TITLE%>"VALUE="<%=title%>"TYPE="text"><BR>
URL:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_URL%>"VALUE="<%=url%>"TYPE="text"><BR>
Width:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_WIDTH%>"VALUE="<%=width%>"TYPE="text"><BR>
Height:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_HEIGHT%>"VALUE="<%=height%>"TYPE="text"><BR>
MaxWidth:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_MAXWIDTH%>"VALUE="<%=maxwidth%>"TYPE="text"><BR>
MaxHeight:
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_MAXHEIGHT%>"VALUE="<%=maxheight%>"TYPE="text"><BR>
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_SUBMIT%>"TYPE="submit" value="Save">
<
INPUT
NAME
=
"<%=PortletExamplePortlet.CONFIG_CANCEL%>"TYPE="submit" value="Cancel">
</
FORM
>
<%
}
else
{
%>
Error: PortletPreferences is null.
<%
}
%>
(4)修改PortletExamplePortletView.jsp,输出网页内容,使用的是自组织html的方法。getWindowState()方法可以获取目前portlet的窗口状态,是最大化、最小化还是普通状态,从而确定网页宽度和高度。
<%@
page
session
=
"false"
contentType
=
"text/html"
pageEncoding
=
"GB18030"
import
=
"javax.portlet.*,portletexample.*"
%>
<%@
taglib
uri
=
"http://java.sun.com/portlet"
prefix
=
"portlet"
%>
<
portlet:defineObjects
/>
<%
StringBuffer sbContentHTML =
new
StringBuffer();
PortletPreferences prefs = renderRequest.getPreferences();
String sFrameWidth, sFrameHeight;
if
(prefs !=
null
) {
if
(renderRequest.getWindowState().equals(WindowState.MAXIMIZED)) {
sFrameWidth = prefs.getValue(PortletExamplePortlet.CONFIG_MAXWIDTH,
"100%"
);
sFrameHeight = prefs.getValue(PortletExamplePortlet.CONFIG_MAXHEIGHT,
"800"
);
}
else
{
sFrameWidth = prefs.getValue(PortletExamplePortlet.CONFIG_WIDTH,
"50%"
);
sFrameHeight = prefs.getValue(PortletExamplePortlet.CONFIG_HEIGHT,
"400"
);
}
sbContentHTML.append(
"<iframe frameborder=0"
);
sbContentHTML.append(
" src=/""
+ prefs.getValue(PortletExamplePortlet.CONFIG_URL,
"http://www.csdn.net"
) +
"/""
);
sbContentHTML.append(
" width=/""
+ sFrameWidth +
"/""
);
sbContentHTML.append(
" height=/""
+ sFrameHeight +
"/""
);
sbContentHTML.append(
"></iframe>"
);
out.print(sbContentHTML.toString());
}
else
{
%>
Error: PortletPreferences is null.
<%
}
%>
5.全部修改完成后保存,导出WAR安装包,更新Portal6上的Web模块,然后查看页面。可以看到初始页面显示的是CSDN,这是由于没有初始值,所以各参数取出的都是getValue函数中设置的默认值,Portlet窗体高度为400象素,网页宽度50%。
选择最大化菜单,可以发现网页宽度变为100%,显示的是完整网页了,窗体高度也拉长了,这就是由于在最大化状态下网页使用的宽度和高度参数值不同。
选择配置菜单进入配置模式,输入各参数值然后保存。
保存后页面再次转往视图,此时显示的页面就改变了,Portlet窗体高度为300象素,网页宽度100%,这都是刚才设置的内容。
如此,第二个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,并读取该值才能显示。
下面是实现步骤。在示例2的代码中进行修改实现。
(1)修改皮肤。
复制IBM皮肤文件夹,重命名为IBM_DT,修改其中的control.jsp。
找到其中如下一段代码
<portal-skin:portletTitle>
<portal-fmt:problem bundle="nls.problem"/>
</portal-skin:portletTitle>
为其添加span或者div标签,用于修改时的定位,修改为
<span id="title.<portal-skin:portletID/>">
<portal-skin:portletTitle>
<portal-fmt:problem bundle="nls.problem"/>
</portal-skin:portletTitle>
</span>
然后在control.jsp文件的最下方,添加如下代码用于修改标题栏文字。
<script type="text/javascript">
var dynamicTitle ="<%=request.getAttribute(com.ibm.portal.portlet.Constants.DYNAMIC_TITLE)%>";
var titleElement = document.getElementById("title.<portal-skin:portletID/>");
if (titleElement != null) {
if (dynamicTitle != "" && dynamicTitle != "null")
titleElement.innerHTML = dynamicTitle;
}
</script>
如此,皮肤就修改完成了。
(2)修改PortletExamplePortletView.jsp,在其中添加一行代码。
renderResponse.setTitle(prefs.getValue(PortletExamplePortlet.CONFIG_TITLE, "ConfigTitle"));
(3)转入Portal中查看显示效果。
安装该皮肤,并且设置要修改标题的Portlet都要使用该皮肤。
为了演示此种方式可以同时在一个页面中给多个portlet设置不同的标题文字,我们可以再复制一个PortletExample Portlet,命名为PortletExample2,然后将其也添加到测试页面上。然后给这两个Portlet配置不同的参数,如下图,可以看到,两个Portlet的标题是不同的,显示内容、高度等也都不同。
为了演示此种方式可以同时在一个页面中给多个portlet设置不同的标题文字,我们可以再复制一个PortletExample Portlet,命名为PortletExample2,然后将其也添加到测试页面上。然后给这两个Portlet配置不同的参数,如下图,可以看到,两个Portlet的标题是不同的,显示内容、高度等也都不同。
这种方式修改的只是View视图时的标题,如果我们进入配置模式,会发现标题栏还是原来的名字。
RenderResponse.setTitle(String title)函数也可以在PortletExamplePortlet.java中的doView、doEdit等函数中调用,显示结果与直接在jsp中调用相同,留待读者自己尝试。
========================================================================================================================================
示例四:JSR 168协作portlet
本实例展现协作portlet的开发方法。
(1
)创建一个新的名为PortletCooperative
的portlet
项目。
Portlet名称为PortletSource,类型选“基本Portlet”。
内容方式只选择“查看”,因为在这个示例中我们只需使用这一个视图。
下面的配置全部都勾去不选,这个示例中用不到。
(2)在项目PortletCooperative中再新建一Portlet名为PortletTarget,设置与PortletSource相同。
(3)使用协作源向导激活这个源portlet共享数据。
1. 展开
Portlet部署描述符 节点。
2. 右键点击PortletSource,选择 协作->使此Portlet能够发送数据(源)。
3. 将数据类型URI变更为
http://portletcooperative#msg,Java类型仍是String。
4. “操作参数”不变,将“操作值”更改为 SendMsg。“位置”仍选择“请求属性”,将“属性名”更改为outputMsg。
5. 保留默认设置。
6. 最后会显示一个配置协作源Portlet步骤的文档,对初学者是个很好的参考。
(4)使用协作目标向导使目标portlet接收数据。
1. 展开
Portlet部署描述符 节点。
2. 右键点击PortletTarget,选择 协作->使此Portlet能够发送数据(源)。
3. 将数据类型URI变更为
http://portletcooperative#msg,注意名称要和PortletSource中的URI相同。
4. “操作参数”不变,将“操作值”更改为
RevMsg。“位置”选择“请求参数”,将“属性名”更改为inputMsg。
5. 保留默认设置。
6. 最后照样会显示一个配置协作目标Portlet步骤的文档。
配置完成后展开Portlet部署描述符可以看到刚定义的行为和数据类型。
(5)添加协作源触发器入PortletSourcePortletView.jsp
1. 在页面中添加一文本框,名为msg。
将Portlet页签中的“协作源触发器”拖放进PortletSourcePortletView设计页,会弹出“插入协作源触发器”向导。“源portlet”选择PortletSource,“操作值”SendMsg,“属性名”outputMsg,“要发送的值”暂时先设为data,下面马上就会修改。“UI控件类型”选择按钮。
设计完成页面如下图。
页面代码:
<%@page session="false" contentType="text/html" pageEncoding="GB18030"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>
<form method="POST" action="<portlet:actionURL/>">
<input type="text" name="msg" size="20" value="">
<input name="ACTION_NAME_PARAM" value="SendMsg" type="hidden">
<input name="submit" value="
发送
" type="submit">
</form>
2. 打开PortletSourcePortlet.java,可以发现RAD已经自动在函数processAction中生成了一段代码,我们稍微做一下改动,让其取msg文本框中的值。
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException {
if(ACTION_NAME != null && ACTION_NAME.equals(request.getParameter(ACTION_NAME_PARAM))) {
request.setAttribute("outputMsg",
request.getParameter("msg"));
}
}
(6)对PortletTarget进行修改
1. 修改PortletTargetPortletView.jsp代码
<%@page session="false" contentType="text/html" pageEncoding="GB18030" import="javax.portlet.*" %>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>
<%PortletPreferences prefs = renderRequest.getPreferences();%>
<p><%=prefs.getValue("msg", "Hello World") %></p>
2. 修改PortletTargetPortlet.java
这个文件无法自动生成代码,只能手动添加了。
在头部添加两常量定义:
public static final String ACTION_NAME = "RevMsg";
public static final String ACTION_NAME_PARAM = "ACTION_NAME_PARAM";
修改processAction函数,将取得的传入值存入PortletPreferences:
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException {
if(ACTION_NAME != null && ACTION_NAME.equals(request.getParameter(ACTION_NAME_PARAM))) {
PortletPreferences prefs = request.getPreferences();
prefs.setValue("msg",request.getParameter("inputMsg"));
prefs.store();
}
}
(7)安装测试
开发完成,将Portlet文件导出然后在Portal上安装。
分别建立两个页面SourcePage和TargetPage,然后将两个portlet分别放置在它们上面。在此我们测试跨页面的传值。
1. 进入TargetPage的“编辑页面布局”,在“联结”标签中,点击“管理操作”。
在页面中勾选“RevMsg Action”的“全局”选项,只有在此选择了才可跨页接收。
2. 进入SourcePage的“编辑页面布局”,在“联结”标签中,创建联结。注意,全部设置完成后要点击最后的加号确认添加,如此联结才真正建立。
3. 访问测试。
输入文字后点击“发送”即可发现页面自动跳转到TargetPage,并显示出该文本。
学习Faces Portlet的开发方法可以参考IBM网站上的文章《使用 Application Developer V7 来创建和部署 JSR 168 协作 portlet》。读者可以照着该文操作一遍,体验下JSF开发的优点,代码一句都不用写