Profil de TerryValley of SpiritSeekerSPhotosBlogListesPlus ![]() | Aide |
|
|
03/12/2005 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>Preferences>Java>Code Generation>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>Preferences>Java>Code Generation>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 Mail List
http://news.gmane.org/gmane.comp.jakarta.pluto.user • 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" onclick='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>Preferences>Java>Code Generation>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>Preferences>Java>Code Generation>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>Preferences>Java>Code Generation>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>Preferences>Java>Code Generation>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 Mail List
http://news.gmane.org/gmane.comp.jakarta.pluto.user • Apache的WSRP实现 (WSRP4J)
http://ws.apache.org/wsrp4j/ • Apache’s Portal, JetSpeed:
http://jakarta.apache.org/jetspeed/site/index.html Portlet 应用开发, Part 4 - Portlet 的 Request和Response对象By Terry.li
Portlet的Request 对象
以下是两个例子: 使用actionURL: 注: form表单递交时,使用HTTP post方法,而不用get方法.因为某些Portal/Portlet Container的实现将内部状态编码到URL的Query字符串中.
2. renderURL和actionURL的处理方式有什么不同? renderURL
actionURL 由于以上原因,所以使用renderURL要比使用actionURL的performance来的好. 3. RenderRequest和ActionRequest的parameter参数作用范围有什么不同? JSP的form表单页面: Portlet的处理: public void doView(ActionRequest req,ActionResponse res){ 如上processAction方法中,getParamter方法将能成功得到表单中的参数ACTION所对应的值,因为我们知道,当目标portlet的processAction方法运行完后,Portlet Container将调用Portal页面中所有Portlet的render方法.但是实际上doView方法中使用getParameter不会得到任何值.但是如果把processAction方法中注释了的一行uncomment的话,你就可以在doView方法中的得到参数ACTION对应的值. 这说明action request的参数,render方法中不可以直接取到.必须使用了setRenderParameter方法,再次传递一次.
JSP(view_portletrequest.jsp.jsp): … … <table width=100% border=0> 以上代码使用了actionURL因为是form表单的递交. 详细请参考Portlet的Request 对象部分. 或者也可以使用Tag. 它同样也可以生成一个Portlet的URL, 如下: … … <BR> 注: 它在处理完form后将会将PortletMode设定为EDIT,并且Window state会为最大化. Portlet(PortletRequestExample.java): … …
… … <B>ACTION: <%=getaction%></B> JSP(edit_portletrequest.jsp.jsp) … … 将以上源代码编译后, 再通过Eclipse生成/更新Portlet的web.xml后, 将所有配置及相关文件部署后, 启动Tomcat.
在Browser中加载如下页面: Http://localhost:8080/pluto/portal , 可以看到如下的页面(图:4-1)
单击 GetActionByJava 后, 得到如下(图:4-3): 图:4-3 单击 GetActionByTag 后, 将跳转到edit mode, 如下(图:4-4): Portlet的Response 对象 1。ActionResponse和RenderResponse有什么不同? RenderResponse用来提供如下功能(和Servlet中的Response更相似): A example … … A. Portlet (PortletRequestExample.java) package portlets.portletrequest; /** public class PortletRequestExample extends GenericPortlet{ public void doView(RenderRequest request, RenderResponse response) String jspName = getPortletConfig().getInitParameter("view"); PortletRequestDispatcher rd = rd.include(request, response); public void doEdit(RenderRequest request, RenderResponse response) String jspName = getPortletConfig().getInitParameter("edit"); PortletRequestDispatcher rd = rd.include(request, response); public void processAction(ActionRequest request, ActionResponse response) <!-- Use PortletURL Object//--> <table width=100% border=0> <!-- Use Portlet Tag //--> <BR> <% ACTION: <B><%=getaction%></B> <BR><BR>
<%@ page session="false" %>
ACTION: <B><%=getaction%></B> <BR><BR> … … <expiration-cache>-1</expiration-cache> E. portletentityregistry.xml <?xml version="1.0" encoding="UTF-8"?> F. pageregistry.xml <?xml version="1.0"?> <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation"> … … <!-- PortletRequest Example Page --> … … </portal>
资源: • Pluto Mail List • WSRP Spec1.0 • Apache的WSRP实现 • Apache’s Portal, JetSpeed: • JSR 168:
Java Portlet应用开发 (JSR168), Part 3 - PortletConfig 对象By Jia.li(Terry.li)
• PortletConfig对象 … … 以上Portlet描述文件中的设置用于显示Portlet的Title Bar文字, 同样也可以使用Resource Bundle用以显示Title Bar文字, 如下: … …
这里我们将开发一个简单使用Resource Bundle的Portlet.只需要添加所须的Resource Bundle文件. 我们使用英文及其中文的Resource Bundle, 如下: 3) Base Resource Bundle (portletconfigexample.properties) # English Resource Bundle 2) Chinese Resource Bundle (portletconfigexample_zh.properties) # Chinese Resource Bundle
… …
• 源代码及Portlet相关配置文件 1) Portlet (PortletConfigExample.java) package portlets.portletconfig; /** import javax.portlet.*; public class PortletConfigExample extends GenericPortlet{ public void doView(RenderRequest request, RenderResponse response) public void doEdit(RenderRequest request, RenderResponse response)
… … 3) pageregistry.xml … … 4) PortletRegistry.xml … …
在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.
图3-2
资源: • Pluto Mail List • WSRP Spec1.0 • Apache的WSRP实现 • Apache’s Portal, JetSpeed: • JSR 168:
Java Portlet应用开发 (JSR168), Part 2 - Pluto中添加新的Portal Page 和 PortletBy Jia.li(Terry.li)
在Part1中,我们开发了一个简单的portlet程序,但是几乎所有的代码和文件都是由Eclipse的pluto plugin替我们完成的,如何配置用来在Pluto中的Portal中添加新的Portal Page并且将新的Portlet添加到新的Page中去呢? Part2将一步一步教你如何创建一个新Portal Page.
• portletentityregistry.xml <?xml version="1.0" encoding="UTF-8"?> 其中application 标签表明了目前的application 的 ID, portlet标签定义了一个Portlet , 如果你新开发了一个Portlet , 可以加入以下内容: <?xml version="1.0" encoding="UTF-8"?> 这样一来你又在portal中注册了一个新的Portlet,接下来是将新注册的Portlet加入Page中. • pageregistry.xml <?xml version="1.0"?> <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation"> <fragment name="row" type="row"> <fragment name="col1" type="column"> <fragment name="p1" type="portlet"> </fragment> </fragment> </fragment> 以上是sample portlet的配置. Fragment标签用来配置navigation(导航栏), Page,以及Page中的Column和Row. <property name="portlet" value="1.1"/>中的value值是在portletentityregistry.xml中定义的. 分别对应application id 和portlet id, 将其值用”.”连接起来使用用以定义一个Portlet. 同样 , 如果使用<property name="portlet" value="1.2"/>,则将使用portlets.IntroPortlet.
<fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation"> <fragment name="row" type="row"> <fragment name="col1" type="column"> <fragment name="p1" type="portlet"> <fragment name="p2" type="portlet"> </fragment> </fragment> </fragment> </portal> 2) 配置同一列中的两个Portlet, 如下: <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation"> <fragment name="row1" type="row"> <fragment name="col1" type="column"> <fragment name="p1" type="portlet"> </fragment> </fragment> <fragment name="row2" type="row"> <fragment name="col1" type="column"> <fragment name="p1" type="portlet"> </fragment> </fragment> </fragment> </portal>
• Portlet Modes 和 Portlet window states 以上各模式分别对应GenericPortlet中的 doView(…) , doEdit(…) , doHelp(…) 方法,分别调用以上方法来产生各个模式中的Fragment内容. 非常类似Servlet中的doGet(…) , doPost(…) 方法,都是Helper方法, 但是概念不同. Portlet状态(Portlet window states)提供了对于Portlet窗口的控制功能 , 其中有如下三种最基本的状态: Portlet开发人员可以在处理ActionRequest (以后的章节将讲述其概念) 时使用代码实现Portlet模式, 及其Portlet状态的转变. 注: 只能在处理ActionRequest时改变Portlet Modes和Portlet Window states. A. 添加Custom Portlet Modes <custom-portlet-mode> 1. Portlet代码 (CustomPortletModeExample.java) package portlets.portletmode; /** public class CustomPortletModeExample extends GenericPortlet{ public void doView(RenderRequest request, RenderResponse response) String jspName = getPortletConfig().getInitParameter("all"); PortletRequestDispatcher rd = rd.include(request, response); public void doEdit(RenderRequest request, RenderResponse response) String jspName = getPortletConfig().getInitParameter("all"); PortletRequestDispatcher rd = rd.include(request, response); String jspName = getPortletConfig().getInitParameter("all"); PortletRequestDispatcher rd = rd.include(request, response); 2. JSP(all_mode.jsp) <%@ page session="false" %>
5. Portlet.xml <?xml version="1.0" encoding="UTF-8"?> <!-- Custom PortletMode Example --> </portlet-app> 6. portletregistry.xml. <?xml version="1.0" encoding="UTF-8"?> 7. pageregistry.xml <?xml version="1.0"?> <fragment name="navigation" class="org.apache.pluto.portalImpl.aggregation.navigation.TabNavigation"> </portal>
将以上源代码编译后, 再通过Eclipse生成/更新Portlet的web.xml后, 将所有配置及相关文件部署后, 启动Tomcat.
在Browser中加载如下页面: Http://localhost:8080/pluto/portal , 可以看到如下的页面(图:2_1) 图2-1
单击右上角的config后,可以看到如下页面片段: 以上可以看到新添加的Portlet Mode: config.
添加新的window states同样需要在配置文件中加入相应的描述,如下: 但是同样需要Mapping到Portal提供商所支持的Window state. 总结: 资源: • Pluto Mail List • WSRP Spec1.0 • Apache的WSRP实现 • Apache’s Portal, JetSpeed: • JSR 168: 29/11/2005 Java Portlet应用开发 (JSR168), Part 1By Jia.li (Terry.li)
本系列将介绍如何开发基于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) 相同点:
不同点:
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
• 配置开发环境 希望这编文章可以帮大家搭建一个简单的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) • 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
|
|
|