Appfuse與分頁
Appfuse使用的分頁Plugin是一個叫做DisplayTag的第三方插件,不過Appfuse並沒有完全實作這個部份;所以,當我們的資料多到需要分頁時,Appfuse的預設程式是:
-
將所有資料撈出來。
-
將所有資料送給DisplayTag。
-
DisplayTag實作分頁。
這裡有一個很奇怪的部份是,假設我們的資料是1000筆,但每一頁顯示是10筆,所以會變成:
DisplayTag因為只需要顯示10筆資料,所以它會把顯示的10筆取出來後,把剩下的990筆資料捨棄,而使用者跳到第二頁時,程式會再重新撈出1000筆資料後,DisplayTag再取需要的10筆資料,而捨棄不需要的990筆。
這個當然不是DisplayTag的希望,問題是出在Appfuse,因為它並沒有按照第三方的DisplayTag規範來實作,所以我們必須幫我們的範本程式,把這些程式補上。
下方我們以「查看用戶」的功能來實作。
-
繼承org.displaytag.pagination.PaginatedList。
org.displaytag.pagination.PaginatedList是一個Interface,原本是要實作它,但是因為它沒有宣告排序的功能,所以為了彌補這個部份,我們宣告一個Interface ExtendedPaginatedList 繼承PaginatedList,並放在package com.mycompany.mytest.util裡。
import org.displaytag.pagination.PaginatedList;
import org.displaytag.properties.SortOrderEnum;
import java.util.List;
public interface ExtendedPaginatedList extends PaginatedList {
/** Request params as constants. */
public interface IRequestParameters{
String SORT = "sort";
String PAGE = "page";
String ASC = "asc";
String DESC = "desc";
String DIRECTION = "dir";
}
/** Set the default page size **/
int DEFAULT_PAGE_SIZE = 1;
/** set results list */
void setList(List resultList);
/** Set the Total - total number of records or rows (e.g 10,000 rows found with the query) **/
void setFullListSize(int total);
/** set the Page Size - to display the required number of rows (e.g 25 rows out of 10,000) **/
void setPageSize(int pageSize);
/** Set the Index - start with 0 and keep increamenting **/
void setIndex(int index);
/** get the first record index **/
int getFirstRecordIndex();
int getPageNumber();
/** get page size **/
int getObjectsPerPage();
int getTotalPages();
int getFullListSize();
/** Set the sort Direction - asc or dsc **/
void setSortDirection(SortOrderEnum sortOrderEnum);
/** set sort criterion **/
void setSortCriterion(String sortCriterion);
}
-
實作ExtendedPaginatedList.java。
再來我們要實作剛剛宣告的Interface,程式碼如下,一樣放在package com.mycompany.mytest.util裡:
import javax.servlet.http.HttpServletRequest;
import org.displaytag.properties.SortOrderEnum;
import java.util.List;
/**
* <code>com.gorti.project.web.ui.action.PaginatedListImpl</code> implemnts
* </code>com.gorti.project.web.ui.action.IExtendedPaginatedList</code> This
* class can be used for pagination purpose. This class depends upon
* HttpServletRequest object. To be used by Controllers in case of Http
* requests.
*
* @author
*/
public class PaginatedListImpl implements ExtendedPaginatedList {
/** current page index, starts at 0 */
private int index;
/** number of results per page (number of rows per page to be displayed ) */
private int pageSize;
/** total number of results (the total number of rows ) */
private int fullListSize;
/** list of results (rows found ) in the current page */
private List list;
/** default sorting order */
private SortOrderEnum sortDirection = SortOrderEnum.ASCENDING;
/** sort criteria (sorting property name) */
private String sortCriterion;
/** Http servlet request * */
private HttpServletRequest request;
/** default constructor * */
public PaginatedListImpl() {
}
/**
* Create <code>PaginatedListImpl</code> instance using the
* <code>HttpServletRequest</code> object.
*
* @param request
* <code>HttpServletRequest</code> object.
*/
/**
* Create <code>PaginatedListImpl</code> instance using the
* <code>HttpServletRequest</code> object.
*
* @param request
* <code>HttpServletRequest</code> object.
* @param pageSize
* the page size - the total number of rows per page.
*/
public PaginatedListImpl(HttpServletRequest request, int pageSize) {
sortCriterion = request.getParameter(ExtendedPaginatedList.IRequestParameters.SORT);
sortDirection = ExtendedPaginatedList.IRequestParameters.DESC.equals(request.getParameter(ExtendedPaginatedList.IRequestParameters.DIRECTION)) ? SortOrderEnum.DESCENDING
: SortOrderEnum.ASCENDING;
pageSize = pageSize != 0 ? pageSize : DEFAULT_PAGE_SIZE;
String page = request.getParameter(ExtendedPaginatedList.IRequestParameters.PAGE);
index = page == null ? 0 : Integer.parseInt(page) - 1;
}
/**
* Create <code>PaginatedListImpl</code> instance .
*
* @param pageSize
* the page size - the total number of rows per page.
* @return <code>ExtendedPaginatedList</code> instance.
* @throws Exception
* -
* problem while creating paginatedlist object.
*/
public ExtendedPaginatedList getPaginatedListObject(int pageSize) throws Exception {
if (request == null) {
throw new Exception("Cannot create paginated list. Depends upon HttpServletRequest.");
}
return new PaginatedListImpl(request, pageSize);
}
/**
* Set the non-null <code>HttpServletRequest</code> object.
*
* @param request
* a <code>HttpServletRequest</code> object.
*/
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public int getFirstRecordIndex() {
return index * pageSize;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public List getList() {
return list;
}
public void setList(List results) {
this.list = results;
}
public int getFullListSize() {
return fullListSize;
}
public void setFullListSize(int fullListSize) {
this.fullListSize = fullListSize;
}
public int getTotalPages() {
return (int) Math.ceil(((double) fullListSize) / pageSize);
}
public int getObjectsPerPage() {
return pageSize;
}
public int getPageNumber() {
return index + 1;
}
public String getSearchId() {
// Not implemented for now.
// This is required, if we want the ID to be included in the paginated
// purpose.
return null;
}
public String getSortCriterion() {
return sortCriterion;
}
public SortOrderEnum getSortDirection() {
return sortDirection;
}
public void setSortCriterion(String sortCriterion) {
this.sortCriterion = sortCriterion;
}
public void setSortDirection(SortOrderEnum sortDirection) {
this.sortDirection = sortDirection;
}
}
-
再來我們要生一個Factory來控管PaginateList,還是放在package com.mycompany.mytest.util裡。
import javax.servlet.http.HttpServletRequest;
import org.displaytag.properties.SortOrderEnum;
import org.springframework.stereotype.Service;
@Service("paginateListFactory")
public class PaginateListFactory {
private static final int DEFAULT_PAGE_SIZE = 10;
public ExtendedPaginatedList getPaginatedListFromRequest(HttpServletRequest request) {
ExtendedPaginatedList paginatedList = new PaginatedListImpl();
String sortCriterion = null;
String thePage = null;
if (request != null) {
sortCriterion = request.getParameter(ExtendedPaginatedList.IRequestParameters.SORT);
paginatedList.setSortDirection(ExtendedPaginatedList.IRequestParameters.DESC.equals(request.getParameter(ExtendedPaginatedList.IRequestParameters.DIRECTION)) ? SortOrderEnum.DESCENDING: SortOrderEnum.ASCENDING);
thePage = request.getParameter(ExtendedPaginatedList.IRequestParameters.PAGE);
}
paginatedList.setSortCriterion(sortCriterion);
paginatedList.setPageSize(DEFAULT_PAGE_SIZE);
if (thePage != null) {
int index = paginatedList == null ? 0: Integer.parseInt(thePage) - 1;
paginatedList.setIndex(index);
} else {
paginatedList.setIndex(0);
}
return paginatedList;
}
}
這邊有二點要注意的,一是DEFAULT_PAGE_SIZE=10,也就是說我們預設每一頁是10筆資料,第二點是@Service("paginateListFactory"),我們有設定這個Class是一個Service,所以預計它會被Spring的<context:component-scan base-package="com.xxx"/>(這段程式在applicationContext.xml裡)掃瞄到,所以要確認package是正確可被掃瞄到的;另外,為了方便稍候的測試,我們先將DEFAULT_PAGE_SIZE改為2。
-
在Action中宣告並呼叫PaginateListFactory與ExtendedPaginatedList。
因為預定是大部份的Action中都會用到的內容,所以我們把下方這段Code加在BaseAction中。
protected PaginateListFactory paginateListFactory;
public PaginateListFactory getPaginateListFactory() {
if (null == paginateListFactory) {
paginateListFactory = (PaginateListFactory) getApplicationContext().getBean("paginateListFactory");
}
return paginateListFactory;
}
public void setPaginateListFactory(PaginateListFactory paginateListFactory) {
this.paginateListFactory = paginateListFactory;
}
protected ExtendedPaginatedList getPaginatedList() {
return getPaginateListFactory().getPaginatedListFromRequest(getRequest());
}
protected ApplicationContext getApplicationContext() {
ServletContext sc = getRequest().getSession().getServletContext();
return WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
}
這樣基本的準備就完成了,再來要實作分頁功能。
留言列表