第二十五讲:tapestry的loop组件

tapestry的loop组件,官方没有出分页组件,这里使用了PagedLoop分页组件,这个组件是chenillekit组件里的一个小组件,因不需要其它组件,这里就把PagedLoop组件单独提出来使用。实现从数据库中抓取每页所需的记录,而不是所有记录。下面先看下PagedLoop源码:

PagedLoop.java

/**
* 项目名称:TapestryStart
* 开发模式:Maven+Tapestry5.x+Tapestry-hibernate+Mysql
* 版本:1.0
* 编写:飞风
* 时间:2012-02-29
*/
package com.tapestry.app.components.pagedLoop;
 
import org.apache.tapestry5.Block;
import org.apache.tapestry5.ClientElement;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.annotations.BeginRender;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.corelib.components.Delegate;
import org.apache.tapestry5.corelib.components.Loop;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.ComponentDefaultProvider;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
import org.apache.tapestry5.util.StringToEnumCoercion;
 
import com.tapestry.app.data.pagedloop.PagedSource;
import com.tapestry.app.data.pagedloop.PagerPosition;
 
 
 
public class PagedLoop implements ClientElement
{
    @Environmental
    private JavaScriptSupport javascriptSupport;
 
    @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 element;
 
    /**
     * Defines the collection of values for the loop to iterate over.
     */
    @SuppressWarnings("unused")
    @Parameter(required = true)
    private Iterable<?> source;
 
    private PagedSource<?> pagedSource;
 
    /**
     * 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 PagerPosition 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 isVolatile;
 
    /**
     * The index into the source items.
     */
    @SuppressWarnings("unused")
    @Parameter
    private int index;
 
/**
* Value encoder for the value, usually determined automatically from the type of the property bound to the value
* parameter.
*/
@Parameter(required = true)
private ValueEncoder encoder;
 
    @SuppressWarnings("unused")
    @Component(parameters = {"source=pagedSource",
            "element=prop:element", "value=inherit:value",
            "volatile=inherit:volatile", "encoder=inherit:encoder",
            "index=inherit:index"})
    private Loop loop;
 
    @Component(parameters = {"source=pagedSource", "rowsPerPage=rowsPerPage",
            "currentPage=currentPage"})
    private Pager internalPager;
 
    @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;
 
@Inject
private ComponentResources resources;
 
@Inject
private ComponentDefaultProvider defaultProvider;
 
    private String assignedClientId;
 
    public String getElement()
    {
        return element;
    }
 
    public Object getPagerTop()
    {
        return internalPagerPosition.isMatchTop() ? internalPager : null;
    }
 
    public Object getPagerBottom()
    {
        return internalPagerPosition.isMatchBottom() ? internalPager : null;
    }
 
    public PagedSource<?> getPagedSource()
    {
        return pagedSource;
    }
 
    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;
    }
 
ValueEncoder defaultEncoder()
{
return defaultProvider.defaultValueEncoder("value", resources);
}
 
@SuppressWarnings("unchecked")
    Object setupRender()
    {
if (currentPage == 0)
currentPage = 1;
 
assignedClientId = javascriptSupport.allocateClientId(clientId);
        internalPagerPosition = new StringToEnumCoercion<PagerPosition>(
                PagerPosition.class).coerce(pagerPosition);
 
        pagedSource = new PagedSource(source);
 
        int availableRows = pagedSource.getTotalRowCount();
 
        // If there's no rows, display the empty block placeholder.
        if (availableRows == 0)
        {
            return empty;
        }
 
        int startIndex = (currentPage - 1) * rowsPerPage;
        int endIndex = Math.min(startIndex + rowsPerPage - 1,
                                availableRows - 1);
 
        pagedSource.prepare(startIndex, endIndex);
 
        return null;
    }
 
    @BeginRender
    Object begin()
    {
        // Skip rendering of component (template, body, etc.) when there's
        // nothing to display.
        // The empty placeholder will already have rendered.
        return (pagedSource.getTotalRowCount() != 0);
    }
 
    void onAction(int newPage)
    {
        // TODO: Validate newPage in range
        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.
     */
    public String getClientId()
    {
        return assignedClientId;
    }
}
 

PagedLoop.tml

<!--
  ~ Apache License
  ~ Version 2.0, January 2004
  ~ http://www.apache.org/licenses/
  ~
  ~ Copyright 2008 by chenillekit.org
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~ http://www.apache.org/licenses/LICENSE-2.0
  -->
 
<t:container xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd">
 
    <div t:id="pagerTop"/>
 
    <t:loop t:id="loop"><t:body/></t:loop>
<div class="clear"></div>
    <div t:id="pagerBottom"/>
 
    <t:block>
        <div t:id="internalPager"/>
    </t:block>
 
    <t:block id="empty">${message:empty.list}</t:block>
 
</t:container>
 

Pager.Java

/**
* 项目名称:TapestryStart
* 开发模式:Maven+Tapestry5.x+Tapestry-hibernate+Mysql
* 版本:1.0
* 编写:飞风
* 时间:2012-02-29
*/
package com.tapestry.app.components.pagedLoop;
 
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.EventConstants;
import org.apache.tapestry5.Link;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.annotations.Import;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.runtime.Component;
 
import com.tapestry.app.data.pagedloop.PagedSource;
 
 
 
@Import(stylesheet = {"Pager.css"})
public class Pager
{
/**
* The source of the data displayed by the PagedList (this is used to
* determine
* { @link PagedSource#getTotalRowCount() how many rows are available},
* which in turn determines the page count).
*/
@Parameter
private PagedSource<?> source;
 
/**
* The number of rows displayed per page.
*/
@Parameter
private int rowsPerPage;
 
/**
* The current page number (indexed from 1).
*/
@Parameter
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, name = "for")
private String forId;
 
/**
* 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;
 
@Inject
private ComponentResources resources;
 
@Inject
private Messages messages;
 
private Component pagedLoopComponent;
 
private PagedLoop pagedLoop;
 
void setupRender()
{
if (forId != 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(resources.getContainer().getComponentResources().getElementName(), "class", "ck_paged_loop_pager");
//writer.element("div", "class", "ck_paged_loop_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();
}
 
void onAction(int newPage)
{
// TODO: Validate newPage in range
currentPage = newPage;
if (forId != null)
{
getPagedLoopComponent().getComponentResources().triggerEvent(
EventConstants.ACTION, new Integer[]{newPage},
null);
}
}
 
private Component getPagedLoopComponent()
{
if (forId != null && pagedLoopComponent == null)
pagedLoopComponent = resources.getPage().getComponentResources().getEmbeddedComponent(forId);
 
return pagedLoopComponent;
}
 
private PagedLoop getPagedLoop()
{
if (forId != 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(" ... "); // &#8230; is ellipsis
 
lastIndex = pageIndex;
 
if (pageIndex == currentPage)
{
writer.element("span", "class", "ck_paged_loop_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();
}
}
 

Pager.css

/*
 * Apache License
 * Version 2.0, January 2004
 * http://www.apache.org/licenses/
 *
 * Copyright 2008 by chenillekit.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 */
DIV.ck_paged_loop_pager{padding:10px 0;}
DIV.ck_paged_loop_pager A {
   border: 1px solid silver;
   color: black;
   font-size: medium;
   margin-right: 5px;
   padding: 2px 5px;
   text-decoration: none;
}
DIV.ck_paged_loop_pager A:hover {
   border: 1px solid #000;
   color: black;
   font-size: medium;
   margin-right: 5px;
   padding: 2px 5px;
   text-decoration: none;
}
SPAN.ck_paged_loop_current {
   border: 1px solid silver;
   font-size: medium;
   margin-right: 5px;
   padding: 2px 5px;
   text-decoration: none;
   background-color: #809FFF;
   color: white;
}
 

PagedSource.java

/**
* 项目名称:TapestryStart
* 开发模式:Maven+Tapestry5.x+Tapestry-hibernate+Mysql
* 版本:1.0
* 编写:飞风
* 时间:2012-02-29
*/
package com.tapestry.app.data.pagedloop;
 
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
 
 
public class PagedSource<T> implements Iterable<T>
{
    private List<T> _source = new ArrayList<T>();
 
    private List<T> _pageSource = new ArrayList<T>();
 
    private Integer _iterableSize;
 
    public PagedSource(Iterable<T> source)
    {
        for (T aSource : source)
            _source.add(aSource);
    }
 
    /**
     * @return
     *
     * @see java.lang.Iterable#iterator()
     */
    public Iterator<T> iterator()
    {
        return _pageSource.iterator();
    }
 
    public int getTotalRowCount()
    {
        if (_iterableSize != null)
            return _iterableSize;
 
        _iterableSize = 0;
 
        Iterator<?> it = _source.iterator();
        while (it.hasNext())
        {
            it.next();
            _iterableSize++;
        }
 
        return _iterableSize;
    }
 
    public void prepare(int startIndex, int endIndex)
    {
        for (int i = startIndex; i <= endIndex; i++)
        {
            _pageSource.add(_source.get(i));
        }
    }
 
}
 

PagerPosition.java

/**
* 项目名称:TapestryStart
* 开发模式:Maven+Tapestry5.x+Tapestry-hibernate+Mysql
* 版本:1.0
* 编写:飞风
* 时间:2012-02-29
*/
package com.tapestry.app.data.pagedloop;
 
public enum PagerPosition
{
    /**
     * Position the pager above the paged content.
     */
    TOP(true, false),
 
    /**
     * Position the pager below the paged content (this is the default).
     */
    BOTTOM(false, true),
 
    /**
     * Show the pager above and below the paged content.
     */
    BOTH(true, true),
 
    /**
     * Don't show a pager (the application will need to supply its own
     * navigation mechanism).
     */
    NONE(false, false);
 
    private final boolean _matchTop;
 
    private final boolean _matchBottom;
 
    private PagerPosition(boolean matchTop, boolean matchBottom)
    {
        _matchTop = matchTop;
        _matchBottom = matchBottom;
    }
 
    public boolean isMatchBottom()
    {
        return _matchBottom;
    }
 
    public boolean isMatchTop()
    {
        return _matchTop;
    }
}

下面是使用PagedLoop组件的代码:

PersonList2.java

/**
* 项目名称:TapestryStart
* 开发模式:Maven+Tapestry5.x+Tapestry-hibernate+Mysql
* 版本:1.0
* 编写:飞风
* 时间:2012-02-29
*/
package com.tapestry.app.pages.crud;
 
import java.util.List;
 
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.PageActivationContext;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.ioc.annotations.Inject;
 
import com.tapestry.app.components.pagedLoop.PagedLoop;
import com.tapestry.app.entities.Person;
import com.tapestry.app.services.StartDAO;
 
public class PersonList2 {
 
//打开user读写
@Property
private Person person;
 
//打开user阵列的读写
@Property
private List<Person> persons;
 
//导入操作数据库的服务
@Inject
private StartDAO dao;
 
//当前页面接收user的id值
@PageActivationContext
private Long id;
 
//开启PagedLoop
@Component(parameters={"source=persons", "value=person", "rowsPerPage=1","pagerPosition=bottom"})
private PagedLoop personLoop;
 
//页面加载时设置渲染
void setupRender(){
//查询User数据表
StringBuffer sql = new StringBuffer();
sql.append("from Person");
persons = dao.findWithQuery(sql.toString());
}
 
//单击eventlink执行删除操作
Object onDelete(Long id){
dao.deleteByID(Person.class, id);
return this;
}
 
}
 

PersonList2.tml

<html t:type="layout" title="tapestryStart Index"  t:sidebarTitle="Framework Version"
 xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
 <style>
 .table{border-collapse: collapse; }
 .table td,table th{border:1px solid #999; padding:5px;"}
 .meul{list-style:none;}
 .meul li{ width:80px; float:left; hegiht:20px;}
 .clear{clear:both; height:0; display:block; overflow:hidden;}
 </style>
 <t:pagelink page="crud/PersonCreate">添加用户</t:pagelink><br/><br/>
<ul class="meul">
<li>id</li>
    <li>version</li>
    <li>firstName</li>
    <li>lastName</li>
    <li>region</li>
    <li>startDate</li>
    <li>操作</li>
    <div class="clear"></div>
<div t:id="personLoop">
    <li>${person.id}</li>
    <li>${person.version}</li>
    <li>${person.firstName}</li>
    <li>${person.lastName}</li>
    <li>${person.region}</li>
    <li>${person.startDate}</li>
    <li><t:pagelink page="crud/PersonUpdate" t:context="${person.id}">修改</t:pagelink><t:eventlink t:event="delete" t:context="${person.id}">删除</t:eventlink></li>
  </div>
  </ul>
</html>

http://localhost/grid/personcrud/personlooplist

转载于:https://my.oschina.net/shootercn/blog/53723

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值