在Liferay中,列表通常是使用SearchContainer來實現(xiàn)的,如BBS的欄目列表等。在Liferay的源代碼中,JSP夾雜了大量的本應在Action中實現(xiàn)的代碼,因此導致很難看懂。我嘗試寫一個Portlet,結果就在JSP處耗費了很長時間。
在此簡單總結一下SearchContainer的用法,內(nèi)容有些不恰當。具體可參考message_boards/view.jsp中的代碼。
1.1 概述
作為一個條目的列表,應該包括幾個方面的內(nèi)容:
l Table的標題行
l Table的內(nèi)容
l 每一個條目允許的操作
l 分頁
1.2 Table的標題行(不同的liferay版本可能有所不同,但實質是一樣的)
標題行相對比較簡單,核心代碼如下:
List headerNames = new ArrayList();
headerNames.add("news.column");
headerNames.add("news.columndescript");
headerNames.add("news.childcolumns");
headerNames.add(StringPool.BLANK);
其中注意兩點:
1、 每個標題,應該是i18n的資源,需要在資源文件language.properties中添加內(nèi)容。
2、 最后一行,是用來顯示可能的操作按鈕的,不需要標題行。
1.3 創(chuàng)建SearchContainer
根據(jù)這個headerNames來創(chuàng)建SearchContainer。
首先需要生成一個PortletURL對象,并包括必要的參數(shù)
PortletURL portletURL = res.createRenderURL();
portletURL.setParameter("struts_action", "/ext/news/columnadmin/view");
portletURL.setParameter("columnId", columnId);
如果頁面是分為多個Tab的,還需要將Tab也添加進去。
然后就可以創(chuàng)建SearchContainer
SearchContainer searchContainer = new SearchContainer(req, null, null,"column",
SearchContainer.DEFAULT_DELTA, portletURL,headerNames, null);
檢查源代碼,SearchContainer函數(shù)的定義為
SearchContainer(
RenderRequest req, //javax.portlet.RenderRequest
DisplayTerms displayTerms, //具體意義還不是很清楚,一般設置為null
DisplayTerms searchTerms, //具體意義還不是很清楚,一般設置為null
String curParam, //當前操作的列表,如果某個JSP頁面中有兩個列表需要分頁,則此參數(shù)可以分別設置為“cur1”和“cur2”,暫時沒發(fā)現(xiàn)有什么影響
int delta, //設置每頁顯示的記錄數(shù),默認的是20,可以修改此設置
PortletURL iteratorURL, //設置被循環(huán)的每條記錄的操作URL
List headerNames, //設置表頭信息
String emptyResultsMessage //當查詢結果為空時,即數(shù)據(jù)庫中無數(shù)據(jù)供列表顯示時所顯示的內(nèi)容,如果設置為null,則列表表頭也不顯示出來,也可以設置為“暫無數(shù)據(jù)”等
)
這一步同創(chuàng)建headerNames應該是可以互換的,用searchContainer.setHeaderNames()即可。
1.4 Table的內(nèi)容
主要由幾個小步驟完成
1.4.1 設置總條數(shù)
searchContainer.setTotal(total);
1.4.2 直接設置查詢結果
searchContainer.setResults(results)
變量是一個List,其中的每一個對象將會被用到下一個設置可執(zhí)行操作的JSP中。
1.4.3 設置Table的顯示條目
List resultRows = searchContainer.getResultRows();
for (int i = 0; i < results.size(); i++) {
NewsColumn cutColumn = (NewsColumn) results.get(i);
// 生成新的一個顯示行
ResultRow row = new ResultRow(cutColumn, cutColumn.getPrimaryKey() .toString(), i);
// 設置URL
PortletURL rowURL = res.createRenderURL();
rowURL.setWindowState(WindowState.MAXIMIZED);
rowURL.setParameter("struts_action", "/ext/news/columnadmin/view");
rowURL.setParameter("columnId", cutColumn.getColumnId());
// 設置每一列的顯示內(nèi)容
row.addText(cutColumn.getName(), rowURL);
row.addText(cutColumn.getDescription(), rowURL);
row.addText(childCount), rowURL);
// 設置每一個條目的可用操作
row.addJSP("right", SearchEntry.DEFAULT_VALIGN, "*.jsp");
resultRows.add(row);
}
1.5 每一個條目允許的操作
通過row.addJSP("right", SearchEntry.DEFAULT_VALIGN, "column_action.jsp")來調用JSP顯示相應的操作。
在JSP中,通過下面的語句能夠獲取當前條目的 model 對象
ResultRow row = (ResultRow)request.getAttribute(WebKeys.SEARCH_CONTAINER_RESULT_ROW);
MBCategory category = (MBCategory)row.getObject();
拿到model之后,通過<c:if test="<%= MBCategoryPermission.contains 方式判斷權限,如果允許操作,則首先生成相應的portletURL,然后顯示icon圖標。
<c:if test="<%= MBCategoryPermission.contains(permissionChecker, category, ActionKeys.UPDATE) %>">
<portlet:renderURL windowState="<%= WindowState.MAXIMIZED.toString() %>" var="portletURL">
<portlet:param name="struts_action" value="/message_boards/edit_category" />
<portlet:param name="redirect" value="<%= currentURL %>" />
<portlet:param name="categoryId" value="<%= category.getCategoryId() %>" />
</portlet:renderURL>
<liferay-ui:icon image="edit" url="<%= portletURL %>" />
</c:if>
這部分代碼涉及到Liferay的權限機制。
1.6 顯示table和分頁
顯示table很簡單,在JSP中
<liferay-ui:search-iterator searchContainer="<%= searchContainer %>" />
SearchContainer自身支持分頁。以下幾步
l 創(chuàng)建SearchContainer時設置每頁顯示的條數(shù)
構造函數(shù)SearchContainer的第四個參數(shù)int delta就是每頁顯示的條數(shù),缺省使用SearchContainer.DEFAULT_DELTA,表示每頁顯示20條。我們可以用其他任何我們喜歡的數(shù)值。
l 從邏輯層取數(shù)據(jù)時提供begin和end參數(shù)
searchContainer.getStart() 和searchContainer.getEnd()
l 顯示分頁信息
<liferay-ui:search-paginator searchContainer="<%= searchContainer %>" />
注意:如果因為URL缺其他參數(shù)設置而導致分頁后的頁面不能正常顯示,則可以在<liferay-ui:search-iterator searchContainer="<%= searchContainer %>" />
<liferay-ui:search-paginator searchContainer="<%= searchContainer %>" />標簽之間定義URL,并將需要的參數(shù)設置進去;
例如:
<liferay-ui:search-iterator searchContainer="<%= searchContainer %>" />
<%
//解決分頁時點擊下一頁或是最后一頁時顯示的問題
PortletURL pUrl=renderResponse.createRenderURL();
pUrl=searchContainer.getIteratorURL();
pUrl.setParameter("curAction","viewMagazineEntry");
pUrl.setParameter("magazineTitleId",String.valueOf(magazineTitle.getMagazineTitleId()));
searchContainer.setIteratorURL(pUrl);
%>
<liferay-ui:search-paginator searchContainer="<%= searchContainer %>" />
說明:分頁的那些標簽(如:上一頁,下一頁,最后等等)只有當列表記錄數(shù)達到或超過前面設置的每頁顯示最大記錄條數(shù)時才被顯示出來,否則隱藏。