ssh整合开发中的分页方案(转)
? 分页显示一直是web开发中一大烦琐的难题,传统的网页设计只在一个JSP或者ASP页面中书写所有关于数据库操作的代码,那样做分页可能简单一点,但当把网站分层开发后,分页就比较困难了,下面是我做Spring+Hibernate+Struts2项目时设计的分页代码,与大家分享交流。
1、DAO层接口的设计,在MemberDao接口中定义了如下两个方法:
public?interface?MemberDao{
????
????//省略了其他的代码
????
????/**
?????*?分页查询
?????*?@param?hql?查询的条件
?????*?@param?offset?开始记录
?????*?@param?length?一次查询几条记录
?????*?@return
?????*/
????public?List?queryForPage(final?String?hql,final?int?offset,final?int?length);
????
????/**
?????*?查询所有记录数
?????*?@param?hql?查询的条件
?????*?@return?总记录数
?????*/
????public?int?getAllRowCount(String?hql);
}?
2、DAO层实现类MemberDaoImpl对上面两个方法的实现如下:
public?class?MemberDaoImpl?extends?HibernateDaoSupport?implements?MemberDao?{
???????//省略了其他的代码????
????/**
?????*?分页查询
?????*?@param?hql?查询的条件
?????*?@param?offset?开始记录
?????*?@param?length?一次查询几条记录
?????*?@return
?????*/
????public?List?queryForPage(final?String?hql,final?int?offset,final?int?length){
????????List?list?=?getHibernateTemplate().executeFind(new?HibernateCallback(){
????????????public?Object?doInHibernate(Session?session)?throws?HibernateException,SQLException{
????????????????Query?query?=?session.createQuery(hql);
????????????????query.setFirstResult(offset);
????????????????query.setMaxResults(length);
????????????????List?list?=?query.list();
????????????????return?list;
????????????}
????????});
????????return?list;
????}
????
????
????/**
?????*?查询所有记录数
?????*?@return?总记录数
?????*/
????public?int?getAllRowCount(String?hql){
????????return?getHibernateTemplate().find(hql).size();
????}
}??????? 细心的读者会发现,这个类继承了HibernateDaoSupport类,HibernateDaoSupport是Spring提供的对Hibernate支持的类,getHibernateTemplate().executeFind(new HibernateCallback(){....})方法中的参数,我们使用了接口回调,在其参数内,我们能像原生的Hibernate一样调用query.setFirstResult(offset)和query.setMaxResults(length)来实现分页查询功能。
3、下面我们来新建一个保存分页信息的类PageBean,具体代码如下:
public?class?PageBean?{
????
????private?List?list;????????//要返回的某一页的记录列表
????
????private?int?allRow;?????????//总记录数
????private?int?totalPage;????????//总页数
????private?int?currentPage;????//当前页
????private?int?pageSize;????????//每页记录数
????
????private?boolean?isFirstPage;????//是否为第一页
????private?boolean?isLastPage;????????//是否为最后一页
????private?boolean?hasPreviousPage;????//是否有前一页
????private?boolean?hasNextPage;????????//是否有下一页
????
????
????public?List?getList()?{
????????return?list;
????}
????public?void?setList(List?list)?{
????????this.list?=?list;
????}
????public?int?getAllRow()?{
????????return?allRow;
????}
????public?void?setAllRow(int?allRow)?{
????????this.allRow?=?allRow;
????}
????public?int?getTotalPage()?{
????????return?totalPage;
????}
????public?void?setTotalPage(int?totalPage)?{
????????this.totalPage?=?totalPage;
????}
????public?int?getCurrentPage()?{
????????return?currentPage;
????}
????public?void?setCurrentPage(int?currentPage)?{
????????this.currentPage?=?currentPage;
????}
????public?int?getPageSize()?{
????????return?pageSize;
????}
????public?void?setPageSize(int?pageSize)?{
????????this.pageSize?=?pageSize;
????}
????
????/**
?????*?初始化分页信息
?????*/
????public?void?init(){
????????this.isFirstPage?=?isFirstPage();
????????this.isLastPage?=?isLastPage();
????????this.hasPreviousPage?=?isHasPreviousPage();
????????this.hasNextPage?=?isHasNextPage();
????}
????
????/**
?????*?以下判断页的信息,只需getter方法(is方法)即可
?????*?@return
?????*/
????
????public?boolean?isFirstPage()?{
????????return?currentPage?==?1;????//?如是当前页是第1页
????}
????public?boolean?isLastPage()?{
????????return?currentPage?==?totalPage;????//如果当前页是最后一页
????}
????public?boolean?isHasPreviousPage()?{
????????return?currentPage?!=?1;????????//只要当前页不是第1页
????}
????public?boolean?isHasNextPage()?{
????????return?currentPage?!=?totalPage;????//只要当前页不是最后1页
????}
????
????
????/**
?????*?计算总页数,静态方法,供外部直接通过类名调用
?????*?@param?pageSize?每页记录数
?????*?@param?allRow?总记录数
?????*?@return?总页数
?????*/
????public?static?int?countTotalPage(final?int?pageSize,final?int?allRow){
????????int?totalPage?=?allRow?%?pageSize?==?0???allRow/pageSize?:?allRow/pageSize+1;
????????return?totalPage;
????}
????
????/**
?????*?计算当前页开始记录
?????*?@param?pageSize?每页记录数
?????*?@param?currentPage?当前第几页
?????*?@return?当前页开始记录号
?????*/
????public?static?int?countOffset(final?int?pageSize,final?int?currentPage){
????????final?int?offset?=?pageSize*(currentPage-1);
????????return?offset;
????}
????
????/**
?????*?计算当前页,若为0或者请求的URL中没有"?page=",则用1代替
?????*?@param?page?传入的参数(可能为空,即0,则返回1)
?????*?@return?当前页
?????*/
????public?static?int?countCurrentPage(int?page){
????????final?int?curPage?=?(page==0?1:page);
????????return?curPage;
????}
}
4、Service层接口的设计:
public?interface?MemberService?{
????//省略其他的代码
????/**
?????*?分页查询
?????*?@param?currentPage?当前第几页
?????*?@param?pageSize?每页大小
?????*?@return?封闭了分页信息(包括记录集list)的Bean
?????*/
????public?PageBean?queryForPage(int?pageSize,int?currentPage);
}
5、Service层实现类的部分内码如下:
public?class?MemberServiceImpl?implements?MemberService?{
??
??//通过applicationContext.xml配置文件注入MemberDao的值
????private?MemberDao?memberDao;
????public?void?setMemberDao(MemberDao?memberDao)?{
????????this.memberDao?=?memberDao;
????}
????
????/**
?????*?分页查询
?????*?@param?currentPage?当前第几页
?????*?@param?pageSize?每页大小
?????*?@return?封闭了分页信息(包括记录集list)的Bean
?????*/
????public?PageBean?queryForPage(int?pageSize,int?page){
????????final?String?hql?=?"from?Member";????????//查询语句
????????int?allRow?=?memberDao.getAllRowCount(hql);????//总记录数
????????int?totalPage?=?PageBean.countTotalPage(pageSize,?allRow);????//总页数
????????final?int?offset?=?PageBean.countOffset(pageSize,?page);????//当前页开始记录
????????final?int?length?=?pageSize;????//每页记录数
????????final?int?currentPage?=?PageBean.countCurrentPage(page);
????????List<Member>?list?=?memberDao.queryForPage(hql,offset,?length);????????//"一页"的记录
????????
????????//把分页信息保存到Bean中
????????PageBean?pageBean?=?new?PageBean();
????????pageBean.setPageSize(pageSize);????
????????pageBean.setCurrentPage(currentPage);
????????pageBean.setAllRow(allRow);
????????pageBean.setTotalPage(totalPage);
????????pageBean.setList(list);
????????pageBean.init();
????????return?pageBean;
????}
6、在Struts2中调用queryForPageMemberService层的queryForPage()方法即可return一个包含分页信息、符合条件的结果集list, 代码如下:
public?class?ListMember?extends?ActionSupport{
????//通过applicationContext.xml配置文件注入memberService的值
????private?MemberService?memberService;
????public?void?setMemberService(MemberService?memberService)?{
????????this.memberService?=?memberService;
????}
????
????private?int?page;????//第几页
????
????private?PageBean?pageBean;????//包含分布信息的bean
????
????public?int?getPage()?{
????????return?page;
????}
????public?void?setPage(int?page)?{????????//若URL中无此参数,会默认为第1页
????????this.page?=?page;
????}
????public?PageBean?getPageBean()?{
????????return?pageBean;
????}
????public?void?setPageBean(PageBean?pageBean)?{
????????this.pageBean?=?pageBean;
????}
????@Override
????public?String?execute()?throws?Exception?{
????????//分页的pageBean,参数pageSize表示每页显示记录数,page为当前页
????????this.pageBean?=?memberService.queryForPage(2,?page);
????????return?SUCCESS;
????}
}
7、最后在listMember.jsp页面中,用到了Struts2标签:
<s:iterator?value="pageBean.list">
????????????<s:property?value="title"/>
????????????<a?href="getArticle.action?id=<s:property?value="id"/>">modify</a>
????????????<a?href="deleteArticle.action?id=<s:property?value="id"/>"?onclick="return?askDel()"/>delete</a><br/>
????????</s:iterator>
????????共<s:property?value="pageBean.allRow"/>?条记录
????????共<s:property?value="pageBean.totalPage"/>?页
????????当前第<s:property?value="pageBean.currentPage"/>页<br/>
????????
????????<s:if?test="%{pageBean.currentPage?==?1}">
????????????第一页?上一页
????????</s:if>
????????<s:else>
????????????<a?href="listMyArticle.action?page=1">第一页</a>
????????????<a?href="listMyArticle.action?page=<s:property?value="%{pageBean.currentPage-1}"/>">上一页</a>
????????</s:else>
????????<s:if?test="%{pageBean.currentPage?!=?pageBean.totalPage}">
????????????<a?href="listMyArticle.action?page=<s:property?value="%{pageBean.currentPage+1}"/>">下一页</a>
????????????<a?href="listMyArticle.action?page=<s:property?value="pageBean.totalPage"/>">最后一页</a>
????????</s:if>
????????<s:else>
????????????下一页?最后一页
????????</s:else>?到这里,Hibernate+Spring+Struts2整合开发中的分页问题就已经解决了,在我上述过程中,省略了许多Hibernate,Spring,Struts2的配置,那不是本文的重点,大家可以参考有关的书与资料,由于篇幅有限,在此就不一一列举。在以后的文章中,我也会详细地跟大家讲述SSH整合开发。