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(richfaces)只读输入文本验证[重复]

JSF / Seam / RichFaces 中是不是有“服务器端注释”?

JSF、RichFaces、PrimeFaces 和 IceFaces 之间的区别

将 RICHFACES 添加到现有的 JSF2 项目

JSF Richfaces 前端性能调优