顯示具有 display tag 標籤的文章。 顯示所有文章
顯示具有 display tag 標籤的文章。 顯示所有文章

2007年8月26日 星期日

分頁效能的實作

Displaytag 有一個常見的 issue, 就是在撈出大量資料時, 會出現 Outofmemory 的錯誤.
因為 displaytag 的預設值, 是將所有的資料一次撈到記憶體, 再執行分頁的動作, 然而這樣的作法是相當消耗記憶體的, 也容易引起exception.
在 displaytag 1.1 版本中(若您的版本是1.0, 請記得切換至1.1), 我們只需要幾個簡單的設定, 就可以改善這個狀況.

先看下列的設定:

<display:table id="row" name="RESULT_LIST" partialList="true" requestURI=""
class="list" pagesize="10" size="${RESULT_SIZE}">

基本上跟 display tag1.0 無太大差異, 但是請記得將 partialList="true" 加入, 表示 displaytag 開啟了有限制的分頁機制,
而 pagesize 為每頁的 record 數目, size 則為資料的總筆數. 該機制與以前最大的不同, 就是只抓取 pagesize 所指定的數量
(該例為10筆, 也就是一次只取出十個物件).

為了確切的達成分頁功能, 我們還需要幾個實作,
先看 Controller 的部分:
...
int pageIndex = getPageIndex(request, getPageIndexName("row"));
//利用 displaytag 的屬性 id="row", 取得目前在第幾頁

int resultSize = dao.getAllCount();
//總共的筆數

List list = dao.search(pageIndex, pageSize);
//目前的筆數

....
request.setAttribute("RESULT_SIZE", new Integer(resultSize));
request.setAttribute("RESULT_LIST", list);

在這個例子當中, 要注意的是 pageIndex 利用到兩個 mtehod getPageIndexName(),
getPageIndex(), 其用意即註解所示, 取得當前的頁數, 詳細實作如下:
....

import org.apache.commons.validator.GenericValidator;
import org.displaytag.util.ParamEncoder;
import org.displaytag.tags.TableTagParameters;

public static String getPageIndexName(String encoder) {
String pageIndexName = new ParamEncoder(encoder).
encodeParameterName(TableTagParameters.PARAMETER_PAGE);
return pageIndexName;
}

public static int getPageIndex(HttpServletRequest request, String pageIndexName) {
int pageIndex = GenericValidator.isBlankOrNull(request.getParameter(pageIndexName)) ? 0
:(Integer.parseInt(request.getParameter(pageIndexName)) - 1 );
return pageIndex;
}
....

而在 dao.getAllCount(), dao.search(), 這兩個呼叫當中, 是為了分別取得總筆數及目前的筆數,
當然 DAO 層的實作可能依照您的 persistence, 而有所不同.

若 dao.search() 是利用 Hibernate 實作的, 範例大致如下:
....
public List search(int pageIndex, int pageSize){
List values;

String hql = "from Person";
Query query = getSession().createQuery(hql);

if (pageIndex >= 0) {
query.setFirstResult(pageSize * pageIndex);
}

if (pageSize > 0) {
query.setMaxResults(pageSize);
}

values = query.list();

return values;
}
....

2007年8月16日 星期四

Implicit objects 的顯示方式

一般我們在 displaytag 顯示 List 物件時, 會使用下列的方式:


< id="row" name="${queryHospital}" requesturi="" class="sample" pagesize="">" >

< titlekey="text.id" sortable="true">
< href="hospitalList.do?METHOD=editHospital&id=< c:out value=">" >
< value="${row.id}">< value="${row.id}">< /a >
< /display:column >
......
< /display:table >


也就是將物件以 EL 的方式接收, 並利用 display:table 中的屬性 "id", 來作轉換,如此就可以很容易的在
<> 標籤裡,利用屬性 id 所設定的值, 將List物件的property一一取出.

但由於各家伺服器的Web Container所支援的方式不盡相同, 導致在 displaytag 的 "id" 屬性失效, 如此一來 id 完全無法帶出 property 中的資料.

若您的需求僅是將資料作動態的連結, displaytag 還是有幾個方便好用的屬性,
可以解決該問題.

引用一下上面這段:

< titlekey="text.id" sortable="true">
< href="hospitalList.do?METHOD=editHospital&id=< c:out value=">" >< value="${row.id}">< /a >
< /display:column >

可以簡化成:

< property="id" href="hospitalList.do?METHOD=editHospital" titlekey="text.id" paramid="id" paramproperty="id" sortable="true">

該屬性很簡單明瞭, 尤其 paramProperty 可以讓我們動態的去呼叫 Property, 而使用 href, paramId, paramProperty 也有某種程度達到簡化的目的.

該方法在 weblogic 9.2 是測試通過的, 但是displaytag 從去年的六月就停止開發了, 若有相關的 bug, 可能需要自己動修改.
若您的頁面需求比較複雜, 也可以考慮別種solution來實作.

#後記:該問題又找到了一個解決方案,將 display:table 內的ID屬性,更新為UID即可.

displaytag - Implicit objects created by table
http://displaytag.sourceforge.net/11/tut_implicitobjects.html
eXtremeComponents
http://code.google.com/p/extremetable/
jmesa
http://code.google.com/p/jmesa/