马尔代夫
学会真心付出
posts - 0,comments - 0,trackbacks - 0

分页,这是Web应用中经常要涉及的问题,相信每一位开发人员都有这个自信解决这个问题,看了不少各式各样的分页实现代码,总觉得应该有一个比较好的规范来处理分页。有没有一个比较好、规范的分页接口,这样大家都可以围绕此接口做实现,这样分页处理就统一起来,简单多,而不我们看到现象:不同公司个人的不同版本的分页实现。个人非常欣赏aopalliance项目,虽然只是一些接口的定义,但定于规范化AOP确实做出不小的贡献,不然不同的AOP实现的互通如何实现?规范的作用就发挥出来啦。

在Hibernate的站点上有一个分页的参考实现(http://www.hibernate.org/248.html),定义了分页处理所需的接口Page,这个接口非常不错,至少是我目前看到最完善和合理的(关于分页处理),将分页的信息全部包含啦,简单明了,代码如下:

				
JavaZoo.com © 2006. Code Language:java.
  1.  
  2.  
  3. public interface Page {
  4. boolean isFirstPage();
  5. boolean isLastPage();
  6. boolean hasNextPage();
  7. boolean hasPreviousPage();
  8. int getLastPageNumber();
  9. List getThisPageElements();
  10. Logger getLogger();
  11. int getTotalNumberOfElements();
  12. int getThisPageFirstElementNumber();
  13. int getThisPageLastElementNumber();
  14. int getNextPageNumber();
  15. int getPreviousPageNumber();
  16. int getPageSize();
  17. int getPageNumber();
  18. }
  19.  
  20.  
  21.  
  22.  
Parsed in 0.063 seconds, using GeSHi 1.0.7.12

这里可能要做一些调整,个人觉得getLogger()没有必要放在这个接口中,它是用于处理日志的,这个可以在具体的实现代码完成,getThisPageElements()获取当前页的数据,这里返回为List类型数据,这里可能需要更改一下返回类型,当前页的数据可能涉及许多种类型:数组、RowSet、List等等,所以我们拟定将其返回值定为Object,在具体的代码中再去考虑究竟返回何种类型,所以这个接口修改后如下:

				
JavaZoo.com © 2006. Code Language:java.
  1.  
  2. public interface Page {
  3. boolean isFirstPage();
  4. boolean isLastPage();
  5. boolean hasNextPage();
  6. boolean hasPreviousPage();
  7. int getLastPageNumber();
  8. Object getThisPageElements();
  9. int getTotalNumberOfElements();
  10. int getThisPageFirstElementNumber();
  11. int getThisPageLastElementNumber();
  12. int getNextPageNumber();
  13. int getPreviousPageNumber();
  14. int getPageSize();
  15. int getThisPageNumber ();
  16. }
  17.  
  18.  
  19.  
  20.  
Parsed in 0.066 seconds, using GeSHi 1.0.7.12

接口定义完毕后我们需要根据实际情况实现这个接口,这里主要讲三种情况:Hibernate的Query分页、Jdbc的ResultSet分页和List数据类型分页。在Hibernate的站点上提供了一个Hibernate分页的实现类HibernatePage,这个类处理从0开始,这可能与我们的实际情况不太一样,同时可能还有一些分页处理方面的bug,让我们看看HibernatePage的一个具体实现:

				
JavaZoo.com © 2006. Code Language:java.
  1.  
  2.  
  3. /**
  4. * Hibernate分页信息
  5. */
  6. public class HibernatePage implements Page
  7. {
  8. private List elements;
  9. private int pageSize;
  10. private int pageNumber;
  11. private int totalElements = 0;
  12.  
  13.  
  14. /**
  15. * 构建HibernatePage对象,完成Hibernate的Query数据的分页处理
  16. *
  17. * @param query Hibernate的Query对象
  18. * @param pageNumber 当前页编码,从1开始,如果传的值为Integer.MAX_VALUE表示获取最后一页。
  19. * 如果你不知道最后一页编码,传Integer.MAX_VALUE即可。如果当前页超过总页数,也表示最后一页。
  20. * 这两种情况将重新更改当前页的页码,为最后一页编码。
  21. * @param pageSize 每一页显示的条目数
  22. */
  23. public HibernatePage(Query query, int pageNumber, int pageSize)
  24. {
  25. this.pageNumber = pageNumber;
  26. this.pageSize = pageSize;
  27. try
  28. {
  29. ScrollableResults scrollableResults = query.scroll();
  30. //get the total elements number
  31. scrollableResults.last();
  32. this.totalElements = scrollableResults.getRowNumber();
  33. if ( Integer .MAX_VALUE == this.pageNumber || this.pageNumber > getLastPageNumber())//last page
  34. {
  35. this.pageNumber = getLastPageNumber();
  36. }
  37. elements = query.setFirstResult((this.pageNumber - 1) * this.pageSize).setMaxResults(this.pageSize + 1).list();
  38. } catch (HibernateException e)
  39. {
  40. throw new RuntimeException (e);
  41. }
  42. }
  43.  
  44.  
  45. public boolean isFirstPage()
  46. {
  47. return getThisPageNumber() == 1;
  48. }
  49.  
  50.  
  51. public boolean isLastPage()
  52. {
  53. return getThisPageNumber() >= getLastPageNumber();
  54. }
  55.  
  56.  
  57. public boolean hasNextPage()
  58. {
  59. return getLastPageNumber() > getThisPageNumber();
  60. }
  61.  
  62.  
  63. public boolean hasPreviousPage()
  64. {
  65. return getThisPageNumber() > 1;
  66. }
  67.  
  68.  
  69. public int getLastPageNumber()
  70. {
  71. return totalElements % this.pageSize == 0 ? totalElements / this.pageSize : totalElements / this.pageSize + 1;
  72. }
  73.  
  74.  
  75. /**
  76. * 返回List类型数据
  77. *
  78. * @return List数据源
  79. */
  80. public Object getThisPageElements()
  81. {
  82. return elements;
  83. }
  84.  
  85.  
  86. public int getTotalNumberOfElements()
  87. {
  88. return totalElements;
  89. }
  90.  
  91.  
  92. public int getThisPageFirstElementNumber()
  93. {
  94. return (getThisPageNumber() - 1) * getPageSize() + 1;
  95. }
  96.  
  97.  
  98. public int getThisPageLastElementNumber()
  99. {
  100. int fullPage = getThisPageFirstElementNumber() + getPageSize() - 1;
  101. return getTotalNumberOfElements() < fullPage ? getTotalNumberOfElements() : fullPage;
  102. }
  103.  
  104.  
  105. public int getNextPageNumber()
  106. {
  107. return getThisPageNumber() + 1;
  108. }
  109.  
  110.  
  111. public int getPreviousPageNumber()
  112. {
  113. return getThisPageNumber() - 1;
  114. }
  115.  
  116.  
  117. public int getPageSize()
  118. {
  119. return pageSize;
  120. }
  121.  
  122.  
  123. public int getThisPageNumber()
  124. {
  125. return pageNumber;
  126. }
  127. }
  128.  
  129.  
  130.  
  131.  
Parsed in 1.548 seconds, using GeSHi 1.0.7.12

当然上述只是参考实现,你可以依据自己的分页算法进行实现,只要遵循这个接口即可。这里就不在给出List和ResultSet分页的实现逻辑,附件包含了源代码,大家可以参考一下。

总结:分页处理并不难,关键是没有一个好的接口和指导如何去实现的思想,这样造成了许多不规范,Hibernate站点上的Page接口设计的非常不错,同时给出了如何去实现的指导,相信有了一个规范接口和相关的实现逻辑,这样就分页处理就规范化多啦。

附件为分页实例的源代码!

posted on 2006-10-03 21:14 马尔代夫 阅读(161) 评论(0)  编辑  收藏 所属分类: 框架学习Hibernate