<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    幸せのちから

    平凡的世界
    看似平常實崎嶇
    成如容易卻艱辛

    extremeComponents指南

    eXtremeComponents指南

    eXtremeComponents指南

    Jeff Johnston

    版本1.0.0

    本文檔允許在遵守以下兩條原則的條件下被使用和傳播: 1)不能憑借本文檔索取任何費用 2)以任何方式(印刷物或電子版)使用和傳播時本文檔時,必須包含本版權申明

    (更新中...)


    定制FilterCell


    1. 引言

    列的filterCell屬性控制過濾器如何顯示,它和cell屬性非常相像并且也是實現Cell接口。馬上要定義的是默認的和droplist這兩個過濾器cells。 默認的是一個輸入框元素而droplist是一個下拉列表元素。當然,如果你需要進行一些定制你可以插接自己的實現。

    最近,我被問到是否能夠實現一個過濾器cell,顯示已經通過別的過濾器過濾得到數據子集。答案當然是肯定的,而且這是我將在這里示范的。通常定制的 cell可以很容易被創建,這個示例將印證這點。在這個示例里last name列里顯示的將是通過first name過濾后的子集。如果沒有通過 first name過濾那么所有值都將被顯示。

    1.1. 定制Droplist過濾器Cell示例

    通常你只需要為過濾器cell實現Cell接口。然而,因為我們要創建的過濾器cell是一個下拉列表,我們可以通過擴展 FilterDroplistCell來獲得它已經提供的很多功能,FilterDroplistCell是發行包已經提供的cells之一。

    我們需要覆蓋FilterDroplistCell的唯一方法是getFilterDropList()。這是整個類的全部代碼:

    public class FilteredDroplistCell extends FilterDroplistCell {
    private static Log logger = LogFactory.getLog(FilterDroplistCell.class);

    protected List getFilterDropList(TableModel model, Column column) {
    List droplist = new ArrayList();

    String firstNameFilter = model.getLimit().getFilterSet().getValue("firstName");

    Collection beans = model.getCollectionOfBeans();
    for (Iterator iter = beans.iterator(); iter.hasNext();) {
    Object bean = iter.next();
    try {
    String firstName = BeanUtils.getProperty(bean, "firstName");
    if (StringUtils.isNotBlank(firstNameFilter) && !firstName.equals(firstNameFilter)) {
    continue;
    }

    String lastName = BeanUtils.getProperty(bean, column.getProperty());
    if ((lastName != null) && !droplist.contains(lastName)) {
    droplist.add(lastName);
    }
    } catch (Exception e) {
    logger.debug("Problems getting the droplist.", e);
    }
    }

    Collections.sort(droplist);

    return droplist;
    }
    }

    如果你比較這個類和父類,你會發現它們只有微小的區別。

    首先需要注意的是我們需要找出first name是否已經被過濾了。

    String firstNameFilter = model.getLimit().getFilterSet().getValue("firstName");

    然后我們需要判斷當前bean的first name值是否和first name過濾器值相同。如果相同,將當前的last name值 添加到droplist中。

    String firstName = BeanUtils.getProperty(bean, "firstName");
    if (StringUtils.isNotBlank(firstNameFilter) && !firstName.equals(firstNameFilter)) {
    continue;
    }

    如果last name將添加到droplist中,我們需要檢查droplist中是否已經包含了這個值。如果沒有,我們就把它添加到droplist中。

    String lastName = BeanUtils.getProperty(bean, column.getProperty());
    if ((lastName != null) && !droplist.contains(lastName)) {
    droplist.add(lastName);
    }

    為了使用這個Cell你應該在Preferences中聲明一個別名。 當然,你可以省略這步而在JSP中提供這個Cell實現類的全路徑,但是使用Preferences更簡潔。

    column.filterCell.filteredDroplist=org.extremesite.cell.FilteredDroplistCell

    在ColumnTag通過設置filterCell屬性來使用FilteredDroplistCell。

    <ec:column property="lastName" filterCell="filteredDroplist"/>

    如果不清楚Preferences和ColumnTag定義語法請參考Preferences指南。

    定制FilterRowsCallback


    1. 引言

    FilterRowsCallback被用來過濾傳給eXtremeTable的Beans的Collection。 FilterRowsCallback的默認實現是得到Beans或Maps的Collection,然后通過實現jakarta Predicate接口來進行過濾。當然,如果你需要進行一些定制你可以插接自己的實現。

    首先聲明,本示例代碼包含一些從原包中剪切、粘貼的代碼(雖然不是很多)。在 最初的最終發行包之后,值過濾得到進一步改善使得更具復用性并更容易實現,可能和定制cell代碼行數相同。 當然,我被要求并非常樂意示范如何在當前代碼基礎上實現定制過濾。這有非常清晰的hooks實現,并且很容易實現。

    本示例示范了如何調整代碼為過濾器提供一個精確的比較功能。當前的實現是通過使用StringUtils.contains()方法進行模糊比較。 本示例將使用StringUtils.equals()方法。你可以按照你的需要來調整代碼進行更多定制。

    1.1. 定制FilterRowsCallback示例

    首先你需要做的是創建一個實現Predicate接口的定制類。Predicate要求我們實現evaluate()方法來判斷是否包含 當前bean。因為你僅僅調整現在已有的功能,首先得到filterPredicate的源代碼(在發行包的callback包下), 拷貝到你的工程里。然后向下面展示的一樣將 StringUtils.contains()方法修改為StringUtils.equals()方法:

    public final class ExactMatchFilterPredicate implements Predicate {
    private boolean isSearchMatch(String value, String search) {

    ...

    else if (StringUtils.equals(value, search)) {
    return true;
    }

    ...

    }
    }

    然后我們需要實現和Predicate共同作用的FilterRowsCallback接口。再一次從發行包的callback包下拷貝ProcessRowsCallback源代碼到你的工程里。 請參照我們創建的定制的ExactMatchFilterPredicate 類來確認僅僅實現了FilterRowsCallback和修改Predicate。

    public class ExactMatchFilterRows implements FilterRowsCallback {
    public Collection filterRows(TableModel model, Collection rows) throws Exception {

    ...

    if (filtered) {
    Collection collection = new ArrayList();
    Predicate filterPredicate = new ExactMatchFilterPredicate(model);
    CollectionUtils.select(rows, filterPredicate, collection);

    return collection;
    }

    ...

    }
    }

    為了使用這個FilterRowsCallback你應該在Preferences中聲明一個別名。當然,你可以省略這步而在JSP中提供這個FilterRowsCallback實現類的全路徑,但是使用Preferences更簡潔。

    table.filterRowsCallback.exactMatch=org.extremesite.callback.ExactMatchFilterRows

    在TableTag通過設置filterRowsCallback屬性來使用ExactMatchFilterRows。

    <ec:table filterRowsCallback="exactMatch"/>

    如果不清楚Preferences和ColumnTag定義語法請參考Preferences指南。

    Form指南


    1. 引言

    eXtremeTable本質上是一個form組件,所以我假定表被包在form里,所有的功能都被認為是對form元素的操作。如果你想在表體中包含一些定制的form元素, 或者想將eXtremeTable嵌入到另外的form中,那么你就要使用表標簽的form屬性用來參照最近的form。

    為了示范form特性,我們要做的工作將分解為JSP,Cell和Controller。

    1.1. JSP

    下面列出的是checkbox示例的完整代碼。想要強調的主要事情是表標簽form屬性設置為presForm,它參照被稱為presForm的form元素。

    同時請注意表標簽的autoIncludeParameters屬性。進行排序、過濾、分頁時,默認的eXtremeTable將保持所有傳至JSP頁面的參數。 這個特性對于內部其他的form進行排序、過濾、分頁時,用于高效復制form元素同樣有效。可以設置 autoIncludeParameters屬性為false來固定它。

    在這個form使用id屬性是因為xhtm標準的要求,同時你也可以使用form的name屬性。

    <form id="presForm" action="<c:url value="selectedPresidentsListedController.run"/>" method="post">

    Enter your name:
    <input
    type="text"
    name="userName"
    style="font-family:verdana,arial,helvetica,sans-serif;font-size:11px;"
    value="<c:out value="${param.userName}"/>"
    />

    <ec:table
    items="presidents"
    action="${pageContext.request.contextPath}/selectedPresidentsController.run"
    view="compact"
    imagePath="${pageContext.request.contextPath}/images/table/compact/*.gif"
    rowsDisplayed="8"
    autoIncludeParameters="false"
    form="presForm"
    >
    <ec:exportPdf
    fileName="output.pdf"
    tooltip="Export PDF"
    headerColor="black"
    headerBackgroundColor="#b6c2da"
    headerTitle="Presidents"
    />
    <ec:row>
    <ec:column
    alias="checkbox"
    title=" "
    width="5px"
    filterable="false"
    sortable="false"
    viewsAllowed="compact"
    cell="selectedPresident"
    />
    <ec:column property="fullName" title="Name"/>
    <ec:column property="nickName" />
    <ec:column property="term" />
    </ec:row>
    </ec:table>

    <input
    type="button"
    name="sel"
    class="button"
    value="List Selected Presidents"
    onclick="document.forms.presForm.submit();"
    />

    <script type="text/javascript">
    function setPresidentState(chkbx) {
    //make sure that always know the state of the checkbox
    if (chkbx.checked) {
    eval('document.forms.presForm.chkbx_' + chkbx.name).value='SELECTED';
    } else {
    eval('document.forms.presForm.chkbx_' + chkbx.name).value='UNSELECTED';
    }
    }
    </script>

    </form>

    1.1.1. Form特性的技術說明

    表標簽form屬性參照最近的form是你使用這個特性所必須知道的,為了更好的理解這個特性,介紹更多的關于內部實現技術的細節是值得的。

    如果您不特意指定form屬性,eXtremeTable自動在表附近包上一個form。所有表的動作例如:排序、過濾、分頁將自動給一些隱藏的input元素賦值,然后提交這個form到表標簽action屬性設置的Aciton。 這非常有效,除非您想要將自己的form元素設置到表體,或者想將這個表放到別的form里。

    表標簽form屬性參照最近的form,所有表的動作例如:排序、過濾、分頁將自動給一些隱藏的input元素賦值,但是現在 最近form的action屬性將要改變表標簽的動作。這非常重要,因為:當排序、過濾、分頁時,eXtremeTable能夠從一個controller得到數據集合 ,但是提交這個form到別的controller來處理這個form時需要對用戶的輸入進行處理。然而,這些對于你使用表標簽來說都是透明的。 就像你現在做的那樣簡單地設置表標簽的action屬性,然后設置相關的form到你想提交的位置。

    1.1.2. Checkbox

    示例的第一列是checkbox。因為這列不需要參照bean的屬性,alias屬性用來唯一地標識這列。你可以使用property 屬性,但是alias屬性使這列如何使用更清楚。alias屬性還被用來當同樣的屬性被多列使用時唯一地標識一列。

    1.1.3. Custom Cell

    您也許想知道定制的cell是如何通過名稱selectedPresident被參照的(cell="selectedPresident")。這是一個 對eXtremeTable的preferences特性更強的使用。所有要做的就是在extremecomponents.properties文件中添加一個屬性。 請參考Preferences來了解更多的信息

    column.cell.selectedPresident=org.extremesite.cell.SelectedPresidentCell

    column.cell.selectedPresident就是你定義的用來參照這個cell的名稱。

    當然你也可以使用這個Cell的全名來進行參照。

    <ec:column 
    alias="checkbox"
    title=" "
    width="5px"
    filterable="false"
    sortable="false"
    viewsAllowed="compact"
    cell="org.extremesite.cell.SelectedPresidentCell"
    />

    在屬性文件中定義參照更方便,它可以被任何JSP文件引用。如果類名或包名改變的話你只需要對一個地方進行修改。

    1.1.4. JavaScript

    JavaScript的setPresidentState()方法被定制cell用來設置每個checkbox元素的是否被選中。 設置一個隱藏元素的原因是為了獲得瀏覽器的動作而不提交沒有選中的checkbox。通過這個Controller將一直知道一個元素是否別選中。

    1.2. Cell

    定制的cell被用來生成checkbox,另外它也創建一個隱藏元素用來表示這個checkbox元素是否被選中。 當用戶進行排序、過濾、分頁時,被選中的數據集合將被放到session里。

    getExportDisplay()方法沒有返回值,因為治理只需要Html顯示。

    public class SelectedPresidentCell implements Cell {
    public String getExportDisplay(TableModel model, Column column) {
    return null;
    }

    public String getHtmlDisplay(TableModel model, Column column) {
    HtmlBuilder html = new HtmlBuilder();

    CellBuilder.tdStart(html, column);

    try {
    Object bean = model.getCurrentRowBean();
    String presidentId = BeanUtils.getProperty(bean, "presidentId");

    Collection selectedPresidentsIds = (Collection)model.getContext().getSessionAttribute(SelectedPresidentsConstants.SELECTED_PRESIDENTS);
    if (selectedPresidentsIds != null && selectedPresidentsIds.contains(presidentId)) {
    html.input("hidden").name("chkbx_" + presidentId).value(SelectedPresidentsConstants.SELECTED).xclose();
    html.input("checkbox").name(BeanUtils.getProperty(bean, "presidentId"));
    html.onclick("setPresidentState(this)");
    html.checked();
    html.xclose();
    } else {
    html.input("hidden").name("chkbx_" + presidentId).value(SelectedPresidentsConstants.UNSELECTED).xclose();
    html.input("checkbox").name(BeanUtils.getProperty(bean, "presidentId"));
    html.onclick("setPresidentState(this)");
    html.xclose();
    }
    } catch (Exception e) {}

    CellBuilder.tdEnd(html);

    return html.toString();
    }
    }

    1.3. Controller

    提示:Spring框架的Controller和Struts框架的Action非常相像。

    當在另外的form中使用eXtremeTable時,你可能有1個或2個controllers。當form被提交時,你需要一個controller 來處理用戶的輸入并重新定向到另外的JSP頁面。當排序、過濾、分頁時,你可能有另外的controller來得到表使用的數據集合并重定向會本頁。或者你可以在同一個controller中分別處理。

    checkbox示例里我使用一個controller來關聯表標簽的action屬性。我也使用另外一個controller來關聯form元素的動作。

    1.3.1. 表標簽動作Controller

    這個controller負責調用SelectedPresidentsUtils來保存被選中的presidentIds到session里并回到同一頁。

    SelectedPresidentsUtils.saveSelectedPresidentsIDs(request);
    Collection presidents = presidentsService.getPresidents();
    request.setAttribute("presidents", presidents);

    1.3.2. Form動作Controller

    這個controller負責通過presidentIds得到數據集并重定向到下一個Jsp頁面

    Collection selectedPresidentsIds = SelectedPresidentsUtils.saveSelectedPresidentsIDs(request);
    Collection selectedPresidents = SelectedPresidentsUtils.getSelectedPresidents(presidentsService.getPresidents(), selectedPresidentsIds);
    request.setAttribute("selected", selectedPresidents);
    request.getSession().removeAttribute(SelectedPresidentsConstants.SELECTED_PRESIDENTS);

    1.3.3. 重新得到Checkbox的值

    我將列出保存presidentIds到session的代碼。我經常被問到如何重新得到eXtremeTable中form元素的值。 它的原理是設置form輸入元素名字屬性值前面加上一些東西來唯一標識元素

    本示例中我關心的是以chkbx開頭參數的元素。chkbx后面是唯一的關聯到checkbox的presidentId。它被用來判斷這個checkbox是否別選中。

    public static Collection saveSelectedPresidentsIDs(HttpServletRequest request) {
    Collection presidents = (Collection) request.getSession().getAttribute(SelectedPresidentsConstants.SELECTED_PRESIDENTS);

    if (presidents == null) {
    presidents = new ArrayList();
    request.getSession().setAttribute(SelectedPresidentsConstants.SELECTED_PRESIDENTS, presidents);
    }

    Enumeration parameterNames = request.getParameterNames();
    while (parameterNames.hasMoreElements()) {
    String parameterName = (String) parameterNames.nextElement();
    if (parameterName.startsWith("chkbx_")) {
    String presidentId = StringUtils.substringAfter(parameterName, "chkbx_");
    String parameterValue = request.getParameter(parameterName);
    if (parameterValue.equals(SelectedPresidentsConstants.SELECTED)) {
    if (!presidents.contains(presidentId)) {
    presidents.add(presidentId);
    }
    } else {
    presidents.remove(presidentId);
    }
    }
    }

    return presidents;
    }

    Html視圖定制指南


    1. 引言

    eXtremeTable使用View接口來生成HTML。你可以使用發行包已經提供的視圖,或者你可以插入自己的視圖實現。 現在,創建你自己的視圖相對比較簡單,但討論一些設計想法和如何著手實現一個定制的視圖還是有價值的。

    我想使創建定制視圖簡單,但不是想構造一個更復雜的類似swing的模型,原因是那需要創建大量的對象來處理對應的內部工作。 eXtremeTable以高效為目標,我也想在視圖的實現上貫徹這種想法,所以我決定創建一系列的靜態構造器類來實現分解的最小功能。你可以通過組合這些功能來實現你的定制視圖。

    學習定制視圖的最好途徑是閱讀已經存在的視圖的源代碼,修改它來滿足你的需求。如果我示范所有東西的話,這篇指南將變的非常冗長。取而代之的是我將直接修改默認視圖的工具條作為定制視圖的一個示例。 對于不同構造器的具體細節我建議你閱讀源代碼。我也將盡量更新javadocs來提供更好的幫助。

    1.1. View接口

    實現View接口的類有3次插入內容的機會。beforeBody()方法會被立刻調用,body()方法在每一行的每一列處理的時候調用。 afterBody()方法是被eXtremeTable調用的最后方法,它將返回代表視圖的一個對象。在這個HTML視圖示例里,它將是一個字符串。

    public interface View {
    public void beforeBody(TableModel model);
    public void body(TableModel model, Column column);
    public Object afterBody(TableModel model);
    }

    1.2. Messages示例

    在這篇指南里我將直接修改工具條來實現這網站上Messages示例的定制視圖。

    public class MessagesView extends AbstractHtmlView { 
    protected void toolbar(TableModel model) {
    TwoColumnTableLayout toolbar = new MessagesToolbar();
    toolbar.layout(getHtmlBuilder(), model);
    }

    protected void statusBar(TableModel model) {
    TwoColumnRowLayout statusBar = new MessagesStatusBar();
    statusBar.layout(getHtmlBuilder(), model);
    }
    }

    這里使用的是默認視圖,因此它擴展了虛擬視圖來修改工具條和狀態條。如何修改工具條和(或)狀態條也是開發人員問的最多問題。

    默認視圖的工具條位于表的上方包括翻頁鏈接和標題。工具條使用TwoColumnTableLayout,它是一個用于提供在自己表中實現左右兩列布局的虛擬類。 它將實現能夠浮在表上方的完美布局。下面就是你需要關心的虛擬方法,在實際的html視圖中已經為你完成了這個布局。

    public abstract class TwoColumnTableLayout {
    protected abstract boolean showLayout(TableModel model);
    protected abstract void columnLeft(HtmlBuilder html, TableModel model);
    protected abstract void columnRight(HtmlBuilder html, TableModel model);
    }

    showLayout()方法用來阻止或導致布局的展現。在我的定制視圖中如果翻頁或(和)導出顯示那么工具條將展現。

    protected boolean showLayout(TableModel model) {
    boolean showPagination = BuilderUtils.showPagination(model);
    boolean showExports = BuilderUtils.showExports(model);
    if (!showPagination && !showExports) {
    return false;
    }

    return true;
    }

    下面顯示了左列和右列的部分代碼。注意在我的定制視圖中首頁和前一頁使用了文字來替代圖片顯示。我真正希望示范的是你需要做的:找到正確的構造器類并且僅僅是擴展HtmlBuilder的標簽。 構造器類對于示范如何找到模型里的信息(以便你能夠做比他們能夠提供的更多的定制工作)也非常有用,。

    protected void columnLeft(HtmlBuilder html, TableModel model) {
    html.td(2).close();
    TableBuilder.title(html, model);
    html.tdEnd();
    }

    protected void columnRight(HtmlBuilder html, TableModel model) {
    boolean showPagination = BuilderUtils.showPagination(model);
    ...
    if (showPagination) {
    html.td(4).close();
    ToolbarBuilder.firstPageItemAsText(html, model);
    html.tdEnd();

    html.td(4).close();
    ToolbarBuilder.prevPageItemAsText(html, model);
    html.tdEnd();
    ...
    }
    ...
    }

    為了使用這個視圖你需要在Preferences定義一個別名。 你可以省略這部而在JSP直接給出這個視圖的完整有效的類名,不過Preferences更為簡潔。

    table.view.messages=org.extremesite.view.MessagesView

    TableTag也將設置視圖屬性來使用MessagesView視圖。

    <ec:table view="messages">

    如果不清楚Preferences和TableTag定義語法請參考Preferences指南。

    攔截器使用指南


    1. 引言

    攔截特性被用在運行時需要修改屬性值的時候,它使得改變基于數據的eXtremeTable的行為成為可能。在閱讀擴展標簽屬性時,你會發現它和擴展標簽屬性具有同樣的概念和方法標識。 區分使用他們的首要準則是:如果需要向TLD里已經定義的并且能夠在JSP中訪問的標簽添加新的屬性時,應該使用擴展標簽屬性;如果僅僅是需要修改已經定義好的屬性的值的時候,應該使用攔截器。

    你可能需要了解更多的eXtremeTable如何運作的技術背景才能完全理解這種特性。 eXtremeTable首先做的就是遍歷所有標簽并創建對應的模型beans (pojos)。beans是具有和標簽一樣屬性,但是使用真實類型來替換僅僅使用字符串類型的對象。beans是被模型使用并且是你需要使用攔截特性修改的對象。 所有的攔截器接口都定義了一個add方法, add方法被用來處理模型bean第一次創建時的屬性。行和列的攔截器還有一個modify 方法。modify方法可以在當行和類進行處理是對屬性值進行操作。

    1.1. 攔截器列表

    下面列出了具有攔截特性的標簽和他們需要被實現的接口,Bean欄顯示了被模型創建的Bean。

    標簽 接口 Bean
    TableTag org.extremecomponents.table.intercept.InterceptTable org.extremecomponents.table.bean.Table
    RowTag org.extremecomponents.table.intercept.InterceptRow org.extremecomponents.table.bean.Row
    ColumnTag org.extremecomponents.table.intercept.InterceptColumn org.extremecomponents.table.bean.Column
    ExportTag org.extremecomponents.table.intercept.InterceptExport org.extremecomponents.table.bean.Export

    1.2. 行攔截器示例

    示范攔截特性的完美示例就是根據一定的標準來對行進行高亮顯示,這也是我們將要完成的示例。它很短也很簡單,不過它實現的概念同樣適用于每一個攔截器接口。

    我們需要做的第一件事就是實現InterceptRow接口。你會注意到這個接口有兩個方法:addRowAttributes() 和modifyRowAttributes()。addRowAttributes方法在行bean創建的時候被調用, modifyRowAttributes方法在表處理當前頁面行的時候被調用。

    public class MarkerIntercept implements InterceptRow {
    public void addRowAttributes(TableModel tableModel, Row row) {
    }

    public void modifyRowAttributes(TableModel model, Row row) {
    President president = (President) model.getCurrentRowBean();
    String career = president.getCareer();
    if (StringUtils.contains(career, "Soldier")) {
    row.setStyle("background-color:#fdffc0;");
    } else {
    row.setStyle("");
    }
    }
    }

    在Preferences里你應該定義這個行攔截器的別名。

    row.intercept.marker=org.extremesite.intercept.MarkerIntercept

    這樣就可以在行標簽中使用攔截器MarkerIntercept了。

    <ec:row intercept="marker">

    如果不清楚Preferences和TableTag定義語法請參考Preferences指南。

    Limit指南


    1. 引言

    在你需要處理大量數據時你應該考慮使用eXtremeTable的Limit特性。Limit這個名字來自MySQL的limit 命令,Limit接口的目的就是如何對表的結果集進行limit處理。Limit實現知道當排序、過濾、分頁、導出時,用戶如何與表互相作用。有了這些信息你 將能夠使用可能是最有效的方式顯示正確的過濾、排序后的請求頁面。

    為了示范Limit特性,我將要做的工作將分解為JSP、Controller、Service和DAO。這示范了一種使用分層的方式來處理 Limit。你可以根據自己的需要來增加或減少層。本示例也使用了Spring框架來重新得到使用Spring的JDBC取得的數據,因此你的代碼看起來可能有點不同。eXtremeTable的一個特點就是不依賴任何框架和容器。

    1.1. JSP

    為了使用Limit特性,eXtremeTable需要使用limit特定的RetrieveRowsCallback、 FilterRowsCallback和SortRowsCallback接口。eXtremeComponents提供了每個接口的一個實現,可以簡單地通過設置每個屬性值為limit來簡單來使用。

    <ec:table 
    items="presidents"
    retrieveRowsCallback="limit"
    filterRowsCallback="limit"
    sortRowsCallback="limit"
    view="limit"
    >
    ...

    另外視圖屬性參照一個名為limit的定制視圖。這是一個簡單修改默認eXtremeTable視圖,不包含最后頁工具條的實現。這僅僅關系到你是否能取得確切需要的行。 一些數據庫例如Oracle和MySQL都提供了一種得到確定行的特性,但是,其他的數據庫例如:Sybase沒有提供特性。在我的示例中我考慮最壞的情況你的數據庫不支持這種特性。

    即使你的數據庫不提供取得特定行的特性,當你考慮用戶如何和表協同工作時,Limit仍然非常有意義。用戶通常會對一些數據進行排序、過濾和分頁。 這個例子中15條數據構成一頁,第一頁需要15條數據,第二頁需要30條數據,第三頁需要45條數據,以此類推。在經過一段時間分頁后,他們常常使用過濾來提煉數據。 即使他們不這樣做,他們也必須在此之前對大量的數據進行分頁,這將影響效率。當然如果允許用戶點擊最后頁,那么所有的數據都將被取出,這將非常影響效率。

    1.2. Controller

    提示:Spring框架的Controller和Struts框架的Action非常相像。

    controller首先需要創建一個Limit。為了完成這個你需要得到一些關于Context和LimitFactory的幫助。

    Context context = new HttpServletRequestContext(request);
    LimitFactory limitFactory = new TableLimitFactory(context);
    Limit limit = new TableLimit(limitFactory);

    Context是一個處理取得屬性的接口,LimitFactory使用Context來找出用戶如何和eXtremeTable交互。 然后Limit使用LimitFactory來組裝自己。

    為了初始化Limit,它將包含所有的有用的信息。這些信息包括數據將被如何排序和過濾,哪一頁將被顯示和是否允許被導出。

    然而,Limit仍然需要得到行的信息,這樣正確的信息頁面才能被顯示給用戶。行信息包括開始行、結束行、當前顯示行。 controller必須從service得到這些信息,而Service將從dao中得到這些信息。這里我只給出Controller端的代碼。

    int totalRows = presidentsService.getTotalPresidents(limit.getFilterSet(), limit.isExported());
    limit.setRowAttributes(totalRows, defaultRowsDisplayed);

    limit需要得到所有的行來得到行的信息。service需要知道那些被過濾,不管這些數據是否要導出。為了設置行信息,默認的一頁顯示的行數需要被設置。 這可以通過對TableTag的rowsDisplayed屬性設置一個確定的數值來實現。

    現在我們只需要從services得到Collection數據。

    Collection presidents = presidentsService.getPresidents(limit.getFilterSet(), limit.getSort(), limit.getRowEnd());

    因為limit已經包含所有信息,這將十分容易。所有需要做的就是傳入過濾器,排序和最后行的信息。 最后要做的是將Collections和totalRow這些信息傳送回JSP以便eXtremeTable知道如何顯示這些信息。

    request.setAttribute("presidents", presidents);
    request.setAttribute("totalRows", new Integer(totalRows));

    1.3. Service

    service需要和dao進行交互來得到總行數和Collection。

    1.3.1. 取得總行數

    controller需要到第一條信息就是總行數。

    public int getTotalPresidents(FilterSet filterSet, boolean isExported) {
    String totalQuery = presidentsDao.getTotalPresidentsQuery();
    String modTotalQuery = filterQuery(filterSet, totalQuery);
    int totalRows = presidentsDao.getTotalPresidents(modTotalQuery);
    if (isExported && totalRows > maxExportRows) {
    totalRows = maxExportRows;
    }
    return totalRows;
    }

    service和dao一起來過濾結果集,它的工作方式是在Where語句后面增加更多的AND語句來修改查詢字符串。為此,你需要和Limit FilterSet一起工作。

    FilterSet是一個過濾器對象數組,一個過濾器包括一個bean property和這個過濾器的值。或者,簡單的說就是用戶想要過濾的行和他們輸入的值。這使得它非常容易交互。service只需要迭代所有的 FilterSet并調用dao來拼接查詢語句。(譯者注:過濾的實現方式是:在Where后面增加And語句來改變查詢語句以達到對數據進行過濾的效果)

    private String filterQuery(FilterSet filterSet, String query) {
    if (!filterSet.isFiltered() || filterSet.isCleared()) {
    return query;
    }

    Filter filters[] = filterSet.getFilters();
    for (int i = 0; i < filters.length; i++) {
    Filter filter = filters[i];
    String property = filter.getProperty();
    String value = filter.getValue();
    query = presidentsDao.filterQuery(query, property, value);
    }

    return query;
    }

    query修改包括了filter信息,總行數。在一些情況下這就足夠,但是當用戶導出數據時仍然存在一個潛在的問題。為了保持高效 service不允許導出超出一個最大行數的數據。

    1.3.2. 取得Collection

    controller需要到第二條信息就是Collection。

    public Collection getPresidents(FilterSet filterSet, Sort sort, int rowEnd) {
    String patientsQuery = presidentsDao.getPresidentsQuery();
    String modPatientsQuery = filterQuery(filterSet, patientsQuery);
    modPatientsQuery = sortQuery(sort, modPatientsQuery);
    modPatientsQuery = presidentsDao.limitQuery(rowEnd, modPatientsQuery);
    return presidentsDao.getPresidents(modPatientsQuery);
    }

    和前面一樣,service和dao一起來過濾結果集。

    另外query字符串需要擴展ORDER BY語句以便數據按照正確的方式進行排序。Sort包含一個bean property和 sortOrder值(正序還是逆序)。service僅僅需要使用Sort來調用dao。

    private String sortQuery(Sort sort, String query) {
    if (!sort.isSorted()) {
    String defaultSortOrder = presidentsDao.getDefaultSortOrder();
    if (StringUtils.isNotBlank(defaultSortOrder)) {
    return query + defaultSortOrder;
    }

    return query;
    }

    String property = sort.getProperty();
    String sortOrder = sort.getSortOrder();

    return presidentsDao.sortQuery(query, property, sortOrder);
    }

    query字符串最后需要的修改就是增加數據庫特別的指令來limit將要被返回的結果集。這就是limitQuery() 方法的作用。

    1.4. DAO

    dao為service負責底層數據工作。

    1.4.1. 定義Query字符串

    為了真正理解dao,query字符串需要被展示。

    這就是得到數據的presidents query字符串:

    private final static String presidentsQuery = 
    " SELECT " +
    " president_id presidentId, " +
    " first_name firstName, " +
    " last_name lastName, " +
    " nick_name nickName, " +
    " concat(first_name, ' ',last_name) fullName, " +
    " term, " +
    " born, " +
    " died, " +
    " education, " +
    " career, " +
    " political_party politicalParty " +
    " FROM presidents ";

    這是得到總行數的query字符串:

    private final static String totalPresidentsQuery = 
    " SELECT count(*) FROM presidents ";

    1.4.2. Filter 和 Sort Query 字符串

    兩個最有趣的方法就是過濾和排序。

    filter看起來像這樣:

    public String filterQuery(String query, String property, String value) {
    StringBuffer result = new StringBuffer(query);

    if (query.indexOf("WHERE") == -1) {
    result.append(" WHERE 1 = 1 "); //stub WHERE clause so can just append AND clause
    }

    if (property.equals("fullName")) {
    result.append(" AND concat(first_name, ' ',last_name) like '%" + value + "%'");
    } else if (property.equals("nickName")) {
    result.append(" AND nick_name like '%" + value + "%'");
    } else {
    result.append(" AND " + property + " like '%" + value + "%'");
    }

    return result.toString();
    }

    filterQuery()方法需要增加正確的AND語句到query字符串。

    sort看起來非常類似:

    public String sortQuery(String query, String property, String sortOrder) {
    StringBuffer result = new StringBuffer(query + " ORDER BY ");

    if (property.equals("fullName")) {
    result.append("concat(first_name, ' ',last_name) " + sortOrder);
    } else {
    result.append(property + " " + sortOrder);
    }

    return result.toString();
    }

    sortQuery()方法需要增加正確的ORDER BY語句到query字符串。

    1.4.3. Limit Query String

    現在query字符串修改能夠正確的進行filter和sort,它還需要修改以便只取頁面顯示相關的數據。MySQL為s the limit命令。

    public String limitQuery(int rowEnd, String query) {
    return query + " limit " + rowEnd;
    }

    1.4.4. 取回總行數和Collection.

    service需要的唯一東西就是:總行數和Collection。

    public Collection getPresidents(final String query) {
    return jdbcTemplate.query(query, new ResultReader() {
    List results = new ArrayList();
    public List getResults() {
    return results;
    }

    public void processRow(ResultSet rs)
    throws SQLException {
    President president = new President();
    president.setPresidentId(new Integer(rs.getInt("presidentId")));
    president.setFirstName(rs.getString("firstName"));
    president.setLastName(rs.getString("lastName"));
    president.setNickName(rs.getString("nickName"));
    president.setFullName(rs.getString("fullName"));
    president.setTerm(rs.getString("term"));
    president.setBorn(rs.getDate("born"));
    president.setDied(rs.getDate("died"));
    president.setEducation(rs.getString("education"));
    president.setCareer(rs.getString("career"));
    president.setPoliticalParty(rs.getString("politicalParty"));
    results.add(president);
    }
    });
    }

    public int getTotalPresidents(final String query) {
    return jdbcTemplate.queryForInt(query);
    }

    ResultReader是一個幫助處理JDBC查詢的Spring特殊類,作為一個callback來處理JDBC ResultSet。jdbcTemplate是對JDBC連接的抽象。

    1.4.5. 默認的Sort順序

    最后,這是service需要的默認sort順序:

    public String getDefaultSortOrder() {
    return " ORDER BY concat(first_name, ' ', last_name) ";
    }

    Preferences 指南


    1. 引言

    為了設置全局屬性和設置,你需要使用Preferences特性,它現在使用一個屬性文件來實現。本文檔將很好地介紹如何在web.xml里設置Preferences, 以及一些需要被定義的通用屬性。在這里我非常樂意介紹一些關于Preferences的進一步用法。

    所有標簽屬性表示一個可插接的接口,它可以通過給出實現的全路徑來設置。這為插接實現提供了一條便利的途徑。當然這存在一些為過長術語的設計和維護的考慮。 第一,對你的接口實現進行硬編碼;第二,如果你需要在別的JSP中用到同一個接口實現,你需要拷貝你全路徑。解決這兩個問題的有效辦法就是在Preferences中聲明一切。

    1.1. Preferences表

    下面列出的是可以在Preferences中申明的所有接口。Tag列展示的是eXtremeTable的標簽,Attribute 列展示的是相關標簽的對應屬性。Interface列展示的是需要被實現的Java接口。Preference Key列展示的是 Preferences里對應的健。

    Tag Attribute Interface Preference Key
    TableTag filterRowsCallback org.extremecomponents.table.callback.FilterRowsCallback table.filterRowsCallback
    TableTag intercept org.extremecomponents.table.intercept.InterceptTable table.intercept
    TableTag retrieveRowsCallback org.extremecomponents.table.callback.RetrieveRowsCallback table.retrieveRowsCallback
    TableTag sortRowsCallback org.extremecomponents.table.callback.SortRowsCallback table.sortRowsCallback
    TableTag state org.extremecomponents.table.state.State table.state
    TableTag view org.extremecomponents.table.view.View table.view
    RowTag intercept org.extremecomponents.table.intercept.InterceptRow row.intercept
    ColumnTag calc org.extremecomponents.table.calc.Calc column.calc
    ColumnTag cell org.extremecomponents.table.cell.Cell column.cell
    ColumnTag filterCell org.extremecomponents.table.cell.Cell column.filterCell
    ColumnTag headerCell org.extremecomponents.table.cell.Cell column.headerCell
    ColumnTag intercept org.extremecomponents.table.intercept.InterceptColumn column.intercept
    ExportTag intercept org.extremecomponents.table.intercept.InterceptExport export.intercept
    ExportTag view org.extremecomponents.table.view.View export.view
    ExportTag viewResolver org.extremecomponents.table.filter.ViewResolver export.viewResolver

    提示:當在寫作本指南的時候,我意識到我忘記了讓標簽ColumnsTag的autoGenerateColumns 屬性和Preferences協同工作。這將在下一版修正。

    1.2. 指定Preference別名

    上表展示了如何聲明preference鍵,但是沒有解釋如何指定有意義的別名。如果你注意到preference鍵提供了一致的語法 tag.attribute,指定鍵的別名僅僅是在它的基礎上進行擴展。它的語法為: tag.attribute.alias

    eXtremeTable提供了一個名為RowCountCell定制的cell,它的作用是現實當前的行數。我將在Preferences里使用ColumnTag cell聲明來示范RowCountCell的使用。

    首先通過實現Cell接口或者擴展AbstractCell來編寫具體的實現類。

    public class RowCountCell extends AbstractCell {
    protected String getCellValue(TableModel model, Column column) {
    int rowcount = ((model.getLimit().getPage() - 1)
    * model.getLimit().getCurrentRowsDisplayed())
    + model.getRowHandler().getRow().getRowCount();
    return String.valueOf(rowcount);
    }
    }

    然后在Preferences (屬性文件)進行聲明并給出別名。eXtremeTable在一個Preferences里保存所有的配置信息,你可以通過使用本地 Preferences的來覆蓋任何的這些屬性。

    RowCountCell默認的別名是rowCount:

    column.cell.rowCount=org.extremecomponents.table.cell.RowCountCell

    在ColumnTag中通過別名引用Cell:

    <ec:column alias="count" cell="rowCount"/>

    現在你可以通過rowCount來引用這個Cell,如果包名改變了你只需要對Preferences進行修改。

    提示:本示例中我使用了ColumnTag的別名屬性。別名屬性應用在有兩列使用同樣的property,也應用在列不直接和列的 bean property關聯的情況下。本示例就屬于這種情況。

    posted on 2006-02-26 11:00 Lucky 閱讀(16207) 評論(27)  編輯  收藏 所屬分類: extremeComponents

    評論

    # re: extremeComponents指南 2006-03-04 11:33 一滴水

    正好用上,謝謝:)  回復  更多評論   

    # re: extremeComponents指南 2006-03-04 11:47 Lucky

    不客氣,希望能為大家帶來方便。現在我正在熟悉它的源代碼,Jeff讓我幫著添加一些小的特性(feature),希望大家有什么想法、建議...,請和我(xplucky@gmail.com)聯系。  回復  更多評論   

    # 提一個小bug 2006-04-13 16:18 snowolf

    翻頁按鈕提示是通過圖片的title屬性實現國際化的,但圖片又定義了alt,使用的英文,當這個按鈕沒有鏈接的時候,title就沒有定義,顯示的提示就是alt的內容。  回復  更多評論   

    # re: extremeComponents指南 2006-04-13 16:54 xplucky

    @snowolf
    我自己測試了一下,并沒有出現你說的那種情況啊?你用的extremeComponents的版本是多少?你能不能提供更詳細一點的情況,或者抓副圖mail給我。在線聯系也行,我的MSN: zlh326@msn.com  回復  更多評論   

    # re: extremeComponents指南 2006-04-13 19:33 snowolf

    我用的是1.0.1M4,從sf上下的,我看你提到m5,我想要到cvs里去下吧
    我碰到的bug,舉個例子說,列表有多頁,現在處在第一頁,那么按鈕第1頁(First),前一頁(Prev)這個時候是沒有鏈接的,下一頁(Next)、最后一頁(Last)是有鏈接的,這時候我把鼠標放在這些按鈕上時,會出現一個提示信息,
    First、Prev是英文的,Next、Last是中文的。
    生成的html代碼是這樣的
    <td><img src="/eXtremeTable/images/table/firstPageDisabled.gif" style="border:0" alt="First" /></td>
    <td><img src="/eXtremeTable/images/table/prevPageDisabled.gif" style="border:0" alt="Prev" /></td>
    <td><a href="javascript:document.forms.ec.ec_p.value='2';document.forms.ec.action='/eXtremeTable/test.jsp';document.forms.ec.submit()"><img src="/eXtremeTable/images/table/nextPage.gif" style="border:0" title="下一頁" alt="Next" /></a></td>
    <td><a href="javascript:document.forms.ec.ec_p.value='2';document.forms.ec.action='/eXtremeTable/test.jsp';document.forms.ec.submit()"><img src="/eXtremeTable/images/table/lastPage.gif" style="border:0" title="最后頁" alt="Last" /></a></td>

    注意里面img里的title屬性,當按鈕有鏈接時,才會有這個屬性

    我剛到springside里看到這個用的是正常的,他用的是我下的這個版本的改造版(改造了excel輸出的中文問題)
    不知道是不是我配置的問題,郁悶  回復  更多評論   

    # re: extremeComponents指南 2006-04-13 19:37 snowolf

    問題我想找到了,是資源文件的原因
    我把springside里面改過的資源文件拿過來就行了
    里面多了幾行
    toolbar.firstPageText=\u7b2c\u4e00\u9875
    toolbar.lastPageText=\u6700\u540e\u9875
    toolbar.nextPageText=\u4e0b\u4e00\u9875
    toolbar.prevPageText=\u4e0a\u4e00\u9875
      回復  更多評論   

    # re: extremeComponents指南 2006-04-13 19:40 snowolf

    原來**PageText才是定義alt的,沒看源代碼,推測出的問題出處有誤,不好意思,麻煩你了  回復  更多評論   

    # re: extremeComponents指南 2006-04-13 19:41 xplucky

    你還在線嗎?M4版的中文資源文件比英文的少了一下東西。  回復  更多評論   

    # re: extremeComponents指南 2006-04-13 19:44 xplucky

    如果你愿意嘗試,我可以給你最新的jar。有一些朋友已經再使用了,還沒有收到太大問題的反饋。  回復  更多評論   

    # re: extremeComponents指南 2006-04-14 12:21 snowolf

    好啊,麻煩你發到我的郵箱snowolf9929(at)163.com 謝謝

    我現在正在為新項目選一些組件和標簽,剛開始看到displaytag,看到網上一些評論,發現eXtremeTable很不錯,運行里面的test感受了一下,也嘗試修改里面的一些屬性,看到你翻譯的文章,介紹里面有很多地方可以自己擴展,這種設計確實不錯,還沒嘗試去做一個擴展的例子,感覺人還是挺懶,能不擴展就不擴展了,呵呵。

    現在開源的東西很多,選用哪種也很令人頭疼啊。。。  回復  更多評論   

    # re: extremeComponents指南 2006-04-14 12:41 xplucky

    @snowolf
    我已經給你的163信箱發了,不過點的快了點,沒加標題,不好意思。  回復  更多評論   

    # re: extremeComponents指南 2006-06-17 16:17 sfd

    extremeComponents的單元格能不能編輯!

      回復  更多評論   

    # re: extremeComponents指南 2006-06-18 19:02 Lucky

    到目前為止,還不具備編輯功能!  回復  更多評論   

    # re: extremeComponents指南 2006-06-19 13:53 sfd

    能不能加上水平,垂直滾動條!  回復  更多評論   

    # re: extremeComponents指南 2006-07-28 00:46 woo

    有沒有可能實現這種表格:表頭很復雜的表
    _______________
    |_______A______|
    |___B______| C |
    |__D__|__E_|___|
    | x1 | y1 | z1 |
    | ... | ... | ... |   回復  更多評論   

    # re: extremeComponents指南 2006-08-02 21:29 馮彥瑋

    Dear xplucky以及各位高手:
    關于在extremeComponents中使用checkbox,我還是沒有弄太明白,尤其是翻頁不影響checkbox的選中狀態、如何得到已經選中的checkbox的值。
    希望能給我一份有源代碼的例子。項目緊張急需要解決,不甚感激!

    謝謝!

    我的msn:adam_feng1981@hotmail.com.
    QQ:5550406
    郵箱:fyxxq2000@yahoo.com.cn
      回復  更多評論   

    # re: extremeComponents指南 2006-09-18 22:54 zk

    我想在每個顯示頁面上顯示如下:
    1 ff ..
    2 rr..
    3 gg..
    .
    .
    既1,2,3..總是當前頁顯示的數目向下排,不知如何處理?
      回復  更多評論   

    # re: extremeComponents指南 2006-09-21 12:48 tony lee

    我也想用這個東東做查詢分頁,您有簡單一點的例子嗎?有的話請發一份給我.
    lzm163@163.com  回復  更多評論   

    # re: extremeComponents指南 2006-10-09 16:48 地主

    請問怎么用標簽顯示圖片,
    是這樣的,我從數據庫中讀出圖片地址.但不知道怎么用其標簽顯示在表格中.  回復  更多評論   

    # re: extremeComponents指南 2006-10-31 19:42 jeffrey[匿名]

    頂,遇到同樣的問題@zk
      回復  更多評論   

    # re: extremeComponents指南 2006-10-31 19:43 jeffrey[匿名]

    我想在每個顯示頁面上顯示如下:
    1 ff ..
    2 rr..
    3 gg..
    .
    .
    既1,2,3..總是當前頁顯示的數目向下排,不知如何處理?   回復  更多評論   

    # 關于eXtremeTable顯示的問題! 2006-11-14 10:20 firefly[匿名]

    正文:
    showStatusBar="true" 會顯示如下:
    找到15 條記錄, 顯示 1 到 5

    showPagination="true"
    顯示下一頁,上一頁,\

    對吧
    但是它們顯示下在同一行,如何做到讓他們顯示在一同行嗎?

    現在都是顯示在Table的上面,
    如何把他們顯示在Table的下面呢?

      回復  更多評論   

    # re: extremeComponents指南 2006-11-20 17:36 kirk

    不知道有沒有exportxlstag擴展的例子,謝謝!  回復  更多評論   

    # re: extremeComponents指南 2006-11-29 17:44 joe[匿名]

    剛才看了上面的文章,limit是通過例如:limit 20這樣來取得前20行,那如果翻頁至最后一行的話,例如:limit 1000那就是取道1000行,還是相當于讀出數據庫的所有數據阿,不知道我的理解是否正確,請各位指正阿,謝謝!  回復  更多評論   

    # re: extremeComponents指南 2007-04-28 19:23 zhangky

    請教一下,我用limit 限制了取前20行,那么合計肯定也是只求前20行數據的合計,這肯定不行,我應該怎么處理?  回復  更多評論   

    # re: extremeComponents指南 2008-05-06 01:08 隔葉黃鶯

    關注一下你的 extremeComponents 的用法,以前只粗略的用過 DisplayTag 標簽,也只是在表格這一塊,不知這兩種哪個強?  回復  更多評論   

    # re: extremeComponents指南 2009-10-27 17:33 buzhi

    遇到同樣的問題@地主
      回復  更多評論   


    只有注冊用戶登錄后才能發表評論。


    網站導航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    <2006年3月>
    2627281234
    567891011
    12131415161718
    19202122232425
    2627282930311
    2345678

    導航

    隨筆分類(125)

    文章分類(5)

    日本語

    搜索

    積分與排名

    最新隨筆

    最新評論

    主站蜘蛛池模板: 伊人久久免费视频| 一个人看的免费高清视频日本| 永久免费A∨片在线观看| 亚洲国产精品毛片av不卡在线| 亚洲avav天堂av在线网毛片| 麻豆精品国产免费观看| 亚洲精品无码aⅴ中文字幕蜜桃| 欧亚精品一区三区免费| 亚洲一卡一卡二新区无人区| 成人黄18免费视频| 国产午夜亚洲精品不卡免下载| 国产在线观看免费完整版中文版| 国产精品成人亚洲| 亚洲国产午夜福利在线播放| 国产精品午夜免费观看网站| 国产成人亚洲综合色影视| 一级毛片成人免费看免费不卡| 亚洲精品国产情侣av在线| 成年女人男人免费视频播放| 色偷偷亚洲第一综合| 国产成人精品日本亚洲专区61| 国产一区二区三区免费| 亚洲国产成人久久99精品| 日韩精品免费电影| 好猛好深好爽好硬免费视频| 久久精品国产亚洲av高清漫画 | 日韩亚洲精品福利| baoyu122.永久免费视频| 亚洲图片校园春色| 在线免费观看国产视频| 亚洲精品视频免费| 亚洲男人的天堂在线| 国产极品美女高潮抽搐免费网站| 黄视频在线观看免费| 亚洲av永久无码嘿嘿嘿| 亚洲福利中文字幕在线网址| 无码人妻一区二区三区免费看| 亚洲国产精品无码久久久秋霞1| 久久久久亚洲精品天堂久久久久久| 最近2019免费中文字幕6| 国产精品亚洲精品久久精品|