基于Seam/JSF开发,直接使用Rich组件确实是使界面达到较为美观和专业的最简单途径。
一般来说,基于rich:datascroller和rich:dataTable进行配合,马上就实现了表格及分页,但这种分布是一种“伪分页”,即:只是表现层分页,在数据层并没有进行分页查询。
下面给出一个我在使用的支持数据层分布查询的方法:
基类:
public abstract class BaseExtendedDataModel<T, ID extends Serializable> extends ExtendedDataModel { @Logger private Log log; public List<T> listRow = null; private int firstRow_old = 0; private ID currentId; private Map<ID, T> wrappedData = new HashMap<ID, T>(); private Long rowCount; // better to buffer row count locally public abstract Long getCount(); public abstract List<T> getList(Integer firstRow, Integer maxResults); public abstract T findById(ID id); public void wrap(FacesContext context, DataVisitor visitor, Range range, Object argument, List<T> list) throws IOException { wrappedData = new HashMap<ID, T>(); for (T row : list) { ID id = null; try { id = (ID) PropertyUtils.getProperty(row, "id"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } // wrappedKeys.add(id); wrappedData.put(id, row); visitor.process(context, id, argument); } } public boolean hasById(ID id) { return wrappedData.get(id) != null; } @Override public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException { int firstRow = ((SequenceRange) range).getFirstRow(); int maxResults = ((SequenceRange) range).getRows(); if (firstRow != firstRow_old || listRow == null){ listRow = getList(firstRow, maxResults); firstRow_old = firstRow; } wrap(context, visitor, range, argument, listRow); } /* * This method normally called by Visitor before request Data Row. */ @Override public void setRowKey(Object key) { this.currentId = (ID) key; } @Override public int getRowCount() { if (rowCount == null) return (rowCount = this.getCount()).intValue(); else return rowCount.intValue(); } @Override public boolean isRowAvailable() { if (currentId == null) { return false; } else { return hasById(currentId); } } /** * This is main way to obtain data row. It is intensively used by framework. We strongly recommend use of local cache in that method. */ @Override public Object getRowData() { if (currentId == null) { return null; } else { T ret = wrappedData.get(currentId); if (ret == null) { ret = this.findById(currentId); wrappedData.put(currentId, ret); return ret; } else { return ret; } } } /** * Unused rudiment from old JSF staff. */ @Override public Object getWrappedData() { throw new UnsupportedOperationException(); } private int rowIndex = 0; @Override public int getRowIndex() { //throw new UnsupportedOperationException(); return rowIndex; } @Override public void setRowIndex(int rowIndex) { //throw new UnsupportedOperationException(); this.rowIndex = rowIndex; } @Override public void setWrappedData(Object data) { throw new UnsupportedOperationException(); } @Override public Object getRowKey() { if (true) throw new UnsupportedOperationException(); return currentId; } }
数据列表类
public class PeopleListExtendedDataModel extends BaseExtendedDataModel<People, Long>{ ... @Override public People findById(Long id) { return entityManager.find(People.class, id); } @Override public Long getCount() { return (Long)createQuery(true).getSingleResult(); } @Override public List<People> getList(Integer firstRow, Integer maxResults) { return createQuery(false).setFirstResult(firstRow).setMaxResults(maxResults).getResultList(); } ... }
页面代码:
<rich:datascroller align="left" for="peopleList" maxPages="20" rendered="#{peopleListExtendedDataModel.size>20}"/> <rich:dataTable width="100%" id="peopleList" rows="20" columnClasses="col" value="#{peopleListExtendedDataModel}" var="people">