tapestry的loop組件,官方沒有出分頁組件,這裏使用了PagedLoop分頁組件,這個組件是chenillekit組件裏的一個小組件,因不須要其它組件,這裏就把PagedLoop組件單獨提出來使用。實現從數據庫中抓取每頁所需的記錄,而不是全部記錄。下面先看下PagedLoop源碼:javascript
PagedLoop.javacss
/**
* 項目名稱: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;
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.tmlhtml
<!--
~ 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.Javajava
/**
* 項目名稱: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(" ... "); // … 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.csssql
/*
* 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.javaapache
/**
* 項目名稱: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組件的代碼:app
PersonList2.javaless
/**
* 項目名稱: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.tmlide
<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