• extremeComponents(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 extends Attributes {
        private TableModel model;
    
        private String action;
        private Boolean autoIncludeParameters;
        private String border;
        private Boolean bufferView;
        private String cellpadding;
        private String cellspacing;
        private Boolean filterable;
        private String filterRowsCallback;
        private String form;
        private String imagePath;
        private String interceptor;
        private Object items;
        private String locale;
        private int maxRowsDisplayed;
        private int medianRowsDisplayed;
        private String method;
        private String onInvokeAction;
        private String retrieveRowsCallback;
        private int rowsDisplayed;
        private Boolean saveFilterSort;
        private String scope;
        private Boolean showExports;
        private Boolean showPagination;
        private Boolean showStatusBar;
        private Boolean showTitle;
        private Boolean showTooltips;
        private String sortRowsCallback;
        private Boolean sortable;
        private String state;
        private String stateAttr;
        private String style;
        private String styleClass;
        private String tableId;
        private String title;
        private String theme;
        private String var;
        private String view;
        private String width;
    
        public Table(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() throws JspException {
            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 = new Table(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));
            }
    
            return EVAL_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() throws JspException {
            try {
                if (iterator == null) {
                    iterator = model.execute().iterator();
                }
    
                if (iterator != null && iterator.hasNext()) {
                    Object bean = iterator.next();
                    model.setCurrentRowBean(bean);
                    return EVAL_BODY_AGAIN;
                }
            } catch (Exception e) {
                throw new JspException("TableTag.doAfterBody() Problem: " + ExceptionUtils.formatStackTrace(e));
            }
    
            return SKIP_BODY;
        }
    
        public int doEndTag() throws JspException {
            try {
                pageContext.getOut().println(model.getViewData());
            } catch (Exception e) {
                throw new JspException("TableTag.doEndTag() Problem: " + ExceptionUtils.formatStackTrace(e));
            }
    
            return EVAL_PAGE;
        }

    3. 深入追踪到TableModel

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

     public Collection execute() throws Exception {
          //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(); return rows; }

    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() throws Exception {
            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 void beforeBody(TableModel model) {
            this.model = model;
            
            bufferView = model.getTableHandler().getTable().isBufferView();
            if (bufferView) {
                html = new HtmlBuilder();
            } else {
                html = new HtmlBuilder(model.getContext().getWriter());
            }
    
            formBuilder = new FormBuilder(html, model);
    
            init(html, model);
            
            formBuilder.formStart();
    
            tableBuilder.themeStart();
            
            beforeBodyInternal(model);
        }

    调用HtmlView的beforeBodyInternal处理

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

    工具栏:

        protected void toolbar(HtmlBuilder html, TableModel model) {
        //layout 布局
    new DefaultToolbar(html, model).layout(); }

    左右布局格式:

        public void layout() {
            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 void columnLeft(HtmlBuilder html, TableModel model) {
            html.td(2).close();
            new TableBuilder(html, model).title();
            html.tdEnd();
        }
    
        protected void columnRight(HtmlBuilder html, TableModel model) {
            boolean showPagination = BuilderUtils.showPagination(model);
            boolean showExports = BuilderUtils.showExports(model);
    
            ToolbarBuilder toolbarBuilder = new ToolbarBuilder(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 void buildNextPage(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(int page) {
            StringBuffer action = new StringBuffer("javascript:");
    
            action.append(getClearedExportTableIdParameters());
    
            action.append(getFormParameter(TableConstants.PAGE, "" + page));
            action.append(getOnInvokeAction());
            
            return action.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

  • 相关阅读:
    1022. 从根到叶的二进制数之和
    剑指 Offer 54. 二叉搜索树的第k大节点
    枚举--百练2811--熄灯问题
    UVA 572 BFS 图论入门
    百练1088 DP+DFS 迷宫问题
    poj 1661 动态规划 拯救老鼠
    入坑动态规划!POJ 1458字符串最大公共子序列
    文件后缀批处理
    奇妙的算法--UVA 679(二叉树的编号)
    栈_uva514
  • 原文地址:https://www.cnblogs.com/davidwang456/p/4401742.html
Copyright © 2020-2023  润新知