Java Web中如何更好地分页呢?
并且分页时要记住当时的查询条件(现场恢复)
我以一个案例来详细说明.
我做了一个订单查询,界面如下:
这个订单查询有6个条件,而且有分页,每页显示10条记录.
查询页面(list.jsp)代码如下:
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme() + "://"
- + request.getServerName() + ":" + request.getServerPort()
- + path + "/";
- %>
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>个人信息管理</title>
- <link rel="stylesheet" type="text/css" href="<%=path%>/static/css/tongy_xx.css">
- <link rel="stylesheet" type="text/css" href="<%=path%>/static/css/ddcx.css">
- <script type="text/javascript" src="<%=path%>/static/js/common_util.js"></script>
- <script type="text/javascript" src="<%=path%>/static/js/jquery-1.10.1.js"></script>
- <script type="text/javascript" src="<%=path%>/static/js/jquery.form.js"></script>
- <script type="text/javascript" src="<%=path%>/static/js/page.js"></script>
- <jsp:include page="/WEB-INF/jsp/orders/orders.jsp"/>
- </head>
- <body>
- <div class="box">
- <jsp:include page="../public/top.jsp"/>
- <jsp:include page="../public/left.jsp"/>
- <form id="form" method="POST" action="<%=path%>/orders/list" >
- <div class="r_lr">
- <ul>
- <h3>订单查询</h3>
- <h4>检索条件</h4>
- <Li>
- <label>条码/订单号:</label><input type="text" id="barCode" name="barCode" value="${view.barCode }" />
- </Li>
- <Li>
- <label>订单类别:</label>
- <select id="orderclass" name="orderclass" value="${view.orderclass }" >
- <c:forEach items="${orderclass_map }" var="item" >
- <option value="${item.key }" > ${item.value }</option>
- </c:forEach>
- </select>
- </Li>
- <Li>
- <label>医院/诊所:</label><input type="text" id="hospital" name="hospital" value="${view.hospital }" />
- </Li>
- <Li>
- <label>医生:</label><input type="text" id="doctor" name="doctor" value="${view.doctor }" />
- </Li>
- <Li>
- <label>患者:</label><input type="text" id="patient" name="patient" value="${view.patient }" />
- </Li>
- <Li>
- <label>登记人:</label><input type="text" id="regname" name="regname" value="${view.regname }" />
- </Li>
- <Li class="submit"><input type="submit" value="查询" onclick="orders.checkForm()" /></Li>
- </ul>
- <h3>订单列表</h3>
- <table style="color: white" >
- <tr><th style="width:3">序号</th>
- <th>条码</th><th>类别</th>
- <th style="width:120" >医院/诊所</th>
- <th>医生</th><th>患者</th>
- <th style="display:none" >联系方式</th>
- <th >登记人</th>
- <th style="width:100" >到厂日期</th>
- <th style="width:120">操作</th></tr>
- <c:forEach var="orders" items="${view.recordList}" varStatus="status">
- <tr style="color:'red'" >
- <td>${status.count }</td>
- <td>${orders.barCode }</td>
- <td>${orders.orderclass }</td>
- <td>${orders.hospital }</td>
- <td>${orders.doctor }</td>
- <td>${orders.patient }</td>
- <td style="display:none">${orders.tel }</td>
- <td>${orders.regname }</td>
- <td>${orders.inDate }</td>
- <td>
- <a
- href="<%=path%>/orders/detail?barCode=${orders.barCode }&fsdf=${currentTime}">详情</a>
- |<a
- href="<%=path%>/osType/editInput?id=${orders.barCode }&fsdf=${currentTime}">防伪码</a>
- </td>
- </tr>
- </c:forEach>
- </table>
- <jsp:include page="../pageBottom.jsp">
- <jsp:param name="action" value="orders.query" />
- </jsp:include>
- </div>
- </form>
- </div>
- </body>
- </html>
我使用的是spring MVC框架,拿其中一个查询项来说,比如
<input type="text" id="doctor" name="doctor" value="${view.doctor }" />这是查询医生的.
后台控制器是如何接受查询的参数的呢?
后台controller 的action代码如下:
- @RequestMapping(value = "/list")
- public String list(Model model,ToothOrders toothOrders, OrdersView view) {
- String barCode=toothOrders.getBarCode();
- ToothOrders toothOrders2=null;
- try {
- toothOrders2=toothOrders.clone();
- BeanUtils.copyProperties(view, toothOrders2);
- } catch (CloneNotSupportedException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- if(ValueWidget.isNullOrEmpty(barCode)){
- PageAssistant.paging(toothOrders,true,view, toothOrdersDao);
- }else{
- PageAssistant.paging("barCode",barCode,view, toothOrdersDao);
- }
- int size=view.getRecordList().size();
- for(int i=0;i<size;i++){
- ToothOrders toothOrders3=null;
- toothOrders3=(ToothOrders)view.getRecordList().get(i);
- toothOrders3.setOrderclass(DictionaryParam.get("orderclass", toothOrders3.getOrderclass()));
- }
- model.addAttribute("orderclass_map", DictionaryParam.get(Constant2.DICTIONARY_GROUP_ORDERCLASS));
- model.addAttribute("orders", toothOrders2);
- model.addAttribute("view", view);
- model.addAttribute("currentTime", TimeHWUtil.getCurrentTimestamp()
- .getTime());
- return "orders/list";
- }
spring MVC 会自动把请求要素doctor 注入到action 方法list() 的参数ToothOrders toothOrders中,即toothOrders 中将会包含所有的请求要素(查询项).下面是查询时执行到controller 的list方法时的状态:
接受到请求要素之后,连接数据库进行查询操作.
我们发现list方法还有一个形参,OrdersView view,view是用于接收分页的信息(当前是第多少页,共有多少页,每页显示多少条记录)的.
查询之后,重新设置view 中的分页信息,然后返回给视图(页面)
是如何把分页信息返回给页面的呢?
controller 的代码:
- model.addAttribute("view", view);
页面pageBottom.jsp
该页面是所有分页页面需要include进去的,是一个公共的页面
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
- <table style="height: 35px" >
- <tr>
- <td nowrap="nowrap" style="width: 6%">
- <td nowrap="nowrap" style="width: 43%"><span style="color: white" >共
- <c:choose>
- <c:when test="${view.totalRecords==0}"><font color="#df625c">0</font> </c:when>
- <c:otherwise>
- ${view.totalRecords }
- </c:otherwise>
- </c:choose>
- 条记录, 当前第<font color="#46bbfe"> <c:choose>
- <c:when test="${view.totalPages==0 }">0</c:when>
- <c:otherwise>
- ${view.currentPage}
- </c:otherwise>
- </c:choose></font> / ${view.totalPages}页
- </span></td>
- <td nowrap="nowrap" style="display: none">
- <!-- 首页,view.currentPage的值为1 -->
- <td colspan="9"><span> <c:choose>
- <c:when test="${view.currentPage<=1}">首页</c:when>
- <c:otherwise>
- <a href="javascript:toPageFirst(${param.action})">首页</a>
- </c:otherwise>
- </c:choose> <c:choose>
- <c:when test="${view.currentPage<=1}">上一页</c:when>
- <c:otherwise>
- <a href="javascript:toPagePre(${param.action})">上一页</a>
- </c:otherwise>
- </c:choose> <c:choose>
- <c:when test="${view.currentPage>=view.totalPages }">下一页</c:when>
- <c:otherwise>
- <a href="javascript:toPageNext(${param.action})">下一页</a>
- </c:otherwise>
- </c:choose> <c:choose>
- <c:when test="${view.currentPage>=view.totalPages}">尾页</c:when>
- <c:otherwise>
- <a href="javascript:toPageLast(${param.action})">尾页</a>
- </c:otherwise>
- </c:choose> <strong>转</strong> <c:choose>
- <c:when test="${view.totalPages==0 }">
- <input type="text" id="view.currentPage" name="currentPage" value="0" />
- </c:when>
- <c:otherwise>
- <input type="text" id="view.currentPage" name="currentPage"
- value="${view.currentPage }" />
- </c:otherwise>
- </c:choose> <strong> 页</strong> <a href="javascript:toPageGo(${param.action})">GO</a>
- </span> <input type="hidden" id="view.thisPage" value="${view.currentPage }" />
- <input type="hidden" id="view.totalPages" name="totalPages"
- value="${view.totalPages }"> <input type="hidden"
- id="view.ascDesc" name="ascDesc" value="${view.ascDesc }"> <input
- type="hidden" id="view.sortKey" name="sortKey"
- value="${view.sortKey }"></td>
- </tr>
- </table>
上述页面包含的控件:
那么是如何恢复现场的呢?
也是通过view.
疑问:
(1)list方法中为什么需要toothOrders 呢,有view 就足够了?
不是的,还需要toothOrders,因为条件查询时,我使用的是Example,所以必须使用ToothOrders对象
(2)toothOrders和view 能同时接收到请求要素吗?
是的,这两个对象都会接收到请求要素.要注意,页面表单控件的name不是toothOrders.doctor,而是doctor,这一点与struts2 是不同的.
(3)点击[下一页]时是如何保证查询原来的条件呢?
点击[下一步]时,会触发表单提交,同点击[查询]按钮,即会把表单提交,与点击[查询]不同的是:点击查询时会把当前页重置为1(currentPage初始值为1,而不是0).
点击[上一页]或[下一页]时,应该查询原来的条件.比如我先查询文医生的订单,然后点击[上一页]或[下一页]应该仍然查询文医生的订单,但是此时我输入其他查询条件,再点击[上一页]或[下一页],那么查询条件就变化了.这就是问题.
界面如下,我先查询订单类型为"正常"的订单:
然后我在查询条件中添加条件:"文医生",然后点击[下一页],结果如下:
确实是进入了第二页,但是原来是共有2324页,但现在只有33页,因为查询条件变化了.但是这是不正常的,点击[上一页]或[下一页]时查询条件不应该变化.
原因:点击[查询]和点击[上一页]或[下一页],触发的是同一个表单提交.
但是存在一个问题,点击[上一页]或[下一页]时查询条件应该是原来的.
如何解决这个问题呢?
我的方案如下:点击[查询]时,把查询条件存储到session中,然后点击[上一页]或[下一页]时,表单提交新增一个参数,用于区分点击[查询].
详细方案见下一篇博客.
项目源码见附件demo_channel_terminal.zip
注意:
项目使用spring MVC,hibernate框架,使用maven构建
大家可以提出自己的方案,多谢!!!