改进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
plain
copy

  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. public void setRecordsSubst(List recordsSubset);
  11. public void setRealRecordCount(long realRecordCount);
  12. /**
  13. * 设置每页应有多少条记录。
  14. */
  15. public void setPageSize(int pageSize);
  16. /**
  17. * 返回每页共有多少条记录
  18. */
  19. public int getPageSize();
  20. /**
  21. * 根据pageSize,返回共有多少页
  22. */
  23. public int getPageCount();
  24. /**
  25. * 返回当前页码。
  26. * 首页为0
  27. */
  28. public int getPage();
  29. /**
  30. * 设置当前页码。
  31. * 首页为0
  32. */
  33. public void setPage(int page);
  34. /**
  35. * 设置围绕当前页最多可以显示多少链接的页数。
  36. * 此方法<strong>会</strong>影响getFirstLinkedPage()及getLastLinkedPage()
  37. */
  38. public void setMaxLinkedPages(int maxLinkedPages);
  39. /**
  40. * 返回围绕当前页最多可以显示多少链接的页数
  41. */
  42. public int getMaxLinkedPages();
  43. /**
  44. * 返回首页的页码(来源 www.iocblog.net)
  45. */
  46. public int getFirstLinkedPage();
  47. /**
  48. * 返回最后一页的页码
  49. */
  50. public int getLastLinkedPage();
  51. /**
  52. * 转至前一页。
  53. * 如果已经是首页,则停在该页。
  54. */
  55. public void previousPage();
  56. /**
  57. * 转至下一页。
  58. * 如果已经是最后一页,则停在该页。
  59. */
  60. public void nextPage();
  61. /**
  62. * 转至首页。
  63. */
  64. public void firstPage();
  65. /**
  66. * 转至最后一页
  67. */
  68. public void lastPage();
  69. /**
  70. * 返回总的记录数
  71. */
  72. public long getNrOfElements();
  73. /**
  74. * 返回在当前页面上的第一个记录在所有记录(从0开始)中的编号
  75. */
  76. public int getFirstElementOnPage();
  77. /**
  78. * 返回在当前页面上的最后一个记录在所有记录(从0开始)中的编号
  79. */
  80. public int getLastElementOnPage();
  81. /**
  82. * 返回在当前页面上的所有记录
  83. */
  84. public List getPageList();
  85. }

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

下面是此接口的实现:

[java] view
plain
copy

  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. private int page = 0;
  12. private List recordsSubset;
  13. private long realRecordCount;
  14. /** Creates a new instance of RequestPagedListHolder */
  15. public RequestPagedListHolder(HttpServletRequest request, long realRecordCount, PagedListProvider pagedListProvider) {
  16. setRealRecordCount(realRecordCount);
  17. ServletRequestDataBinder binder = new ServletRequestDataBinder(this);
  18. binder.bind(request);
  19. checkPageNavigation(request);
  20. setRecordsSubst(pagedListProvider.getRecordsSubset(getPageSize() * getPage(), getPageSize()));
  21. }
  22. private void checkPageNavigation(final HttpServletRequest request) {
  23. String pageNavAction = request.getParameter("pageNavAction");
  24. if (pageNavAction != null) {
  25. if (pageNavAction.equals("firstPage")) {
  26. firstPage();
  27. } else if (pageNavAction.equals("previousPage")) {
  28. previousPage();
  29. } else if (pageNavAction.equals("nextPage")) {
  30. nextPage();
  31. } else if (pageNavAction.equals("lastPage")) {
  32. lastPage();
  33. }
  34. }
  35. }
  36. public void setRecordsSubst(List recordsSubset) {
  37. this.recordsSubset = recordsSubset;
  38. }
  39. public void setRealRecordCount(long realRecordCount) {
  40. this.realRecordCount = realRecordCount;
  41. }
  42. public void setPageSize(int pageSize) {
  43. this.pageSize = pageSize;
  44. }
  45. public int getPageSize() {
  46. return pageSize;
  47. }
  48. public int getPageCount() {
  49. float nrOfPages = (float) getNrOfElements() / getPageSize();
  50. return (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages);
  51. }
  52. public int getPage() {
  53. if (page >= getPageCount()) {
  54. page = getPageCount() - 1;
  55. }
  56. return page;
  57. }
  58. public void setPage(int page) {
  59. this.page = page;
  60. }
  61. public void setMaxLinkedPages(int maxLinkedPages) {
  62. this.maxLinkedPages = maxLinkedPages;
  63. }
  64. public int getMaxLinkedPages() {
  65. return maxLinkedPages;
  66. }
  67. public int getFirstLinkedPage() {
  68. return Math.max(0, getPage() - (getMaxLinkedPages() / 2));
  69. }
  70. public int getLastLinkedPage() {
  71. return Math.min(getFirstLinkedPage() + getMaxLinkedPages() - 1, getPageCount() - 1);
  72. }
  73. public void previousPage() {
  74. if (!isAtFirstPage()) {
  75. page--;
  76. }
  77. }
  78. public void nextPage() {
  79. if (!isAtLastPage()) {
  80. page++;
  81. }
  82. }
  83. public void firstPage() {
  84. setPage(0);
  85. }
  86. public void lastPage() {
  87. setPage(getPageCount() - 1);
  88. }
  89. public long getNrOfElements() {
  90. return realRecordCount;
  91. }
  92. public int getFirstElementOnPage() {
  93. return (getPageSize() * getPage());
  94. }
  95. public int getLastElementOnPage() {
  96. int endIndex = getPageSize() * (getPage() + 1);
  97. return (endIndex > getNrOfElements() ? (int)getNrOfElements() : endIndex) - 1;
  98. }
  99. public List getPageList() {
  100. return recordsSubset;
  101. }
  102. public boolean isAtFirstPage() {
  103. return getPage() == 0;
  104. }
  105. public boolean isAtLastPage() {
  106. return getPage() == getPageCount() - 1;
  107. }
  108. }

此类有以下特点:

1. pageSize及maxLinkedPages均设为static,这样不因每个Request而改变。因此用户不必每次显示一个不同的页面后都在UI中重新设置它们。

2. 在构造函数中包装了所有的使用过程,既简化了该类的使用,也保证了该类被正确初始化。

3. 摒弃了newPageSet变量,减少了各个方法的耦合强度。

4. 在Spring环境中使用了ServletRequestDataBinder,大大简化了各个参数的读取设置过程。

5. 通过回调机制,每次只检索PagedListProvider所提供的记录子集,节约了内存,提高了程序效率。

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

[java] view
plain
copy

  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,也没关系,自己实现此接口就行了。(接口实现起来很简单,但技术细节却非简单,Hibernate用户在此居于明显的优势)(来源 www.iocblog.net)

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

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

[java] view
plain
copy

  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. PagedListHolder holder = new RequestPagedListHolder(request, totalRecordsCount, listProvider);
  9. mav.addObject("pagedRecords", holder);
  10. }<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
plain
copy

  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
plain
copy

  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已经为我们检索出来的记录子集。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 08:51:17

改进Spring中的分页技术的相关文章

tp中使用分页技术

1 public function showList() { 2 $m_ld = D ( 'guangxi_ld' ); 3 $page = I ( 'get.p', 1 ); 4 // 在配置中获取分页值 5 $pagesize = C ( 'PAGESIZE' );//在config配置分页显示的条数 6 $list = $m_ld->field('id,delivery_address,receiver_address,time,price,heavy,low,corp_name,link

如何在Spring框架中使用RMI技术

在博客<RMI远程方法调用技术>中使用纯Java代码演示了RMI技术的使用,本篇博客将介绍如何在Spring中使用RMI技术. 正如博客<RMI远程方法调用技术>提到的那样--RMI技术的应用通常包括在两个独立的应用程序中:RMI服务端应用程序和RMI客户端应用程序.本博客也从这两方面入手:        RMI服务端应用程序: 1.自定义远程接口 代码如下: package com.ghj.packageofrmi; /** * 定义远程接口. * * @author 高焕杰 *

使用JDK中的Proxy技术来实现动态代理

我举个例子来说明一下代理的原理: 现实生活的例子:我大学放假了,我想要去放松一下去海洋馆买个门票,我看见海洋馆门前坐个人,看起来就是卖票的,于是,我上他那去买票,于是,他出去一下说给我拿票来,在他去拿票的过程中又去找了另外一个人,那个人把票给他了,他把票给我了,可是在这个过程中我却什么都不知道,我知道我要拿票,他把票给我就ok了. java中的例子:客户端用一个接口引用一个对象,然后用这个=接口去调用一些方法,表面上我只看到了这个接口的引用,而程序在运行的时候找的却是具体的对象,这就是多态,所以

jsp中利用MySQL实现分页技术

分页是很常用的一种技术,而mysql中对于分页的操作也很简单,今天就说说如何在jsp页面中利用标签来最简化的实现分页: 链接:MySQL分页技术详解http://blog.csdn.net/u011637069/article/details/49928513 step1:编写DAO中代码: [java] view plain copy public List<Employee> findAll2(int page, int perPageRows) throws Exception { Li

JaveWeb中实现分页的总结

分页技术:将所有数据分段展示给用户的技术. 分页的意义:增加系统的复杂度,另外可以将大量的数据限制在某一个特定的范围. 选择分页的标准: 首先,判断的标准是速度,显而易见,数据库服务器,Web应用服务器和客户端之间是网络,如果网络传递的数据量越少,则客户端获得响应的速度越快.一般来说,数据库服务器和Web应用服务器的处理能力一般比客户端要强很多.从这两点来看,在客户端分页的方案是最不可取的. 其次,在Web服务器端分页和在数据库端分页,如果选择在Web服务器端分页的话,大部分的被过滤掉的数据还是

django分页技术django-pagination和Paginator

转载前还请注明出处:http://blog.csdn.net/gugugujiawei 一.概述 几乎所有的web应用,都需要分页功能,但分页技术总体来说分两种,一种是全部加载,存于浏览器的缓存中,一种是分页访问,部分加载.前一种方法优点是实现简单,在一些对项目要求不多的特定应用上用得较多,可以利用的插件譬如datatables,而后一种方法优点是不会占用服务器太多的缓存,对于数据量大的列表项必须用到这种技术.由于我现在的项目属于管理后台,管理来自成千上万用户的数据,因而只能用到第二种方法.初期

25、连接池(DBCP、C3P0)、动态代理与分页技术

连接池 思考: 程序中连接如何管理? 1. 连接资源宝贵:需要对连接管理 2. 连接: a) 操作数据库,创建连接 b) 操作结束, 关闭! 分析: 涉及频繁的连接的打开.关闭,影响程序的运行效率! 连接管理: 预先创建一组连接,有的时候每次取出一个: 用完后,放回: 学习连接池: a. 自定义一个连接池 b. 学习优秀的连接池组件 a) DBCP b) C3P0 动态代理 Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需

项目中PageHelper分页插件的使用实例(SSM)

分页(英语:Paging),是一种操作系统里存储器管理的一种技术,可以使计算机的主存可以使用存储在辅助存储器中的数据.操作系统会将辅助存储器(通常是磁盘)中的数据分区成固定大小的区块,称为“页”(pages).当不需要时,将分页由主存(通常是内存)移到辅助存储器:当需要时,再将数据取回,加载主存中.相对于分段,分页允许存储器存储于不连续的区块以维持文件系统的整齐.[1]分页是磁盘和内存间传输数据块的最小单位. 分页/虚拟内存能有助“大大地”降低整体及额外非必要的 I/O 次数,提高系统整体运作性

Spring中如何使用工厂模式实现程序解耦?

目录 1. 啥是耦合.解耦? 2. jdbc程序进行解耦 3.传统dao.service.controller的程序耦合性 4.使用工厂模式实现解耦 5.工厂模式改进 6.结语 @ 1. 啥是耦合.解耦? 既然是程序解耦,那我们必须要先知道啥是耦合,耦合简单来说就是程序的依赖关系,而依赖关系则主要包括 1. 类之间的依赖 2. 方法间的依赖 比如下面这段代码: public class A{ public int i; } public class B{ public void put(A a)