分页,心中的痛?

来源:互联网 发布:多米诺激光机软件 编辑:程序博客网 时间:2024/04/26 00:58

http://www.jetmaven.net/contents/documents/j_page.php

 

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

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


public interface Page {
boolean isFirstPage();
boolean isLastPage();
boolean hasNextPage();
boolean hasPreviousPage();
int getLastPageNumber();
List getThisPageElements();
Logger getLogger();
int getTotalNumberOfElements();
int getThisPageFirstElementNumber();
int getThisPageLastElementNumber();
int getNextPageNumber();
int getPreviousPageNumber();
int getPageSize();
int getPageNumber();
}

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


public interface Page {
boolean isFirstPage();
boolean isLastPage();
boolean hasNextPage();
boolean hasPreviousPage();
int getLastPageNumber();
Object getThisPageElements();
int getTotalNumberOfElements();
int getThisPageFirstElementNumber();
int getThisPageLastElementNumber();
int getNextPageNumber();
int getPreviousPageNumber();
int getPageSize();
int getThisPageNumber ();
}

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


/**
* Hibernate分页信息
*/
public class HibernatePage implements Page
{
private List elements;
private int pageSize;
private int pageNumber;
private int totalElements = 0;

/**
* 构建HibernatePage对象,完成Hibernate的Query数据的分页处理
*
* @param query Hibernate的Query对象
* @param pageNumber 当前页编码,从1开始,如果传的值为Integer.MAX_VALUE表示获取最后一页。
* 如果你不知道最后一页编码,传Integer.MAX_VALUE即可。如果当前页超过总页数,也表示最后一页。
* 这两种情况将重新更改当前页的页码,为最后一页编码。
* @param pageSize 每一页显示的条目数
*/
public HibernatePage(Query query, int pageNumber, int pageSize)
{
this.pageNumber = pageNumber;
this.pageSize = pageSize;
try
{
ScrollableResults scrollableResults = query.scroll();
//get the total elements number
scrollableResults.last();
this.totalElements = scrollableResults.getRowNumber();
if (Integer.MAX_VALUE == this.pageNumber || this.pageNumber > getLastPageNumber()) //last page
{
this.pageNumber = getLastPageNumber();
}
elements = query.setFirstResult((this.pageNumber - 1) * this.pageSize).setMaxResults(this.pageSize + 1).list();
} catch (HibernateException e)
{
throw new RuntimeException(e);
}
}

public boolean isFirstPage()
{
return getThisPageNumber() == 1;
}

public boolean isLastPage()
{
return getThisPageNumber() >= getLastPageNumber();
}

public boolean hasNextPage()
{
return getLastPageNumber() > getThisPageNumber();
}

public boolean hasPreviousPage()
{
return getThisPageNumber() > 1;
}

public int getLastPageNumber()
{
return totalElements % this.pageSize == 0 ? totalElements / this.pageSize : totalElements / this.pageSize + 1;
}

/**
* 返回List类型数据
*
* @return List数据源
*/
public Object getThisPageElements()
{
return elements;
}

public int getTotalNumberOfElements()
{
return totalElements;
}

public int getThisPageFirstElementNumber()
{
return (getThisPageNumber() - 1) * getPageSize() + 1;
}

public int getThisPageLastElementNumber()
{
int fullPage = getThisPageFirstElementNumber() + getPageSize() - 1;
return getTotalNumberOfElements() < fullPage ? getTotalNumberOfElements() : fullPage;
}

public int getNextPageNumber()
{
return getThisPageNumber() + 1;
}

public int getPreviousPageNumber()
{
return getThisPageNumber() - 1;
}

public int getPageSize()
{
return pageSize;
}

public int getThisPageNumber()
{
return pageNumber;
}
}

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

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

原创粉丝点击