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

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

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

    Java學(xué)習(xí)

    java,spring,structs,hibernate,jsf,ireport,jfreechart,jasperreport,tomcat,jboss -----本博客已經(jīng)搬家了,新的地址是 http://www.javaly.cn 如果有對文章有任何疑問或者有任何不懂的地方,歡迎到www.javaly.cn (Java樂園)指出,我會盡力幫助解決。一起進(jìn)步

     

    在JSF中實現(xiàn)分頁(二)

    zhuan(http://www.steadyxp.com/archives/187.html)

    前面一篇直接使用了Myfaces中的兩個Component完成了一個簡單的分頁,這里將會介紹一種On-demand loading的方法來進(jìn)行分頁,僅僅在需要數(shù)據(jù)的時候加載。

         先來說一些題外話,為了實現(xiàn)這種方式的分頁,公司里大約5-6個人做了半個多月的工作,擴展了dataTable,修改了dataScrollor,以及 各種其他的方法,但是都不是很優(yōu)雅。在上個月底的時候,在Myfaces的Mail List中也針對這個問題展開了一系列的討論,最后有人總結(jié)了討論中提出的比較好的方法,提出了以下的分頁方法,也是目前實現(xiàn)的最為優(yōu)雅的方法,也就是不 對dataTable和dataScrollor做任何修改,僅僅通過擴展DataModel來實現(xiàn)分頁。

         DataModel 是一個抽象類,用于封裝各種類型的數(shù)據(jù)源和數(shù)據(jù)對象的訪問,JSF中dataTable中綁定的數(shù)據(jù)實際上被包裝成了一個DataModel,以消除各種 不同數(shù)據(jù)源和數(shù)據(jù)類型的復(fù)雜性,在前面一篇中我們訪問數(shù)據(jù)庫并拿到了一個List,交給dataTable,這時候,JSF會將這個List包裝成 ListDataModel ,dataTable訪問數(shù)據(jù)都是通過這個DataModel進(jìn)行的,而不是直接使用List。

         接下來我們要將需要的頁的數(shù)據(jù)封裝到一個DataPage中去,這個類表示了我們需要的一頁的數(shù)據(jù),里面包含有三個元 素:datasetSize,startRow,和一個用于表示具體數(shù)據(jù)的List。datasetSize表示了這個記錄集的總條數(shù),查詢數(shù)據(jù)的時候, 使用同樣的條件取count即可,startRow表示該頁的起始行在數(shù)據(jù)庫中所有記錄集中的位置。

     

    /**
     * A simple class that represents a “page” of data out of a longer set, ie a
     * list of objects together with info to indicate the starting row and the full
     * size of the dataset. EJBs can return instances of this type when returning
     * subsets of available data.
      */
     public   class  DataPage
      {
         private   int  datasetSize;
         private   int  startRow;
         private  List data;

       /**
         * Create an object representing a sublist of a dataset.
         *
         *  @param  datasetSize
         *            is the total number of matching rows available.
         *
         *  @param  startRow
         *            is the index within the complete dataset of the first element
         *            in the data list.
         *
         *  @param  data
         *            is a list of consecutive objects from the dataset.
         */
         public  DataPage( int  datasetSize,  int  startRow, List data)
          {
             this .datasetSize  =  datasetSize;
             this .startRow  =  startRow;
             this .data  =  data;
        }
     
        /**
         * Return the number of items in the full dataset.
         */
         public   int  getDatasetSize()
          {
             return  datasetSize;
        }
     
        /**
         * Return the offset within the full dataset of the first element in the
         * list held by this object.
         */
         public   int  getStartRow()
          {
             return  startRow;
        }
     
        /**
         * Return the list of objects held by this object, which is a continuous
         * subset of the full dataset.
         */
         public  List getData()
          {
             return  data;
        }
    }

         接下來,我們要對DataModel進(jìn)行封裝,達(dá)到我們分頁的要求。該DataModel僅僅持有了一頁的數(shù)據(jù)DataPage,并在適當(dāng)?shù)臅r候加載數(shù)據(jù),讀取我們需要頁的數(shù)據(jù)。
    /**
     * A special type of JSF DataModel to allow a datatable and datascroller to page
     * through a large set of data without having to hold the entire set of data in
     * memory at once.
     * <p>
     * Any time a managed bean wants to avoid holding an entire dataset, the managed
     * bean should declare an inner class which extends this class and implements
     * the fetchData method. This method is called as needed when the table requires
     * data that isn’t available in the current data page held by this object.
     * <p>
     * This does require the managed bean (and in general the business method that
     * the managed bean uses) to provide the data wrapped in a DataPage object that
     * provides info on the full size of the dataset.
      */
     public   abstract   class  PagedListDataModel  extends  DataModel
      {
         int  pageSize;
         int  rowIndex;
        DataPage page;

       /**
         * Create a datamodel that pages through the data showing the specified
         * number of rows on each page.
         */
         public  PagedListDataModel( int  pageSize)
          {
             super ();
             this .pageSize  =  pageSize;
             this .rowIndex  =   - 1 ;
             this .page  =   null ;
        }
     
        /**
         * Not used in this class; data is fetched via a callback to the fetchData
         * method rather than by explicitly assigning a list.
         */
     
         public   void  setWrappedData(Object o)
          {
             if (o  instanceof  DataPage)
              {
                 this .page  =  (DataPage) o;
            }
             else
               {
                 throw   new  UnsupportedOperationException( ” setWrappedData ” );
            }
        }
     
         public   int  getRowIndex()
          {
             return  rowIndex;
        }
     
        /**
         * Specify what the “current row” within the dataset is. Note that the
         * UIData component will repeatedly call this method followed by getRowData
         * to obtain the objects to render in the table.
         */
     
         public   void  setRowIndex( int  index)
          {
            rowIndex  =  index;
        }
     
        /**
         * Return the total number of rows of data available (not just the number of
         * rows in the current page!).
         */
     
         public   int  getRowCount()
          {
             return  getPage().getDatasetSize();
        }
     
        /**
         * Return a DataPage object; if one is not currently available then fetch
         * one. Note that this doesn’t ensure that the datapage returned includes
         * the current rowIndex row; see getRowData.
         */
         private  DataPage getPage()
          {
             if  (page  !=   null )
              {
                 return  page;
            }
     
             int  rowIndex  =  getRowIndex();
             int  startRow  =  rowIndex;
             if  (rowIndex  ==   - 1 )
              {
                 //  even when no row is selected, we still need a page
                 //  object so that we know the amount of data available.
                 startRow  =   0 ;
            }
     
             //  invoke method on enclosing class
             page  =  fetchPage(startRow, pageSize);
             return  page;
        }
     
        /**
         * Return the object corresponding to the current rowIndex. If the DataPage
         * object currently cached doesn’t include that index then fetchPage is
         * called to retrieve the appropriate page.
         */
     
         public  Object getRowData()
          {
             if  (rowIndex  <   0 )
              {
                 throw   new  IllegalArgumentException(
                         ” Invalid rowIndex for PagedListDataModel; not within page ” );
            }
     
             //  ensure page exists; if rowIndex is beyond dataset size, then
             //  we should still get back a DataPage object with the dataset size
             //  in it
              if  (page  ==   null )
              {
                page  =  fetchPage(rowIndex, pageSize);
            }
     
             int  datasetSize  =  page.getDatasetSize();
             int  startRow  =  page.getStartRow();
             int  nRows  =  page.getData().size();
             int  endRow  =  startRow  +  nRows;

             if  (rowIndex  >=  datasetSize)
              {
                 throw   new  IllegalArgumentException( ” Invalid rowIndex ” );
            }
     
             if  (rowIndex  <  startRow)
              {
                page  =  fetchPage(rowIndex, pageSize);
                startRow  =  page.getStartRow();
            }
             else   if  (rowIndex  >=  endRow)
              {
                page  =  fetchPage(rowIndex, pageSize);
                startRow  =  page.getStartRow();
            }
             return  page.getData().get(rowIndex  -  startRow);
        }
     
         public  Object getWrappedData()
          {
             return  page.getData();
        }
     
        /**
         * Return true if the rowIndex value is currently set to a value that
         * matches some element in the dataset. Note that it may match a row that is
         * not in the currently cached DataPage; if so then when getRowData is
         * called the required DataPage will be fetched by calling fetchData.
         */
     
         public   boolean  isRowAvailable()
          {
            DataPage page  =  getPage();
             if  (page  ==   null )
              {
                 return   false ;
            }
     
             int  rowIndex  =  getRowIndex();
             if  (rowIndex  <   0 )
              {
                 return   false ;
            }
             else   if  (rowIndex  >=  page.getDatasetSize())
              {
                 return   false ;
            }
             else
               {
                 return   true ;
            }
        }
     
        /**
         * Method which must be implemented in cooperation with the managed bean
         * class to fetch data on demand.
         */
         public   abstract  DataPage fetchPage( int  startRow,  int  pageSize);
       
    }

         最后,我們需要在Backing Bean中加一些東西,調(diào)用業(yè)務(wù)邏輯,并將數(shù)據(jù)交給PagedListDataModel,來幫我們完成最后的分頁工作。

     

         public  SomeManagedBean   {
        .
         private  DataPage getDataPage( int  startRow,  int  pageSize)   {
           //  access database here, or call EJB to do so
         }
     
          public  DataModel getDataModel()   {
             if  (dataModel  ==   null )   {
                dataModel  =   new  LocalDataModel(20);
            }
     
             return  dataModel;
        }
     
          private   class  LocalDataModel  extends  PagedListDataModel   {
             public  LocalDataModel( int  pageSize)   {
                 super (pageSize);
            }
           
             public  DataPage fetchPage( int  startRow,  int  pageSize)   {
                 //  call enclosing managed bean method to fetch the data
                  return  getDataPage(startRow, pageSize);
            }
    }

     

    這里面有一個getDataPage的方法,只需要把所有業(yè)務(wù)邏輯的調(diào)用放在這里就可以了,最后業(yè)務(wù)邏輯調(diào)用的結(jié)果返回一個List,總條數(shù)返回一個int型的count放到DataPage中去就可以了。

    為了實現(xiàn)復(fù)用,把上面第三段的代碼中的LocalDataModel類和getDataPage方法抽到BasePagedBackingBean中,把getDataPage方法改成:

    protected abstract DataPage getDataPage(int startRow, int pageSize);

    這樣我們把所有需要分頁的Backing Bean繼承自這個抽象類,并實現(xiàn)getDataPage方法即可很容易的實現(xiàn)分頁。

     

       在具體應(yīng)用中可以這么寫:

     

          protected  DataPage getDataPage( int  startRow,  int  pageSize)
          {
            List scheduleList  =  scheduleService.getSchedulesByDate(scheduleDate, startRow, pageSize);
             int  dataSetSize  =  scheduleService.getSchedulesCountByDate(scheduleDate);
             return   new  DataPage(dataSetSize, startRow, scheduleList);
        }
     

     

    在數(shù)據(jù)訪問中,我們只需要取出我們需要行數(shù)的記錄就可以了,這在hibernate中非常容易實現(xiàn)。

    如果使用Criteria查詢的話,只要加上:

         criteria.setFirstResult(startRow);

         criteria.setMaxResults(pageSize);

    使用Query查詢的話,只要加上

         query.setFirstResult(startRow);

         query.setMaxResults(pageSize);

    并把兩個參數(shù)傳入即可。

    我們還需要另外寫一個Count的DAO,取出相同查詢條件的記錄條數(shù)即可。

    還要修改一下Backing Bean中與dataTable綁定的property,將返回類型由List改成DataModel,而第一篇中用到的頁面不需要做任何修改就可以滿足新的需求了。

    里面最重要的是 PagedListDataModel 中 fetchPage 這個方法,當(dāng)滿足取數(shù)據(jù)的條件時,都會調(diào)用它取數(shù)據(jù),因為業(yè)務(wù)邏輯不同,不便于將業(yè)務(wù)邏輯的調(diào)用放在里面實現(xiàn),于是將其作為抽象方法,將具體的實現(xiàn)放到具 體的Backing Bean中進(jìn)行,在BaseBackingBean中,實現(xiàn)了這個方法,調(diào)用了getDataPage(startRow, pageSize)這個方法,而在BaseBackingBean中,這個方法又推遲到更具體的頁面中實現(xiàn),這樣,我們在具體的頁面中只需要實現(xiàn)一個 getDataPage(startRow, pageSize)這個方法訪問業(yè)務(wù)邏輯。

    大功告成,這個實現(xiàn)把前面遇到的兩個問題都解決了, On-demand loading 是沒有問題了,因為只有在首次讀取和換頁的時候DataModel才會向數(shù)據(jù)庫請求數(shù)據(jù),雖然在JSF的生命周期中多次調(diào)用與dataTable綁定的方 法,但是因為每次業(yè)務(wù)邏輯請求以后,數(shù)據(jù)都會存放在DataPage中,如果里面的數(shù)據(jù)滿足需求的話,就不再請求訪問數(shù)據(jù)庫,這樣多次訪問數(shù)據(jù)庫的問題也 解決了。

    雖然這樣的話,dataScrollor的Tag使用起來還是很復(fù)雜,通常在同一個項目中,我們只會使用一種樣式的分頁導(dǎo)航,不過沒關(guān)系,我們只需 要修改以下DataScrollor的Render Kit,把一些可以定義的值固定下來,再定義一個TLD文件,就可以在項目中使用簡化版的Tag了。

    這個方法一開始發(fā)布在Myfaces的Wiki中,http://wiki.apache.org/myfaces/WorkingWithLargeTables,那里很少有人關(guān)注到,大家有興趣可以看看原文,本文只是對這種方法做一些簡單的介紹,并非自創(chuàng),希望大家能夠多多關(guān)注開源社區(qū),因為那里有最新最好的東西。

    從Nightly Build服務(wù)器中拿到的12.27的Myfaces包,發(fā)現(xiàn)里面擴充了很多新的Component,只是并沒有正式發(fā)布,大家有興趣的話可以研究研究。

    posted on 2009-03-09 15:48 找個美女做老婆 閱讀(199) 評論(0)  編輯  收藏


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     

    導(dǎo)航

    統(tǒng)計

    公告

    本blog已經(jīng)搬到新家了, 新家:www.javaly.cn
     http://www.javaly.cn

    常用鏈接

    留言簿(6)

    隨筆檔案

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲一日韩欧美中文字幕在线 | 久久久久免费视频| 男女作爱免费网站| 国产黄在线播放免费观看| 久久中文字幕免费视频| 成人毛片18女人毛片免费96 | 精品国产免费观看一区| 亚洲精品tv久久久久| 亚洲国产精品久久久久久| 亚洲欧美成aⅴ人在线观看| 中文字幕av免费专区| 亚洲色中文字幕无码AV| 亚洲国产美女精品久久| 一级做a爱过程免费视| 免费下载成人电影| 亚洲精品无码你懂的网站| 七次郎成人免费线路视频| 久久精品夜色噜噜亚洲A∨| 亚洲精品伦理熟女国产一区二区 | 亚洲GV天堂无码男同在线观看| 好男人www免费高清视频在线| 亚洲va无码专区国产乱码| 亚洲精品乱码久久久久久蜜桃图片| 成人免费a级毛片无码网站入口| 亚洲精品第一国产综合精品99| 国产精品免费久久久久电影网| 国产AV无码专区亚洲AV男同 | 一级特黄a免费大片| 亚洲精品卡2卡3卡4卡5卡区| 免费无毒a网站在线观看| 在线a亚洲v天堂网2019无码| 色吊丝免费观看网站| 在线a毛片免费视频观看| 国产亚洲视频在线观看| 永久中文字幕免费视频网站| 又硬又粗又长又爽免费看 | 国外亚洲成AV人片在线观看 | 国产92成人精品视频免费| 久久精品国产亚洲| 在线观看免费人成视频色9| 亚洲一区无码中文字幕乱码|