`

JSF 中处理分页问题

    博客分类:
  • JSF
阅读更多

WorkingWithLargeTables

本文转自http://wiki.apache.org/myfaces/WorkingWithLargeTables,由于该文最后一部分没有jsp代码部分,所有又加上了一些jsp代码。

Components t:dataModel and t:dataScroller work together nicely to allow a user to "page" through a set of a few dozen to a few hundred records. However the implementation does assume that the entire set of available records are in memory and wrapped up inside a ListDataModel or ArrayDataModel.

When the available dataset is quite large, and the application can have many users, this can lead to memory usage problems.

This page contains discussions on how to handle this scenario.

On-demand loading

A custom DataModel can be used to allow data to be loaded "on demand".

First, a class needs to be defined which your "business methods" (eg EJBs) can use to pass "pages" of data back to the UI. This class needs to be defined in your project, as the "business" level shouldn't be extending MyFaces classes:

  1. package example;   
  2.   
  3. import java.util.List;   
  4.   
  5. /**  
  6.  * A simple class that represents a "page" of data out of a longer set, ie  
  7.  * a list of objects together with info to indicate the starting row and  
  8.  * the full size of the dataset. EJBs can return instances of this type  
  9.  * when returning subsets of available data.  
  10.  */  
  11. public class DataPage<t></t> {   
  12.   
  13.   private int datasetSize;   
  14.   private int startRow;   
  15.   private List<t></t> data;   
  16.            
  17.   /**  
  18.    * Create an object representing a sublist of a dataset.  
  19.    *   
  20.    * @param datasetSize is the total number of matching rows  
  21.    * available.  
  22.    *   
  23.    * @param startRow is the index within the complete dataset  
  24.    * of the first element in the data list.  
  25.    *   
  26.    * @param data is a list of consecutive objects from the  
  27.    * dataset.  
  28.    */  
  29.   public DataPage(int datasetSize, int startRow, List<t></t> data) {   
  30.     this.datasetSize = datasetSize;   
  31.     this.startRow = startRow;   
  32.     this.data = data;   
  33.   }   
  34.   
  35.   /**  
  36.    * Return the number of items in the full dataset.  
  37.    */  
  38.   public int getDatasetSize() {   
  39.     return datasetSize;   
  40.   }   
  41.   
  42.   /**  
  43.    * Return the offset within the full dataset of the first  
  44.    * element in the list held by this object.  
  45.    */  
  46.   public int getStartRow() {   
  47.     return startRow;   
  48.   }   
  49.   
  50.   /**  
  51.    * Return the list of objects held by this object, which  
  52.    * is a continuous subset of the full dataset.  
  53.    */  
  54.   public List<t></t> getData() {   
  55.     return data;   
  56.   }   
  57. }   

Now a custom DataModel can use this DataPage stuff. Again, it is recommended that you copy this code into your project and change the package name appropriately. This class can't go in the MyFaces libraries as it depends on DataPage, and as noted above, DataPage is accessed by your business level code so it really can't be in the MyFaces libs:

  1. package example;   
  2.   
  3. import javax.faces.model.DataModel;   
  4.   
  5. import example.DataPage;   
  6.   
  7. /**  
  8.  * A special type of JSF DataModel to allow a datatable and datascroller  
  9.  * to page through a large set of data without having to hold the entire  
  10.  * set of data in memory at once.  
  11.  * 

     

     
  12.  * Any time a managed bean wants to avoid holding an entire dataset,  
  13.  * the managed bean should declare an inner class which extends this  
  14.  * class and implements the fetchData method. This method is called  
  15.  * as needed when the table requires data that isn't available in the  
  16.  * current data page held by this object.  
  17.  * 

     

     
  18.  * This does require the managed bean (and in general the business  
  19.  * method that the managed bean uses) to provide the data wrapped in  
  20.  * a DataPage object that provides info on the full size of the dataset.  
  21.  */  
  22. public abstract class PagedListDataModel<t></t> extends DataModel {   
  23.   
  24.     int pageSize;   
  25.     int rowIndex;   
  26.     DataPage<t></t> page;   
  27.        
  28.     /*  
  29.      * Create a datamodel that pages through the data showing the specified  
  30.      * number of rows on each page.  
  31.      */  
  32.     public PagedListDataModel(int pageSize) {   
  33.         super();   
  34.         this.pageSize = pageSize;   
  35.         this.rowIndex = -1;   
  36.         this.page = null;   
  37.     }   
  38.   
  39.     /**  
  40.      * Not used in this class; data is fetched via a callback to the  
  41.      * fetchData method rather than by explicitly assigning a list.  
  42.      */  
  43.     @Override  
  44.     public void setWrappedData(Object o) {   
  45.         throw new UnsupportedOperationException("setWrappedData");   
  46.     }   
  47.   
  48.     @Override  
  49.     public int getRowIndex() {   
  50.         return rowIndex;   
  51.     }   
  52.   
  53.     /**  
  54.      * Specify what the "current row" within the dataset is. Note that  
  55.      * the UIData component will repeatedly call this method followed  
  56.      * by getRowData to obtain the objects to render in the table.  
  57.      */  
  58.     @Override  
  59.     public void setRowIndex(int index) {   
  60.         rowIndex = index;   
  61.     }   
  62.   
  63.     /**  
  64.      * Return the total number of rows of data available (not just the  
  65.      * number of rows in the current page!).  
  66.      */  
  67.     @Override  
  68.     public int getRowCount() {   
  69.         return getPage().getDatasetSize();   
  70.     }   
  71.        
  72.     /**  
  73.      * Return a DataPage object; if one is not currently available then  
  74.      * fetch one. Note that this doesn't ensure that the datapage  
  75.      * returned includes the current rowIndex row; see getRowData.  
  76.      */  
  77.     private DataPage<t></t> getPage() {   
  78.         if (page != null)   
  79.             return page;   
  80.            
  81.         int rowIndex = getRowIndex();   
  82.         int startRow = rowIndex;   
  83.         if (rowIndex == -1) {   
  84.             // even when no row is selected, we still need a page   
  85.             // object so that we know the amount of data available.   
  86.            startRow = 0;   
  87.         }   
  88.   
  89.         // invoke method on enclosing class   
  90.         page = fetchPage(startRow, pageSize);   
  91.         return page;   
  92.     }   
  93.   
  94.     /**  
  95.      * Return the object corresponding to the current rowIndex.  
  96.      * If the DataPage object currently cached doesn't include that  
  97.      * index then fetchPage is called to retrieve the appropriate page.  
  98.      */  
  99.     @Override  
  100.     public Object getRowData(){   
  101.         if (rowIndex < 0) {   
  102.             throw new IllegalArgumentException(   
  103.                 "Invalid rowIndex for PagedListDataModel; not within page");   
  104.         }   
  105.   
  106.         // ensure page exists; if rowIndex is beyond dataset size, then    
  107.         // we should still get back a DataPage object with the dataset size   
  108.         // in it...   
  109.         if (page == null) {   
  110.             page = fetchPage(rowIndex, pageSize);   
  111.         }   
  112.   
  113.         // Check if rowIndex is equal to startRow,   
  114.         // useful for dynamic sorting on pages   
  115.                    
  116.         if (rowIndex == page.getStartRow()){   
  117.                 page = fetchPage(rowIndex, pageSize);   
  118.         }   
  119.   
  120.         int datasetSize = page.getDatasetSize();   
  121.         int startRow = page.getStartRow();   
  122.         int nRows = page.getData().size();   
  123.         int endRow = startRow + nRows;   
  124.            
  125.         if (rowIndex >= datasetSize) {   
  126.             throw new IllegalArgumentException("Invalid rowIndex");   
  127.         }   
  128.            
  129.         if (rowIndex < startRow) {   
  130.             page = fetchPage(rowIndex, pageSize);   
  131.             startRow = page.getStartRow();   
  132.         } else if (rowIndex >= endRow) {   
  133.             page = fetchPage(rowIndex, pageSize);   
  134.             startRow = page.getStartRow();   
  135.         }   
  136.            
  137.         return page.getData().get(rowIndex - startRow);   
  138.     }   
  139.   
  140.     @Override  
  141.     public Object getWrappedData() {   
  142.         return page.getData();   
  143.     }   
  144.   
  145.     /**  
  146.      * Return true if the rowIndex value is currently set to a  
  147.      * value that matches some element in the dataset. Note that  
  148.      * it may match a row that is not in the currently cached   
  149.      * DataPage; if so then when getRowData is called the  
  150.      * required DataPage will be fetched by calling fetchData.  
  151.      */  
  152.     @Override  
  153.     public boolean isRowAvailable() {   
  154.         DataPage<t></t> page = getPage();   
  155.         if (page == null)   
  156.             return false;   
  157.            
  158.         int rowIndex = getRowIndex();   
  159.         if (rowIndex < 0) {   
  160.             return false;   
  161.         } else if (rowIndex >= page.getDatasetSize()) {   
  162.             return false;   
  163.         } else {   
  164.             return true;   
  165.         }   
  166.     }   
  167.   
  168.     /**  
  169.      * Method which must be implemented in cooperation with the  
  170.      * managed bean class to fetch data on demand.  
  171.      */  
  172.     public abstract DataPage<t></t> fetchPage(int startRow, int pageSize);   
  173. }   

Finally, the managed bean needs to provide a simple inner class that provides the fetchPage implementation:

java 代码
  1. public SomeManagedBean {   
  2.    ....   
  3.   
  4.   
  5.    private DataPage<somerowobject></somerowobject> getDataPage(int startRow, int pageSize) {   
  6.      // access database here, or call EJB to do so   
  7.    }   
  8.   
  9.    public DataModel getDataModel() {   
  10.        if (dataModel == null) {   
  11.            dataModel = new LocalDataModel(getRowsPerPage());   
  12.        }   
  13.   
  14.        return dataModel;   
  15.    }   
  16.   
  17.    private class LocalDataModel extends PagedListDataModel {   
  18.        public LocalDataModel(int pageSize) {   
  19.            super(pageSize);   
  20.        }   
  21.           
  22.        public DataPage<somerowobject></somerowobject> fetchPage(int startRow, int pageSize) {   
  23.            // call enclosing managed bean method to fetch the data   
  24.            return getDataPage(startRow, pageSize);   
  25.        }   
  26.    }   

The jsp pages should be like this:

     

  1.   
  2. public class PagedTableListBean {   
  3.   
  4.     private DataModel pagedDataModel;   
  5.   
  6.     private TableListBean listBean;   
  7.   
  8.     /**  
  9.      *   
  10.      */  
  11.     public PagedTableListBean() {   
  12.   
  13.     }   
  14.   
  15.     /**  
  16.      * @return the itemList  
  17.      */  
  18.     public DataModel getItemList() {   
  19.         if (pagedDataModel == null) {   
  20.             pagedDataModel = new LocalDataModel(15);   
  21.         }   
  22.   
  23.         return pagedDataModel;   
  24.     }   
  25.   
  26.     /**  
  27.      * @return the pagedDataModel  
  28.      */  
  29.     public DataModel getPagedDataModel() {   
  30.         return pagedDataModel;   
  31.     }   
  32.   
  33.     /**  
  34.      * @param pagedDataModel  
  35.      *            the pagedDataModel to set  
  36.      */  
  37.     public void setPagedDataModel(DataModel pagedDataModel) {   
  38.         this.pagedDataModel = pagedDataModel;   
  39.     }   
  40.   
  41.     /**  
  42.      * @return the listBean  
  43.      */  
  44.     public TableListBean getListBean() {   
  45.         return listBean;   
  46.     }   
  47.   
  48.     /**  
  49.      * @param listBean  
  50.      *            the listBean to set  
  51.      */  
  52.     public void setListBean(TableListBean listBean) {   
  53.         this.listBean = listBean;   
  54.     }   
  55.   
  56.     // local class   
  57.     private class LocalDataModel extends PagedListDataModel {   
  58.         public LocalDataModel(int pageSize) {   
  59.             super(pageSize);   
  60.         }   
  61.   
  62.         public DataPage fetchPage(int startRow, int pageSize) {   
  63.             // call enclosing managed bean method to fetch the data   
  64.             return getDataPage(startRow, pageSize);   
  65.         }   
  66.     }   
  67.   
  68.     // get datePage from DAO   
  69.     private DataPage getDataPage(int startRow, int pageSize) {   
  70.         // access database here, or call EJB to do so   
  71.        
  72.         List subList = listBean.getTableList(startRow, pageSize);   
  73.         DataPage dataPage = new DataPage(listBean.getTotal(), startRow, subList);   
  74.         return dataPage;   
  75.     }   
  76.   
  77. }   

页面的绑定:

  1. <hx:dataTableEx id="tableEx1" value="#{pagedTableListBean.itemList}"  
  2.                 var="vartableList" styleClass="dataTableEx" headerClass="headerClass"  
  3.                 footerClass="footerClass" rowClasses="rowClass1, rowClass2"  
  4.                 columnClasses="columnClass1" border="1" cellpadding="2"  
  5.                 cellspacing="0" rows="15">  
分享到:
评论
5 楼 sunyson 2008-03-21  
引用
我是利用起始行和每页多少行来显示一页的数据的
现在我如果把管理页面4 的支撑bean 其Scope设为request时,另用一个属性变量来获取每页的一个first行并用session保侟,在getDataPage时再来check该变量,如果有时则获取的数据将从first行开始,这样的实现效果是可以,可是总要慢一个节拍,在经过...


DataPage getDataPage(startRow, pageSize); 中的startRow 和pageSize可以通过 <hx:dataTableEx id="tableEx1" value="#{pagedTableListBean.itemList}"   binding="table"...>
中的table获取相关参数
table 在ManagerBean中定义为UIDataTable
table.getFirst(), table.getRows
4 楼 hintcnuie 2008-03-09  
这个问题好像是JSF的生命周期中出问题了,具体原因忘记了,你逐步debug一下会看出。后来我们套用seam的pagescope,就把这个问题解决了,不过这一部分不是我具体做的,所以我也说不很清楚,只能给你个思路了,呵呵。
3 楼 fangbiao23 2008-03-07  
我是利用起始行和每页多少行来显示一页的数据的
现在我如果把管理页面4 的支撑bean 其Scope设为request时,另用一个属性变量来获取每页的一个first行并用session保侟,在getDataPage时再来check该变量,如果有时则获取的数据将从first行开始,这样的实现效果是可以,可是总要慢一个节拍,在经过
现在在管理页面4-->>通过修改操作-->>返回管理页面按钮--返回管理页面4
后,其管理页面4显示的数据是页面1的数据,如果此时我再去单击datatable上的任可一个按钮时将显示正确的(管理页面4),这好像就是一个响应慢一拍的感觉,请给予帮助?

现在我如果把管理页面4 的支撑bean 其Scope设为session时,另用一个属性变量来获取每页的一个first行并用session保侟,在getDataPage时再来check该变量,如果有时则获取的数据将从first行开始,这样的实现效果是可以,但是好像一旦有新的数据加进去后,不能及时显示出来,这是非常不好的地方,好像dataPage的数据被缓存了一样,真是奇怪,请给予帮助,谢谢

这两种方式都有一些小毛病,能否把你的实现思路说一下吗?谢谢

2 楼 hintcnuie 2008-03-07  
这个问题遇到过,解决办法就是记住页码,等到修改完成的时候再根据这个页码分页。
1 楼 fangbiao23 2008-03-04  
朋友,如果要做到
现在在管理页面4-->>通过修改操作-->>返回管理页面按钮--返回管理页面4
用了你楼上的那种方式后要怎么做到这种效果?

相关推荐

    jsf分页 jsf分页 jsf分页

    以PrimeFaces为例,`p:dataTable`组件自带了分页功能,只需配置`rows`属性(每页记录数)和`paginator`属性(启用分页),它会自动处理分页的前后端逻辑。 4. **自定义分页**: 如果组件库提供的分页功能不能满足...

    jsf自带分页

    在JSF中,处理大量数据时,分页功能是必不可少的,它可以提高用户体验,减少一次性加载过多数据对服务器和网络资源的压力。本文将深入探讨JSF自带的分页功能,并结合提供的博客链接进行讲解。 在JSF中,分页通常...

    JSF经典的js分页

    3. **JavaScript实现**:编写JavaScript函数来处理分页逻辑。这些函数通常会监听按钮点击事件,根据当前页码和每页记录数计算出显示的数据范围,然后更新页面上的数据显示区。 4. **DOM操作**:使用JavaScript库如...

    jsf 分页

    总之,在JSF中实现分页,我们可以选择利用第三方库如PrimeFaces提供的组件,或者自己编写逻辑处理分页。这两种方法都有其优缺点,具体选择取决于项目需求和个人喜好。无论哪种方式,关键在于理解分页的基本原理,...

    JSF分页控件 ,支持大容量可查询分页

    描述中提到的“具体的分页可继承PagerBean”,这表明可能有一个名为`PagerBean`的后台bean,用于处理分页逻辑。在JSF中,Managed Bean是存储业务逻辑和状态的Java类,它们可以与视图层交互。`PagerBean`可能包含以下...

    JSF分页组件

    - **编写后台逻辑**: 编写Java代码处理分页操作,包括计算总页数、根据用户选择的页码获取相应数据等。 - **集成到JSF生命周期**: 使用JSF的生命周期方法(如`@PostConstruct`、`processAction`等)确保组件与JSF...

    JSF分页组件2

    在JSF中,我们可以使用各种分页组件来实现这一功能。本文将深入探讨JSF分页组件2的相关知识点,包括其原理、使用方法和最佳实践。 ### 1. 分页组件的基本概念 分页组件允许用户以有限的数量逐页查看数据,而不是一...

    JSF分页实现,内含建表语句

    综上所述,这个JSF分页实现项目涵盖了Web开发中的多个重要方面,包括前端界面的组件化设计、后端数据的分页处理、数据库操作以及Java的高级特性运用。通过学习和理解这个案例,开发者可以深化对JSF框架、SQL查询和...

    jsf 分页实例jsf 分页实例

    在JSF页面(通常是`.xhtml`文件)中,使用`p:datatable`展示数据,`p:datascroller`处理分页。 ```html &lt;!DOCTYPE html&gt; xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:p="http://primefaces.org/ui"&gt; ...

    JSF数据分页的简单例子(源码)

    在这个简单的例子中,我们关注的是如何在JSF应用中实现数据分页。 **数据分页**是一种在大量数据展示时优化用户体验的技术,它允许用户逐步加载和查看数据,而不是一次性加载所有内容,这可以提高页面加载速度,...

    jsf分页——详细源码 测试通过

    在JavaScript Server Faces (JSF) 中,分页是一种常见的功能,用于处理大量数据时提高用户体验。这个"jsf分页——详细源码 测试通过"的压缩包文件提供了一个实现JSF分页功能的详细源代码,且经过了测试验证其有效性...

    JSF中自定义分页呈现器(Render)的实现和应用

    然而,在处理大量数据分页查询时,JSF的标准组件可能显得力不从心。因此,本文将探讨如何通过自定义渲染器来解决这一问题。 #### 自定义分页呈现器的需求分析 在使用JSF构建的应用系统中,特别是在涉及到大量数据...

    jsf 动态分页 带jar包 解压直接导入eclipse即可,方便学习~

    本篇将详细讲解如何在JSF中实现动态分页。 **1. JSF组件库与动态分页** JSF提供了一些基本的UI组件,但默认并未包含分页组件。在实际开发中,我们通常会借助第三方库来实现这一功能。在给定的资源中,"myfaces-...

    利用自定义渲染器实现JSF数据库表分页显示

    在JavaServer Faces (JSF) 应用程序中处理大量的数据时,分页是一个非常实用且必要的功能。通过合理地分页展示数据,不仅可以提高用户体验,还可以减少服务器的压力。本文将详细介绍一种基于自定义渲染器的高效分页...

    JSF分页代码和学习文件1

    通过这个压缩包中的实例,你可以深入理解JSF如何处理分页,以及如何将分页与其他功能(如搜索、排序)结合使用。同时,也可以从中学习到如何组织和管理JSF项目,以及如何调试和优化JSF应用。最后,别忘了JSF的强大...

    struts和jsf分页

    2. **Managed Bean**:创建一个Managed Bean,处理分页逻辑,如`@ManagedBean`和`@ViewScoped`注解的Bean,包含当前页码、每页大小等属性,并提供相应的业务方法。 3. **数据绑定**:使用`h:dataTable`组件展示数据...

    JSF+Spring+Hibernate 分页显示

    在分页中,Spring MVC的`ModelAndView`或`@ResponseBody`注解可以用来处理HTTP请求并返回分页数据。同时,Spring的数据层服务可以整合Hibernate,实现对数据库的高效操作。 **Hibernate ORM** Hibernate是一个强大...

    jsf增删改查分页例子

    在“jsf增删改查分页例子”这个项目中,我们可以看到JSF如何被用来实现一个基本的CRUD(创建、读取、更新和删除)功能,以及数据的分页展示。以下是关于这些知识点的详细解释: 1. **JSF组件库**:JSF包含了一系列...

Global site tag (gtag.js) - Google Analytics