By Terry.li
SpiritSeekerS@sqatester.com
本文使用本系列中
Part1
搭建的开发环境
,
如果没有搭建好开发环境
,
请参考
Portlet
应用开发
Part1
进行开发环境的搭建
.
在
Part1
中我们已经介绍了
Portlet
的
GenericPortlet
类
.
从形式上来看
, Portlet
与
Servlet
非常相似
,
但是从
request
和
response
对象的具体特点及功能来说
,
又有所不同
.
本部分主要描述了
Portlet
的
Request
和
Response
对象
的特点及其与
Servlet
的
Request
和
Response
对象
的不同点
.
l
Portlet
的
Request
对象
Portlet
中的
Request
与
Servlet
的
Request
一样接受
Client
端发送的
Request,
但是与
Servlet
不同
, Portlet
的
Request
分为
Action Request
及
Render Request
两种类型
,
因此
Portlet
接口中定义了两种方法用来处理不同的
Request.
分别是
processAction(ActionRequest request,ActionResponse response)
和
render(RenderRequest request,RenderResponse response),
分别用以处理
Action Request
和
Render Request.
某种意义上来讲
,render
方法类似
Servlet
中的
service
方法
,doView,doEdit,doHelp
方法又类似
doGet,doPost
方法
,
如下图
:
1.
RenderRequest
和
ActionRequest
有什么不同呢
?
对于
Portlet
来说
PortletRequest
分为
ActionRequest
和
RenderRequest
两种
,
分别是由
renderURL
和
actionURL
来触发的
.
可以这样理解
, renderURL
是
actionURL
的一种优化形式
.Portlet
开发过程中尽可能使用
renderURL
而避免使用
actionURL. actionURL
适用于有确实的
Action(
行为
)
的情况下
.
比如说
, form
表单的递交
. Persistent
状态的改变,
session
的操作,
preference
的修改
,
这种情况下使用
actionURL,
而不使用
renderURL, renderURL
通常用来操作
portlet
内容的导航
.
以下是两个例子:
使用
actionURL:
<%
PortletURL pu=renderResponse.createActionURL();
pu.setParameter("ACTION","LOGIN");
…
%>
<form name="usrfrm" method="post" action="<%=pu.toString()%>">
注
: form
表单递交时,使用
HTTP post
方法,而不用
get
方法.因为某些
Portal/Portlet Container
的实现将内部状态编码到
URL
的
Query
字符串中.
使用
renderURL:
<%
PortletURL pu=renderResponse.createRenderURL();
pu.setParameter("PAGE",Number);
…
%>
<a href=”<%=pu%>”>
下一页
</a>
2. renderURL
和
actionURL
的处理方式有什么不同?
当客户端
request
是由
一个
renderURL
触发
时,
Portlet/Portlet Container
会调用
Portal
页面中所有
Portlet
的
render
方法.
如下
:
renderURL
/ | \
render render render
而
当客户端
request
一个
actionURL
触发时
, Portlet/Portlet Container
会先调用目标
Portlet
的
processAction()
方法,
当
processAction
方法处理完毕后
,
再分别调用
Portal
页面中所有
Portlet
的
render
方法.如下
:
actionURL
|
processAction
/ | \
render render render
由于以上原因,所以使用
renderURL
要比使用
actionURL
的
performance
来的好.
3. RenderRequest
和
ActionRequest
的
parameter
参数作用范围有什么不同?
当客户端
request
一个
actionURL
触发时,比如一个
form
表单的提交,所有的
Parameter
的
get
操作必须在
processAction
方法中进行
.
例如:
JSP
的
form
表单页面
:
<%
PortletURL pu=renderResponse.createActionURL();
pu.setParameter("ACTION","LOGIN");
…
%>
<form name="usrfrm" method="post" action="<%=pu.toString()%>">
…
Portlet
的处理:
public
void processAction
(ActionRequest req,ActionResponse res){
String str=req.getParameter(“ACTION”);
//response.setRenderParameter("ACTION",action);
}
public
void
doView(ActionRequest req,ActionResponse res){
String str=req.getParameter(“ACTION”);
}
如上
processAction
方法中,
getParamter
方法将能成功得到表单中的参数
ACTION
所对应的值
,
因为我们知道,当目标
portlet
的
processAction
方法运行完后,
Portlet Container
将调用
Portal
页面中所有
Portlet
的
render
方法.但是实际上
doView
方法中使用
getParameter
不会得到任何值.但是如果把
processAction
方法中注释了的一行
uncomment
的话,你就可以在
doView
方法中的得到参数
ACTION
对应的值.
这说明
action request
的参数,
render
方法中不可以直接取到.必须使用了
setRenderParameter
方法,再次传递一次.
l
A case study
在这部分中
,
我们来做一个简单的
Portlet,
实现一个简单的
Form submit
功能
.
以下是代码片段
:
(
完整代码请参考文章末尾
)
JSP(
view_portletrequest.jsp.jsp
):
… …
<!-- Use PortletURL Object//-->
<%
PortletURL pu1=renderResponse.createActionURL();
pu1.setParameter(
"ACTION"
,
"Use PortletURL Object"
);
pu1.setPortletMode(PortletMode.VIEW);
%>
<
table
width
=100%
border
=0>
<
TR
><
TD
>1.
Use
PortletURL
object
to
get
an
ActionURL
and
set
current
portlet
mode
to
view</
TD
></
TR
>
<
tr
><
td
>
<
form
name
="usrfrm"
method
="post"
action
="
<%=
pu1.toString()
%>
">
<
input
type
=submit
name
=bt1
value
="GetActionByJava">
</
form
>
<
tr
><
td
>
</
table
>
… …
注
:
处理完
form
后将会将
PortletMode
设定为
VIEW
.
以上代码使用了
actionURL
因为是
form
表单的递交
.
详细请参考
Portlet
的
Request
对象
部分
.
或者也可以使用
Tag.
它同样也可以生成一个
Portlet
的
URL,
如下
:
… …
<!-- Use Portlet Tag //-->
<portlet:actionURL
windowState="maximized"
portletMode="edit"
var
="pu2">
<portlet:
param
name
="
ACTION
"
value
="Use
Portlet
Tag"/>
</portlet:actionURL>
<
BR
>
<
table
width
=100%
border
=0>
<
TR
><
TD
>2.
Use
Portlet
Tag
to
get
a
ActionURL
and
and
set
current
portlet
mode
to
edit</
TD
></
TR
>
<
tr
><
td
>
<
form
name
="usrfrm"
method
="post"
action
="
<%=
pu2
%>
">
<
input
type
=submit
name
=bt2
value
="GetActionByTag">
</
form
>
<
tr
><
td
>
</
table
>
… …
注
:
它在处理完
form
后将会将
PortletMode
设定为
EDIT
,
并且
Window state
会为最大化
.
Portlet
(
PortletRequestExample
.
java
):
… …
public
void
processAction(ActionRequest
request,
ActionResponse
response)
throws
PortletException,
IOException
{
String
action=request.getParameter(
"ACTION"
);
System.out.println(
"ACTION"
+
action);
if
(action==
null
){
action=
""
;
}
response.setRenderParameter(
"ACTION"
,action);
}
… …
JSP(
view_portletrequest.jsp
)
… …
<%
String getaction=
""
;
if
(
request
.getParameter(
"ACTION"
)!=
null
){
getaction=
request
.getParameter(
"ACTION"
);
}
%>
<
B
>
ACTION
:
<%=
getaction
%>
</
B
>
… …
JSP(
edit_portletrequest.jsp.jsp
)
… …
<%
String getaction=
""
;
if
(
request
.getParameter(
"ACTION"
)!=
null
){
getaction=
request
.getParameter(
"ACTION"
);
}
%>
<
B
>
ACTION
:
<%=
getaction
%>
</
B
>
… …
将以上源代码编译后
,
再通过
Eclipse
生成
/
更新
Portlet
的
web.xml
后
,
将所有配置及相关文件部署后
,
启动
Tomcat.
在
Browser
中加载如下页面
:
Http://localhost:8080/pluto/portal ,
可以看到如下的页面
(
图
:4-1)
图
:4-1
单击
PortletRequest Example Page
后可以看到如下
Portlet
页面
(
图
4-2)
图
:4-2
单击
GetActionByJava
后
,
得到如下
(
图
:4-3):
图
:4-3
单击
GetActionByTag
后
,
将跳转到
edit mode,
如下
(
图
:4-4):
图
:4-4
l
Portlet
的
Re
sponse
对象
与
Request
对象类似,
Response
对象也有两种:分别是
ActionResponse
和
RenderResponse,
分别封装了对应
ActionRequest
和
RenderRequest
对象返回的所有信息。例如,重定向,
windows state,portlet mode
等的信息。其中他们的父类,
PortletResponse
拥有
setProperty
和
addProperty
方法,用以传递提供商指定的信息给
portal/portlet container
1
。
ActionResponse
和
RenderResponse
有什么不同?
ActionResonse
可以用来处理以下相关功能:
1)
重定向
sendRedirect
方法用来进行帮助
portal/portlet-container
进行头信息,及其内容的设定
,
并且将
URL
重定向到用户指定的页面。
2)
改变
windows state, portlet mode
,我们在以前章节中介绍了
window state
和
portlet mode
概念
.
3)
传递
Parameter
参数到
RenderRequest
中去,如上面
request
部分中用到的例子。
RenderResponse
用来提供如下功能
(
和
Servlet
中的
Response
更相似
)
:
1)
设置
ContentType
2)
得到
Output Stream and Writer
对象,用来产生页面内容
3) Buffering
4)
设定
Portlet
的
Title ,
但必须先于
portlet
的输出递交前来调用,否则将会被忽略。
(注:目前的
pluto
没有实现,如果调用不会修改
title
)
l
A example
… …
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
response.setContentType("text/html");
PrintWriter pw=response.getWriter();
pw.print(“Hello, Portlet”);
… …
·
源
代码及
Portlet
相关配置文件
A. Portlet (
PortletRequestExample
.java
)
package
portlets.portletrequest;
/**
*
@author
terry
*
*
To
change
the
template
for
this
generated
type
comment
go
to
*
Window>Preferences>Java>Code
Generation>Code
and
Comments
*/
import
javax.portlet.*;
import
java.io.IOException;
public
class
PortletRequestExample
extends
GenericPortlet{
public
void
doView(RenderRequest
request,
RenderResponse
response)
throws
PortletException,
IOException
{
response.setContentType(
"text/html"
);
String
jspName
=
getPortletConfig().getInitParameter(
"view"
);
PortletRequestDispatcher
rd
=
getPortletContext().getRequestDispatcher(jspName);
rd.include(request,
response);
}
public
void
doEdit(RenderRequest
request,
RenderResponse
response)
throws
PortletException,
IOException
{
response.setContentType(
"text/html"
);
String
jspName
=
getPortletConfig().getInitParameter(
"edit"
);
PortletRequestDispatcher
rd
=
getPortletContext().getRequestDispatcher(jspName);
rd.include(request,
response);
}
public
void
processAction(ActionRequest
request,
ActionResponse
response)
throws
PortletException,
IOException
{
String
action=request.getParameter(
"ACTION"
);
System.out.println(
"ACTION"
+
action);
if
(action==
null
){
action=
""
;
}
response.setRenderParameter(
"ACTION"
,action);
}
}
B. JSP (view_portletrequest.jsp
)
<%@
page
session
=
"false"
%>
<%@
page
import
=
"javax.portlet.*"
%>
<%@
page
import
=
"java.util.*"
%>
<%@
taglib uri=
'/WEB-INF/tld/portlet.tld'
prefix=
'portlet'
%>
<portlet:defineObjects/>
<
BR
>
<
h3
>Request
Example</
h3
>
<!-- Use PortletURL Object//-->
<%
PortletURL pu1=renderResponse.createActionURL();
pu1.setParameter(
"ACTION"
,
"Use PortletURL Object"
);
pu1.setPortletMode(PortletMode.VIEW);
%>
<
table
width
=100%
border
=0>
<
TR
><
TD
>1.
Use
PortletURL
object
to
get
an
ActionURL
and
set
current
portlet
mode
to
view</
TD
></
TR
>
<
tr
><
td
>
<
form
name
="usrfrm"
method
="post"
action
="
<%=
pu1.toString()
%>
">
<
input
type
=submit
name
=bt1
value
="GetActionByJava">
</
form
>
<
tr
><
td
>
</
table
>
<!-- Use Portlet Tag //-->
<portlet:actionURL
windowState="maximized"
portletMode="edit"
var
="pu2">
<portlet:
param
name
="
ACTION
"
value
="Use
Portlet
Tag"/>
</portlet:actionURL>
<
BR
>
<
table
width
=100%
border
=0>
<
TR
><
TD
>2.
Use
Portlet
Tag
to
get
a
ActionURL
and
and
set
current
portlet
mode
to
edit</
TD
></
TR
>
<
tr
><
td
>
<
form
name
="usrfrm"
method
="post"
action
="
<%=
pu2
%>
">
<
input
type
=submit
name
=bt2
value
="GetActionByTag">
</
form
>
<
tr
><
td
>
</
table
>
<%
String getaction=
""
;
if
(
request
.getParameter(
"ACTION"
)!=
null
){
getaction=
request
.getParameter(
"ACTION"
);
}
%>
ACTION
:
<
B
>
<%=
getaction
%>
</
B
>
<
BR
><
BR
>
Current
Portlet
Mode:
<
B
><
big
>
<%=
renderRequest.getPortletMode()
%>
</
big
></
font
></
B
><
br
>
C. JSP (edit_portletrequest.jsp
)
<%@
page
session
=
"false"
%>
<%@
page
import
=
"javax.portlet.*"
%>
<%@
page
import
=
"java.util.*"
%>
<%@
taglib uri=
'/WEB-INF/tld/portlet.tld'
prefix=
'portlet'
%>
<portlet:defineObjects/>
<
BR
>
<
h3
>Request
Example</
h3
>
<%
String getaction=
""
;
if
(
request
.getParameter(
"ACTION"
)!=
null
){
getaction=
request
.getParameter(
"ACTION"
);
}
%>
ACTION
:
<
B
>
<%=
getaction
%>
</
B
>
<
BR
><
BR
>
Current
Portlet
Mode:
<
big
><
B
>
<%=
renderRequest.getPortletMode()
%>
</
font
></
big
></
B
><
br
>
D. Portlet.xml
… …
<!-- PortletRequest Example -->
<description>PortletRequest Example</description>
<portlet-name>PortletRequestExample</portlet-name>
<display-name>PortletRequest Example</display-name>
<portlet-class>portlets.portletrequest.PortletRequestExample</portlet-class>
<init-param>
<name>view</name>
<value>/fragments/portletrequest/view_portletrequest.jsp</value>
</init-param>
<init-param>
<name>edit</name>
<value>/fragments/portletrequest/edit_portletrequest.jsp</value>
</init-param>
<expiration-cache>-1</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
<portlet-mode>VIEW</portlet-mode>
<portlet-mode>EDIT</portlet-mode>
</supports>
<supported-locale>en</supported-locale>
<portlet-info>
<title>PortletRequest Example</title>
<short-title>PortletRequest</short-title>
<keywords>PortletRequest</keywords>
</portlet-info>
</portlet>
… …
E. portletentityregistry.xml
<?xml version="1.0" encoding="UTF-8"?>
<portlet-entity-registry>
<application id="10">
<definition-id>portlets</definition-id>
… …
<portlet id="30">
<definition-id>portlets.PortletRequestExample</definition-id>
</portlet>
… …
</application>
</portlet-entity-registry>
F. pageregistry.xml
<?xml version="1.0"?>
<portal>
<fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation">
</fragment>
… …
<!-- PortletRequest Example Page -->
<fragment name="portletrequestpage" type="page">
<navigation>
<title>PortletRequest Example Page</title>
<description>PortletConfig Example Page</description>
</navigation>
<fragment name="row1" type="row">
<fragment name="col1" type="column">
<fragment name="p1" type="portlet">
<property name="portlet" value="10.30"/>
</fragment>
</fragment>
</fragment>
</fragment>
… …
</portal>
注
: web.xml
文件可以从
portlet.xml
通过
Eclipse
的
Plugin
直接生成
,
所以没有列出配置文件
,
请参考本系列中的
Part1.
资源
:
·
Pluto
http://jakarta.apache.org/pluto
·
Pluto Mail List
http://news.gmane.org/gmane.comp.jakarta.pluto.user
·
WSRP Spec1.0
http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wsrp
·
Apache
的
WSRP
实现
http://ws.apache.org/wsrp4j/
·
Apache’s Portal, JetSpeed:
http://jakarta.apache.org/jetspeed/site/index.html
·
JSR 168:
http://www.jcp.org/en/jsr/detail?id=168
·
"Portlet
规范介绍
" By Stefan Hepper
和
Stephan Hesmer