extremeComponents(ec)源码分析

摘要:
eXtremeComponents是一系列提供高级显示的开源JSP定制标签,当前的包含的组件为eXtremeTable,用于以表形式显示数据。其本质是jsp的自定义标签,抓住这一点就抓住了ec的本源。

eXtremeComponents(简称ec)是一系列提供高级显示的开源JSP定制标签,当前的包含的组件为eXtremeTable,用于以表形式显示数据。

其本质是jsp的自定义标签,抓住这一点就抓住了ec的本源。

1. Table定义

我们先看一下标签的定义:extremComponents.tld,其中table的标签定义如下:

 <tag>
      <name>table</name>
      <tag-class>org.extremecomponents.table.tag.TableTag</tag-class>
      <body-content>JSP</body-content>
      <display-name>TableTag</display-name>
      <description><![CDATA[The container which holds all the main table information. Will also hold global information if needed. The table tag is copied into the Table and encapsulated in the Model.]]></description>
      <attribute>
         <name>action</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The URI that will be called when the filter, sort and pagination is used.]]></description>
      </attribute>
      <attribute>
         <name>autoIncludeParameters</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not to automatically include the parameters, as hidden inputs, passed into the JSP.]]></description>
      </attribute>
      <attribute>
         <name>border</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The table border attribute. The default is 0.]]></description>
      </attribute>
      <attribute>
         <name>bufferView</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Whether of not to buffer the view. Boolean value with the default being false.]]></description>
      </attribute>
      <attribute>
         <name>cellpadding</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The table cellpadding attribute. The default is 0.]]></description>
      </attribute>
      <attribute>
         <name>cellspacing</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The table cellspacing attribute. The default is 0.]]></description>
      </attribute>
      <attribute>
         <name>filterable</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not the table is filterable. Boolean value with the default being true.]]></description>
      </attribute>
      <attribute>
         <name>filterRowsCallback</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[A fully qualified class name to a custom FilterRowsCallback implementation. Could also be a named type in the preferences. Used to filter the Collection of Beans or Collection of Maps.]]></description>
      </attribute>
      <attribute>
         <name>form</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The reference to a surrounding form element.]]></description>
      </attribute>
      <attribute>
         <name>imagePath</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The path to find the images. For example imagePath=/extremesite/images/*.png is saying look in the image directory for the .png images.]]></description>
      </attribute>
      <attribute>
         <name>interceptor</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[A fully qualified class name to a custom InterceptTable implementation. Could also be a named type in the preferences. Used to add table attributes.]]></description>
      </attribute>
      <attribute>
         <name>items</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Reference the collection that will be retrieved.]]></description>
      </attribute>
      <attribute>
         <name>locale</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The locale for this table. For example fr_FR is used for the French translation.]]></description>
      </attribute>
      <attribute>
         <name>method</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Used to invoke the table action using a POST or GET.]]></description>
      </attribute>
      <attribute>
         <name>onInvokeAction</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The javascript that will be invoked when a table action enabled.]]></description>
      </attribute>
      <attribute>
         <name>retrieveRowsCallback</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[A fully qualified class name to a custom RetrieveRowsCallback implementation. Could also be a named type in the preferences. Used to retrieve the Collection of Beans or Collection of Maps.]]></description>
      </attribute>
      <attribute>
         <name>rowsDisplayed</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The number of rows to display in the table.]]></description>
      </attribute>
      <attribute>
         <name>scope</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The scope (page, request, session, or application) to find the Collection of beans or Collection of Maps defined by the collection attribute.]]></description>
      </attribute>
      <attribute>
         <name>showPagination</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not the table should use pagination. Boolean value with the default being true.]]></description>
      </attribute>
      <attribute>
         <name>showExports</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not the table should use the exports. Boolean value with the default being true.]]></description>
      </attribute>
      <attribute>
         <name>showStatusBar</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not the table should use the status bar. Boolean value with the default being true.]]></description>
      </attribute>
      <attribute>
         <name>showTitle</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not to show the title. Boolean value with the default being true.]]></description>
      </attribute>
      <attribute>
         <name>showTooltips</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not to show the tooltips. Boolean value with the default being true.]]></description>
      </attribute>
      <attribute>
         <name>sortRowsCallback</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[A fully qualified class name to a custom SortRowsCallback implementation. Could also be a named type in the preferences. Used to sort the Collection of Beans or Collection of Maps.]]></description>
      </attribute>
      <attribute>
         <name>sortable</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Specify whether or not the table is sortable. Boolean value with the default being true.]]></description>
      </attribute>
      <attribute>
         <name>state</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The table state to use when returning to a table. Acceptable values are default, notifyToDefault, persist, notifyToPersist.]]></description>
      </attribute>
      <attribute>
         <name>stateAttr</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The table attribute used to invoke the state change of the table.]]></description>
      </attribute>
      <attribute>
         <name>style</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The css inline style sheet.]]></description>
      </attribute>
      <attribute>
         <name>styleClass</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The css class style sheet.]]></description>
      </attribute>
      <attribute>
         <name>tableId</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The unique identifier for the table.]]></description>
      </attribute>
      <attribute>
         <name>theme</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The theme to style the table. The default is eXtremeTable.]]></description>
      </attribute>
      <attribute>
         <name>title</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The title of the table. The title will display above the table.]]></description>
      </attribute>
      <attribute>
         <name>var</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[The name of the variable to hold the current row bean.]]></description>
      </attribute>
      <attribute>
         <name>view</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Generates the output. The default is the HtmlView to generate the HTML. Also used by the exports to generate XLS-FO, POI, and CSV.]]></description>
      </attribute>
      <attribute>
         <name>width</name>
         <required>false</required>
         <rtexprvalue>true</rtexprvalue>
           <description><![CDATA[Width of the table.]]></description>
      </attribute>
   </tag>

从上面我们可以看到,先定义了table标签的实现类:org.extremecomponents.table.tag.TableTag,其作用是:

The container which holds all the main table information. Will also hold global information if needed. The table tag is copied into the Table and encapsulated in the Model.

一句话:保存table的信息及一些全局信息,通过table封装到Model中。

然后定义了table的一些属性,这些属性和org.extremecomponents.table.bean.Table一致。

public class Table extendsAttributes {
    privateTableModel model;
    privateString action;
    privateBoolean autoIncludeParameters;
    privateString border;
    privateBoolean bufferView;
    privateString cellpadding;
    privateString cellspacing;
    privateBoolean filterable;
    privateString filterRowsCallback;
    privateString form;
    privateString imagePath;
    privateString interceptor;
    privateObject items;
    privateString locale;
    private intmaxRowsDisplayed;
    private intmedianRowsDisplayed;
    privateString method;
    privateString onInvokeAction;
    privateString retrieveRowsCallback;
    private introwsDisplayed;
    privateBoolean saveFilterSort;
    privateString scope;
    privateBoolean showExports;
    privateBoolean showPagination;
    privateBoolean showStatusBar;
    privateBoolean showTitle;
    privateBoolean showTooltips;
    privateString sortRowsCallback;
    privateBoolean sortable;
    privateString state;
    privateString stateAttr;
    privateString style;
    privateString styleClass;
    privateString tableId;
    privateString title;
    privateString theme;
    privateString var;
    privateString view;
    privateString width;
    publicTable(TableModel model) {
        this.model =model;
    }
//setter and getter
}

2. TableTag实现

我们来看一下TableTage如何实现table标签?首先:TableTage继承了TagSupport:

web容器执行自定义标签的过程如下
初始化时调用setPageContent()方法,完了在调用setParent方法
2.1 web容器首先执行自定义标签的开始标记,同时调用doStartTag方法。
2.2 如果doStartTag方法返回EVAL_BODY_INCLUDE,web容器在执行完标签体的内容后,会调用标签类得doAfterBody方法;
如果doStartTag方法返回SKIP_BODY,doAfterBody方法不会调用,web容器会直接调用标签类得doEndTag方法
2.3 如果doAfterBody方法被调用,并且方法返回EVAL_BODY_AGIN,web容器会再次执行标签体的内容;
如果doAfterBody方法返回SKIP_BODY,web容器会调用标签类的doEndTag方法
2.4 如果doEndTag方法返回EVAL_PAGE,web容器会执行标签后面的内容;
如果doEndTag方法返回SKIP_PAGE,web容器会忽略自定义标签后面的内容

 public int doStartTag() throwsJspException {
        try{
            //initialize the attributes
            iterator = null;
            pageContext.setAttribute(TableConstants.ROWCOUNT, "0");
            //fire up the model with the context, preferences and messages
            model = new TableModelImpl(new JspPageContext(pageContext), TagUtils.evaluateExpressionAsString("locale", this.locale, this, pageContext));
            //make the table
            Table table = newTable(model);
            table.setAction(TagUtils.evaluateExpressionAsString("action", action, this, pageContext));
            table.setAutoIncludeParameters(TagUtils.evaluateExpressionAsBoolean("autoIncludeParameters", this.autoIncludeParameters, this, pageContext));
            table.setBorder(TagUtils.evaluateExpressionAsString("border", this.border, this, pageContext));
            table.setBufferView(TagUtils.evaluateExpressionAsBoolean("bufferView", this.bufferView, this, pageContext));
            table.setCellpadding(TagUtils.evaluateExpressionAsString("cellpadding", this.cellpadding, this, pageContext));
            table.setCellspacing(TagUtils.evaluateExpressionAsString("cellspacing", this.cellspacing, this, pageContext));
            table.setFilterable(TagUtils.evaluateExpressionAsBoolean("filterable", this.filterable, this, pageContext));
            table.setFilterRowsCallback(TagUtils.evaluateExpressionAsString("filterRowsCallback", this.filterRowsCallback, this, pageContext));
            table.setForm(TagUtils.evaluateExpressionAsString("form", this.form, this, pageContext));
            table.setImagePath(TagUtils.evaluateExpressionAsString("imagePath", this.imagePath, this, pageContext));
            table.setInterceptor(TagUtils.evaluateExpressionAsString("interceptor", this.interceptor, this, pageContext));
            table.setItems(TagUtils.evaluateExpressionAsObject("items", this.items, this, pageContext));
            table.setLocale(TagUtils.evaluateExpressionAsString("locale", this.locale, this, pageContext));
            table.setMethod(TagUtils.evaluateExpressionAsString("method", this.method, this, pageContext));
            table.setOnInvokeAction(TagUtils.evaluateExpressionAsString("onInvokeAction", this.onInvokeAction, this, pageContext));
            table.setRetrieveRowsCallback(TagUtils.evaluateExpressionAsString("retrieveRowsCallback", this.retrieveRowsCallback, this, pageContext));
            table.setRowsDisplayed(TagUtils.evaluateExpressionAsInt("rowsDisplayed", this.rowsDisplayed, this, pageContext));
            table.setScope(TagUtils.evaluateExpressionAsString("scope", scope, this, pageContext));
            table.setShowExports(TagUtils.evaluateExpressionAsBoolean("showExports", this.showExports, this, pageContext));
            table.setShowPagination(TagUtils.evaluateExpressionAsBoolean("showPagination", this.showPagination, this, pageContext));
            table.setShowStatusBar(TagUtils.evaluateExpressionAsBoolean("showStatusBar", this.showStatusBar, this, pageContext));
            table.setShowTitle(TagUtils.evaluateExpressionAsBoolean("showTitle", this.showTitle, this, pageContext));
            table.setShowTooltips(TagUtils.evaluateExpressionAsBoolean("showTooltips", this.showTooltips, this, pageContext));
            table.setSortRowsCallback(TagUtils.evaluateExpressionAsString("sortRowsCallback", this.sortRowsCallback, this, pageContext));
            table.setSortable(TagUtils.evaluateExpressionAsBoolean("sortable", this.sortable, this, pageContext));
            table.setState(TagUtils.evaluateExpressionAsString("state", this.state, this, pageContext));
            table.setStateAttr(TagUtils.evaluateExpressionAsString("stateAttr", this.stateAttr, this, pageContext));
            table.setStyle(TagUtils.evaluateExpressionAsString("style", style, this, pageContext));
            table.setStyleClass(TagUtils.evaluateExpressionAsString("styleClass", this.styleClass, this, pageContext));
            table.setTableId(TagUtils.evaluateExpressionAsString("tableId", tableId, this, pageContext));
            table.setTheme(TagUtils.evaluateExpressionAsString("theme", this.theme, this, pageContext));
            table.setTitle(TagUtils.evaluateExpressionAsString("title", this.title, this, pageContext));
            table.setVar(TagUtils.evaluateExpressionAsString("var", this.var, this, pageContext));
            table.setView(TagUtils.evaluateExpressionAsString("view", this.view, this, pageContext));
            table.setWidth(TagUtils.evaluateExpressionAsString("width", this.width, this, pageContext));
            addTableAttributes(model, table);
            model.addTable(table);
        } catch(Exception e) {
            throw new JspException("TableTag.doStartTag() Problem: " +ExceptionUtils.formatStackTrace(e));
        }
        returnEVAL_BODY_INCLUDE;
    }
    /**
     * Two things need to be accomplished here. First, need to iterate once over
     * the columns to load up all the attributes. Second, need to iterate over
     * the columns as many times as specified by the rowsDisplayed attribute so
     * the columns row can be resolved. On each iteration over the columns the
     * current bean in the collection is passed via the pageScope.
     */
    public int doAfterBody() throwsJspException {
        try{
            if (iterator == null) {
               iterator =model.execute().iterator();
            }
            if (iterator != null &&iterator.hasNext()) {
                Object bean =iterator.next();
                model.setCurrentRowBean(bean);
                returnEVAL_BODY_AGAIN;
            }
        } catch(Exception e) {
            throw new JspException("TableTag.doAfterBody() Problem: " +ExceptionUtils.formatStackTrace(e));
        }
        returnSKIP_BODY;
    }
    public int doEndTag() throwsJspException {
        try{
            pageContext.getOut().println(model.getViewData());
        } catch(Exception e) {
            throw new JspException("TableTag.doEndTag() Problem: " +ExceptionUtils.formatStackTrace(e));
        }
        returnEVAL_PAGE;
    }

3. 深入追踪到TableModel

在doAfterBody()方法中调用了TableModel的excute方法:

 public Collection execute() throwsException {
//1. 查询记录 Collection rows
= TableModelUtils.retrieveRows(this); rows = new ArrayList(rows); //copy for thread safety this.collectionOfBeans =rows;       //2. 过滤和排序记录 rows = TableModelUtils.filterRows(this, rows);       rows = TableModelUtils.sortRows(this, rows); this.collectionOfFilteredBeans =rows;      // 3. 获取记录总数和pagesize Integer totalRows = getTableHandler().getTotalRows();
int defaultRowsDisplayed =getTableHandler().getTable().getRowsDisplayed(); if (totalRows != null) {
//4. 设置记录总数和默认pagesize limit.setRowAttributes(totalRows.intValue(), defaultRowsDisplayed); }
else{ limit.setRowAttributes(rows.size(), defaultRowsDisplayed); } if(logger.isDebugEnabled()) { logger.debug(limit.toString()); }      //5. 获取本次显示的记录 rows = TableModelUtils.getCurrentRows(this, rows); this.collectionOfPageBeans =rows;      //6. 视图显示 viewHandler.setView(); returnrows; }

4. 视图显示

默认定义了三种视图模式:extremetable.properties

table.view.compact=org.extremecomponents.table.view.CompactView
table.view.limit=org.extremecomponents.table.view.LimitView
table.view.html=org.extremecomponents.table.view.HtmlView

    public void setView() throwsException {
        boolean isExported =model.getLimit().isExported();
        String currentView = null;
        if(isExported) {
            currentView =model.getExportHandler().getCurrentExport().getView();
            String preference = model.getPreferences().getPreference(PreferencesConstants.EXPORT_VIEW +currentView);
            if(StringUtils.isNotBlank(preference)) {
                currentView =preference;
            }
        } else{
            currentView =model.getTableHandler().getTable().getView();
            String preference = model.getPreferences().getPreference(PreferencesConstants.TABLE_VIEW +currentView);
            if(StringUtils.isNotBlank(preference)) {
                currentView =preference;
            }
        }
        Class classDefinition =Class.forName(currentView);
        this.view =(View) classDefinition.newInstance();
        getView().beforeBody(model);
    }

调用抽象类的beforeBody方法:

    public final voidbeforeBody(TableModel model) {
        this.model =model;
        bufferView =model.getTableHandler().getTable().isBufferView();
        if(bufferView) {
            html = newHtmlBuilder();
        } else{
            html = newHtmlBuilder(model.getContext().getWriter());
        }
        formBuilder = newFormBuilder(html, model);
        init(html, model);
        formBuilder.formStart();
        tableBuilder.themeStart();
     beforeBodyInternal(model);
    }

调用HtmlView的beforeBodyInternal处理

    protected voidbeforeBodyInternal(TableModel model) {
        toolbar(getHtmlBuilder(), getTableModel());
        getTableBuilder().tableStart();
        getTableBuilder().theadStart();
        statusBar(getHtmlBuilder(), getTableModel());
        getTableBuilder().filterRow();
        getTableBuilder().headerRow();
        getTableBuilder().theadEnd();
        getTableBuilder().tbodyStart();
    }

工具栏:

    protected voidtoolbar(HtmlBuilder html, TableModel model) {
//layout 布局
newDefaultToolbar(html, model).layout(); }

左右布局格式:

    public voidlayout() {
        if (!showLayout(model)) {
            return;
        }
        html.table(0).border("0").cellPadding("0").cellSpacing("0");
        Table table =model.getTableHandler().getTable();
        html.width(table.getWidth()).close();
        html.tr(1).close();
        // layout area left
        columnLeft(html, model);
        // layout area right
columnRight(html, model);
        html.trEnd(1);
        html.tableEnd(0);
        html.newline();
    }

布局的实现:

protected voidcolumnLeft(HtmlBuilder html, TableModel model) {
        html.td(2).close();
        newTableBuilder(html, model).title();
        html.tdEnd();
    }
    protected voidcolumnRight(HtmlBuilder html, TableModel model) {
        boolean showPagination =BuilderUtils.showPagination(model);
        boolean showExports =BuilderUtils.showExports(model);
        ToolbarBuilder toolbarBuilder = newToolbarBuilder(html, model);
        html.td(2).align("right").close();
        html.table(2).border("0").cellPadding("0").cellSpacing("1").styleClass(BuilderConstants.TOOLBAR_CSS).close();
        html.tr(3).close();
        if(showPagination) {
            html.td(4).close();
            toolbarBuilder.firstPageItemAsImage();
            html.tdEnd();
            html.td(4).close();
            toolbarBuilder.prevPageItemAsImage();
            html.tdEnd();
            html.td(4).close();
            toolbarBuilder.nextPageItemAsImage();
            html.tdEnd();
            html.td(4).close();
            toolbarBuilder.lastPageItemAsImage();
            html.tdEnd();
            html.td(4).close();
            toolbarBuilder.separator();
            html.tdEnd();
            html.td(4).style("20px").close();
            html.newline();
            html.tabs(4);
            toolbarBuilder.rowsDisplayedDroplist();
            html.img();
            html.src(BuilderUtils.getImage(model, BuilderConstants.TOOLBAR_ROWS_DISPLAYED_IMAGE));
            html.style("border:0");
            html.alt("Rows Displayed");
            html.xclose();
            html.tdEnd();
            if(showExports) {
                html.td(4).close();
                toolbarBuilder.separator();
                html.tdEnd();
            }
        }
        if(showExports) {
            Iterator iterator =model.getExportHandler().getExports().iterator();
            for (Iterator iter =iterator; iter.hasNext();) {
                html.td(4).close();
                Export export =(Export) iter.next();
                toolbarBuilder.exportItemAsImage(export);
                html.tdEnd();
            }
        }
        html.trEnd(3);
        html.tableEnd(2);
        html.newline();
        html.tabs(2);
        html.tdEnd();
    }

状态栏和工具栏类似,就不一一赘述了。

5. 动作触发

下一页来理解ectable中是如何触发事件的:

public void nextPageItemAsImage() {
ImageItem item = new ImageItem();
item.setTooltip(messages.getMessage(BuilderConstants.TOOLBAR_NEXT_PAGE_TOOLTIP));
item.setDisabledImage(BuilderUtils.getImage(model, BuilderConstants.TOOLBAR_NEXT_PAGE_DISABLED_IMAGE));
item.setImage(BuilderUtils.getImage(model, BuilderConstants.TOOLBAR_NEXT_PAGE_IMAGE));
item.setAlt(messages.getMessage(BuilderConstants.TOOLBAR_NEXT_PAGE_TEXT));
item.setStyle("border:0");
ToolbarItemUtils.buildNextPage(html, model, item);
}

下一页的构建

    public static voidbuildNextPage(HtmlBuilder html, TableModel model, ToolbarItem item) {
        int page = model.getLimit().getPage();
        String action = new TableActions(model).getPageAction(page + 1);
        item.setAction(action);
        int totalPages =BuilderUtils.getTotalPages(model);
        if (!BuilderUtils.isNextPageEnabled(page, totalPages)) {
            item.disabled(html);
        } else{
            item.enabled(html, model);
        }
    }

触发动作,js实现

    public String getPageAction(intpage) {
        StringBuffer action = new StringBuffer("javascript:");
        action.append(getClearedExportTableIdParameters());
        action.append(getFormParameter(TableConstants.PAGE, "" +page));
        action.append(getOnInvokeAction());
        returnaction.toString();
    }

一个完整的table示例如下:

<table border="0"cellpadding="0"cellspacing="0"width="60%" >
    <tr>
        <td><span class="title" >persons</span></td>
        <td align="right" >
        <table border="0"cellpadding="0"cellspacing="1"class="toolbar" >
            <tr>
                <td><img src="/address-book/public/images/table/firstPageDisabled.gif"style="border:0"alt="第一页" /></td>
                <td><img src="/address-book/public/images/table/prevPageDisabled.gif"style="border:0"alt="上一页" /></td>
                <td><img src="/address-book/public/images/table/nextPageDisabled.gif"style="border:0"alt="下一页" /></td>
                <td><img src="/address-book/public/images/table/lastPageDisabled.gif"style="border:0"alt="最后页" /></td>
                <td><img src="/address-book/public/images/table/separator.gif"style="border:0"alt="Separator" /></td>
                <td style="20px" >
                <select name="ec_rd"onchange="javascript:document.forms.ec.ec_crd.value=this.options[this.selectedIndex].value;document.forms.ec.ec_p.value='1';document.forms.ec.setAttribute('action','/address-book/person/list');document.forms.ec.setAttribute('method','post');document.forms.ec.submit()" >
                <option value="5"selected="selected">5</option><option value="50" >50</option><option value="100" >100</option>
                </select><img src="/address-book/public/images/table/rowsDisplayed.gif"style="border:0"alt="Rows Displayed" /></td>
            </tr>
        </table>
        </td>
    </tr>
</table>

6. 小结:

eXtremeComponents为jsp开发table提供了比较好的支持,它的源码可以作为学习jsp tag的一个很好示例,研究该源码可以加深对jsp的理解,通过对上述源码进行合适的扩展后可以作为组件库使用。

参考文献:

1.http://liuna718-163-com.iteye.com/blog/1318991

2.http://www.51cto.com/specbook/11/57761.htm

免责声明:文章转载自《extremeComponents(ec)源码分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Cortex-A15架构解析:它为什么这么强(转)NeatUpload 的使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

数据库基本概念及简单的单表操作

一:MySQL的基本介绍:MySQL是一种关系型数据库mysql是属于Oracle旗下的一款数据库产品。分为商业版和社区版 技术角度分析:MySQL数据库是一种C/S(客户端/服务器)模型的服务     B/S(浏览器/服务器)MySQL的网络通信模型为:NIO+连接池来实现,支持高并发的应用场景   SQL: Structred Query Langu...

Vue笔记:Vue3 Table导出为Excel

1、安装 npm install -S file-saver 用来生成文件的web应用程序 npm install -S xlsx 电子表格格式的解析器 npm install -D script-loader 将js挂载在全局下npm install -S element-ui...

打印divjs方法

方法 printdiv(printpage) { var css = "<style> " + " .zbtable { " + " border-collapse: collapse; " + " text-align: center; " +...

TCP/UDP简易通信框架源码,支持轻松管理多个TCP服务端(客户端)、UDP客户端

目录 说明 TCP/UDP通信主要结构 管理多个Socket的解决方案 框架中TCP部分的使用 框架中UDP部分的使用 框架源码结构 补充说明 源码地址 说明 之前有好几篇博客在讲TCP/UDP通信方面的内容,也有做过一些Demo(包括整理出来的、可供学习使用的简单通信框架)。具体可以参见以下博客: http://www.cnblogs.com/xia...

三篇文章了解 TiDB 技术内幕——说计算

在这我们将关系模型简单理解为 Table 和 SQL 语句,那么问题变为如何在 KV 结构上保存 Table 以及如何在 KV 结构上运行 SQL 语句。 假设我们有这样一个表的定义: CREATE TABLE User { ID int, Name varchar(20), Role varchar(20), Age int, PRIMARY KEY (...

[转]oracle在删除表表空间用户时,如何释放磁盘空间

一、drop表 执行drop table xx 语句 drop后的表被放在回收站(user_recyclebin)里,而不是直接删除掉。这样,回收站里的表信息就可以被恢复,或彻底清除。 通过查询回收站user_recyclebin获取被删除的表信息,然后使用语句 flashback table...