[Tapestry5] 关于自定义分页的Loop组件:PagedLoop实现
Linuxboy
2011-01-22
我根据Grid的实现方式,写了一个pagedloop组件,设计了一个LoopDataSource接口作为pagedloop的source,主要是希望从数据库中抓取每页所需的记录,而不是所有记录。
LoopDataSource.java: public interface LoopDataSource extends Iterable<Object>{ int getTotalRowCount(); void prepare(int startIndex, int endIndex, String propertyName); } HibernateLoopDataSource.java public class HibernateLoopDataSource implements LoopDataSource { private final Session session; private final Class<?> entityType; private int startIndex; private List<Object> preparedResults; public HibernateLoopDataSource(Session session, Class<?> entityType){ assert session != null; assert entityType != null; this.session = session; this.entityType = entityType; } public int getTotalRowCount(){ Criteria criteria = session.createCriteria(entityType); criteria.setProjection(Projections.rowCount()); Number result = (Number) criteria.uniqueResult(); return result.intValue(); } @SuppressWarnings("unchecked") public void prepare(int startIndex, int endIndex, String propertyName){ Criteria crit = session.createCriteria(entityType); crit.setFirstResult(startIndex).setMaxResults(endIndex - startIndex + 1); if(propertyName!=null){ crit.addOrder(Order.desc(propertyName)); } this.startIndex = startIndex; preparedResults = crit.list(); } @Override public Iterator<Object> iterator() { // TODO Auto-generated method stub return preparedResults.iterator(); } } PagedLoop.java: public class PagedLoop implements ClientElement { //@Parameter(value = "prop:componentResources.id", defaultPrefix = "literal") //private String clientId; /** * The element to render. If not null, then the loop will render the * indicated element around its body (on each pass through the loop). The * default is derived from the component template. */ @Parameter(value = "prop:componentResources.elementName", defaultPrefix = "literal") private String elementName; /** * The element to render. If not null, then the loop will render the * indicated element around its body (on each pass through the loop). The * default is derived from the component template. */ @Parameter(required = true, principal = true, autoconnect = true) private LoopDataSource source; /** * A wrapper around the provided Data Source that caches access to the * availableRows property. This is the source provided to sub-components. */ private LoopDataSource cachingSource; /** * Defines where the pager (used to navigate within the "pages" of results) * should be displayed: "top", "bottom", "both" or "none". */ @Parameter(value = "bottom", defaultPrefix = "literal" ) private String pagerPosition; private GridPagerPosition internalPagerPosition; /** * The number of rows of data displayed on each page. If there are more rows * than will fit, the Grid will divide up the rows into "pages" and * (normally) provide a pager to allow the user to navigate within the * overall result set. */ @Parameter("25") private int rowsPerPage; @Persist private int currentPage; /** * The current value, set before the component renders its body. */ @SuppressWarnings("unused") @Parameter private Object value; /** *If true and the Loop is enclosed by a Form, then the normal state saving logic is turned off. * Defaults to false, enabling state saving logic within Forms. */ @SuppressWarnings("unused") @Parameter(name = "volatile") private boolean volatileState; /** * The index into the source items. */ @SuppressWarnings("unused") @Parameter private int index; /** * Optional primary key converter; if provided and inside a form and not * volatile, then each iterated value is converted and stored into the form. */ @SuppressWarnings("unused") @Parameter private ValueEncoder<?> encoder; @SuppressWarnings("unused") @Component(parameters = { "source=dataSource", "elementName=prop:elementName", "value=inherit:value", "volatile=inherit:volatileState", "encoder=inherit:encoder", "index=inherit:index" }) private Loop loop; @Component(parameters = { "source=dataSource", "rowsPerPage=rowsPerPage", "currentPage=currentPage" }) private Pager pager; @SuppressWarnings("unused") @Component(parameters = "to=pagerTop") private Delegate pagerTop; @SuppressWarnings("unused") @Component(parameters = "to=pagerBottom") private Delegate pagerBottom; /** * A Block to render instead of the table (and pager, etc.) when the source * is empty. The default is simply the text "There is no data to display". * This parameter is used to customize that message, possibly including * components to allow the user to create new objects. */ @Parameter(value = "block:empty") private Block empty; private String assignedClientId; @Parameter(name="OrderBy", defaultPrefix="literal") private String propertyName; /** * A version of LoopDataSource that caches the availableRows property. */ static class CachingDataSource implements LoopDataSource { private final LoopDataSource delegate; private boolean availableRowsCached; private int availableRows; CachingDataSource(LoopDataSource delegate) { this.delegate = delegate; } public int getTotalRowCount() { if (!availableRowsCached) { availableRows = delegate.getTotalRowCount(); availableRowsCached = true; } return availableRows; } public void prepare(int startIndex, int endIndex, String propertyName) { delegate.prepare(startIndex, endIndex, propertyName); } @Override public Iterator<Object> iterator() { return delegate.iterator(); } } public String getElementName() { return elementName; } public Object getPagerTop() { return internalPagerPosition.isMatchTop() ? pager : null; } public Object getPagerBottom() { return internalPagerPosition.isMatchBottom() ? pager : null; } public int getRowsPerPage() { return rowsPerPage; } public void setRowsPerPage(int rowsPerPage) { this.rowsPerPage = rowsPerPage; } public int getCurrentPage() { return currentPage; } public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } void setupDataSource() { cachingSource = new CachingDataSource(source); int availableRows = cachingSource.getTotalRowCount(); if (availableRows == 0) return; int maxPage = ((availableRows - 1) / rowsPerPage) + 1; // This captures when the number of rows has decreased, typically due to deletions. int effectiveCurrentPage = getCurrentPage(); if (effectiveCurrentPage > maxPage) effectiveCurrentPage = maxPage; int startIndex = (effectiveCurrentPage - 1) * rowsPerPage; int endIndex = Math.min(startIndex + rowsPerPage - 1, availableRows - 1); cachingSource.prepare(startIndex, endIndex, propertyName); } Object setupRender() { if (currentPage == 0) currentPage = 1; internalPagerPosition = new StringToEnumCoercion<GridPagerPosition>( GridPagerPosition.class).coerce(pagerPosition); setupDataSource(); // If there's no rows, display the empty block placeholder. return cachingSource.getTotalRowCount() == 0 ? empty : null; } Object beginRender() { // Skip rendering of component (template, body, etc.) when there's // nothing to display. // The empty placeholder will already have rendered. return (cachingSource.getTotalRowCount() != 0); } void onAction(int newPage){ currentPage = newPage; } /** * Returns a unique id for the element. This value will be unique for any given rendering of a * page. This value is intended for use as the id attribute of the client-side element, and will * be used with any DHTML/Ajax related JavaScript. */ @Override public String getClientId() { return assignedClientId; } public LoopDataSource getDataSource(){ return cachingSource; } public String getPropertyName(){ return propertyName; } } @Property private Blog blog; @Inject private Session session; public LoopDataSource getList(){ return new HibernateLoopDataSource(session, Blog.class); } <t:pagedloop source="list" value="blog" rowsperpage="10" orderby="postDate"/> 引用 这个组件运行正常。但是,我希望从数据库获取的数据可以根据blog的某个字段逆序排列,不知应该如何实现?
引用 已修正pagedloop组件,增加orderby参数。
|
|
Linuxboy
2011-01-23
给pagedloop加上一个orderby参数,只要orderby不为空,就按orderby参数提供的字段降序排列。
同时修正loopdatasource方法为prepare(int startIndex, int endIndex, String propertyName). 修改内容如上。 |
|
lya_love
2011-01-23
源码 分享 一下撒下 啊 嘻嘻!
|
|
Linuxboy
2011-01-23
上面就是源码啊,至于pagedloop中用到的Pager,代码如下:
public class Pager { /** * The source of the data displayed by the PagedList (this is used to * determine * {@link LoopDataSource#getTotalRowCount() how many rows are available}, * which in turn determines the page count). */ @Parameter(required = true) private LoopDataSource source; /** * The number of rows displayed per page. */ @Parameter(required = true) private int rowsPerPage; /** * The current page number (indexed from 1). */ @Parameter(required = true) private int currentPage; /** * If this pager is in a custom position it must provide the id of the * PagedLoop it is associated with. */ @Parameter(defaultPrefix = BindingConstants.LITERAL) private String _for; /** * Number of pages before and after the current page in the range. The pager * always displays links for 2 * range + 1 pages, unless that's more than * the total number of available pages. */ @Parameter("5") private int range; private int lastIndex; private int maxPages; //private String pagedLoopElementName; @Inject private ComponentResources resources; @Inject private Messages messages; private Component pagedLoopComponent; private PagedLoop pagedLoop; void setupRender() { if (_for != null) { source = getPagedLoop().getPagedSource(); rowsPerPage = getPagedLoop().getRowsPerPage(); currentPage = getPagedLoop().getCurrentPage(); } } void beginRender(MarkupWriter writer) { int availableRows = source.getTotalRowCount(); maxPages = ((availableRows - 1) / rowsPerPage) + 1; if (maxPages < 2) { return; } writer.element("div", "class", "t-data-grid-pager"); lastIndex = 0; for (int i = 1; i <= 2; i++) { writePageLink(writer, i); } int low = currentPage - range; int high = currentPage + range; if (low < 1) { low = 1; high = 2 * range + 1; } else { if (high > maxPages) { high = maxPages; low = high - 2 * range; } } for (int i = low; i <= high; i++) { writePageLink(writer, i); } for (int i = maxPages - 1; i <= maxPages; i++) { writePageLink(writer, i); } writer.end(); //writer.end(); } /** * Normal, non-Ajax event handler. */ void onAction(int newPage) { // TODO: Validate newPage in range currentPage = newPage; if (_for != null) { getPagedLoopComponent().getComponentResources().triggerEvent( EventConstants.ACTION, new Integer[]{newPage}, null); } } private Component getPagedLoopComponent() { if (_for != null && pagedLoopComponent == null) { pagedLoopComponent = resources.getPage().getComponentResources().getEmbeddedComponent(_for); } return pagedLoopComponent; } private PagedLoop getPagedLoop() { if (_for != null && pagedLoop == null) { pagedLoop = (PagedLoop) getPagedLoopComponent(); } return pagedLoop; } private void writePageLink(MarkupWriter writer, int pageIndex) { if (pageIndex < 1 || pageIndex > maxPages) return; if (pageIndex <= lastIndex) return; if (pageIndex != lastIndex + 1) writer.write(" ... "); // … is ellipsis lastIndex = pageIndex; if (pageIndex == currentPage) { writer.element("span", "class", "current"); writer.write(Integer.toString(pageIndex)); writer.end(); return; } Link link = resources.createEventLink(EventConstants.ACTION, pageIndex); writer.element("a", "href", link, "title", messages.format("goto-page", pageIndex)); writer.write(Integer.toString(pageIndex)); writer.end(); } } |
|
ibatismm
2013-05-22
用Grid组件
|
|
oak2008
2013-11-12
如果要按照某些字段,某些条件进行多表关联查询排序,怎么处理?
|