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("width: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="width: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)源码分析的更多相关文章

  1. 【Zookeeper】源码分析之持久化--FileTxnSnapLog

    一.前言 前面分析了FileSnap,接着继续分析FileTxnSnapLog源码,其封装了TxnLog和SnapShot,其在持久化过程中是一个帮助类. 二.FileTxnSnapLog源码分析 2 ...

  2. JS/Jquery版本的俄罗斯方块(附源码分析)

    转载于http://blog.csdn.net/unionline/article/details/63250597 且后续更新于此 1.前言 写这个jQuery版本的小游戏的缘由在于我想通过从零到有 ...

  3. EasyUI学习总结(三)——easyloader源码分析(转载)

    声明:这一篇文章是转载过来的,转载地址忘记了,原作者如果看到了,希望能够告知一声,我好加上去! easyloader模块是用来加载jquery easyui的js和css文件的,而且它可以分析模块的依 ...

  4. 【Zookeeper】源码分析之持久化(三)之FileTxnSnapLog

    一.前言 前面分析了FileSnap,接着继续分析FileTxnSnapLog源码,其封装了TxnLog和SnapShot,其在持久化过程中是一个帮助类. 二.FileTxnSnapLog源码分析 2 ...

  5. Akka源码分析-local-DeathWatch

    生命周期监控,也就是死亡监控,是akka编程中常用的机制.比如我们有了某个actor的ActorRef之后,希望在该actor死亡之后收到响应的消息,此时我们就可以使用watch函数达到这一目的. c ...

  6. 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视GCC编译全过程 | 百篇博客分析OpenHarmony源码| v57.01

    百篇博客系列篇.本篇为: v57.xx 鸿蒙内核源码分析(编译过程篇) | 简单案例窥视编译全过程 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙 ...

  7. 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 百篇博客分析OpenHarmony源码 | v55.01

    百篇博客系列篇.本篇为: v55.xx 鸿蒙内核源码分析(重定位篇) | 与国际接轨的对外部发言人 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程 ...

  8. 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 百篇博客分析OpenHarmony源码 | v51.04

    百篇博客系列篇.本篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应用程序入口并不是main | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | ...

  9. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  10. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

随机推荐

  1. Windows 之间用rsync同步数据(cwRsyncServer配置)

    rsync是一款优秀的数据同步软件,在跨服务器,跨机房,跨国备份服务器的首选工具,下面就来介绍下如何配置安装cwRsyncServer很大多数软件一样是B/C架构,cwRsyncServer是rsyn ...

  2. 序列化类型为XX的对象时检测到循环引用

    /// 产品列表展示 /// </summary> /// <returns></returns> ) { //获得所有组别 Galasys_IBLL.IT_BIZ ...

  3. Spring注释@Qualifier

    在学习@Autowired的时候我们已经接触到了@Qualifier, 这节就来详细学习一下自定义@Qualifier. 例如定义一个交通工具类:Vehicle,以及它的子类Bus和Sedan. 如果 ...

  4. Java操作Hbase进行建表、删表以及对数据进行增删改查,条件查询

    1.搭建环境 新建JAVA项目,添加的包有: 有关Hadoop的hadoop-core-0.20.204.0.jar 有关Hbase的hbase-0.90.4.jar.hbase-0.90.4-tes ...

  5. jquery 单行滚动、批量多行滚动、文字图片翻屏滚动效果代码

    jquery单行滚动.批量多行滚动.文字图片翻屏滚动效果代码,需要的朋友可以参考下. 以下代码,运行后,需要刷新下,才能加载jquery,要不然看不到效果.一.单行滚动效果 <!DOCTYPE ...

  6. Physics2D.Linecast中的参数layerMask

    static RaycastHit2D Linecast(Vector2 start, Vector2 end, int layerMask = DefaultRaycastLayers, float ...

  7. js基础第二天

    函数:是由事件驱动的或者当它被调用时执行的可以重复使用的代码块. 函数声明: 1. 自定义函数(常用) var num=10; function fun() { alert("我是自定义函数 ...

  8. mac中viso的兼容工具

    http://www.orsoon.com/Mac/77738.html破解教程 http://www.pc6.com/mac/111747.html下载地址 很强大,很爽.

  9. Nginx负载均衡SFTP

    1.CentOS安装SFTP,参考 2.Nginx-1.8.1 下载 ,Nginx_TCP插件 下载 3.安装Nginx [root@localhost nginx-1.8.1]# yum -y in ...

  10. 五个小例子教你搞懂 JavaScript 作用域问题

    众所周知,JavaScript 的作用域和其他传统语言(类C)差别比较大,掌握并熟练运用JavaScript 的作用域知识,不仅有利于我们阅读理解别人的代码,也有助于我们编写自己的可靠代码. 下面笔者 ...