这个东西用来帮助自己以后review的。没有什么特殊价值。
·使用JSR 168来开发Portlet。
·开发环境:
1. RAD
2. 测试环境是RAD中专门的门户测试环境(需要跟Portal Server配合)
3. 把Portlet导出成war包,部署在stand-alone的Portal中。
·Portlet应用程序特点:
1. 有组合模式,包括 view,edit,configure
2. 一个模式有多重页面views,来展示portlet页面导航
3. Portlet要对某些数据有CRUD create read update delelte功能
4. 一些数据要在db中永久保存。
·理解:
1. Portlet不应该依赖于不属于local的机器,不应该依赖于外网
2. Portlet不关注商务功能的每个细节,也不提供所有的全面的操作。他只是一个展示的窗口。
一个需求完整的portlet就像一个联系人簿。主页面是联系人的列表,你选择一个人就会显示这个人的详细信息,电话,地址,单位等,然后你可以使用edit来对这些信息进行add, update, delete。你也可以使用configure来配置这些信息存放在数据库的什么地方。这些恰好满足一个porlet的全部需求。
我的开发环境:
RAD7.0
WebSphere Portal6
DB2 9.1
·发布生成的portlet到portal上。
包前缀 com.ibm.samples.standard
我们看到portlet类是 com.ibm.samples.standard.ContactsPortlet
资源束resource bundle是com.ibm.samples.standard.nl.ContactsPortletResource
资源束作用:存放我们的portlet应用程序中可能用到的可译字符串
这些可译字符串的语言翻译将会在“语言特定资源束文件”中存在。
如果是nl的话,可译字符串就存在缺省的自动生成的英语语言资源束中。
Porlet部署描述符中定义了portlet类、资源束、所支持的模式(view,edit,cofigure…)、portlet参数选项。Portlet参数选项是名称-值对,可以选择为只读。
建议只看source XML文件。这样就会清晰的看到定义了什么。其他的视图都比较多余。
· 在portlet类文件中doView(),doEdit(),doCustomConfigure()中指定这些操作view,edit,config所对应的动作,其中
PortletRequestDispather rd = getPortletContext().getRequestDispather(“/jsp/XXXView.jsp”);
来决定页面的转向。
·在RAD7中是没法直接给PortalServer配置数据源的。所以需要访问Portal server运行的WAS console。地址是:https://portalserver.ibm.com:10039/ibm/console/ 然后给我们的portlet配置数据源。
数据库选用的是DB2 v9。 默认端口50000。
1. 首先在 环境-〉Websphere变量 中修改DB2UNIVERSAL_JDBC_DRIVER_PATH的值,这里是你的db2的jdbc驱动包的位置。如果db2是远程的,就去DB2服务器下的sqllib/java/下把db2jcc_license_cu.jar和db2jcc.jar拷过来,放在DB2UNIVERSAL_JDBC_DRIVER_PATH的文件夹值下。
2. 然后到全局安全性-> J2EE连接器体系结构(J2C)认证数据条目 下新建一个属于自己应用程序所对应的数据库的JAAS条目。其中输入访问test数据库所需要的用户名和密码。
3.最后到 资源-〉JDBC提供程序下新建一个JDBC Universal DB2 Driver Provider。(注意,如果你的DB2是在远程,就一定要选择这个Provider,这样就会在数据源创建的时候,让你输入db2所在服务器的地址和访问端口号了。)
4. 多余不赘述,其中在创建 数据源的时候,选择“组件管理认证别名”和“容器管理认证别名”Tab中,都选择在步骤2里创建的JAAS条目。
最后不要忘记测试连接。成功!
· 写个Bean。Bean就是一个java类,有固定的命名规则并实现java.io.Serializable接口。
这个bean的类成员变量都是protect的数据库数据表中的字段名String类型。使用RAD的源代码-〉添加getter&setter功能自动添加这些类成员变量的对应方法。
·写个访问DB的类。
上面的url有客户机访问数据的类模板和最佳实践。
String sql = "select userid,oid,first_name,last_name,email,business_phone from contacts where userid= "+ uid +"order by first_name";
上述方式不好的是uid可能是个错误参数,这样就会有sql运行时错误了。所以,我们采用下面的方法:
String sql=
"select userid,oid,first_name,last_name,email,business_phone from contacts where userid= ? order by first_name";
成功后发生的SQLException是:
[ibm][db2][jcc][10103][10941] Method executeQuery cannot be used for update.
我检查了sql语句,发现select和userid中间没有空格,修复即可。
这个DB类就是JDBC链接DB2数据库获得ResultSet并把值赋给List的作用。其中getContactList方法就是主要被调用的函数。
※ 在写Bean类,写DBAccess类的时候,最佳实践是把他们分别放在不同的包下。比如说package com.ibm.sample.standard.persistence; package com.ibm.sample.standard.beans;
因为在真正的工程中,bean和db的访问类会很多。还是分别放在不同的包下能够让整个工程的层次结构更清晰。
这三者准备好后,我们修改ContactsPortlet类的doView()方法:
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
// Set the MIME type for the render response
response.setContentType(request.getResponseContentType());
//get login userid
String uid = "wpsadmin";
//get the list of Contacts
DbAccess da = new DbAccess();
List contactlist = da.getContactList(uid);
request.setAttribute("contactList", contactlist);
// Invoke the JSP to render
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(VIEW_JSP);
rd.include(request,response);
}
其中的uid是可以用参数代替的,也就是说根据不同的用户就会获得不同的contactList。
注意:request.setAttribute()的第一个参数是在jsp中使用的属性。要和jsp中的声明保持一致。
·修改View.jsp文件,使用bean,并在form中显示出查询结果:
<%@page session="false" contentType="text/html"
import="com.ibm.sample.standard.beans.Contact" %>
<jsp:useBean id ="contactList" type="java.util.List" scope="request"/>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<portlet:defineObjects/>
<form method="POST" name="<portlet:namespace/>viewform">
<table>
<% for(int i=0; i<contactList.size();i++){
Contact contact = (Contact)contactList.get(i);%>
<tr><td>
<%=contact.getFirstName() %> <%=contact.getLastName() %>
</td></tr>
<%} %>
</table></form>
??????? 其中<portlet:namespace/>viewform ?????????有待理解。
·编写configure模式。
其中我们要定义一个read-only的portlet参数选项。这个只读的参数是可以被wps管理员在config模式下修改的。如果参数没有设置成只读,那么普通用户在edit(个性化编辑)中就可以修改该参数。
1. 修改portlet部署描述符。为数据源名称增加一个portlet参数选项。
注意:portlet被安装在portal上,那么这些参数选项会在portlet启动的时候从portlet部署描述符中读取,然后load到portal配置数据库中用于调用。但是在运行时的更新参数选项的时候(从edit或config模式下)更改数据是存放在portal配置数据库中的。那么如果portlet重启,就会又从portlet部署描述符中读取参数。
2. 修改doCustomConfigure方法。
protected void doCustomConfigure(RenderRequest request, RenderResponse response) throws PortletException, IOException {
// Set the MIME type for the render response
response.setContentType(request.getResponseContentType());
//Get the portlet preference for the datasource name
String dsname="";
PortletPreferences prefs = request.getPreferences();
if(prefs!=null){
dsname = (String)prefs.getValue("datasource", "");
}
//put list of Contacts on request for rendering
request.setAttribute("dsName", dsname);
// Invoke the JSP to render
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(CONFIG_JSP);
rd.include(request,response);
}
3. 修改Config.jsp
<%@page session="false" contentType="text/html" pageEncoding="GB18030" import="javax.portlet.*,com.ibm.sample.standard.*" %>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
<<jsp:useBean id="dsName" type="java.lang.String" scope="request"></jsp:useBean>
<portlet:defineObjects/>
<form action="<portlet:actionURL/> method="post">
<div style = "margin-top: 10px" class="wpsPortletHead">
输入数据源名称:
</div>
<input name="datasource" value="<%=dsName %>" type="text"/>
<input name="actionEvent" value="保存" type="submit"/>
</form>
说明:<%@page session.... 这行,确定jsp不会创建一个session,
<jsp:useBean…………..这行,声明了我们获得并在portlet代码中放入得request对象的数据源名称。
<%@taglib..........这行,加入了portlet的标记库,使JSP标记可用。
<portlet:actionURL/>………就是在portlet标记库中定义的。 defineObjects标记也是在这里面,它用来创建request,response和portlet Context对象。尽管这里没有被使用上。
<form action="<portlet:actionURL/>" method="post"> 。。。。指出了如果点击提交按钮,什么url会被激活。
在Portlet运行过程中,有两个词汇代表了porlet的主要动作:render和action。他们的区别在于:如果一个页面被rendered了,所有的在这个页面上的portlets都被要求render他们自己,这样才能建立HTML标记来构建整个页面。可是,当用户在与某一个特定的portlet在打交道的时候,比如在此一个用户点击提交按钮时,portlet能够在portlet被rendered前执行一个action事件。所以我们创建一个url链接指向我们的portlet来执行portlet类中的processAction方法。我们用actionURL来生成这个URL链接。
JSP用<%=(script)%>表达式来显示我们从portlet参数选项中获得的数据源名称。
我们使用style类wpsPortletHead,这个类和其他很多类似的类在css提供用来配合Portal使用。使用这些专门为portal准备的style类是很好的,能够保持不同portlet间一致的风格。
4. 修改processAction方法
proccessAction方法就是对应actionURL的标记所生成的链接的,它会直接触发processAction内容。这里会对Submit按钮后要执行的操作进行描述。
<input name="actionEvent" value="保存" type="submit"/>
上条中actionEvent是参数名,这个名可以在request对象中查到,如果他的value是“保存”,我们就知道用户操作是什么。我们也可以在其他元素上使用相同的名字,根据value的不同在processAction方法中进行不同的操作。
public void processAction(ActionRequest request, ActionResponse response) throws PortletException, java.io.IOException {
//get actionEvent's value.
String actionEventName = request.getParameter("actionEvent");
//Save the configuration update
if("保存".equalsIgnoreCase(actionEventName)){
PortletPreferences prefs = request.getPreferences();//此处对portlet参数选项的修改//在portal配置数据库中进行。
try{
prefs.setValue("datasource", request.getParameter("datasource"));
prefs.store();
}
catch(ReadOnlyException e){
e.printStackTrace();
}
catch(ValidatorException ve){
ve.printStackTrace();
}
}
}
这个方法就是察看config模式叶面request中的actionEvent的值,如果是“保存”,就获取PortletPreferences对象,然后把其中的datasource设定成叶面输入的datasource的值,然后保存这个portlet参数项。
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
// Set the MIME type for the render response
response.setContentType(request.getResponseContentType());
//get login userid
String uid = "wpsadmin";
String ds = null;
PortletPreferences prefs = request.getPreferences();
if(prefs != null){
ds = prefs.getValue("datasource", "");
}
//get the list of Contacts
DbAccess da = new DbAccess(ds);
List contactlist = da.getContactList(uid);
request.setAttribute("contactList", contactlist);
// Invoke the JSP to render
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(VIEW_JSP);
rd.include(request,response);
}
doView修改如上。