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

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

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

    lyyb2001

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

    eXtremeComponents代碼結構解讀

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

    以下內容為程序代碼:

    <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接口及其實現類。
    就整個軟件的設計架構來說,ec也是非常優秀的。ec完全面向對象,并充分運用了設計模式,重構后的整個代碼簡潔且高效。

    1.? 代碼結構

    1.1四個第一級包:

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

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

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

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

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

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

    1.2table包下的主要內容:

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

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

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

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

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

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

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

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

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

    說明:用于檢索、過濾和排序行集數據,由TableModel中的execute方法調用。

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

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

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

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

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

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

    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實現了Cell,用于在頭部輸出一個用于過濾的輸入框。

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

    HeaderCell實現了Cell,用于輸出頭部標題的單元格內容。

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

    RowCountCell繼承了AbstractCell,用于輸出數據集合的序號。

    SelectAllHeaderCell實現了Cell,用于在頭部生成一個選擇框,用于選擇所有的數據。

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

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

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

    HttpServletRequestContext實現了Context接口。

    ServletRequestContext實現了Context接口。

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

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

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

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

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

    AbstractRegistry抽象類實現了Registry,保存一些ec的內部參數及用戶參數。

    TableRegistry繼承了AbstractRegistry類,由TableModel中的addTable函數調用。

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

    Messages messages = TableModelUtils.getMessages(this);

    messages.init(context, this.locale);

    this.messages = messages;


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

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

    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中被調用:

    Preferences preferences = new TableProperties();

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

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

    為了設置屬性文件,你應該如下例所示在/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接口,是系統的核心接口,包括其實現類TableModelImpl,因為它們把系統中的所有變量都聯系了起來。

    TableModelImpl實現了TableModel,初始化時獲取Context,Preferences及Messages實例;通過addTable函數獲取Registry及LimitFactory,Limit實例。

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

    變量currentRowBean保存當前處理的bean,并在上下文中設置var變量(table中的var屬性)的值指向該bean,這樣的話,Row和Column標簽中便可以通過var變量來應用這個當前的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函數在標簽第一次迭代時被調用,先過濾,后排序,然后通過ViewHandler.setView()來設置輸出的視圖。


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

    說明:過濾器,用于導出時的過濾,實現了javax.servlet.Filter。

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

    說明:各種處理句柄,幫助TableModel處理對應的bean,即關聯model和bean。

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

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

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

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

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

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

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

    LimitFactory接口,Limit的工廠接口。

    AbstractLimitFactory抽象類實現LimitFactory,用于獲取是否導出、當前頁面數、排序字段及值及過濾集合等。

    TableLimitFactory繼承了AbstractLimitFactory。

    ModelLimitFactory也繼承了AbstractLimitFactory。

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

    FilterSet類,內含一個Filter數組。

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

    TableLimit最終類,實現了Limit。其構造函數的參數是LimitFactory,即Limit的值是由工廠類得到的。

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


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

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

    TableResourceBundle實現了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;

    說明:處理表格的狀態。

    State接口,定義了saveParameters和getParameters兩個函數。

    AbstractState抽象類,實現了State接口,定義了saveParameters函數。

    DefaultState類實現了State接口,默認兩個函數為空。


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

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

    ColumnsTag繼承TagSupport,用于生成自動產生的類。


    ColumnTag繼承BodyTagSupport并實現了ColumnInterceptor攔截器。

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

    Column column = new Column(model);

    //設置一些屬性。。。

    addColumnAttributes(model, column);

    model.getColumnHandler().addColumn(column);

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

    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);

    }

    最后那個語句的函數代碼如下:

    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()函數的調用便完成了視圖的輸出。

    ?

    RowTag繼承了TagSupport并實現了RowInterceptor。

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

    public void body(TableModel model, Column column) {

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

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

    ??????? }

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

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

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

    ??????? }

    ??? }

    ?

    TableTag繼承了TagSupport,實現TryCatchFinally和TableInterceptor接口。

    在doStartTag()函數中:

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

    在doAfterBody()函數中:

    在doEndTag()函數中:

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

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

    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類則封裝了幾個處理函數,如利用ExpressionEvaluatorManager類完成屬性的設置?


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

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

    View接口,定義三個函數:beforeBody, body, afterBody。

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

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

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

    說明:用于幫助視圖構建輸出的類,如ColumnBuilder,FormBuilder,RowBuilder,TableBuilder等,如ColumnBuilder.tdEnd()函數生成的代碼是“</td>”。

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


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

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

    ToolbarItem接口,

    AbstractItem抽象類。

    ButtonItem,ImageItem,TextItem繼承AbstractItem實現了ToolbarItem接口。



    Lyyb2001
    主站蜘蛛池模板: 韩国亚洲伊人久久综合影院| 亚洲性无码一区二区三区| 亚洲国产综合专区电影在线| 亚洲综合久久综合激情久久 | 成人免费视频网址| 日韩电影免费在线观看视频| 亚洲精品国自产拍在线观看| 亚洲色成人中文字幕网站| 久久久久亚洲精品日久生情| 亚洲国产成a人v在线观看 | 亚洲美国产亚洲AV| h视频在线观看免费| 日本中文字幕免费高清视频| 免费无码精品黄AV电影| 亚洲AV蜜桃永久无码精品| 亚洲av无码一区二区三区乱子伦 | 亚洲AV成人无码网天堂| yellow视频免费看| 久久青草91免费观看| 国产精品1024永久免费视频 | 免费在线观影网站| 国产成人精品免费午夜app| 色窝窝免费一区二区三区| 91久久精品国产免费一区| 99视频在线看观免费| 99在线热视频只有精品免费| 97免费人妻在线视频| 成人无码区免费A片视频WWW| 亚洲电影日韩精品| 亚洲国产香蕉碰碰人人| 国产91在线|亚洲| 免费夜色污私人影院网站| a国产成人免费视频| av无码久久久久不卡免费网站| 日韩一品在线播放视频一品免费| 亚洲国产精品成人AV无码久久综合影院| 在线观看亚洲av每日更新| 亚洲婷婷在线视频| 日亚毛片免费乱码不卡一区| 久操视频在线免费观看| 最近2019中文字幕mv免费看|