Portlet 应用开发

Portlet 应用开发, Part 6 - Portlet 的 Preference对象
By Jia.li(Terry.li)
SpiritSeekerS@sqatester.com

本部分将阐述了Portlet的Preference对象,  Preference 对象是Portlet所特有的对象,用来实现用户的个性化设置,可以替代部分数据库的功能.
• 为什么使用Preference 对象?
Preference 主要用来帮助用户对Portlet进行符合用户需要的显示定制或者行为定制.
举一个简单的例子:  用户有一个用来显示商品列表的Portlet, 可能有些用户需要在Portlet窗口中每页显示10个商品, 但是也有用户需要在Portlet的窗口中显示20个或者是30个商品. 这样的话, 对于同一个Portlet应用, 用户可以定制自己满意的用户界面.
以上的Preference 使用有一个前提, Preference对象只用来存取简单的配置信息,并不能替代数据库的应用.
• 如何使用Preference 对象?
Preference对象对于Portlet的配置信息存取使用KEY=VALUE , 或者是 KEY=VALUES 形式.  如果你的Portlet有需要使用用户定制的元素,可以将其加入到Preference对象中. 如下:
PortletPreference p= req.getPortletPreferences();
p.setValue(“PageSize”,”10”);
p.store();
• Preference的属性的作用范围
因为Preference的属性是用来存取用户的个性化信息的, 因此两个用户之间不可以share属性.
注: Pluto因为是单用户的Portal/PortletContainer的实现,因此如果两个用户使用同一个preference属性名称,互相会有冲突.
• 如何配置Preference 属性?
在Portlet.xml中设置Preference的初始或者是默认属性. 如下:
<portlet-preferences>
  <preference>
    <name>PageSize</name>
    <value>20</value>
    <read-only>true</read-only>
  </preference>
</portlet-preferences>
在以上配置中配置了一个preference 属性PageSize, 注意read-only标签中设置了true, 那么这样一来这个preference 属性便不可以通过编程更改.
• 为什么使用PreferencesValidator对象?
PreferencesValidator对象允许Portlet的preference在被储存之前进行验证.用以保证portlet的Preference存取的正确性.
• 如何配置PreferencesValidator对象 ?
Servlet开发中有一种叫filter Servlet, 它的配置和PreferencesValidator的配置方式非常相似, 只不过一个在web.xml中配置, 而另一个在portlet.xml中配置. 如下XML:
<portlet-preferences>
<preferences-validator>
com.sss.PortletValidator
</preferences-validator>
</portlet-preferences>

• Case Study
以下我们将使用Preference和PreferencesValidator对象来开发一个简单的Portlet实现一个简单的用户登陆auditing. 以下是代码片段:
1. Portlet (PortletPreferenceExample.java)
         … …
PortletPreferences prefs = request.getPreferences();
prefs.setValue("audit_enabled",audit_enabled);
prefs.store();
 … …
 
   以上代码片段将一个Portlet的配置参数audit_enabled赋予相应的值.
  … …
PortletPreferences prefs = request.getPreferences();
prefs.reset("audit_enabled");
prefs.store();  
… …
以上代码片段将一个Portlet的配置参数audit_enabled重新reset到初始时Portlet.xml配置文件中audit_enabled所对应的值.
2. JSP (edit_preference.jsp)
 
<%
 PortletPreferences prefs = renderRequest.getPreferences();
 String flag=prefs.getValue("audit_enabled","").toString();
%> 
    Edit 模式下Fragment 用来取得 Preference 的KEY值的代码 .

3. JSP (view_portletpreference.jsp)
 <%
 PortletPreferences prefs = renderRequest.getPreferences();
 String flag=prefs.getValue("audit_enabled","").toString(); 
%>
   View 模式下Fragment 用来取得 Preference 的KEY值的代码.

     4. PreferencesValidator (PortletPreferencesValidator.java)
public class PortletPreferencesValidator implements
PreferencesValidator{
… …
… …
public void validate(PortletPreferences preferences)
  throws ValidatorException
  { 
  … …
  … …
  }
 }
PortletPreferencesValidator执行了PreferencesValidator接口, 其具体的功能实现由validate方法执行. 我们这里将应用逻辑在validate方法中执行. 其功能主要是验证KEY所对应的值是否符合要求.(本例中Validator将验证audit_enabled所对应的值是否为”0”或者”1”,  否则将抛出错误).
• Preference Portlet的运行结果
将Tomcat启动, 在IE 或者 NetScape 中敲入以下地址:
http://localhost:8080/pluto/portal

  

单击Preference Example Page后可以看到如下页面(图6-1)
 图6-1

输入”SpiritSeekerS” , 单击 Enter Button, 进入如下页面 (图6-2)
 图6-2
进入edit mode , 将enable audit 选项选中 , 如下(图6-3):
 图6-3
单击 SAVE button , 将回到view mode , 再次登陆后, 如下图(图6-4)
 图6-4
• 源代码及Portlet相关配置文件
1. Portlet (PortletPreferenceExample.java)
package portlets.portletpreference;
/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import javax.portlet.*;
import java.io.IOException;
public class PortletPreferenceExample  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, java.io.IOException 
   { 
   
 String action = request.getParameter("action");
 String audit_enabled = request.getParameter("audit_enabled");
 
 
 if(action.equals("edit")&&audit_enabled!=null){
  PortletPreferences prefs = request.getPreferences();
  prefs.setValue("audit_enabled",audit_enabled);
  prefs.store();
 }else if(action.equals("edit")){
  PortletPreferences prefs = request.getPreferences();
  prefs.reset("audit_enabled");
  prefs.store();  
 }else if(action.equals("view")){
  String usr= request.getParameter("usr");
  response.setRenderParameter("usr",usr);
 }
 else{
  throw new PortletException("Unexpected Error!");
 }
  }
}
2. JSP (view_portletpreference.jsp)
<%@ page session="false" %>
<%@ page import="javax.portlet.*"%>
<%@ page import="java.util.*"%>
<%@ taglib uri='/WEB-INF/tld/portlet.tld' prefix='portlet'%>
<portlet:defineObjects/>
<BR>
<%
 PortletPreferences prefs = renderRequest.getPreferences();
 String flag=prefs.getValue("audit_enabled","").toString(); 
%>
<portlet:actionURL portletMode="view" var="url">
<portlet:param name="action" value="view"/>
</portlet:actionURL>
<form method=post action=<%=url%>>
<table border=0>
 <tr><td><b>Name:</b></td><td><input type=text name=usr></tr>
 <tr><td colspan=2 align=right><input type=submit value="Enter"></td></tr>
</table>
</form>

<%
 String usr=renderRequest.getParameter("usr");
 if(usr!=null){
  %>Welcome, <%=usr%> !! <BR><%
 
%>
<%
  if(flag.equals("1")){
%>
===============================================<BR>
<table border=0>
 <tr>
  <td><b>INFO:</b> <%=usr.toUpperCase()%> login at </td>
  <td><%=new Date().toString()%></td>
 </tr>
</table>
===============================================<BR>
<%
  }
 }
%>
3. JSP (edit_portletpreference.jsp)
 <%@ page session="false" %>
<%@ page import="javax.portlet.*"%>
<%@ taglib uri='/WEB-INF/tld/portlet.tld' prefix='portlet'%>
<portlet:defineObjects/>
<BR>
<%
 PortletPreferences prefs = renderRequest.getPreferences();
 String flag=prefs.getValue("audit_enabled","").toString();
%>

<portlet:actionURL portletMode="view" var="url">
<portlet:param name="action" value="edit"/>
</portlet:actionURL>
<form method=post action=<%=url%>>
<table border=0>
 <tr>
  <td><b>Auditing Enabled:</b></td>
  <td><input type=checkbox name="audit_enabled" value="1" <%=flag.equals("1")?"checked":""%>></td>
 </tr>
 <tr>
  <td colspan=2 align=right><input type=submit value="SAVE"></td>
 </tr>
</table>
</form>
4. Preference Validator (PortletPreferencesValidator.java)
package portlets.portletpreference;
/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import javax.portlet.*;
import java.util.*;
public class PortletPreferencesValidator implements PreferencesValidator{
 public static final String AUDITING_ENABLED="1";
 public static final String AUDITING_DISABLED="0";
 
 public void validate(PortletPreferences preferences)
  throws ValidatorException
 {
  Enumeration prefnms = preferences.getNames();
  Collection errKeys = new ArrayList();
  while (prefnms.hasMoreElements()){
    String prefnm = prefnms.nextElement().toString();
    String value = preferences.getValue(prefnm, AUDITING_DISABLED);
    System.out.println(value);
    if((value.equals(AUDITING_ENABLED))||(value.equals(AUDITING_DISABLED))){
   System.out.println("#### INFO: VALID KEY.");
    }else{
   System.out.println("#### ERROR: INVALID KEY.");
   throw new ValidatorException("INVALID KEY",new Throwable("Incorrect Value!"),errKeys);
    }
  }
 }
}
 
 5. Portlet.xml
… …
 <!-- Preference Example -->
 <portlet>
  <description>PortletPreference Example</description>
  <portlet-name>PortletPreferenceExample</portlet-name>
  <display-name>PortletPreferenceExample</display-name>
  <portlet-class>portlets.portletpreference.PortletPreferenceExample</portlet-class>
  <init-param>
   <name>view</name>
   <value>/fragments/portletpreference/view_portletpreference.jsp</value>
  </init-param>
  <init-param>
   <name>edit</name>
   <value>/fragments/portletpreference/edit_portletpreference.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>PortletPreference Example</title>
   <short-title>PortletPreference</short-title>
   <keywords>PortletPreference</keywords>
  </portlet-info>
  <portlet-preferences>
   <preference>
    <name>audit_enabled</name>
    <value>0</value>
   </preference>
   <preferences-validator>portlets.portletpreference.PortletPreferencesValidator</preferences-validator>
  </portlet-preferences>
 </portlet>
 
 … …
6. pageregistry.xml
… …
 <!-- Preference Example Page -->
    <fragment name="preferencepage" type="page">
        <navigation>
            <title>Preference Example Page</title>
            <description>Preference Example Page</description>
        </navigation>
        <fragment name="row1" type="row">
            <fragment name="col1" type="column">
                <fragment name="p1" type="portlet">
                    <property name="portlet" value="10.70"/>
                </fragment>
            </fragment>
        </fragment>
</fragment>
 … …
7. portletregistry.xml
… …
        <portlet id="70">
<definition-id>portlets.PortletPreferenceExample</definition-id>
</portlet> 
       … …

资源:
• Pluto
http://jakarta.apache.org/pluto
• 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
Part 1: Get your feet wet with the specification's underlying terms and concepts (August 2003)
Part 2: The Portlet API's reference implementation reveals its secrets (September 2003)


Java Portlet 应用开发, Part 5 - Portlet 的 Session对象
By Jia.li(Terry.li)
SpiritSeekerS@sqatester.com  
 
本系列前一部分阐述了Portlet的Request和Response对象,本部分继续讲解Portlet中Session对象.及其与Servlet中Session对象的不同点.
• Portlet Session中存取对象的作用范围 (Scope)
Servlet中的Session属性和Portlet中的Session属性有一个非常大的不同点, 由于Portlet处于Portal中的缘故, Portlet的Session属性分为两种, 分别作用于不同的范围中:
1.  Application Scope
2.  Portlet Scope
这两者的区别在于:
1) Application Scope类型的PortletSession中保存的对象对于同一个Portlet Application中的所有其它Portlet来说是可以被访问到的.
2) Portlet Scope类型的PortletSession中保存的对象对于同一个Portlet Application中的所有其它Portlet来说是不可见的.
但对于Portlet Application来说,其实它也是个Web Application , 因此不论是Application Scope也好,或者是Portlet Scope也好,同样都属于HttpSession,因此都可以通过HttpSession 来访问.
实际上Application Scope的Session就是HttpSession , 而Portlet Scope的Session 由于不可被其他Portlet访问, 它的session属性名称有它独特的存取方式, 如下:
javax.portlet.p.<ID>?<ATTRIBUTE_NAME>
其中ID是Portal/Portlet-Container生成用来唯一确定一个Portlet.
Portlet Scope 的Session 使用以上的Attribute Name 用以存取Session上绑定的属性.  我们所设制的Portlet Scope 的Session属性由Portlet容器自动转化成以上格式. 用以保证不被其它的Portlet访问到.
注:  以javax.portlet开头的Session属性名称是保留的,不可以用于Portlet的Session 属性名称.
• Case study: 不同Scope Session的比较
 
以下我们将编码实现两个Portlet, 其中一个用来创建session属性的Portlet 和另一个用来验证session属性作用范围的Portlet. 用以验证Session属性的正确性.

1. Portlet (PortletSessionExample1_GenerateSesssion.java)
… …
 public void processAction(ActionRequest request,ActionResponse response)
  throws PortletException,IOException{
  String action=request.getParameter("ACTION");
  if(action.equals("ApplicationScope")){
   PortletSession ps=request.getPortletSession();
   ps.setAttribute("PortletSession.AS",action,PortletSession.APPLICATION_SCOPE);
  }else{
   PortletSession ps=request.getPortletSession();
   ps.setAttribute("PortletSession.PS",action,PortletSession.PORTLET_SCOPE);   
  }
   }
 
      … …
 
以上代码片段根据不同参数分别产生不同Scope的PortletSession 的属性 , 作用范围分别为Application 和 Portlet.
2. Portlet (PortletSessionExample1_DisplaySession.java)
这个Portlet调用一个JSP (jspShowSession.jsp) 来获得Portlet session和HttpSession, 并且示出来.
3. JSP(view_portletsession1_generatesession.jsp)
这个JSP将创建两个ActionURL , 分别用来产生两种PortletSession属性:
… …
<portlet:actionURL windowState="NORMAL" portletMode="view" var="pu1">
<portlet:param name="ACTION" value="ApplicationScope"/>
</portlet:actionURL>
<portlet:actionURL windowState="NORMAL" portletMode="view" var="pu2">
<portlet:param name="ACTION" value="PortletScope"/>
</portlet:actionURL>
  
… … 
4. JSP (jspShowSession.jsp)
取得以上创建的两个PortletSession 的属性值, 由Browser中可以看到只有Application Scope的Session 属性可以被获得.
 if(ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE)!=null){
  app=ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE).toString();
 }
 
 if(ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE)!=null){
  portlet=ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE).toString();
 }

以下代码将Httpsession中的所有属性全部列出:
      可以看到PortletContainer是如何存取Portlet Scope类型的session属性的.
      <%
  HttpSession s=request.getSession();
for (Enumeration e = s.getAttributeNames() ; e.hasMoreElements() ;) {
         %><tr><td><%=e.nextElement()%></td></tr>
<%
}
         %>
 
将以上源代码编译后, 再通过Eclipse生成/更新Portlet的web.xml后,  将所有配置及相关文件部署后, 启动Tomcat.

在Browser中加载如下页面: Http://localhost:8080/pluto/portal , 可以看到如下的页面(图:5-1)
    图:5-1

单击PortletSession Example1 Page后可以看到如下两个Portlet 页面(图5-2)

 图:5-2

上图中上边的一个Generate Portlet用来创建两个PortletSession属性,分别是Application Scope 和 Portlet Scope 类型.
下方的Display Portlet用以验证Session的作用范围.
单击Application Scope Session, 可以看到如下页面(图5-3)

                                                                   图5-3
如上图,生成了一个Application Scope的属性, 名称: PortletSession.AS

单击Portlet Scope Session, 可以看到如下页面(图5-4)
 图5-5
生成了一个Portlet Scope Session属性,所以Display portlet 无法取得. 但是从HttpSession 可以看到又创建了一个session属性.

Case study: Session的共享
以上例子验证了Portlet中Session的作用范围, 可能在开发过程中经常需要有Popup页面的处理这个时候就无法使用Portlet, 但是可以使用Servlet或者是JSP, 以下这个例子是一个Portlet和Servlet的Session共享的应用 (或许是Tomcat4的一个BUG), 我们将使用一个Portlet创建一个Application Scope的Session, 然后在一个Servlet中得到它.
1. Portlet (PortletSessionExample2_ShareSession.java)
以下代码将创建一个application scope的Portlet Session:
… …
if(INF!=null){
  PortletSession ps=request.getPortletSession();
  ps.setAttribute("INF",INF,PortletSession.APPLICATION_SCOPE);
}
… …
2. JSP (jspLoginView.jsp)
… …
<%
 PortletSession ps = renderRequest.getPortletSession();
 
 String app=null;
 
 if(ps.getAttribute("INF",PortletSession.APPLICATION_SCOPE)!=null){
  app=ps.getAttribute("INF",PortletSession.APPLICATION_SCOPE).toString();
%>  <u><a style="cursor:hand" οnclick='window.open("/pluto/popup","a","width=400,height=330,scrollbars=1")'>Click here to Popup</a></u> <%   
}
%>
… …
3. Servlet (PopupServlet.java)
… …
   HttpSession se=request.getSession();
 Object info=se.getAttribute("INF");
 … …
注: 由于Tomcat下webapps目录下的pluto和portlets分别是两个web application, 所以将以上的PopupServlet配置到pluto目录下,而非portlets目录下.

将以上源代码编译后, 再通过Eclipse生成/更新Portlet的web.xml后,  将所有配置及相关文件部署后, 启动Tomcat.

在Browser中加载如下页面: Http://localhost:8080/pluto/portal , 可以看到如下的页面
  

单击PortletSession Example2 Page后可以看到如下页面(图5-6)
 
 
 图5-6
单击 Click here to generate a session , 后可以看到如下页面(图5-7)
                                                              图5-7
单击 Click here to Popup , 后可以看到如下页面(图5-8)
 
图5-8
• 源代码及Portlet相关配置文件
A. Session Example1
1. Portlet (PortletSessionExample1_GenerateSesssion.java)
package portlets.portletsession;
/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import javax.portlet.*;
import java.io.IOException;
public class PortletSessionExample1_GenerateSesssion 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 processAction(ActionRequest request,ActionResponse response)
  throws PortletException,IOException{
  String action=request.getParameter("ACTION");
  if(action.equals("ApplicationScope")){
   PortletSession ps=request.getPortletSession();
   ps.setAttribute("PortletSession.AS",action,PortletSession.APPLICATION_SCOPE);
  }else{
   PortletSession ps=request.getPortletSession();
   ps.setAttribute("PortletSession.PS",action,PortletSession.PORTLET_SCOPE);   
  }
   }
 
}
   
2. Portlet (PortletSessionExample1_DisplaySession.java)
 package portlets.portletsession;
/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import javax.portlet.*;
import java.io.IOException;
public class PortletSessionExample1_DisplaySession 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);
  } 
}
3. JSP (view_portletsession1_displaysession.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>Display PortletSession and HttpSession Example</h3>
<%
 PortletSession ps = renderRequest.getPortletSession();
 
 String app="NULL";
 String portlet="NULL";
 
 if(ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE)!=null){
  app=ps.getAttribute("PortletSession.AS",PortletSession.APPLICATION_SCOPE).toString();
 }
 
 if(ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE)!=null){
  portlet=ps.getAttribute("PortletSession.PS",PortletSession.PORTLET_SCOPE).toString();
 } 
%>
<b>PortletSession list:</b>
<table border=1>
 <tr><td><b>Session Scope</b></td><td><b>Attribute Name</b></td><td><b>Attribute Value</b></td></tr>
 <tr><td>Application scope</td><td>PortletSession.AS</td><td><b><%=app%></b></td></tr>
 <tr><td>Portlet scope</td><td>PortletSession.PS</td><td><b><%=portlet%></b></td></tr>
</table>
<br>
<b>HttpSession list:</b>
<table border=1>
<tr><td><b>Attribute Name</b></td></tr>
<%
  HttpSession s=request.getSession();
     for (Enumeration e = s.getAttributeNames() ; e.hasMoreElements() ;) {
         %><tr><td><%=e.nextElement()%></td></tr>
<%
     }
%>
</table>
<BR><BR>
4. JSP (view_portletsession1_generatesession.jsp)
<%@ page session="false" %>
<%@ page import="javax.portlet.*"%>
<%@ page import="java.util.*"%>
<%@ taglib uri='/WEB-INF/tld/portlet.tld' prefix='portlet'%>
<portlet:defineObjects/>
<portlet:actionURL windowState="NORMAL" portletMode="view" var="pu1">
<portlet:param name="ACTION" value="ApplicationScope"/>
</portlet:actionURL>
<portlet:actionURL windowState="NORMAL" portletMode="view" var="pu2">
<portlet:param name="ACTION" value="PortletScope"/>
</portlet:actionURL>
<BR>
<h3>Generate PortletSession Example</h3>
<a href="<%=pu1%>">Application Scope Session</a>
<Br>
<a href="<%=pu2%>">Portlet Scope Session</a>
<Br><BR>

B. Session Example2
1.Portlet (PortletSessionExample2_ShareSession.java)
package portlets.portletsession;
/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import javax.portlet.*;
import java.io.IOException;
public class PortletSessionExample2_ShareSession 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 processAction(ActionRequest request,
         ActionResponse response)
        throws PortletException,
         java.io.IOException{
  String INF=request.getParameter("INF");
  if(INF!=null){
  PortletSession ps=request.getPortletSession();
  ps.setAttribute("INF",INF,PortletSession.APPLICATION_SCOPE);
  }
  }
}
 
2. Servlet (PopupServlet.java)
package servlet;
/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
public class PopupServlet extends HttpServlet{
  
 public void doGet(HttpServletRequest request,
         HttpServletResponse response)
   throws IOException, ServletException
  {
   PrintWriter pw=response.getWriter();
   HttpSession se=request.getSession();
    Object info=se.getAttribute("INF");
    if(info!=null){
     pw.println("<table border=1 bordercolor=black>");
     pw.println(" <tr>");
     pw.println("  <td><b>Attribute</b><td><td><b>Value</b></td> ");
     pw.println(" </tr>");
     pw.println(" <tr>");
     pw.println("  <td>INF<td><td>"+ info.toString() +"</td> ");
     pw.println(" </tr>");
     pw.println("</table>");
    }else{
     pw.println("No session");
    }
  }
}
 
C. 配置文件
1. Portlet.xml
… …
 <!-- PortletSession Example -->
 <!-- PortletSession Example1 - GenerateSession -->
 <portlet>
  <description>PortletSession_Generator Example</description>
  <portlet-name>PortletSession_GeneratorExample</portlet-name>
  <display-name>PortletSession_Generator Example</display-name>
  <portlet-class>portlets.portletsession.PortletSessionExample1_GenerateSesssion</portlet-class>
  
  <init-param>
   <name>view</name>
   <value>/fragments/portletsession/view_portletsession1_generatesession.jsp</value>
  </init-param>
  <expiration-cache>-1</expiration-cache>
  <supports>
   <mime-type>text/html</mime-type>
   <portlet-mode>VIEW</portlet-mode>
  </supports>
  <supported-locale>en</supported-locale>
  <portlet-info>
   <title>PortletSession_Generator Example</title>
   <short-title>PortletSession_Generator</short-title>
   <keywords>PortletSession_Generator</keywords>
  </portlet-info>
 </portlet>
 
 <!-- PortletSession Example1 - DisplaySession -->
 <portlet>
  <description>PortletSession_Display Example</description>
  <portlet-name>PortletSession_DisplayExample</portlet-name>
  <display-name>PortletSession_Display Example</display-name>
  <portlet-class>portlets.portletsession.PortletSessionExample1_DisplaySession</portlet-class>
  
  <init-param>
   <name>view</name>
   <value>/fragments/portletsession/view_portletsession1_displaysession.jsp</value>
  </init-param>
  <expiration-cache>-1</expiration-cache>
  <supports>
   <mime-type>text/html</mime-type>
   <portlet-mode>VIEW</portlet-mode>
  </supports>
  <supported-locale>en</supported-locale>
  <portlet-info>
   <title>PortletSession_Display Example</title>
   <short-title>PortletSession_Display</short-title>
   <keywords>PortletSession_Display</keywords>
  </portlet-info>
 </portlet>
… … 
2.  pageregistry.xml
… …
 <!-- PortletSession Example1 Page -->
    <fragment name="portletsessionpage1" type="page">
        <navigation>
            <title>PortletSession Example1 Page</title>
            <description>PortletSession Example Page</description>
        </navigation>
        <fragment name="row1" type="row">
            <fragment name="col1" type="column">
                <fragment name="p1" type="portlet">
                    <property name="portlet" value="10.40"/>
                </fragment>
            </fragment>
        </fragment>
        <fragment name="row2" type="row">
            <fragment name="col1" type="column">
                <fragment name="p1" type="portlet">
                    <property name="portlet" value="10.50"/>
                </fragment>
            </fragment>
        </fragment>       
    </fragment>
 <!-- PortletSession Example2 Page -->
    <fragment name="portletsessionpage2" type="page">
        <navigation>
            <title>PortletSession Example2 Page</title>
            <description>PortletSession Example Page</description>
        </navigation>
        <fragment name="row1" type="row">
            <fragment name="col1" type="column">
                <fragment name="p1" type="portlet">
                    <property name="portlet" value="10.60"/>
                </fragment>
            </fragment>
        </fragment>     
    </fragment>
… …
3. Portletregiestry.xml
… …
        <portlet id="40">
            <definition-id>portlets.PortletSession_GeneratorExample</definition-id>
        </portlet>
        <portlet id="50">
            <definition-id>portlets.PortletSession_DisplayExample</definition-id>
        </portlet>
        <portlet id="60">
            <definition-id>portlets.PortletSession_ShareExample</definition-id>
        </portlet>
… …
 

总结
Session对于Web 开发来说是非常重要且必要的元素, 对于Portlet来说, 其Session的功能和Servlet略有不同. 但实际还是HttpSession的延伸及包装.
资源:
• Pluto
http://jakarta.apache.org/pluto
• Apache的WSRP实现 (WSRP4J)
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 应用开发, Part 4 - Portlet 的 Request和Response对象

By Terry.li
SpiritSeekerS@sqatester.com


本文使用本系列中Part1搭建的开发环境,如果没有搭建好开发环境,请参考Portlet应用开发Part1进行开发环境的搭建.在Part1中我们已经介绍了Portlet的GenericPortlet类. 从形式上来看, Portlet与Servlet非常相似, 但是从request和response对象的具体特点及功能来说, 又有所不同. 本部分主要描述了Portlet的Request和Response对象的特点及其与Servlet的Request和Response对象的不同点.

 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方法,再次传递一次.


 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

 Portlet的Response 对象
与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)

 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&gt;Preferences&gt;Java&gt;Code Generation&gt;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 -->
 <portlet>
  <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
o Part 1: Get your feet wet with the specification's underlying terms and concepts (August 2003)
o Part 2: The Portlet API's reference implementation reveals its secrets (September 2003)

 

Java Portlet应用开发 (JSR168), Part 3 - PortletConfig 对象

By Jia.li(Terry.li)
SpiritSeekerS@sqatester.com


 本部份将讲述PortletConfig对象及其PortletContext对象的概念及应用.

• PortletConfig对象
和ServletConfig对象类似, PortletConfig对象提供Portlet初始的所需的参数及其对PortletContext对象存取提供相关方法.
和ServletConfig不同处在于, PortletConfig对象提供对Portlet Title Bar资源的I18N支持,我们可以设定不同的Resource Bundle文件用以提供多语言的支持, 如下portlet.xml文件:

… …
  <portlet-info>
   <title>PortletConfig Example</title>
   <short-title>PortletConfig</short-title>
   <keywords>PortletConfig</keywords>
 </portlet-info>
 … …

以上Portlet描述文件中的设置用于显示Portlet的Title Bar文字, 同样也可以使用Resource Bundle用以显示Title Bar文字, 如下:

  … …
 <resource-bundle>
portlets.portletconfig.portletconfigexample
</resource-bundle>
  … …


• A case study

这里我们将开发一个简单使用Resource Bundle的Portlet.只需要添加所须的Resource Bundle文件.

我们使用英文及其中文的Resource Bundle, 如下:

3) Base Resource Bundle (portletconfigexample.properties)

# English Resource Bundle
#
# filename: portletconfigexample.properties
# Portlet Info resource bundle example
javax.portlet.title=PortletConfig Example
javax.portlet.short-title=PortletConfig
javax.portlet.keywords=PortletConfig

2) Chinese Resource Bundle (portletconfigexample_zh.properties)

# Chinese Resource Bundle
#
# filename: portletconfigexample.properties
# Portlet Info resource bundle example
javax.portlet.title=Portlet配置 例子
javax.portlet.short-title=Portlet配置
javax.portlet.keywords=Portlet配置


3) portlet.xml

… …
<resource-bundle>
portlets.portletconfig.portletconfigexample
</resource-bundle>
… …

 

 

• 源代码及Portlet相关配置文件

1) Portlet (PortletConfigExample.java)

package portlets.portletconfig;

/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */

import javax.portlet.*;
import java.io.IOException;
import java.io.Writer;

public class PortletConfigExample  extends GenericPortlet{

  public void doView(RenderRequest request, RenderResponse response)
 throws PortletException, IOException
  {
 response.setContentType("text/html");
 String view = getPortletConfig().getInitParameter("view");
 Writer writer=response.getWriter();
 writer.write(view);
  }

  public void doEdit(RenderRequest request, RenderResponse response)
 throws PortletException, IOException
  {
 response.setContentType("text/html");
 String edit = getPortletConfig().getInitParameter("edit");
 Writer writer=response.getWriter();
 writer.write(edit);
  }
 
}


2) Portlet.xml

… …
 <!-- PortletConfig Example -->
 <portlet>
  <description>PortletConfig Example</description>
  <portlet-name>PortletConfigExample</portlet-name>
  <display-name>disPortletConfigExample</display-name>
  <portlet-class>portlets.portletconfig.PortletConfigExample</portlet-class>
  <init-param>
   <name>view</name>
   <value>Here is View Mode</value>
  </init-param>
  <init-param>
   <name>edit</name>
   <value>Here is Edit Mode</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>zh</supported-locale>
  <supported-locale>en</supported-locale>
  <resource-bundle>portlets.portletconfig.portletconfigexample</resource-bundle>
 </portlet>
… …

3) pageregistry.xml

… …
  <!-- PortletConfig Example Page -->
    <fragment name="portletconfigpage" type="page">
        <navigation>
            <title>PortletConfig 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.20"/>
                </fragment>
            </fragment>
        </fragment>
    </fragment>
… …

4) PortletRegistry.xml

… …
              <portlet id="20">
             <definition-id>portlets.PortletConfigExample</definition-id>
        </portlet>
… …


将以上源代码编译后, 再通过Eclipse生成/更新Portlet的web.xml后,  将所有配置及相关文件部署后, 启动Tomcat.

 

在Browser中加载如下页面: Http://localhost:8080/pluto/portal , 可以看到如下的页面(图:3-1)

 如果机器的Locale及语言设定是以中文简体为缺省,则单击PortletConfig Example Page后可以看到如下Portlet 页面(图3-1):

   图3-1

注: 因为现在Pluto的开发中没有做I18N的处理,这里如果你的机器的Locale是中文的话, 显示是乱码,请将IE的encoding设定为GB2312(View -> Encoding -> Chinese Simplified), 如图3-1.


如果机器的Locale及语言设定是英文的话, 将看到如下Portlet 页面(图3-2):

 图3-2

 

资源:
• 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
Part 1: Get your feet wet with the specification's underlying terms and concepts (August 2003)
Part 2: The Portlet API's reference implementation reveals its secrets (September 2003)

 

Java Portlet应用开发 (JSR168), Part 2 - Pluto中添加新的Portal Page 和 Portlet

By Jia.li(Terry.li)
SpiritSeekerS@sqatester.com


本部分使用本系列中Part1搭建的开发环境,如果还没有搭建好开发环境,请参考Portlet应用开发(JSR168),Part1进行开发环境的搭建.

在Part1中,我们开发了一个简单的portlet程序,但是几乎所有的代码和文件都是由Eclipse的pluto plugin替我们完成的,如何配置用来在Pluto中的Portal中添加新的Portal Page并且将新的Portlet添加到新的Page中去呢? Part2将一步一步教你如何创建一个新Portal Page.


• Portal的设定
Tomcat 中Webapps目录: 其中pluto是portal所在目录, 用以配置Portal Page的两个文件分别是pageregistry.xml和portletentityregistry.xml (如图Figure1_1)

 


Figure1_1


其中pageregistry.xml用来在Portal中配置Portal Page, 而portletentityregistry.xml 用来在Page中配置Portlet.

• portletentityregistry.xml
打开pageregistry.xml, 内容如下 :

<?xml version="1.0" encoding="UTF-8"?>
<portlet-entity-registry>
    <application id="1">
        <definition-id>portlets</definition-id>
        <portlet id="1">
            <definition-id>portlets.SimplePortlet</definition-id>
        </portlet>
    </application>
</portlet-entity-registry>

其中application 标签表明了目前的application 的 ID, portlet标签定义了一个Portlet , 如果你新开发了一个Portlet , 可以加入以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<portlet-entity-registry>
    <application id="1">
        <definition-id>portlets</definition-id>
        <portlet id="1">
            <definition-id>portlets.SimplePortlet</definition-id>
        </portlet>
        <portlet id="2">
            <definition-id>portlets.IntroPortlet</definition-id>
        </portlet>
    </application>
</portlet-entity-registry>

这样一来你又在portal中注册了一个新的Portlet,接下来是将新注册的Portlet加入Page中.

• pageregistry.xml
打开pageregistry.xml, 内容如下 :

<?xml version="1.0"?>
<portal>

    <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation">
    </fragment>
   
    <fragment name="sample" type="page">
        <navigation>
            <title>Sample Portlet</title>
            <description>Basic page to show the simple portlet</description>
        </navigation>

        <fragment name="row" type="row">

            <fragment name="col1" type="column">

                <fragment name="p1" type="portlet">
                    <property name="portlet" value="1.1"/>
                </fragment>

            </fragment>

        </fragment>

    </fragment>
</portal>

以上是sample portlet的配置.

Fragment标签用来配置navigation(导航栏), Page,以及Page中的Column和Row.
分别用fragment标签的type属性来标识. Pluto自带的Portal使用fragment标签来配置及处理简单的Portlet Layout.

<property name="portlet" value="1.1"/>中的value值是在portletentityregistry.xml中定义的. 分别对应application id 和portlet id, 将其值用”.”连接起来使用用以定义一个Portlet. 同样 , 如果使用<property name="portlet" value="1.2"/>,则将使用portlets.IntroPortlet.
 


1) 配置同一行中的两个Portlet, 如下:
<?xml version="1.0"?>
<portal>

    <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation">
    </fragment>
   
    <fragment name="sample" type="page">
        <navigation>
            <title>Sample Portlet</title>
            <description>Basic page to show the simple portlet</description>
        </navigation>

        <fragment name="row" type="row">

            <fragment name="col1" type="column">

                <fragment name="p1" type="portlet">
                    <property name="portlet" value="1.1"/>
                </fragment>

                <fragment name="p2" type="portlet">
                    <property name="portlet" value="1.1"/>
                </fragment>

            </fragment>

        </fragment>

    </fragment>

</portal>
 

2) 配置同一列中的两个Portlet, 如下:
<?xml version="1.0"?>
<portal>

    <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation">
    </fragment>
   
    <fragment name="sample" type="page">
        <navigation>
            <title>Sample Portlet</title>
            <description>Basic page to show the simple portlet</description>
        </navigation>

        <fragment name="row1" type="row">

            <fragment name="col1" type="column">

                <fragment name="p1" type="portlet">
                    <property name="portlet" value="1.1"/>
                </fragment>

            </fragment>

        </fragment>

        <fragment name="row2" type="row">

            <fragment name="col1" type="column">

                <fragment name="p1" type="portlet">
                    <property name="portlet" value="1.1"/>
                </fragment>

            </fragment>

        </fragment>

    </fragment>

</portal>

 

 

• Portlet Modes 和 Portlet window states
Portlet模式(Portlet Mode)是Portlet提供的用以区分 Portlet所执行功能的一个概念.通常情况下其拥有以下几种模式:
1. VIEW
2. EDIT
3. HELP

以上各模式分别对应GenericPortlet中的 doView(…) , doEdit(…) , doHelp(…) 方法,分别调用以上方法来产生各个模式中的Fragment内容. 非常类似Servlet中的doGet(…) , doPost(…) 方法,都是Helper方法, 但是概念不同.

Portlet状态(Portlet window states)提供了对于Portlet窗口的控制功能 , 其中有如下三种最基本的状态:
1. Normal
2. Maximized
3. Minimized

Portlet开发人员可以在处理ActionRequest (以后的章节将讲述其概念) 时使用代码实现Portlet模式, 及其Portlet状态的转变.

注: 只能在处理ActionRequest时改变Portlet Modes和Portlet Window states.
 
以上Portlet Modes和Portlet window states都可以配置成custom Portlet mode和custom portlet window state. 不同的地方在于对于Mode来说, 定制化的Mode需要对GenericPortlet的doDispatch方法进行重写(Overriding), 因为GenericPortlet类通过render方法按照不同的Portlet Mode将request分别分发给doView,doEdit,doHelp等辅助方法. 如果需要定制的Mode , 必须重写doDispatch 方法. 同时如果使用Portal提供商的Portlet Modes 或者 Portlet window States,都必须在部署描述中添加相关的设定.

A. 添加Custom Portlet Modes
以下使用代码实现了一个新的Portlet Mode: CONFIG , 当然也可以使用Portal提供商支持的Portlet Mode. 但是需要Mapping到Portal提供商所支持的Portlet Mode. 使用如下描述:

    <custom-portlet-mode>
  <description>Provides administration functions</description>
  <portlet-mode>CONFIG</portlet-mode>
    </custom-portlet-mode>

1. Portlet代码 (CustomPortletModeExample.java)

package portlets.portletmode;

/**
 * @author terry
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import javax.portlet.*;
import java.io.IOException;

public class CustomPortletModeExample extends GenericPortlet{

  public void doView(RenderRequest request, RenderResponse response)
 throws PortletException, IOException
  {
 response.setContentType("text/html");

 String jspName = getPortletConfig().getInitParameter("all");

 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("all");

 PortletRequestDispatcher rd =
   getPortletContext().getRequestDispatcher(jspName);

 rd.include(request, response);
  }
  
 public void render(RenderRequest request, RenderResponse response)
 throws PortletException, IOException{
  doDispatcher(request,response);
 }
  
 public void doDispatcher(RenderRequest request, RenderResponse response)
  throws PortletException, IOException{
  if(!request.getWindowState().equals(WindowState.MINIMIZED)){
  if(request.getPortletMode().equals(PortletMode.VIEW)){
   doView(request,response);
  }else if(request.getPortletMode().equals(PortletMode.EDIT)){
   doEdit(request,response);
  }else if(request.getPortletMode().equals(new PortletMode("CONFIG"))){
   doConfig(request,response);
  }
}
 }
 
 public void doConfig(RenderRequest request, RenderResponse response)
   throws PortletException, IOException
 {
   response.setContentType("text/html");

   String jspName = getPortletConfig().getInitParameter("all");

   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);
 }
}

2. JSP(all_mode.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>Custom Portlet Mode Example</h3>
Current Portlet Mode: <b><%=renderRequest.getPortletMode()%></b><br>
Current Window State: <b><%=renderRequest.getWindowState()%></b><br>
<br>

 

5. Portlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<portlet-app xmlns="/org/apache/pluto/portalImpl/xml/portlet-app_1_0.xsd" version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="/org/apache/pluto/portalImpl/xml/portlet-app_1_0.xsd /org/apache/pluto/portalImpl/xml/portlet-app_1_0.xsd">

 <!-- Custom PortletMode Example -->
 <portlet>
  <description>CustomPortletModeExample Example</description>
  <portlet-name>CustomPortletModeExample</portlet-name>
  <display-name>CustomPortletModeExample</display-name>
  <portlet-class>portlets.portletmode.CustomPortletModeExample</portlet-class>
  <init-param>
   <name>all</name>
   <value>/fragments/portletmode/all_mode.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>
   <portlet-mode>CONFIG</portlet-mode>
  </supports>
  <supported-locale>en</supported-locale>
  <portlet-info>
   <title>Custom PortletMode Example</title>
   <short-title>PortletMode</short-title>
   <keywords>PortletMode</keywords>
  </portlet-info>
 </portlet>

</portlet-app>

6. portletregistry.xml.

<?xml version="1.0" encoding="UTF-8"?>
<portlet-entity-registry>
    <application id="10">
        <definition-id>portlets</definition-id>
        <portlet id="10">
            <definition-id>portlets.CustomPortletModeExample</definition-id>
        </portlet>
    </application>
</portlet-entity-registry>

7. pageregistry.xml

<?xml version="1.0"?>
<portal>

    <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation">
    </fragment>
   
   <!-- Custom PortletMode Example Page -->
       <fragment name="customportletmodepage" type="page">
        <navigation>
            <title>Custom PortletMode Example Page</title>
            <description>Custom PortletMode Example Page</description>
        </navigation>
        <fragment name="row1" type="row">
            <fragment name="col1" type="column">
                <fragment name="p1" type="portlet">
                    <property name="portlet" value="10.10"/>
                </fragment>
            </fragment>
        </fragment>
  </fragment>

</portal>

 

将以上源代码编译后, 再通过Eclipse生成/更新Portlet的web.xml后,  将所有配置及相关文件部署后, 启动Tomcat.

 

在Browser中加载如下页面: Http://localhost:8080/pluto/portal , 可以看到如下的页面(图:2_1)

       图2-1


单击Custom PortletMode Example Page后可以看到如下Portlet 页面:

 
图2-2

单击右上角的config后,可以看到如下页面片段:

 
图2-3

以上可以看到新添加的Portlet Mode: config.


B. 添加Custom Window States

 添加新的window states同样需要在配置文件中加入相应的描述,如下:
<custom-window-state>
<description>Occupies 50% of the portal page</description>
<name>half_page</name>
</custom-window-state>

但是同样需要Mapping到Portal提供商所支持的Window state.

总结:
因为Eclipse 的Pluto plugin使用的是version1.0 , 所以可能有许多Bugs或者没有实现的功能, 所以如果需要最新版本的Pluto , 可以在Apache的CVS上下载, 下载的代码中有现成的Build scripts 以及相关的deploy script.请参考相关文档资料.

资源:
• 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
Part 1: Get your feet wet with the specification's underlying terms and concepts (August 2003)
Part 2: The Portlet API's reference implementation reveals its secrets (September 2003)



Java Portlet应用开发 (JSR168), Part 1

By Jia.li (Terry.li)

SpiritSeekerS@sqatester.com

 

本系列将介绍如何开发基于Portlet Specification v1.0 (JSR168) 的Portlet应用程序以及相关的概念. 这里使用Pluto v1.0作为Portal/Portlet Container. 并且可以将开发完成的Portlet应用程序发布到任何遵循JSR168规范的其他Portlet Container和Portal Server上.

 

• 为什么要发布Portlet Specification? 什么是JSR168?

越来越多的公司开发了各自的Portal组件和基于其的Portal产品(如Bea, IBM, Oracle, Sun, Sybase, Vignette, Novell, SAP, Plumtree, Apache 等.这种互不兼容的接口实现带给软件开发商以及Web开发人员各种问题, 为了解决这些问题, JCP发布了JSP168 (Java Specification Request), Portlet Specification v1.0, 用以提供不同Portal和Portlets的实现之间的互通性.可能许多软件开发商 (如上所列) 提供更为强大的Portlet实现, 但是如果希望开发人员希望所开发的Portlet程序能够不依赖于某一种或者几种平台, 那么使用JSR168 Portlet毫无疑问是你的首选.

• 什么是Portal?

Portal是基于WEB的应用程序, 一个信息平台, 它将不同来源的各种资源进行整合并集中展现给客户. 通常其有如下三个特点:

a. Personalization (个性化)

b. Single sign on (单点登陆)

c. Content aggregation (内容聚合)

Personalization是Portal提供的特性之一, 用来提供用户的个性化设置. Single sign on是J2EE的一个特性.其中Content aggregation是Portal比较有特色的特性, 它将不同来源的信息整合到一个同一个页面中, 使得用户可以更便捷, 更快速的进行某些商业应用. 这里举一个简单的商业应用的例子, 如果某一客户需要进行一次商业采购行为,以往需要访问不同的产品供应商的主页得到相关信息,这往往是一个耗时耗力的过程, 但如果使用Portal将所有经常使用的相关商品供应商的商品浏页面都整合到一个Portal页面中, 那么所有的供应商的商品都可以更快的被浏览,筛选, 加快了客户的商业运作效率.

• 什么是Portlet?

Portlet是一种基于WEB组件的JAVA技术, 由Portlet Container进行管理. 处理请求并动态返回页面, 可以作为Portal的可即插即用的界面组件.

• 什么是Portlet Container?

Portlet Container用来管理Portlet的生命周期并且提供其运行所需要的必要环境. 并且给Portlet Preferences提供持久性(Persistent)存取服务.但是其不支持Portlet的aggregation(内容聚合). 内容聚合由Portal组件提供.这个概念需要弄清楚. 注: Portlet Preferences是Portlet的一个新特性,提供类似数据库的功能.但是不是用来取代数据库. 只能用来存取简单的Portlet配置参数.

• 什么是WSRP?

WSRP 是 OASIS Web Service for Remote Portlets的缩写. WSRP是Web service的一种新的商业应用, 一种新的标准, 主要用来简化Portal对于各种资源或者程序整合的复杂性, 可以避免编程带来的整合麻烦和问题. 而且Portal的管理员可以从海量的WSRP服务中选择需要的功能用以整和到目前使用的Portal中.

它有三种Roles:

1) Producer -> 提供Portlet

2) Consumer -> 使用Portlet

3) End User -> 最终用户

 

它的特点在于Producer将Consumer所需要的信息通过WSRP返回给Consumer,这些信息是相对的标记Fragment(片段),例如HTML,XHTML等, 直接可以镶入用户的Page中,而不用象Web service一样需要单独开发用户端接口. 再举个WSRP的商业应用的例子: 如果一个客户需要采购一些PC软件,那么这个客户通过互联网登陆某家PC软件代理供应商的网页,查询相关信息,但是做为软件代理公司,PC软件的高级使用指南及配置工具是非常缺乏或者是无法及时更新的,这样一来使得用户需要登陆软件开发商的站点上才能得到相关信息. 然后再回到代理商主页进行订购. 而比较理想的商业应用应该是代理公司可以整合软件开发商提供的使用指南或者配置工具(可以由开发商及时更新).但是如果使用XML API, 那么需要针对不同软件提供商开发不同的接口实现. 而使用WSRP可以将相关的信息及工具直接镶入到代理商的页面用以动态,及时提供给客户. WSRP4J是Apache的WSRP标准实现, 请参考文章末尾的资源部分.

 

• Portlet and Servlet 比较 摘自(Portlet Specs v1.0)

相同点: 

  • Portlets are Java technology based web components 
  • Portlets are managed by a specialized container
  • Portlets generate dynamic content
  • Portlets lifecycle is managed by a container
  • Portlets interact with web client via a request/response paradigm

不同点: 

  • Portlets only generate markup fragments, not complete documents. The Portal aggregates portlet markup fragments into a complete portal page 
  • Portlets are not directly bound to a URL
  • Web clients interact with portlets through a portal system 
  • Portlets have a more refined request handling, action requests and render requests 
  • Portlets have predefined portlet modes and window states that indicate the function the portlet is performing and the amount of real state in the portal page
  • Portlets can exist many times in a portal page

Portlet特有: 

Portlets have means for accessing and storing persistent configuration and customization data Portlets have access to user profile information

Portlets have URL rewriting functions for creating hyperlinks within their content, which allow portal server agnostic creation of links and actions in page fragments

Portlets can store transient data in the portlet session in two different scopes: the application-wide scope and the portlet private scope

 

Servlet特有: 

Setting the character set encoding of the response

Setting HTTP headers on the response 

The URL of the client request to the portal

 • 什么是Pluto ?

Pluto 是 Apache 的一个Open Source项目, 是基于Portlet Spec (v1.0) (JSR168) 的一个 Portlet Container 的实现. 它也提供了 一个演示版的Sample Portal实现,用以进行Portlet Container的测试. 但是功能相对简单: 例如, 1) 没有复杂的Layout实现. 2) 不是multi-user enabled, 比如, 不同User之间的Portlet Preferences互相是 可以share的. 请记住Pluto只是一个Portlet Container的实现, 不是一个Portal的实现. 如果你需要功能更为强大的Portal,可以使用JetSpeed或者其他功能更强大的Portal , 它同样也是Apache的一个Open Source Project. 请参考文章末尾的资源部分.

• 概念 如图: Figure 1.1

a. Decorations and controls (修饰部分及 控制部分)

b. Portlet fragment (Portlet 片段)

c. Portlet window (Portlet 窗口)

d. Portlet page (Portlet 页面)

Figure 1.1

 

• 开发工具( Eclipse2.1, Pluto-plugin, Jakarta-tomcat-4.1.29)

下载地址:

Eclipse

http://www.eclipse.org/downloads/index.php

Ant 

http://prdownloads.sourceforge.net/plutoeclipse/org.eclipsefan.pluto.ui_1.0.0.zip?download

Pluto

http://

JDK1.4

http://Java.sun.com

 

• 配置开发环境

希望这编文章可以帮大家搭建一个简单的Portlet开发环境, 熟悉Portlet相关的知识.

 

 

资源:

• 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实现 (WSRP4J)

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

  • Part 1: Get your feet wet with the specification's underlying terms and concepts (August 2003) 
  • Part 2: The Portlet API's reference implementation reveals its secrets (September 2003)
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值