lyyb2001

          只是為方便自己找記錄而已
          posts - 57, comments - 27, trackbacks - 0, articles - 5
            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 ::  :: 管理

          eXtremeComponents代碼結(jié)構(gòu)解讀

          Posted on 2008-02-29 14:33 skycity 閱讀(1203) 評論(0)  編輯  收藏 所屬分類: J2EE技術(shù)
          ec是一系列提供高級顯示的開源JSP定制標簽,當前的包含的組件為eXtremeTable,用于以表形式顯示數(shù)據(jù)。ec現(xiàn)在的版本是1.0.1,由Jeff Johnston開發(fā)的,網(wǎng)址:http://www.extremecomponents.org
          應(yīng)該說eXtremeComponents已經(jīng)實現(xiàn)了一些較為完善的功能,包括排序、過濾等,現(xiàn)在還支持Ajax功能。
          用戶通過設(shè)置標簽(如table,row,column等)的屬性(大部分的屬性和html中的table、tr,td等的屬性相同,另外添加一些用于控制的屬性)便可輕松實現(xiàn)數(shù)據(jù)的列表。ec的強大還在于其良好的可擴展性,因為用戶可以方便地對其進行二次開發(fā),以滿足一些特殊的需求。
          由于本文主要是分析ec的代碼設(shè)計而不是使用說明,因此如何使用ec可以參考相關(guān)的指南和參考文檔。以下僅列舉了發(fā)行包中的一個例子test.jsp:(大部分屬性的含義都很明顯,這里也不作說明了)

          以下內(nèi)容為程序代碼:

          <ec:table
          items="pres"
          action="${pageContext.request.contextPath}/test.jsp"
          imagePath="${pageContext.request.contextPath}/images/table/*.gif"
          title="test"
          width="60%"
          rowsDisplayed="5"
          >
          <ec:exportXls fileName="resourceList.xls" tooltip="Export Excel"/>
          <ec:exportPdf fileName="resourceList.pdf" tooltip="Export PDF"/>
          <ec:row highlightRow="true">
          ???????? <ec:column property="rowcount" cell="rowCount" onClick="alert('${pres[0]}');"
          ??????????? title="No." sortable="false" filterable="false" width="5%"
          ??????????? style="text-align:center"/>
          <ec:column property="name" title="姓名" href="#" filterCell="droplist"/>
          <ec:column property="nickname" title="昵稱" filterable="true" sortable="false"/>
          <ec:column property="term"/>
          </ec:row>
          </ec:table>

          ec的精彩點之一是Limit接口及其實現(xiàn)類。
          就整個軟件的設(shè)計架構(gòu)來說,ec也是非常優(yōu)秀的。ec完全面向?qū)ο螅⒊浞诌\用了設(shè)計模式,重構(gòu)后的整個代碼簡潔且高效。

          1.? 代碼結(jié)構(gòu)

          1.1四個第一級包:

          package org.extremecomponents.table.*;(列表)

          package org.extremecomponents.test;(用于測試)

          package org.extremecomponents.tree;(樹型,尚處于開發(fā)中)

          package org.extremecomponents.util;(工具類)

          其中,util包下的HtmlBuilder類封裝了視圖輸出(如html格式)的各種操作,如函數(shù)table()用于輸出一個HTML標簽<table,該類包含一個StringWriter的私有變量。

          而ExtremeUtils類則封裝了一些常用的函數(shù),如函數(shù)formatDate和formatNumber等。

          1.2table包下的主要內(nèi)容:

          (1)package org.extremecomponents.table.bean;

          說明:簡單的bean類,類似VO。

          Attributes抽象類包含一個HashMap的私有變量,用于關(guān)聯(lián)屬性及其值。類Column,Export,Row,Table都繼承了Attributes并添加了各種的屬性變量,如Column中的style變量便是對應(yīng)HTML中td的style屬性,Table中的border變量對應(yīng)的是HTML中table的border屬性,等等。當然,這些bean中還有一些屬性是用于控制的,Column中的cell變量用于指明該單元格的輸出是用哪個Cell類(其實就是用于控制輸出的格式),如果cell=”date”,那么該單元格的輸出就采用DateCell類的輸出,即日期格式;等等。

          還有ColumnDefaults,ExportDefault,RowDefault,TableDefault這幾個最終類用于對應(yīng)的Column,Export,Row,Table初始化時設(shè)置一些默認的屬性值。這些默認值是由core包下的extremetable.properties文件設(shè)置的,在TableModel初始化時通過類TableProperties來讀取的。

          (2)package org.extremecomponents.table.calc;

          說明:用于列的屬性(calc,和calcTitle)中,由多個列的值計算而成的值。如:總值,平均值等。

          Calc接口,只定義了一個函數(shù)getCalcResult(model,column);

          類AverageCalc和TotalCalc實現(xiàn)了該接口,分別計算平均值和總值。

          (3)package org.extremecomponents.table.callback;

          說明:用于檢索、過濾和排序行集數(shù)據(jù),由TableModel中的execute方法調(diào)用。

          三個接口:RetrieveRowsCallback, FilterRowsCallback, SortRowsCallback分別定義了函數(shù)retrieveRows(model),filterRows(model),sortRows(model),用于檢索、過濾和排序數(shù)據(jù)。FilterRowsCallback的默認實現(xiàn)是得到Beans或Maps的Collection,然后通過實現(xiàn)jakarta Predicate接口來進行過濾。

          ProcessRowsCallback類實現(xiàn)了這三個接口,也是ec中默認的對數(shù)據(jù)進行檢索,過濾和排序的類。但是,這種功能的正確實現(xiàn)是基于這么一個事實,即ec得到的數(shù)據(jù)必須是數(shù)據(jù)庫中未經(jīng)處理(即過濾或排序)的所有原始數(shù)據(jù),否則過濾或排序等處理的結(jié)果便不是正確的。還有,ec也能處理數(shù)據(jù)的分頁,但現(xiàn)實中我們的數(shù)據(jù)量往往都很大(成千上萬的),不可能未經(jīng)處理就把所有的數(shù)據(jù)全部讀出讓ec來處理!顯然,分頁、過濾、排序等等處理都是程序在和數(shù)據(jù)庫交互中完成的,ec僅僅接受處理后的數(shù)據(jù)然后顯示而已。而LimitCallback類便實現(xiàn)了這種處理方案,它也實現(xiàn)了上面的那三個接口,但僅僅是直接返回數(shù)據(jù)而已。這種“Limit”的實現(xiàn)在limit包中再做討論。

          (4)package org.extremecomponents.table.cell;

          說明:用于單元格的格式化輸出。

          Cell接口定義了兩個方法:getExportDisplay和getHtmlDisplay。

          AbstractCell抽象類實現(xiàn)了Cell,其實也定義了cell的輸出框架,其繼承類只需實現(xiàn)getCellValue方法即可。其getHtmlDisplay方法實現(xiàn)如下:

          public String getHtmlDisplay(TableModel model, Column column) {

          ??????? ColumnBuilder columnBuilder = new ColumnBuilder(column);

          ??????? columnBuilder.tdStart();

          ??????? columnBuilder.tdBody(getCellValue(model, column));

          ??????? columnBuilder.tdEnd();

          ??????? return columnBuilder.toString();

          ??? }

          DisplayCell繼承了AbstractCell,是ec中默認的cell。

          DateCell繼承了AbstractCell,用于輸出日期格式化的單元格。

          FilterCell實現(xiàn)了Cell,用于在頭部輸出一個用于過濾的輸入框。

          FilterDroplistCell實現(xiàn)了Cell,用于在頭部輸出一個用于過濾的下拉列表。

          HeaderCell實現(xiàn)了Cell,用于輸出頭部標題的單元格內(nèi)容。

          NumberCell繼承了AbstractCell,用于輸出數(shù)字格式化的單元格。

          RowCountCell繼承了AbstractCell,用于輸出數(shù)據(jù)集合的序號。

          SelectAllHeaderCell實現(xiàn)了Cell,用于在頭部生成一個選擇框,用于選擇所有的數(shù)據(jù)。

          (5)package org.extremecomponents.table.context;

          說明:ec中用到的上下文類的封裝。

          Context接口,用于獲得Application,Page,Session,Request等上下文的變量。

          HttpServletRequestContext實現(xiàn)了Context接口。

          ServletRequestContext實現(xiàn)了Context接口。

          JspPageContext實現(xiàn)了Context接口。TableModel初始化時(在TableTag中)使用了該類:

          model = new TableModelImpl(new JspPageContext(pageContext), TagUtils.evaluateExpressionAsString("locale", this.locale, this, pageContext));

          (6)package org.extremecomponents.table.core;

          說明:ec列表的核心包,包括表格模型,配置文件,屬性文件,參數(shù)封裝等。

          Registry接口,處理所有的參數(shù)(),包括用戶自定義的。

          AbstractRegistry抽象類實現(xiàn)了Registry,保存一些ec的內(nèi)部參數(shù)及用戶參數(shù)。

          TableRegistry繼承了AbstractRegistry類,由TableModel中的addTable函數(shù)調(diào)用。

          Messages接口,即支持國際化顯示,從Local中(如ZH_CN)獲取正確的資源文件。由resource包中的TableResourceBundle類實現(xiàn)。在TableModelImp中初始化:

          Messages messages = TableModelUtils.getMessages(this);

          messages.init(context, this.locale);

          this.messages = messages;


          Preferences接口,用于獲取配置文件中的設(shè)置值。

          TableProperties實現(xiàn)了Preferences,初始化時先加載系統(tǒng)默認的配置文件,然后再加載由用戶自己配置的文件,如下:

          public void init(Context context, String preferencesLocation) {

          ??????? try {

          ??????????? properties.load(this.getClass().getResourceAsStream(EXTREMETABLE_PROPERTIES));

          ??????????? if (StringUtils.isNotBlank(preferencesLocation)) {

          ??????????????? InputStream input = this.getClass().getResourceAsStream(preferencesLocation);

          ??????????????? if (input != null) {

          ??????????????????? properties.load(input);

          ??????????????? }

          ??????????? }

          ??????? } catch (IOException e) {

          ??????????? if (logger.isErrorEnabled()) {

          ??????????????? logger.error("Could not load the eXtremeTable preferences.", e);

          ??????????? }

          ??????? }

          ??? }

          其在TableModelImpl中被調(diào)用:

          Preferences preferences = new TableProperties();

          ??????? preferences.init(context, TableModelUtils.getPreferencesLocation(context));

          ??????? this.preferences = preferences;

          為了設(shè)置屬性文件,你應(yīng)該如下例所示在/WEB-INF/web.xml文件中聲明一個context-param,并 指定你的屬性文件的路徑:

          <context-param>
          ? <param-name>extremecomponentsPreferencesLocation</param-name>? <param-value>/org/extremesite/resource/extremecomponents.properties</param-value>
          </context-param>

          ?

          TableCache類用于獲得一些緩存的對象,包括Cell,State,Callback,Interceptor等,因此這些類都是singleton,并且不再線程安全。

          ?

          TableModel接口,是系統(tǒng)的核心接口,包括其實現(xiàn)類TableModelImpl,因為它們把系統(tǒng)中的所有變量都聯(lián)系了起來。

          TableModelImpl實現(xiàn)了TableModel,初始化時獲取Context,Preferences及Messages實例;通過addTable函數(shù)獲取Registry及LimitFactory,Limit實例。

          定義的變量有:Context,Preferences,Messages,Registry, TableHandler,RowHandler,ColumnHandler,ViewHandler,ExportHandler,Limit,Locale等。

          變量currentRowBean保存當前處理的bean,并在上下文中設(shè)置var變量(table中的var屬性)的值指向該bean,這樣的話,Row和Column標簽中便可以通過var變量來應(yīng)用這個當前的bean對象,獲得一些有意義的值。如下:

          public void setCurrentRowBean(Object bean) {

          ??????? int rowcount = rowHandler.increaseRowCount();

          ??????? this.currentRowBean = bean;

          ??????? context.setPageAttribute(TableConstants.ROWCOUNT, String.valueOf(rowcount));

          ??????? context.setPageAttribute(tableHandler.getTable().getVar(), bean);

          ??? }

          而collectionOfBeans、collectionOfFilteredBeans、collectionOfPageBeans則分別保存了所有的bean、過濾后的bean、當前頁的bean。

          TableModelImpl中的execute函數(shù)在標簽第一次迭代時被調(diào)用,先過濾,后排序,然后通過ViewHandler.setView()來設(shè)置輸出的視圖。


          (7)package org.extremecomponents.table.filter;

          說明:過濾器,用于導(dǎo)出時的過濾,實現(xiàn)了javax.servlet.Filter。

          (8)package org.extremecomponents.table.handler;

          說明:各種處理句柄,幫助TableModel處理對應(yīng)的bean,即關(guān)聯(lián)model和bean。

          類有:ColumnHandler, ExportHandler, RowHandler, TableHandle, ViewHandler。

          (9)package org.extremecomponents.table.interceptor;

          說明:攔截器,用于運行時添加和修改對應(yīng)bean的屬性。

          接口有:TableInterceptor, RowInterceptor, ColumnInterceptor, ExportInterceptor。

          用戶可以實現(xiàn)自己的Interceptor,然后在對應(yīng)的標簽中使用Interceptor屬性來設(shè)置并使用。所有的攔截器接口都定義了一個add方法, add方法被用來處理模型bean第一次創(chuàng)建時的屬性。行和列的攔截器還有一個modify 方法,在當行和類進行處理是對屬性值進行操作。

          (10)package org.extremecomponents.table.limit;

          說明:封裝排序,過濾及分頁的一些信息,用于向后臺程序傳遞Limit對象。

          LimitFactory接口,Limit的工廠接口。

          AbstractLimitFactory抽象類實現(xiàn)LimitFactory,用于獲取是否導(dǎo)出、當前頁面數(shù)、排序字段及值及過濾集合等。

          TableLimitFactory繼承了AbstractLimitFactory。

          ModelLimitFactory也繼承了AbstractLimitFactory。

          Filter最終類,值對象,三個String型私有變量:alias, property, value。

          FilterSet類,內(nèi)含一個Filter數(shù)組。

          Limit接口,定義了一些用于獲取limit信息的函數(shù),如排序值、過濾字段及值、等等。

          TableLimit最終類,實現(xiàn)了Limit。其構(gòu)造函數(shù)的參數(shù)是LimitFactory,即Limit的值是由工廠類得到的。

          Sort最終類,值對象,三個String型私有變量:alias,property,value。


          (11)package org.extremecomponents.table.resource;

          說明:資源文件及操作資源的類。

          TableResourceBundle實現(xiàn)了Messages接口,初始化時會加載特定的資源文件以及用戶自定義的資源文件,通過在web.xml中定義extremecomponentsMessagesLocation值來獲取。

          public void init(Context context, Locale locale) {

          ??????? this.locale = locale;

          ??????? defaultResourceBundle = findResourceBundle(EXTREMETABLE_RESOURCE_BUNDLE, locale);

          ??????? String messagesLocation = TableModelUtils.getMessagesLocation(context);

          ??????? if (StringUtils.isNotBlank(messagesLocation)) {

          ??????????? customResourceBundle = findResourceBundle(messagesLocation, locale);

          ??????? }

          ??? }

          (12)package org.extremecomponents.table.state;

          說明:處理表格的狀態(tài)。

          State接口,定義了saveParameters和getParameters兩個函數(shù)。

          AbstractState抽象類,實現(xiàn)了State接口,定義了saveParameters函數(shù)。

          DefaultState類實現(xiàn)了State接口,默認兩個函數(shù)為空。


          (13)package org.extremecomponents.table.tag;

          說明:標簽類,是ec開始的地方。

          ColumnsTag繼承TagSupport,用于生成自動產(chǎn)生的類。


          ColumnTag繼承BodyTagSupport并實現(xiàn)了ColumnInterceptor攔截器。

          首次迭代時并不生成視圖代碼,而是:

          Column column = new Column(model);

          //設(shè)置一些屬性。。。

          addColumnAttributes(model, column);

          model.getColumnHandler().addColumn(column);

          第2次迭代開始后便執(zhí)行真正的視圖輸出:

          if (column != null) { // null if view not allowed

          ???? Object bean = TagUtils.getModel(this).getCurrentRowBean();

          ???? Object propertyValue = TableModelUtils.getColumnPropertyValue(bean, property);

          ???? column.setValue(getColumnValue(propertyValue));

          ???? column.setPropertyValue(propertyValue);

          ?

          ???? modifyColumnAttributes(model, column);

          ???? model.getColumnHandler().modifyColumnAttributes(column);

          ???? model.getViewHandler().addColumnValueToView(column);

          }

          最后那個語句的函數(shù)代碼如下:

          public void addColumnValueToView(Column column) {

          ??????? Cell cell = TableModelUtils.getCell(column);

          ??????? boolean isExported = model.getLimit().isExported();

          ??????? if (!isExported) {

          ??????????? column.setCellDisplay(cell.getHtmlDisplay(model, column));

          ??????? } else {

          ??????????? column.setCellDisplay(cell.getExportDisplay(model, column));

          ??????? }

          ??????? getView().body(model, column);

          ??? }

          通過getView().body()函數(shù)的調(diào)用便完成了視圖的輸出。

          ?

          RowTag繼承了TagSupport并實現(xiàn)了RowInterceptor。

          和ColumnTag類似,首次迭代時也僅僅是new一個Row對象,然后設(shè)置屬性并添加到model中。但RowTag并不產(chǎn)生視圖的輸出,而是在ColumnTag視圖輸出時判斷是否第一個或最后一個Column,若是,則這時才輸出Row的視圖數(shù)據(jù)。如下(抽象類AbstractHtmlView中:)

          public void body(TableModel model, Column column) {

          ??????? if (column.isFirstColumn()) {

          ??????????? rowBuilder.rowStart();

          ??????? }

          ??????? html.append(column.getCellDisplay());

          ??????? if (column.isLastColumn()) {

          ??????????? rowBuilder.rowEnd();

          ??????? }

          ??? }

          ?

          TableTag繼承了TagSupport,實現(xiàn)TryCatchFinally和TableInterceptor接口。

          在doStartTag()函數(shù)中:

          初始化TableModel的實例為TableModelImpl類,再實例化一個Table類并設(shè)置屬性,最后通過model.addTable(table)把Table添加到model中,在該addTable函數(shù)中完成TableRegistry和TableLimit的初始化。

          在doAfterBody()函數(shù)中:

          在doEndTag()函數(shù)中:

          pageContext.getOut().println(model.getViewData());

          以上這語句便完成了視圖的輸出,而model.getViewData()函數(shù)的代碼如下:

          public Object getViewData() throws Exception {

          ??? Object viewData = viewHandler.getView().afterBody(this);

          ??? if (limit.isExported()) {

          ?????? context.setRequestAttribute(TableConstants.VIEW_DATA, viewData);

          ?????? context.setRequestAttribute(TableConstants.VIEW_RESOLVER, exportHandler.getCurrentExport().getViewResolver());

          ?????? context.setRequestAttribute(TableConstants.EXPORT_FILE_NAME, exportHandler.getCurrentExport().getFileName());

          ??????????? return "";

          ??????? }

          ??????? return viewData;

          ??? }

          還有幾個Tag:ExportCsvTag, ExportPdfTag, ExportTag, ExportXlsTag,ParameterTag.等。

          而TagUtils類則封裝了幾個處理函數(shù),如利用ExpressionEvaluatorManager類完成屬性的設(shè)置?


          (14)package org.extremecomponents.table.view;

          說明:視圖部分,包括HTML,toolbar,pdf,xsl等

          View接口,定義三個函數(shù):beforeBody, body, afterBody。

          AbstractHtmlView抽象類實現(xiàn)了View,其實也便定義了表格輸出的框架,繼承類只需實現(xiàn)beforeBodyInternal和afterBodyInternal兩個函數(shù)即可,分別用于輸出表格的表頭數(shù)據(jù)及表尾數(shù)據(jù),而其body函數(shù)則由ColumnTag標簽處理時調(diào)用。在beforeBody函數(shù)中,該抽象類實例化HtmlBuilder、FormBuilder、TableBuilder、RowBuilder等用于構(gòu)建相應(yīng)視圖的類,如FormBuilder完成Html中form表單等參數(shù)的設(shè)置等。

          HtmlView繼承了AbstractHtmlView類,是ec中默認的視圖。

          (15)package org.extremecomponents.table.view.html;

          說明:用于幫助視圖構(gòu)建輸出的類,如ColumnBuilder,F(xiàn)ormBuilder,RowBuilder,TableBuilder等,如ColumnBuilder.tdEnd()函數(shù)生成的代碼是“</td>”。

          TableActions類封裝了一些js的動作代碼,主要用于form動作。


          (16) package org.extremecomponents.table.html.toobar;

          說明:工具條,類型有:按鈕,字符,圖形等。

          ToolbarItem接口,

          AbstractItem抽象類。

          ButtonItem,ImageItem,TextItem繼承AbstractItem實現(xiàn)了ToolbarItem接口。



          Lyyb2001
          主站蜘蛛池模板: 女性| 苏州市| 新乐市| 甘洛县| 石楼县| 万源市| 张家口市| 汪清县| 济源市| 筠连县| 灵武市| 安西县| 军事| 峡江县| 靖江市| 大名县| 景宁| 乌鲁木齐市| 石家庄市| 山东| 竹山县| 德惠市| 磐安县| 祁阳县| 长兴县| 龙州县| 五常市| 佛冈县| 深州市| 化州市| 定西市| 手游| 咸宁市| 宁陕县| 富裕县| 武义县| 巴里| 从化市| 湘潭市| 新余市| 濮阳市|