【Java EE 学习 57】【酒店会员管理系统之分页模板书写】
分页一直是一个比较麻烦的问题,特别是在我做的这个系统中更是有大量的分页,为了应对该问题,特地写了一个模板以方便代码重用,该模板包括后台分页的模板、前端显示的模板两部分。
一、分页分析
分页需要三种类型的参数:
1.系统启动之后就能够确定的参数,比如每页显示多少条数据pageSize,分页长度:elementLength
2.浏览器动态请求的参数这种情况分为两种:带有请求的页码(requestPage)和不带有请求的页码。
由于后台的分页代码是重用的,所以第一次请求的时候就需要带上请求的页码,如果不带上请求的页码默认是1,这需要后台代码进行判断。
3.服务器响应的数据,比如首页码(startIndex)、尾页码(endIndex)、总共的页码(totalPages)、当前的页码(currentPage=requestPage),当然还有响应的数据。
二、前端页面
发起分页请求的可能是一个超链接触发,也有可能是一个查询按钮触发,请求的方法都是同一个方法。
1.超链接触发
2.查询按钮触发
对于超链接触发的,可以直接访问action,但是查询按钮触发的却需要做一些动作才行。
(1)表单设置隐藏域,设置默认请求页码或者大多部分提供给js进行更改请求页码并提交给Action。
<s:hidden name="requestPage" value="1"></s:hidden>
(2)不能直接提交,需要先通过js进行设置:
/* *多条件查询和分页页面使用的js */ $().ready(function(){ $("#pageSplit a").each(function(){ $(this).unbind("click"); $(this).bind("click",function(){ var requestPage=$(this).attr("href").split("requestPage=")[1]; $("input[name='requestPage']").val(requestPage); $("form").submit(); return false; }); }); $("#query").unbind("click"); $("#query").bind("click",function(){ $("form").submit(); }); });
#pageSplit a是前端的jsp(struts2)分页模板,后边介绍。
3.前端显示的jsp分页模板(struts2)
<div id="pageSplit"> <s:a>首页 <s:param name="requestPage" value="1"></s:param> </s:a> <s:a>上一页 <s:param name="requestPage" value="#requestPage-1>0?#requestPage-1:1"></s:param> </s:a> <s:iterator var="page" begin="%{#startIndex}" end="%{#endIndex}"> <s:if test="#page==#requestPage"> <s:a cssStyle="background-color: #91C0E3;"> <s:param name="requestPage" value="#page"></s:param> <s:property value="#page"/> </s:a> </s:if> <s:else> <s:a> <s:param name="requestPage" value="#page"></s:param> <s:property value="#page"/> </s:a> </s:else> </s:iterator> <s:if test="%{#totalPages>#endIndex}"> ...... <s:a> <s:param name="requestPage" value="#endIndex+1"></s:param> 共有 <s:property value="%{#totalPages}"/>页</s:a> </s:if> <s:else> <s:a> <s:param name="requestPage" value="%{#totalPages}"></s:param> 共有 <s:property value="%{#totalPages}"/>页</s:a> </s:else> <s:a> 下一页 <s:param name="requestPage" value="#requestPage+1>#totalPages?#totalPages:#requestPage+1"></s:param> </s:a> <s:a> 尾页 <s:param name="requestPage" value="#totalPages"></s:param> </s:a> </div>
结合的css样式模板
#pageSplit{ margin-top:7px; margin-bottom:7px; font-size: 14px; text-align: center; } #pageSplit a{ display: inline-block; background-color:#CEE5EA; border :1px solid ; padding-top: 3px; padding-bottom: 3px; padding-left: 7px; padding-right:7px; color: #004779; text-decoration: none; } #pageSplit a:HOVER { background-color: #ADD8E5; } #query{ font-size:12px; width: 50px; height: 24px; text-align: center; margin: 0px; }
二、后台分页逻辑实现
1.通过监听器确定初始化的两个参数:pageSize和elementLength
首先将参数放到配置文件中:init.properties
#every pages show 12 datas pageSize=10 #show the choose length prePage,1,2,3,4,5,6,7,8 nextPage splitPageLength=5
监听器获取
InputStream is=MyServletContextListener.class.getClassLoader().getResourceAsStream("init.properties"); Properties initProperties=new Properties(); initProperties.load(is); PageSplitConfig.splitPageLength=Integer.parseInt(initProperties.getProperty("splitPageLength")); PageSplitConfig.pageSize=Integer.parseInt(initProperties.getProperty("pageSize"));
这样就将两个参数封装到了PageSplitConfig类中:
public class PageSplitConfig { //首先是每页显示多少条数据 public static Integer pageSize; //分页的长度 public static Integer splitPageLength; }
2.Action中进行分页的逻辑控制:
以showAllCards方法为例:
public String showAllCards(){ //预配置代码 /*Collection<Card>list=cardService.getAllCards(); ActionContext.getContext().put("cardlist", list);*/ Collection<CredentialType> credentialTypes=credentialTypeService.getAllCredentialTypes(); List<String> allCredentialTypes=new ArrayList<String>(); for(CredentialType temp:credentialTypes){ allCredentialTypes.add(temp.getCredentialTypeName()); } ActionContext.getContext().put("credentialTypes", allCredentialTypes); //预配置代码结束 //获取请求参数开始 HttpServletRequest request=ServletActionContext.getRequest(); String cardId=request.getParameter("cardId"); if(cardId==null||"".equals(cardId)){ ActionContext.getContext().put("cardId", ""); }else{ ActionContext.getContext().put("cardId", cardId); } String userName=request.getParameter("userName"); if(userName==null||"".equals(userName)){ ActionContext.getContext().put("userName", ""); }else{ ActionContext.getContext().put("userName",userName); } String typeofcredential=request.getParameter("typeofcredential"); if(typeofcredential==null||"".equals(typeofcredential)||"''".equals(typeofcredential)){ ActionContext.getContext().put("typeofcredential", ""); }else{ ActionContext.getContext().put("typeofcredential", typeofcredential); } String sex=request.getParameter("sex"); if(sex==null||"".equals(sex)||"不限".equals(sex)){ ActionContext.getContext().put("sex", "不限"); }else{ ActionContext.getContext().put("sex", sex); } String integral=request.getParameter("integral"); if(integral==null||"".equals(integral)){ ActionContext.getContext().put("integral", ""); }else{ ActionContext.getContext().put("integral", integral); } //获取请求参数结束 //计算分页参数开始 String requestPage=request.getParameter("requestPage"); if(requestPage==null||"".equals(requestPage.trim())){ requestPage="1"; } System.out.println("requestPage:"+requestPage); Collection<Card>cards=cardService.getCardsByMN(Integer.parseInt(requestPage),cardId,userName, typeofcredential,sex,integral); int totalLines=this.cardService.getTotalLines(Integer.parseInt(requestPage),cardId,userName, typeofcredential,sex,integral); System.out.println("totalLines:"+totalLines); PageSplitData.requestPage=Integer.parseInt(requestPage); PageSplitData.calculate(totalLines); //计算分页参数结束 System.out.println("startIndex:"+PageSplitData.startIndex); System.out.println("endIndex:"+PageSplitData.endIndex); System.out.println("totalPages:"+PageSplitData.totalPages); System.out.println("查询到的会员数量:"+cards.size()); ActionContext.getContext().put("startIndex",PageSplitData.startIndex); ActionContext.getContext().put("endIndex", PageSplitData.endIndex); ActionContext.getContext().put("requestPage",PageSplitData.requestPage); ActionContext.getContext().put("totalPages",PageSplitData.totalPages); ActionContext.getContext().put("employees", cards); ActionContext.getContext().put("cardlist", cards); return listAction; }
首先需要调用Service方法获取数据和数据总量
Collection<Card>cards=cardService.getCardsByMN(Integer.parseInt(requestPage),cardId,userName, typeofcredential,sex,integral); int totalLines=this.cardService.getTotalLines(Integer.parseInt(requestPage),cardId,userName, typeofcredential,sex,integral);
(1)获取指定分页数据的方法:
public Collection<Card> getCardsByMN(int requestPage, String cardId, String userName, String typeofcredential, String sex, String integral) { int m=(requestPage-1)*PageSplitConfig.pageSize; int n=PageSplitConfig.pageSize; String sql="from Card where 1=1 "; if(cardId!=null&&!"".equals(cardId.trim())){ sql=sql+" and cardId='"+cardId.trim()+"'"; } if(userName!=null&&!"".equals(userName.trim())){ sql=sql+" and userName='"+userName.trim()+"'"; } if(typeofcredential!=null&&!"".equals(typeofcredential.trim())&&!"''".equals(typeofcredential.trim())){ sql=sql+" and credentialType.credentialTypeName='"+typeofcredential.trim()+"'"; } if(sex!=null&&!"".equals(sex.trim())&&!"不限".equals(sex.trim())){ sql=sql+" and sex='"+sex+"'"; } if(integral!=null&&!"".equals(integral.trim())){ sql=sql+" and integral='"+integral.trim()+"'"; } return this.cardDao.getAllCards(sql,m,n); }
该方法会调用DAO方法:
public Collection<Card> getAllCards(String sql, int m, int n) { Query query=this.hibernateTemplate.getSessionFactory().openSession().createQuery(sql); query.setFirstResult(m); query.setMaxResults(n); return query.list(); }
(2)获取所有数据总量的方法:
public int getTotalLines(int requestPage, String cardId, String userName, String typeofcredential, String sex, String integral) { String sql="from Card where 1=1 "; if(cardId!=null&&!"".equals(cardId.trim())){ sql=sql+" and cardId='"+cardId.trim()+"'"; } if(userName!=null&&!"".equals(userName.trim())){ sql=sql+" and userName='"+userName.trim()+"'"; } if(typeofcredential!=null&&!"''".equals(typeofcredential.trim())&&!"".equals(typeofcredential.trim())){ sql=sql+" and credentialType.credentialTypeName='"+typeofcredential.trim()+"'"; } if(sex!=null&&!"".equals(sex.trim())&&!"不限".equals(sex.trim())){ sql=sql+" and sex='"+sex.trim()+"'"; } if(integral!=null&&!"".equals(integral.trim())){ sql=sql+" and integral='"+integral.trim()+"'"; } return this.cardDao.getAllCards(sql).size(); }
调用DAO方法实现:
public Collection<Card> getAllCards(String sql) { return this.hibernateTemplate.getSessionFactory().openSession().createQuery(sql).list(); }
(3)最重要的分页逻辑的实现在SplitPageData类中:
public class PageSplitData { //该条数据应该在调用响应方法之前赋值 public static Integer requestPage; //请求之后应该强调显示的页码,即响应之后的当前页或者响应时的响应页码。 public static Integer startIndex; //起始页码 public static Integer endIndex; //最后页码 public static Integer totalPages; //一共有多少页 /** * * @param total */ public static void calculate(int totalLines){ //每页显示多少条数据 int pageSize=PageSplitConfig.pageSize; //分页长度 int splitPageLength=PageSplitConfig.splitPageLength; //已经得到了数据一共有多少条:totalLines 和 请求页 requestPage //得到总页数 totalPages=totalLines/pageSize+(totalLines%pageSize==0?0:1); //计算startIndex和endIndex的关键原则就是endIndex-startIndex的结果是splitPageLength-1 if(splitPageLength%2==0){//分页长度是偶数,为了让当前页在中间,采用前多后少的分页方法 //这种情况下splitPageLength/2+splitPageLength/2==splitPageLength startIndex=requestPage-(splitPageLength/2+1);//正常情况(针对大数据) endIndex=requestPage+(splitPageLength/2);//特殊情况(针对大数据) }else{//分页长度是奇数 //这种情况下splitPageLength/2+splitPageLength/2=splitPageLength-1,符合之前说的原则 startIndex=requestPage-(splitPageLength/2);//这样就正好了 endIndex=requestPage+(splitPageLength/2);//正好 } if(startIndex<=0){ startIndex=1; if((startIndex+splitPageLength-1)>totalPages){ endIndex=totalPages; }else{ endIndex=startIndex+splitPageLength-1; } }else{//正常情况 if(endIndex>totalPages){ endIndex=totalPages; if((endIndex-(splitPageLength-1))<=0){ startIndex=1; }else{ startIndex=endIndex-(splitPageLength-1); } }else{ //正常情况,不做处理 } } //需要传递的几个参数都计算完毕 } public static Integer getRequestPage() { return requestPage; } public static Integer getStartIndex() { return startIndex; } public static Integer getEndIndex() { return endIndex; } public static Integer getTotalPages() { return totalPages; } }
三、总结
该分页模板需要的参数通过三种途径传到PageSplitData类中
1.监听器传递pageSize和elementLength两个参数
2.通过set方法设置请求页requestPage
3.直接传递totalLines
计算结果包括
1.首页码:startIndex
2.尾页码:endIndex
3.总页数:totalPages
#pageSplit a