关于自定义分页的Loop组件:PagedLoop实现

我根据Grid的实现方式,写了一个pagedloop组件,设计了一个LoopDataSource接口作为pagedloop的source,主要是希望从数据库中抓取每页所需的记录,而不是所有记录。 
LoopDataSource.java: 

public interface LoopDataSource extends Iterable<Object>{
	
	int getTotalRowCount();
	
	void prepare(int startIndex, int endIndex, String propertyName);
}

 

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();
	}
}

 

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);
}
 

你可能感兴趣的:(JavaScript,Ajax,Blog,Access,UP)