JSF, RichFaces, pagination

后端 未结 1 1360
日久生厌
日久生厌 2021-01-12 08:35

I know there are quite a number of posts regarding JSF paginatin here, but none of them satisfed me.

To split pretty big data into pages I was going to use RichFaces

相关标签:
1条回答
  • 2021-01-12 08:56

    After talking on RichFaces forum came up this the following solution (thanx to 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 (partial)

    ...
    
    <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>
    ...
    
    0 讨论(0)
提交回复
热议问题