zoukankan      html  css  js  c++  java
  • 改进Spring中的分页技术

    Spring中有一个PagedListHolder,能够实现分页。

    但此类有几个缺点:

    1. 使用此类的代码比較繁琐
    2. 此类存放的数据源是全部的记录集,即对于记录数为1000条的数据,即使我们仅仅需在一个页面中显示10条记录,每次均须要检索1000条记录出来,而且没有内在的缓存机制
    3. 假设需将pageSize, maxLinkedPages这些一般为Session级的变量存于Session中。则必须在Session中存放PagedListHolder,从而导致大容量的数据经常撑满了Session
    4. 仅仅是实现了Serializable标识接口。且getPage(), setPage(), setPageSize()方法中直接使用newPageSet (private) 的属性,不利于子类覆盖。

    并且,内部类的各个方法耦合极强。

    特定方法的使用必须信赖于某个方法或标志变量作为前提条件。

    比較理想的情况是。依据每个HttpServletRequest产生一个PagesListHolder,无论记录总数有多少个。每次仅仅检索页面上所显示的记录。但将pageSize, maxLinkedPages设为Session级的效果。

    鉴于上述几点,我从Spring原有的PagedListHolder抽取出一些必需的方法名作为接口,并以一个名为RequestPagedListHolder的类实现之。

    以下是抽取出来的PagedListHolder接口。

    [java] view plaincopy
    1. import java.io.Serializable;  
    2. import java.util.List;  
    3. /** 
    4.  * 
    5.  * @author Sarkuya 
    6.  */  
    7. public interface PagedListHolder extends Serializable {  
    8.     public static final int DEFAULT_PAGE_SIZE = 10;  
    9.     public static final int DEFAULT_MAX_LINKED_PAGES = 10;  
    10.       
    11.     public void setRecordsSubst(List recordsSubset);  
    12.     public void setRealRecordCount(long realRecordCount);  
    13.       
    14.     /** 
    15.      * 设置每页应有多少条记录。 
    16.      */  
    17.     public void setPageSize(int pageSize);  
    18.       
    19.     /** 
    20.      * 返回每页共同拥有多少条记录 
    21.      */  
    22.     public int getPageSize();  
    23.       
    24.     /** 
    25.      * 依据pageSize,返回共同拥有多少页 
    26.      */  
    27.     public int getPageCount();  
    28.       
    29.     /** 
    30.      * 返回当前页码。 
    31.      * 首页为0 
    32.      */  
    33.     public int getPage();  
    34.       
    35.     /** 
    36.      * 设置当前页码。

       

    37.      * 首页为0 
    38.      */  
    39.     public void setPage(int page);  
    40.       
    41.     /** 
    42.      * 设置环绕当前页最多能够显示多少链接的页数。 
    43.      * 此方法<strong>会</strong>影响getFirstLinkedPage()及getLastLinkedPage() 
    44.      */  
    45.     public void setMaxLinkedPages(int maxLinkedPages);  
    46.       
    47.     /** 
    48.      * 返回环绕当前页最多能够显示多少链接的页数 
    49.      */  
    50.     public int getMaxLinkedPages();  
    51.       
    52.     /** 
    53.      * 返回首页的页码(来源 www.iocblog.net) 
    54.      */  
    55.     public int getFirstLinkedPage();  
    56.       
    57.     /** 
    58.      * 返回最后一页的页码 
    59.      */  
    60.     public int getLastLinkedPage();  
    61.       
    62.       
    63.     /** 
    64.      * 转至前一页。

       

    65.      * 假设已经是首页。则停在该页。 
    66.      */  
    67.     public void previousPage();  
    68.       
    69.     /** 
    70.      * 转至下一页。 
    71.      * 假设已经是最后一页。则停在该页。

       

    72.      */  
    73.     public void nextPage();  
    74.       
    75.     /** 
    76.      * 转至首页。 
    77.      */  
    78.     public void firstPage();  
    79.       
    80.     /** 
    81.      * 转至最后一页 
    82.      */  
    83.     public void lastPage();  
    84.       
    85.     /** 
    86.      * 返回总的记录数 
    87.      */  
    88.     public long getNrOfElements();  
    89.       
    90.     /** 
    91.      * 返回在当前页面上的第一个记录在全部记录(从0開始)中的编号 
    92.      */  
    93.     public int getFirstElementOnPage();  
    94.       
    95.     /** 
    96.      * 返回在当前页面上的最后一个记录在全部记录(从0開始)中的编号 
    97.      */  
    98.     public int getLastElementOnPage();  
    99.       
    100.     /** 
    101.      * 返回在当前页面上的全部记录 
    102.      */  
    103.     public List getPageList();  
    104. }  

    setRecordsSubst()用于存放页面显示的记录源,而setRealRecordCount()用于记录满足条件的记录总数。

    以下是此接口的实现:

    [java] view plaincopy
    1. import java.util.List;  
    2. import javax.servlet.http.HttpServletRequest;  
    3. import org.springframework.web.bind.ServletRequestDataBinder;  
    4. /** 
    5.  * 
    6.  * @author Sarkuya 
    7.  */  
    8. public class RequestPagedListHolder implements PagedListHolder {  
    9.     private static int pageSize = DEFAULT_PAGE_SIZE;  
    10.     private static int maxLinkedPages = DEFAULT_MAX_LINKED_PAGES;  
    11.       
    12.     private int page = 0;  
    13.     private List recordsSubset;  
    14.       
    15.     private long realRecordCount;  
    16.       
    17.     /** Creates a new instance of RequestPagedListHolder */  
    18.     public RequestPagedListHolder(HttpServletRequest request, long realRecordCount, PagedListProvider pagedListProvider) {  
    19.         setRealRecordCount(realRecordCount);  
    20.           
    21.         ServletRequestDataBinder binder = new ServletRequestDataBinder(this);  
    22.         binder.bind(request);  
    23.           
    24.         checkPageNavigation(request);  
    25.           
    26.         setRecordsSubst(pagedListProvider.getRecordsSubset(getPageSize() * getPage(), getPageSize()));  
    27.     }  
    28.     private void checkPageNavigation(final HttpServletRequest request) {  
    29.         String pageNavAction = request.getParameter("pageNavAction");  
    30.         if (pageNavAction != null) {  
    31.             if (pageNavAction.equals("firstPage")) {  
    32.                 firstPage();  
    33.             } else if (pageNavAction.equals("previousPage")) {  
    34.                 previousPage();  
    35.             } else if (pageNavAction.equals("nextPage")) {  
    36.                 nextPage();  
    37.             } else if (pageNavAction.equals("lastPage")) {  
    38.                 lastPage();  
    39.             }  
    40.         }  
    41.     }  
    42.       
    43.     public void setRecordsSubst(List recordsSubset) {  
    44.         this.recordsSubset = recordsSubset;  
    45.     }  
    46.       
    47.     public void setRealRecordCount(long realRecordCount) {  
    48.         this.realRecordCount = realRecordCount;  
    49.     }  
    50.       
    51.     public void setPageSize(int pageSize) {  
    52.         this.pageSize = pageSize;  
    53.     }  
    54.       
    55.     public int getPageSize() {  
    56.         return pageSize;  
    57.     }  
    58.       
    59.     public int getPageCount() {  
    60.         float nrOfPages = (float) getNrOfElements() / getPageSize();  
    61.         return (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ?

       nrOfPages + 1 : nrOfPages);  

    62.     }  
    63.       
    64.     public int getPage() {  
    65.         if (page >= getPageCount()) {  
    66.             page = getPageCount() - 1;  
    67.         }  
    68.         return page;  
    69.     }  
    70.       
    71.     public void setPage(int page) {  
    72.         this.page = page;  
    73.     }  
    74.       
    75.     public void setMaxLinkedPages(int maxLinkedPages) {  
    76.         this.maxLinkedPages = maxLinkedPages;  
    77.     }  
    78.       
    79.     public int getMaxLinkedPages() {  
    80.         return maxLinkedPages;  
    81.     }  
    82.       
    83.     public int getFirstLinkedPage() {  
    84.         return Math.max(0, getPage() - (getMaxLinkedPages() / 2));  
    85.     }  
    86.       
    87.     public int getLastLinkedPage() {  
    88.         return Math.min(getFirstLinkedPage() + getMaxLinkedPages() - 1, getPageCount() - 1);  
    89.     }  
    90.       
    91.     public void previousPage() {  
    92.         if (!isAtFirstPage()) {  
    93.             page--;  
    94.         }  
    95.     }  
    96.       
    97.     public void nextPage() {  
    98.         if (!isAtLastPage()) {  
    99.             page++;  
    100.         }  
    101.     }  
    102.       
    103.     public void firstPage() {  
    104.         setPage(0);  
    105.     }  
    106.       
    107.     public void lastPage() {  
    108.         setPage(getPageCount() - 1);  
    109.     }  
    110.       
    111.     public long getNrOfElements() {  
    112.         return realRecordCount;  
    113.     }  
    114.       
    115.     public int getFirstElementOnPage() {  
    116.         return (getPageSize() * getPage());  
    117.     }  
    118.       
    119.     public int getLastElementOnPage() {  
    120.         int endIndex = getPageSize() * (getPage() + 1);  
    121.         return (endIndex > getNrOfElements() ?

       (int)getNrOfElements() : endIndex) - 1;  

    122.     }  
    123.       
    124.     public List getPageList() {  
    125.         return recordsSubset;  
    126.     }  
    127.       
    128.     public boolean isAtFirstPage() {  
    129.         return getPage() == 0;  
    130.     }  
    131.       
    132.     public boolean isAtLastPage() {  
    133.         return getPage() == getPageCount() - 1;  
    134.     }  
    135. }  


    此类有下面特点:

    1. pageSize及maxLinkedPages均设为static,这样不因每一个Request而改变。因此用户不必每次显示一个不同的页面后都在UI中又一次设置它们。
    2. 在构造函数中包装了全部的使用过程。既简化了该类的使用,也保证了该类被正确初始化。
    3. 摒弃了newPageSet变量,降低了各个方法的耦合强度。
    4. 在Spring环境中使用了ServletRequestDataBinder。大大简化了各个參数的读取设置过程。
    5. 通过回调机制,每次仅仅检索PagedListProvider所提供的记录子集,节约了内存。提高了程序效率。

    不难看出。PagedListProvider是个接口,仅仅有一个方法:

    [java] view plaincopy
    1. import java.util.List;  
    2. /** 
    3.  * 
    4.  * @author Sarkuya 
    5.  */  
    6. public interface PagedListProvider {  
    7.     public List getRecordsSubset(int firstResult, int maxResults);  
    8. }  

    熟悉Hibernate的用户知道。Hibernate中就是须要这两个參数来实现分页了。假设不使用Hibernate。也没关系。自己实现此接口即可了。(接口实现起来非常easy,但技术细节却非简单。Hibernate用户在此居于明显的优势)(来源 www.iocblog.net)

    以上的两个接口。一个实现类。便是经过改进后的分页技术了。以下看其用法。

    当用户须要查看带有分面功能的页面时。都会由以下的方法处理:

    [java] view plaincopy
    1. private void setPageListForView(HttpServletRequest request, ModelAndView mav, final String tableName) {  
    2.         long totalRecordsCount = adminService.getTotalRecordCount(tableName);  
    3.         PagedListProvider listProvider = new PagedListProvider() {  
    4.             public List getRecordsSubset(int firstResult, int maxResults) {  
    5.                 return (List) adminService.listTable(tableName, firstResult, maxResults);  
    6.             }  
    7.         };  
    8.           
    9.         PagedListHolder holder = new RequestPagedListHolder(request, totalRecordsCount, listProvider);  
    10.           
    11.         mav.addObject("pagedRecords", holder);  
    12.     }<span style="background-color: rgb(249, 252, 254); font-family: Tahoma, sans-serif;">    </span>  

    这是一个简单的方法,为RequestPagedListHolder的构造函数准备好实參后。生成一个实例。将其置于页面的一个名为"pagedRecords"的attribute中,以供JSP读取。

    adminService.getTotalRecordCount()应不难实现。主要是getRecordsSubset()。

    Service层的listTable()例如以下:

    [java] view plaincopy
    1. public Collection listTable(String tableName, int firstResult, int maxResults) throws DataAccessException {  
    2.     return ((HibernateDao) daoFactory.getDao(tableName)).findByCriteria(firstResult, maxResults);  
    3. }  

    Dao层代码:


    [java] view plaincopy
    1. public Collection findByCriteria(int firstResult, int maxResults) throws DataAccessException {  
    2.        DetachedCriteria criteria = DetachedCriteria.forClass(getEntityClass());  
    3.        return getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);  
    4.    }  

    以下看看视图层的使用。

        ......
        <c:forEach items="${pagedRecords.pageList}" var="record">
          ......
        </c:forEach>
        ......

    通过JSTL方便地读出pagedRecords变量的pageList属性。

    重抄一下上面的RequestPagedListHolder代码对应部分:

        public List getPageList() {
            return recordsSubset;
        }

    返回的正是Hibernate已经为我们检索出来的记录子集。

  • 相关阅读:
    C++11 vector使用emplace_back代替push_back
    Centos6.4 编译安装 nginx php
    Centos 编译安装nodejs&express框架
    zookeeper 入门(二)
    zookeeper 入门(一)
    Paxos算法1-算法形成理论[转载]
    yum只下载软件不安装的两种方法
    Centos 6.4 安装dnsmasq
    Centos 6.4 安装erlang&rabbitmq
    Centos 6.4 安装Python 2.7 python-pip
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7269283.html
Copyright © 2011-2022 走看看