隨筆-348  評論-598  文章-0  trackbacks-0

          之前第一版有個問題,就是如果進行了刪除等操作并立即返回列表頁,被刪除的項還在那,但其實數據庫已經被刪除了,需要做一個刷新列表操作才可以,本版就是修正此問題的。
          如果要修正此問題,就需要將分頁的擴展代碼也就是第一版中TestBean中的代碼放入業務相關管理Bean中。

          頁面代碼(其中testBean已經變成業務Managed-bean user了):

              <f:view>
                  
          <h:form id="formlist">    
                      
          <rich:dataTable id="carList" width="483" columnClasses="col" rows="#{user.pageSize}"
                          value
          ="#{user.dataModel}" var="car">            
                          
          <f:facet name="header">
                              
          <rich:columnGroup>
                                  
          <h:column>
                                      
          <h:outputText styleClass="headerText" value="Name" />
                                  
          </h:column>
                                  
          <h:column>
                                      
          <h:outputText styleClass="headerText" value="Decription" />
                                  
          </h:column>
                                  
          <h:column>
                                      
          <h:outputText styleClass="headerText" value="Base Price" />
                                  
          </h:column>
                                  
          <h:column>
                                      
          <h:outputText styleClass="headerText" value="Time" />
                                  
          </h:column>
                                  
          <h:column>
                                      
          <h:outputText styleClass="headerText" value="操作" />
                                  
          </h:column>                        
                              
          </rich:columnGroup>
                          
          </f:facet>
              
                          
          <h:column>
                              
          <h:outputText value="#{car.name}" />
                          
          </h:column>
                          
          <h:column>
                              
          <h:outputText value="#{car.description}" />
                          
          </h:column>
                          
          <h:column>
                              
          <h:outputText value="#{car.baseprice}" />
                          
          </h:column>
                          
          <h:column>
                              
          <h:outputText value="#{car.timestamp}" />
                          
          </h:column>
                          
          <h:column>
                              
          <h:commandLink action="#{user.delete}" value="刪除" >
                                  
          <f:param name="id" value="#{car.id}"/>
                              
          </h:commandLink>
                          
          </h:column>                
                      
          </rich:dataTable>
                      
          <rich:datascroller for="carList" id="dc1"
                      style
          ="width:483px" page="#{user.scrollerPage}"/>                        
                  
          </h:form>
              
          </f:view>

          DataPage.java(沒有變化):
          import java.util.List;

          public class DataPage
          {

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


              
          private int datasetSize;

              
          private int startRow;

              
          private List data;

              
          /**
               * 
               * 
          @param datasetSize
               *            數據集大小
               * 
          @param startRow
               *            起始行
               * 
          @param data
               *            數據list
               
          */

              
          public DataPage(int datasetSize, int startRow, List data)
              
          {

                  
          this.datasetSize = datasetSize;

                  
          this.startRow = startRow;

                  
          this.data = data;

              }


              
          /**
               * 
               * 
          @return
               
          */

              
          public int getDatasetSize()
              
          {

                  
          return datasetSize;

              }


              
          public int getStartRow()
              
          {

                  
          return startRow;

              }


              
          /**
               * 
               * 
          @return 已填充好的數據集
               
          */

              
          public List getData()
              
          {

                  
          return data;

              }


          }


          PagedListDataModel.java(添加了一些注釋):

          import java.util.List;

          import javax.faces.model.DataModel;

          /**
           * 
           * TODO 分頁所使用的類

           * 
          @author <a href="mailto:tianlu@jsecode.com">TianLu</a>
           * 
          @version $Rev$ <br>
           *          $Id$
           
          */

          /* 使用方法:
           * 前臺的功能模塊Bean(例如User)中加入類似下面的代碼,可根據您的需要進行相應修改
           * private PagedListDataModel dataModel;
              private int pageSize = 10;
              public int getPageSize()
              {
                  return pageSize;
              }

              public PagedListDataModel getDataModel()
              {
                  
                  if ( dataModel == null ) {
                      dataModel = new PagedListDataModel(pageSize)
                      {
                          //查詢分頁函數
                          public DataPage fetchPage(int startRow, int pageSize)
                          {
                              // call enclosing managed bean method to fetch the data
                              CarBeanDAO dao = new CarBeanDAO();
                              String sql = "from CarBean model order by model.id desc";                
                              Query query = EntityManagerHelper.createQuery(sql);                    
                              query.setFirstResult(startRow);                    
                              query.setMaxResults(pageSize);                    
                              List list = query.getResultList();
                              System.out.println("current row count = " + list.size());
                              Query q = EntityManagerHelper.createQuery("select count(*) from CarBean");
                              return new DataPage(Integer.parseInt(q.getSingleResult().toString()), startRow, list);                    
                          }
                      };
                  }
                  
                  return dataModel;
              }
          */


          /* 前臺控件像這樣使用
           * <rich:dataTable id="carList" width="483" columnClasses="col" rows="#{user.pageSize}"
              value="#{user.dataModel}" var="car">            
              <f:facet name="header">
                  <rich:columnGroup>
                      <h:column>
                          <h:outputText styleClass="headerText" value="Name" />
                      </h:column>
                      <h:column>
                          <h:outputText styleClass="headerText" value="Decription" />
                      </h:column>
                      <h:column>
                          <h:outputText styleClass="headerText" value="Base Price" />
                      </h:column>
                      <h:column>
                          <h:outputText styleClass="headerText" value="Time" />
                      </h:column>
                      <h:column>
                          <h:outputText styleClass="headerText" value="操作" />
                      </h:column>                        
                  </rich:columnGroup>
              </f:facet>

              <h:column>
                  <h:outputText value="#{car.name}" />
              </h:column>
              <h:column>
                  <h:outputText value="#{car.description}" />
              </h:column>
              <h:column>
                  <h:outputText value="#{car.baseprice}" />
              </h:column>
              <h:column>
                  <h:outputText value="#{car.timestamp}" />
              </h:column>
              <h:column>
                  <h:commandLink action="#{user.delete}" value="刪除" >
                      <f:param name="id" value="#{car.id}"/>
                  </h:commandLink>
              </h:column>                
          </rich:dataTable>
          <rich:datascroller for="carList" id="dc1"
          style="width:483px" page="#{user.scrollerPage}"/>
          */


          /*
           * 進行刪除等操作后會立即改變列表項并且返回列表頁的,請調用本類的refresh方法刷新當前頁面
           * 使用方法:
           *             dao.delete(bean);
           *            dataModel.refresh();
           
          */

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

              
          /**
               * 進行刪除等操作后會立即改變列表項并且返回列表頁的,請調用此方法,用于刷新列表。
               
          */

              
          public void refresh() {
                  
          if (this.page != null{
                      
          this.page = null;
                      getPage();
                  }

              }

          }



          User中的delete方法:
              public String delete()
              
          {
                  FacesContext ctx 
          = FacesContext.getCurrentInstance();
                  
          int id = Integer.parseInt(ctx.getExternalContext().getRequestParameterMap().get("id"));
                  EntityManagerHelper.beginTransaction();
                  CarBeanDAO dao 
          = new CarBeanDAO();
                  CarBean bean 
          = dao.findById(id);
                  
          if(bean != null)
                  
          {            
                      dao.delete(bean);
                      dataModel.refresh();
                  }

                      
                  EntityManagerHelper.commit();
                  
          return null;
              }

          User中scrollerPage的相關代碼:
              private int scrollerPage = 1;

              
          public int getScrollerPage()
              
          {
                  
          return scrollerPage;
              }


              
          public void setScrollerPage(int scrollerPage)
              
          {
                  
          this.scrollerPage = scrollerPage;
                  System.out.println(
          "current page = " + scrollerPage);
              }

          Faces-config.xml:
           <managed-bean>
            
          <managed-bean-name>user</managed-bean-name>
            
          <managed-bean-class>com.gcoresoft.jsfdemo.bean.User</managed-bean-class>
            
          <managed-bean-scope>session</managed-bean-scope>
           
          </managed-bean>

          有人反映會出現獲取兩次DataModel的情況,為什么呢?
          經過我的測試,是因為設置的datatable的rows屬性的值大于了程序中pageSize的值,比如你設置rows="12",而你的pageSize設置的是10,那么JSF為了滿足顯示12條得條件,就會取兩次數據集組成一個12跳得數據集顯示出來,所以給定的rows屬性最好可以使用相關管理bean的pageSize變量,這樣前后臺統一數據條目,提高性能和可操作性。

          為了方便大家JSF的項目開發,后面我會推出一套我自己寫的一個基于JSF的框架,當然此框架是基于實際項目成功實施后提取出來的,主要是簡化了對表單的操作,增加一些常用的工具套件,例如分頁,驗證器等等。對表單操作部分的簡化主要體現在:每種控件都可以和固定的模型綁定,這樣操作模型就可以做到對前臺控件的控制,比如后臺取值可以使用attributes.get("username"),設置前臺控件值可以使用attributes.put("username","admin"),對選擇控件操作也更加簡便,當使用put的方法的時候,前臺會自動選擇到那項,更重要的是這些簡化不需要你寫程序代碼,寫一些簡單的配置文件即可,而且選擇項不僅可以設置在配置文件中,還可以通過數據庫等其他數據源獲取,大大提高開發效率。

          ---------------------------------------------------------
          專注移動開發

          Android, Windows Mobile, iPhone, J2ME, BlackBerry, Symbian
          posted on 2008-11-01 09:42 TiGERTiAN 閱讀(5581) 評論(13)  編輯  收藏 所屬分類: JavaJSF

          評論:
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-01 16:52 | 金山毒霸2008
          直接通過控件來翻頁不是很方便?  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-01 20:39 | TiGERTiAN
          @金山毒霸2008
          直接通過控件翻頁的確很方便,但是做正式的項目只要數據達到一定規模是不會這樣的,直接通過控件翻頁會將所有數據讀出然后丟入內存進行分頁計算操作等,如果你數據庫有100萬的數據,你可以試試看你的速度。。。  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) [未登錄] 2008-11-03 12:45 | FoxInSky
          請教樓主:
          <rich:datascroller for="carList" id="dc1"
          style="width:483px" page="#{user.scrollerPage}"/>
          分頁控件中的page綁定的代碼可以貼出來么?
          小弟剛接觸java不久,最近一個項目要使用到JSF,尤其dataTable這個,有些問題不太明白,希望能請教樓主!  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-03 19:54 | TiGERTiAN
          @FoxInSky
          文章已經重新編輯過了,把page綁定的相關代碼添加進來了,你看下,對你是否有幫助  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-04 14:16 | foxinsky
          我還需要向樓主請教這些問題:
          以前做C#時,我做類似樓主說的“按需取數”是這樣的:從數據庫中取出數據集所需要的數據記錄數,然后顯示給dataTable,
          比如數據庫中現在有1000條記錄,設置分頁10/頁,現在我需要取第2頁的數據,那么用
          select * from tablename where rownum>10 and rownum<=2*10
          查詢出來記錄(以oracle為例),然后將它保存至ArrayList中,將該ArrayList返回給DataModal以供DataTable綁定使用。

          查詢出來的記錄轉換為ArrayList的過程是否應在fetchData中進行?
          在樓主的上一篇博文的TestBean中的getDataModel方法里重寫的fetchData中的兩個參數(int startRow, int pageSize)在什么地方傳進去?我如何告知datascroller數據集中共有多少條記錄?在查詢的時候我如何知道當前是第幾頁?
          還煩請樓主多我指教!
            回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2008-11-04 19:47 | TiGERTiAN
          @foxinsky
          你可以看下PagedListDataModel.java的注釋
          需要自己實現fetchPage方法,這個方法何時被調用,你可以自己看下PagedListDataModel類,這個實現了JSF里面的一個數據模型,這個數據模型中,獲取數據的時候就是調用了fetchPage方法。
          你不需要告訴dataScroller控件有多少條數據,它不管的,它是和Datatable綁定的,它的作用只是負責翻頁和傳遞當前頁碼。
          還有就是查詢的時候你不需要知道當前是第幾頁,因為數據模型會自動調用fetchPage方法,而他只要知道起始行號,和你要取得數據,所以當前是多少頁你不需要關心,如果你想要得到當前是第幾頁,調用User中scrollerPage變量就可以了,因為它綁定了dataScroller的page屬性,可以設置或者獲得當前頁碼。  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2009-06-26 14:22 | dp
          if (rowIndex < startRow) {
          page = fetchPage(rowIndex, pageSize);
          startRow = page.getStartRow();
          } else if (rowIndex >= endRow) {
          page = fetchPage(rowIndex, pageSize);
          startRow = page.getStartRow();
          }

          樓主,你寫的這段是不是可以直接寫成下面這樣呢;
          page = fetchPage(rowIndex, pageSize);
          startRow = page.getStartRow();
          因為,你的if...else if兩個里面執行的都是一樣的,為什么要加個條件判斷呢?  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) [未登錄] 2009-08-05 14:10 | sam
          為什么我的查詢結果為空的時候報異常, return page.getData().get(rowIndex - startRow);理論上不應該運行到這里的啊  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2009-08-05 14:21 | TiGERTiAN
          @sam
          不會啊,你debug一下呢
            回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2009-09-02 17:23 | x800xl
          datasetSize每一次調用 都 要在數據庫里邊查詢一次,需要把datasetSize的值在pageListDataModel中保存
            回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2009-09-02 17:25 | x800xl
          修改后的代碼:
          public abstract class PageListDataModel extends DataModel {

          int pageSize;
          int rowIndex;
          DataPage page;

          /**
          * 抽像獲取一頁數據方法,由子類實現
          * */
          public abstract DataPage fetchPage(int dataSize,int startRow, int pageSize);

          public PageListDataModel(int pageSize) {
          super();
          this.pageSize = pageSize;
          this.rowIndex = -1;
          this.page = null;
          }

          public int getPageSize() {
          return pageSize;
          }

          public void setPageSize(int pageSize) {
          this.pageSize = pageSize;
          }

          public DataPage getPage() {
          int dataSize = 0;
          if(null !=this.page) {
          dataSize = this.page.getDataSize();
          return this.page;
          }
          int rowIndex = this.getRowIndex();
          int startRow = rowIndex;
          if(rowIndex == -1) {
          startRow = 0;
          }
          return fetchPage(dataSize,startRow, pageSize);
          }

          public void setPage(DataPage page) {
          this.page = page;
          }

          @Override
          public int getRowCount() {
          return this.getPage().getDataSize();
          }

          @Override
          public Object getRowData() {
          if(rowIndex <0) {
          throw new IllegalArgumentException("Invalid rowIndex for PagedListDataModel; not within page");
          }
          if(null == page) {
          page = fetchPage(0,rowIndex, pageSize);
          }
          int dataSize = page.getDataSize();
          int startRow = page.getStartRow();
          int nRows = page.getData().size();
          int endRow = startRow + nRows;
          if(rowIndex >= dataSize) {
          throw new IllegalArgumentException(" Invalid rowIndex ");
          }
          if(rowIndex < startRow) {
          page = fetchPage(dataSize,rowIndex, pageSize);
          startRow = page.getStartRow();
          }else if (rowIndex >= endRow) {
          page = fetchPage(dataSize,rowIndex, pageSize);
          startRow = page.getStartRow();
          }
          return page.getData().get(rowIndex - startRow);
          }

          @Override
          public int getRowIndex() {
          return this.rowIndex;
          }

          @Override
          public Object getWrappedData() {
          return page.getData();
          }

          @Override
          public boolean isRowAvailable() {
          DataPage page = getPage();
          if (page == null) {
          return false;
          }
          int rowIndex = getRowIndex();
          if (rowIndex < 0) {
          return false;
          } else if (rowIndex >= page.getDataSize()) {
          return false;
          } else {
          return true;
          }
          }

          @Override
          public void setRowIndex(int rowIndex) {
          this.rowIndex = rowIndex;
          }

          @Override
          public void setWrappedData(Object o) {
          if (o instanceof DataPage) {
          this.page = (DataPage)o;
          }else {
          throw new UnsupportedOperationException("setWrappedData");
          }
          }

          public void refresh() {
          if (null !=this.page) {
          this.page = null;
          getPage();
          }
          }
            回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) [未登錄] 2010-05-22 18:03 | gary
          這個分頁組件,在表頭排序的時候會查詢多次  回復  更多評論
            
          # re: 【第二版】RichFaces中使用datatable和datascroller進行分頁(使用數據庫分頁,改良版)(含源碼)(JSF 1.2,RichFaces 3.2.1GA) 2011-04-09 16:40 | 救學
          請問,按你這樣子的做法,為什么點翻頁沒有反應呢。打開源碼,翻頁是javascript:void())  回復  更多評論
            
          主站蜘蛛池模板: 麻阳| 乐亭县| 建瓯市| 营山县| 瑞金市| 丰县| 东乡县| 宁晋县| 双鸭山市| 镇雄县| 五大连池市| 五华县| 延庆县| 墨江| 正定县| 乌苏市| 油尖旺区| 新源县| 连平县| 兴国县| 保德县| 邮箱| 环江| 商丘市| 潜山县| 屯门区| 安丘市| 吐鲁番市| 天等县| 舟山市| 东莞市| 怀仁县| 汉川市| 那曲县| 宁化县| 青岛市| 泰和县| 孝昌县| 谷城县| 灌阳县| 乌拉特中旗|