JSF,RichFaces,分页
Posted
技术标签:
【中文标题】JSF,RichFaces,分页【英文标题】:JSF, RichFaces, pagination 【发布时间】:2012-08-09 21:07:54 【问题描述】:我知道这里有很多关于 JSF paginatin 的帖子,但没有一个让我满意。
为了将大数据拆分成页面,我打算使用 RichFaces Data 滚动组件。
它看起来很适合,但它看起来像是在“人工”分页。
我不喜欢这里的是它加载所有数据然后只显示其中的一部分。至少它看起来是这样的。如果我错了,请纠正我。
Rich faces 有很好的演示,但由于某种原因,他们跳过了 bean 定义——只有 xhtml。 我看到有人提到了 ExtendedDataModel,但我发现的唯一例子并没有给我留下深刻印象。 为什么我应该有 5 个屏幕代码只显示数据子集?
老实说,像分页这样简单的问题在 JSF 中恰好非常复杂,我真的不明白为什么。
所以我的问题是: 1.是否可以在 Richfaces 中只加载一页数据 2.不将其存储到会话(我的意思是实际数据未列出状态-当前页面等)
我只对richfaces lib感兴趣,因为我已经在我的项目中使用了它,而不是引入对其他东西的依赖
提前感谢
【问题讨论】:
这是一个有趣的问题,但必须由 RichFaces 团队自己来回答。最好将其发布在RichFaces Developer Forum。如果您在那里得到满意的答案,请在此处发布并标记为答案。 【参考方案1】:在 RichFaces 论坛上讨论后提出了以下解决方案(感谢 Brendan Healey):
RichLazyDataModel.java
/**
* Extended data model
* @author Brendan Healey
*/
public abstract class RichLazyDataModel<T> extends ExtendedDataModel<T>
private SequenceRange cachedRange;
private Integer cachedRowCount;
private List<T> cachedList;
private Object rowKey;
public abstract List<T> getDataList(int firstRow, int numRows);
public abstract Object getKey(T t);
public abstract int getTotalCount();
@Override
public void walk(FacesContext ctx, DataVisitor dv, Range range, Object argument)
SequenceRange sr = (SequenceRange) range;
if (cachedList == null || !equalRanges(cachedRange, sr))
cachedList = getDataList(sr.getFirstRow(), sr.getRows());
cachedRange = sr;
for (T t : cachedList)
if (getKey(t) == null)
/*
* the 2nd param is used to build the client id of the table
* row, i.e. mytable:234:inputname, so don't let it be null.
*/
throw new IllegalStateException("found null key");
dv.process(ctx, getKey(t), argument);
/*
* The rowKey is the id from getKey, presumably obtained from
* dv.process(...).
*/
@Override
public void setRowKey(Object rowKey)
this.rowKey = rowKey;
@Override
public Object getRowKey()
return rowKey;
@Override
public boolean isRowAvailable()
return (getRowData() != null);
@Override
public int getRowCount()
if (cachedRowCount == null)
cachedRowCount = getTotalCount();
return cachedRowCount;
@Override
public T getRowData()
for (T t : cachedList)
if (getKey(t).equals(this.getRowKey()))
return t;
return null;
protected static boolean equalRanges(SequenceRange range1, SequenceRange range2)
if (range1 == null || range2 == null)
return range1 == null && range2 == null;
else
return range1.getFirstRow() == range2.getFirstRow() && range1.getRows() == range2.getRows();
/*
* get/setRowIndex are used when doing multiple select in an
* extendedDataTable, apparently. Not tested. Actually, the get method is
* used when using iterationStatusVar="it" & #it.index.
*/
@Override
public int getRowIndex()
if (cachedList != null)
ListIterator<T> it = cachedList.listIterator();
while (it.hasNext())
T t = it.next();
if (getKey(t).equals(this.getRowKey()))
return it.previousIndex() + cachedRange.getFirstRow();
return -1;
@Override
public void setRowIndex(int rowIndex)
int upperBound = cachedRange.getFirstRow() + cachedRange.getRows();
if (rowIndex >= cachedRange.getFirstRow() && rowIndex < upperBound)
int index = rowIndex % cachedRange.getRows();
T t = cachedList.get(index);
setRowKey(getKey(t));
@Override
public Object getWrappedData()
throw new UnsupportedOperationException("Not supported yet.");
@Override
public void setWrappedData(Object data)
throw new UnsupportedOperationException("Not supported yet.");
public List<T> getCachedList()
return cachedList;
ListState.java
/**
* Holds list state
*/
public class ListState implements Serializable
private int page;
private Map<String, Serializable> searchCriteria = new HashMap<String, Serializable>();
public int getPage()
return page;
public void setPage(int page)
this.page = page;
public Map<String,Serializable> getSearchCriteria()
return searchCriteria;
CardsBean.java
@ManagedBean(name="cardsBean")
public class CardsBean
@ManagedProperty("#cardService")
private CardService cardService;
private ListState state;
private RichLazyDataModel<Card> cardsModel = new RichLazyDataModel<Card>()
@Override
public List<Card> getDataList(int firstRow, int numRows)
MyUserDetails user = SecurityUtils.getCurrentUser();
return cardService.findUserCards(user.getUser(), firstRow, numRows, state.getSearchCriteria());
@Override
public Object getKey(Card card)
return card.getId();
@Override
public int getTotalCount()
MyUserDetails user = SecurityUtils.getCurrentUser();
return cardService.countUserCards(user.getUser(), state.getSearchCriteria());
;
public RichLazyDataModel<Card> getCards()
return cardsModel;
public String getSearchString()
return (String)state.getSearchCriteria().get("searchString");
public int getCurrentPage()
return state.getPage();
public void setCurrentPage(int page)
state.setPage(page);
public void setSearchString(String searchString)
state.getSearchCriteria().put("searchString", searchString);
public void setCardService(CardService cardService)
this.cardService = cardService;
public boolean isPinned()
return Boolean.TRUE.equals(state.getSearchCriteria().get("pinned"));
public void setPinned(boolean pinned)
state.getSearchCriteria().put("pinned", pinned);
public void togglePinned()
setPinned(!isPinned());
@PostConstruct
public void init()
state = getFromSession("cardsList", null);
if (state == null)
state = new ListState();
storeInSession("cardsList", state);
public <T extends Serializable> T getFromSession(String name, T defaultValue)
T ret = (T) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(name);
if (ret == null)
ret = defaultValue;
return ret;
public void storeInSession(String name, Serializable obj)
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(name, obj);
cards.xhtml(部分)
...
<h:form>
<rich:dataGrid value="#cardsBean.cards" var="card" columns="2" elements="20" first="#cardsBean.currentPage" style="margin:0 auto;width:70em" id="cardsTable">
<f:facet name="header">
<h:inputText value="#cardsBean.searchString">
<a4j:ajax event="keyup" render="cardsTable@body, cardsTable@footer">
<a4j:attachQueue requestDelay="700" ignoreDupResponses="true" />
</a4j:ajax>
</h:inputText>
</f:facet>
<rich:panel id="cd">
<ui:include src="WEB-INF/parts/card.xhtml">
<ui:param name="card" value="#card"/>
</ui:include>
</rich:panel>
<f:facet name="footer">
<rich:dataScroller page="#cardsBean.currentPage" />
</f:facet>
</rich:dataGrid>
</h:form>
...
【讨论】:
你不能参考你在论坛上的讨论吗?谢谢。以上是关于JSF,RichFaces,分页的主要内容,如果未能解决你的问题,请参考以下文章
RichFaces 3.3.3 和 JSF 2.0 工作示例
JSF / Seam / RichFaces 中是不是有“服务器端注释”?