第三版是對第二版的一些簡化,多了一個抽象基礎類,方便調用。
頁面代碼(變成了user.defaultDataModel):
<f:view>
<h:form id="formlist">
<rich:dataTable id="carList" width="483" columnClasses="col" rows="#{user.pageSize}"
value="#{user.defaultDataModel}" var="car">
<f:facet name="header">
<rich:columnGroup>
<h:column>
<h:outputText styleClass="headerText" value="Name" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="Decription" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="Base Price" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="Time" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="操作" />
</h:column>
</rich:columnGroup>
</f:facet>
<h:column>
<h:outputText value="#{car.name}" />
</h:column>
<h:column>
<h:outputText value="#{car.description}" />
</h:column>
<h:column>
<h:outputText value="#{car.baseprice}" />
</h:column>
<h:column>
<h:outputText value="#{car.timestamp}" />
</h:column>
<h:column>
<h:commandLink action="#{user.delete}" value="刪除" >
<f:param name="id" value="#{car.id}"/>
</h:commandLink>
</h:column>
</rich:dataTable>
<rich:datascroller for="carList" id="dc1"
style="width:483px" page="#{user.scrollerPage}"/>
</h:form>
</f:view>
DataPage.java(沒有變化):
import java.util.List;

public class DataPage


{


/** *//**
* 將需要的頁的數據封裝到一個DataPage中去, 這個類表示了我們需要的一頁的數據,<br>
* 里面包含有三個元素:datasetSize,startRow,和一個用于表示具體數據的List。<br>
* datasetSize表示了這個記錄集的總條數,查詢數據的時候,使用同樣的條件取count即可,<br>
* startRow表示該頁的起始行在數據庫中所有記錄集中的位置
*/

private int datasetSize;

private int startRow;

private List data;


/** *//**
*
* @param datasetSize
* 數據集大小
* @param startRow
* 起始行
* @param data
* 數據list
*/
public DataPage(int datasetSize, int startRow, List data)

{

this.datasetSize = datasetSize;

this.startRow = startRow;

this.data = data;

}


/** *//**
*
* @return
*/
public int getDatasetSize()

{

return datasetSize;

}

public int getStartRow()

{

return startRow;

}


/** *//**
*
* @return 已填充好的數據集
*/
public List getData()

{

return data;

}

}

PagedListDataModel.java(添加了一些注釋):
package com.jsecode.util.pagination;

import java.util.List;

import javax.faces.model.DataModel;


/** *//**
*
* TODO 分頁所使用的類

* @author <a href="mailto:tianlu@jsecode.com">TianLu</a>
* @version $Rev$ <br>
* $Id$
*/

/**//* 使用方法:
* 前臺的功能模塊Bean(例如User)中繼承PageListBaseBean類,可根據您的需要進行相應修改
* 前臺控件像這樣使用
* <rich:dataTable id="carList" width="483" columnClasses="col" rows="#{user.pageSize}"
value="#{user.defaultDataModel}" var="car">
<f:facet name="header">
<rich:columnGroup>
<h:column>
<h:outputText styleClass="headerText" value="Name" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="Decription" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="Base Price" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="Time" />
</h:column>
<h:column>
<h:outputText styleClass="headerText" value="操作" />
</h:column>
</rich:columnGroup>
</f:facet>

<h:column>
<h:outputText value="#{car.name}" />
</h:column>
<h:column>
<h:outputText value="#{car.description}" />
</h:column>
<h:column>
<h:outputText value="#{car.baseprice}" />
</h:column>
<h:column>
<h:outputText value="#{car.timestamp}" />
</h:column>
<h:column>
<h:commandLink action="#{user.delete}" value="刪除" >
<f:param name="id" value="#{car.id}"/>
</h:commandLink>
</h:column>
</rich:dataTable>
<rich:datascroller for="carList" id="dc1"
style="width:483px" page="#{user.scrollerPage}"/>*/


/**//*
* 進行刪除等操作后會立即改變列表項并且返回列表頁的,請調用本類的refresh方法刷新當前頁面
* 使用方法:
* dao.delete(bean);
* dataModel.refresh();
*/

public abstract class PagedListDataModel extends DataModel
{
int pageSize;
int rowIndex;
DataPage page;


/** *//**
* Create a datamodel that pages through the data showing the specified
* number of rows on each page.
*/

public PagedListDataModel(int pageSize)
{
super();
this.pageSize = pageSize;
this.rowIndex = -1;
this.page = null;
}


/** *//**
* Not used in this class; data is fetched via a callback to the fetchData
* method rather than by explicitly assigning a list.
*/

public void setWrappedData(Object o)
{

if (o instanceof DataPage)
{
this.page = (DataPage) o;

} else
{
throw new UnsupportedOperationException(" setWrappedData ");
}
}


public int getRowIndex()
{
return rowIndex;
}


/** *//**
* Specify what the "current row" within the dataset is. Note that the
* UIData component will repeatedly call this method followed by getRowData
* to obtain the objects to render in the table.
*/

public void setRowIndex(int index)
{
rowIndex = index;
}


/** *//**
* Return the total number of rows of data available (not just the number of
* rows in the current page!).
*/

public int getRowCount()
{
return getPage().getDatasetSize();
}


/** *//**
* Return a DataPage object; if one is not currently available then fetch
* one. Note that this doesn't ensure that the datapage returned includes
* the current rowIndex row; see getRowData.
*/

private DataPage getPage()
{

if (page != null)
{
return page;
}
int rowIndex = getRowIndex();
int startRow = rowIndex;

if (rowIndex == -1)
{
// even when no row is selected, we still need a page
// object so that we know the amount of data available.
startRow = 0;
} // invoke method on enclosing class
page = fetchPage(startRow, pageSize);
return page;
}


/** *//**
* Return the object corresponding to the current rowIndex. If the DataPage
* object currently cached doesn't include that index then fetchPage is
* called to retrieve the appropriate page.
*/

public Object getRowData()
{

if (rowIndex < 0)
{
throw new IllegalArgumentException(
" Invalid rowIndex for PagedListDataModel; not within page ");
} // ensure page exists; if rowIndex is beyond dataset size, then
// we should still get back a DataPage object with the dataset size
// in it

if (page == null)
{
page = fetchPage(rowIndex, pageSize);
}
int datasetSize = page.getDatasetSize();
int startRow = page.getStartRow();
int nRows = page.getData().size();
int endRow = startRow + nRows;

if (rowIndex >= datasetSize)
{
throw new IllegalArgumentException(" Invalid rowIndex ");
}

if (rowIndex < startRow)
{
page = fetchPage(rowIndex, pageSize);
startRow = page.getStartRow();

} else if (rowIndex >= endRow)
{
page = fetchPage(rowIndex, pageSize);
startRow = page.getStartRow();
}
return page.getData().get(rowIndex - startRow);
}


public Object getWrappedData()
{
return page.getData();
}


/** *//**
* Return true if the rowIndex value is currently set to a value that
* matches some element in the dataset. Note that it may match a row that is
* not in the currently cached DataPage; if so then when getRowData is
* called the required DataPage will be fetched by calling fetchData.
*/

public boolean isRowAvailable()
{
DataPage page = getPage();

if (page == null)
{
return false;
}
int rowIndex = getRowIndex();

if (rowIndex < 0)
{
return false;

} else if (rowIndex >= page.getDatasetSize())
{
return false;

} else
{
return true;
}
}


/** *//**
* Method which must be implemented in cooperation with the managed bean
* class to fetch data on demand.
*/
public abstract DataPage fetchPage(int startRow, int pageSize);


/** *//**
* 進行刪除等操作后會立即改變列表項并且返回列表頁的,請調用此方法,用于刷新列表。
*/

public void refresh()
{

if (this.page != null)
{
this.page = null;
getPage();
}
}
}


新增加的PageListBaseBean.java文件,所有需要分頁的bean繼承此類,簡化代碼:
import com.jsecode.util.pagination.DataPage;
import com.jsecode.util.pagination.PagedListDataModel;


/**//*使用方法參考:
public class User extends PageListBaseBean
{
@Override
public PagedListDataModel getDefaultDataModel()
{
if ( defaultDataModel == null ) {
defaultDataModel = new PagedListDataModel(pageSize)
{
public DataPage fetchPage(int startRow, int pageSize)
{
// call enclosing managed bean method to fetch the data
CarBeanDAO dao = new CarBeanDAO();
String sql = "from CarBean model order by model.id desc";
Query query = EntityManagerHelper.createQuery(sql);
query.setFirstResult(startRow);
query.setMaxResults(pageSize);
List list = query.getResultList();
Query q = EntityManagerHelper.createQuery("select count(*) from CarBean");
return new DataPage(Integer.parseInt(q.getSingleResult().toString()), startRow, list);
}
};
}
return defaultDataModel;
}
}
* 如需添加多個分頁功能,請自定義PagedListDataModel變量和實現相關getXXXDataModel方法
*/

/** *//**
* TODO 帶分頁功能的基類
*
* @author <a href="mailto:tianlu@jsecode.com">TianLu</a>
* @version $Rev$ <br>
* $Id$
*/

public abstract class PageListBaseBean
{

/** *//**
* 當前頁碼,跟dataSroller的page屬性綁定
*/
protected int scrollerPage = 1;

/** *//**
* 當前頁面大小
*/
protected int pageSize = 10;

/** *//**
* 默認數據模型,如果你有多個數據集需要分頁,請自定義PagedListDataModel和相應的getDataModel方法
*/
protected PagedListDataModel defaultDataModel;
public int getScrollerPage()

{
return scrollerPage;
}

public void setScrollerPage(int scrollerPage)

{
this.scrollerPage = scrollerPage;
}
public int getPageSize()

{
return pageSize;
}

public void setPageSize(int pageSize)

{
this.pageSize = pageSize;
}
public abstract PagedListDataModel getDefaultDataModel();


}

User中的delete方法:
public String delete()

{
FacesContext ctx = FacesContext.getCurrentInstance();
int id = Integer.parseInt(ctx.getExternalContext().getRequestParameterMap().get("id"));
EntityManagerHelper.beginTransaction();
CarBeanDAO dao = new CarBeanDAO();
CarBean bean = dao.findById(id);
if(bean != null)

{
dao.delete(bean);
dataModel.refresh();
}
EntityManagerHelper.commit();
return null;
}
Faces-config.xml:
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>com.gcoresoft.jsfdemo.bean.User</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
有人反映會出現獲取兩次DataModel的情況,為什么呢?
經過我的測試,是因為設置的datatable的rows屬性的值大于了程序中pageSize的值,比如你設置rows="12",而你的pageSize設置的是10,那么JSF為了滿足顯示12條得條件,就會取兩次數據集組成一個12跳得數據集顯示出來,所以給定的rows屬性最好可以使用相關管理bean的pageSize變量,這樣前后臺統一數據條目,提高性能和可操作性。
為了方便大家JSF的項目開發,后面我會推出一套我自己寫的一個基于JSF的框架,當然此框架是基于實際項目成功實施后提取出來的,主要是簡化了對表單的操作,增加一些常用的工具套件,例如分頁,驗證器等等。對表單操作部分的簡化主要體現在:每種控件都可以和固定的模型綁定,這樣操作模型就可以做到對前臺控件的控制,比如后臺取值可以使用attributes.get("username"),設置前臺控件值可以使用attributes.put("username","admin"),對選擇控件操作也更加簡便,當使用put的方法的時候,前臺會自動選擇到那項,更重要的是這些簡化不需要你寫程序代碼,寫一些簡單的配置文件即可,而且選擇項不僅可以設置在配置文件中,還可以通過數據庫等其他數據源獲取,大大提高開發效率。
posted on 2008-11-23 01:02
Vincent-chen 閱讀(756)
評論(0) 編輯 收藏 所屬分類:
richfaces