高端ajax分页


placeholder image
admin 发布于:2012-6-26 22:09:00
阅读:loading

ajax分页很简单,具体怎么简单这个就不同详细说了,要想写的灵活,通用,以前的那个实现就显得逊色了。

其实ajax分页对我来讲是小菜了,现在为何又关注这个?实在是因为现在改的项目里面有ajax分页的实现,觉得里面几个地方确实是比JSP分页要好。

注意:前端ajax分页略过,这里指使用ajax+json的方式使用所有前端处理分页的方式,在页面上用JS控制分页,只关注这个的话,绕道吧。

ajax分页优点:

第一:在列表页面有,可能会有很多查询条件,一部分查询条件都是从数据库里面查询出来的,类似基础数据,那么在进入页面之前需要先加载,每翻一页害得加载,换成无刷新分页则就只需要加载一次即可。

第二:在按条件查询的时候,需要按条件显示翻页数据,比如,下拉框改选中的选中,单选框,文本框等等(去年听到一个名词叫:“回显”,是一个意思),就不需要页面讲值传来传去的,ajax分页的直接将查询条件获取到后处理,不需要再保存返并返回做数据回显用了,为什么呢?

第三:无刷新当然要比刷新效果要好了。

第四:此处省略一些字。

ajax分页实现:

现在一个jquery的ajax请求返回的数据方式多了,见得多的实现方式是利用ajax+json实现的,前台发送ajax请求,后来不变,只是Dao在处理数据的时候,将返回回来的分页列表对象转换成相应的json数据,这个转换的组件此处略过,返回到前台页面,页面再根据json中的各个属性来做相应的处理。

其实想想就知道,将json数据显示到页面中,常见的做法是动态创建 <tr><td>的形式来创建,既然是这种JS动态创建的,那么开发人员不能直接操作分页表格对象,即操作list数据,假设列表属性中有图片,全选什么的,都还需要做特殊处理。我这里想说的是既如此那么对象中所有的数据到要在后台处理好,比如,User对象有个sex属性,页面需要做国际化,那么数据库中存储的肯定是 user.sex类型的text,需要处理的肯定是在action层中迭代数据,然后将值拿到,再 getText 处理,如果是在页面上那么<s:text />s标签直接就搞定了,等等,再比如说:管理员权限的用户列表,用户有状态:可用、禁用,对于禁用的用户拥有删除的权限,如果这些判断放在后台,我想有这层限制,使用这个组件的人肯定用的也不爽,要么又得改了,要么果断排斥,这是一个比较疼的问题。

/*********************************************************************/

这里关于ajax分页在项目中的应用谈两点。第一点小规模的改动将项目中的jsp分页改造成ajax分页;第二点在以后的项目中使用ajax分页,并且分页的数据,例如显示的分页数据,还是使用<c:forEach />这种后台语言实现,同原始JSP分页实现,页面上可以有后台代码的判断逻辑。

关于小规模的改动将jsp分页修改成ajax分页,这里的实现到最后,只是单纯的将JSP分页转换成ajax的,页面上面无刷新,但是出于对程序的负责态度,性能并没有减少,单纯的无刷新而已,这种效果优点就是代码改动非常小,实现了无刷新,不足:性能没优化到,白搭。这种方式实现提供如下思路:第一:在显示分页列表的时候,页面改怎么写不变,分页的那一部分数据,换成ajax加载,即加载ajax加载的地址是分页的第一页的数据,即给个页号或者相关查询条件去能显示分页显示数据的页面,既然是ajax加载的,也就是相当于JS代码,则把加载的源文件数据获取,然后再将获取分页数据的源文件(鼠标右键——查看源文件),将源文件获取到,用正则也好,将关于分页的那一段数据获取到,然后在显示在页面上,即,有一个js函数,改函数传递一个参数,返回根据这个参数加载的地址的源文件,那么传递一个显示第N页的分页地址,改函数直接将返回第N页的源文件数据,再解析这段源文件,然后显示在页面上,第N+1页也是如此,到此为止,算是完事儿了。至于根据一个地址返回一个地址解析后的源文件的JS技术实现,我所知道有两种形式:1jquerylaod函数,可以将地址返回的源文件,追加到某个对象里头;2dwr中的WebContext对象forwardToString函数。

/*********************************************************************/

现在说的是一种项目中可以运用的ajax分页实现,可能说东西都不难,就是思路不一样,这个思路也是见到项目中的ajax分页之后想了几天想到的,虽然都是ajax分页,但我觉得这个优点就是灵活性强,上手容易,基本不需要关注别的代码。

效果图:


基于这种方式的实现,必须要解决的问题:

每次翻页的时候,页面无刷新,且页面上面的数据不能用json格式的处理,因为要把后台列表的逻辑判断交给开发使用者。

ajax实现分页并且业务逻辑用JSP代码控制,而非JS来控制,则需要处理一下,算了这个方面就不赘述了,如果有心实现的话,必然会遇到这个问题的,等有人遇到了再议。

把这里问题处理好了,基本上就完事儿了。怎么解决这个问题呢,我的实现是采用jquery.form plugin,该插件是什么我这里不说,因为前面的几篇日志有关于这个的介绍。页面大致布局如下:

image.png

直接上代码吧。

/****************************************************************************************************************************************/

1、web.xml,配置分页的servlet

<servlet>
      <servlet-name>person</servlet-name>
      <servlet-class>com.demo.page.servlet.PersonServlet</servlet-class>
</servlet>
<servlet-mapping>
      <servlet-name>person</servlet-name>
      <url-pattern>/person.do</url-pattern>
</servlet-mapping>

2、PersonServlet.java

package com.demo.page.servlet;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.demo.page.PageFinder;
import com.demo.page.Person;

public class PersonServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("PersonServlet.doGet()");
        String encoding = "utf-8";
        request.setCharacterEncoding(encoding);
        response.setCharacterEncoding(encoding);
        response.setContentType("text/html;charset=" + encoding);
        String method = request.getParameter("method");
        if("page".equals(method)){
            String pageNo = request.getParameter("page");
            if(pageNo == null){
                pageNo = "1";
            }
           
            List<Person> dataList = new com.demo.page.Data().getDataList(Integer.parseInt(pageNo));
           
            PageFinder pageFinder = new PageFinder(Integer.parseInt(pageNo), 10, 100, dataList);
           
            request.setAttribute("pageFinder", pageFinder);
           
            request.getRequestDispatcher("/demo/p1table.jsp").forward(request, response);
           
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
       
        this.doGet(req, resp);
    }
}

3、Data.java是我的Dao类,就是生成一些数据并存储在集合中,并返回,来模拟代替我们的从数据库中查询

package com.demo.page;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.UUID;

/**
 * @author cdd
 * 构造100条数据,用于分页
 */
public class Data {

    private static final int pageSize = 10;
    private static final int totalPage = 10;
   
    public final static List<Person> dataList = new ArrayList<Person>();
   
    static{
        for(int i=1;i<=pageSize * totalPage;i++){
            dataList.add(new Person(i,UUID.randomUUID().toString(),new Random().nextBoolean() ? "男" : "女"));
        }
    }
   
    public List<Person> getDataList(int pageNo){
        List<Person> list = new ArrayList<Person>();
        int start = (pageNo-1) * pageSize;
        int end = (pageNo-1) * pageSize + pageSize >= dataList.size() ? dataList.size() : (pageNo-1) * pageSize + pageSize;
        for(int i=start;i<end;i++){
            list.add(dataList.get(i));
        }
        return list;
    }
   
    public static void main(String[] args) {
       
        List<Person> dataList = new Data().getDataList(11);
        for (Person person : dataList) {
            System.out.println(person.getId() + "," + person.getName() + "," + person.getSex());
        }
       
    }
}

4、PageFinder.java该类只是一个对于分页数据的简单封装,将需要分页的数据传递给他,由它来控制分页

package com.demo.page;

public class PageFinder {

    public static final int DEFAULT_PAGE_SIZE = 10;
   
    /**
     * 分页大小,即每页最多能显示的记录条数
     */
    private int pageSize;
    /**
     * 分页的总记录数
     */
    private int totalRows;
    /**
     *当前页数
     */
    private int page;
    /**
     * 上一页
     */
    private int prePage;
    /**
     * 下一页
     */
    private int nextPage;
    /**
     * 最后一页
     */
    private int lastPage;
   
    private Object data;

    public PageFinder(int page, int pageSize, int totalRows) {
        this.setPage(page);
        this.setPageSize(pageSize);
        this.setTotalRows(totalRows);
    }
   
    public PageFinder(int page, int pageSize, int totalRows,Object data) {
        this.setPage(page);
        this.setPageSize(pageSize);
        this.setTotalRows(totalRows);
        this.setData(data);
    }

    public int getLastPage() {
        return (int) Math.round(Math.ceil((double) this.getTotalRows()
                / (double) this.pageSize));
    }

    public void setLastPage(int lastPage) {
        this.lastPage = lastPage;
    }

    public int getTotalRows() {
        return totalRows;
    }

    public void setTotalRows(int totalRows) {
        this.totalRows = totalRows;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public int getNextPage() {
        return this.getPage() + 1 >= this.getLastPage() ? this.getLastPage()
                : (page + 1);
    }

    public void setNextPage(int nextPage) {
        this.nextPage = nextPage;
    }

    public int getPrePage() {

        return (page - 1 >= 1) ? (page - 1) : 1;
    }

    public void setPrePage(int prePage) {
        this.prePage = prePage;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
   
}

5、显示分页的主页面,暂时称为 personManager.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>ajax分页实例</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.5.2.min.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.form.js"></script>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery.page.js"></script>
<script type="text/javascript">
    $(function(){
        $("#mySubmitForm").ajaxSubmitForm();
    });
</script>
</head>
<body>
<center>
    <form action="${pageContext.request.contextPath }/person.do?method=page" method="post" id="mySubmitForm">
        姓名:<input type="text" name="name" />
        性别:<input type="text" name="sex" />
        <input type="submit" value="查询" />
    </form>
    <h4>ajax分页,非返回json形式,<font color="red">代码跟非ajax分页一样灵活</font></h4>
    <div id="showPager"></div>
</center>   
</body>
</html>

6、分页数据迭代页面,暂时称为 personList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<table>
    <tr>
        <td>编号</td>
        <td>姓名</td>
        <td>性别</td>
        <td>操作</td>
    </tr>
    <tbody>
        <c:forEach items="${pageFinder.data }" var="data">
            <tr>
                <td>${data.id }</td>
                <td>${data.name }</td>
                <td>${data.sex }</td>
                <td>
                    <c:if test="${data.id % 2 == 0 }">
                        <a href="?id=${data.id }">修改</a>
                    </c:if>
                </td>
            </tr>
        </c:forEach>
    </tbody>
    <tr>
        <td colspan="3" align="center" >
            <c:import url="../common/page.jsp?formId=mySubmitForm"></c:import>
        </td>
    </tr>
</table>

7、js,暂时称为jquery.page.js

/**
 * jquery form plugin插件简单封装
 * 在少量改动原有JSP分页代码的基础上,将分页转换成ajax形式的,非返回json格式数据的形式,与JSP分页一样灵活
 */
(function($) {
    $.fn.ajaxSubmitForm = function(options) {
        var thisElement = $(this);
        //当每次点击查询按钮时,查询的数据显示第一页
        thisElement.find(":submit").bind("click",function(){
            $("#queryPage").val("1");
        });
        var defaults = {
            target : '#responseoutput',
            type : 'post',
            dataType : 'html',
            beforeSubmit : function(formData, jqForm, options){
                return true;
            },
            success : function(responseText, statusText, xhr, $form){
                $("#" + options.showPagerId).html("");
                $("#" + options.showPagerId).append(responseText);
            },
            resetForm : false,
            timeout : 10000,
            error:function(tip){
                alert("出错了:" + tip.status);
            },
            showPagerId:'showPager'
        };
        var options = $.extend(defaults, options);
        this.each( function() {
            var output = document.getElementById("responseoutput");
            if (output == null) {
                var putdiv = document.createElement("div");
                putdiv.id = "responseoutput";
                putdiv.style.display = "none";
                document.body.appendChild(putdiv);
            }
            $(thisElement).ajaxForm(options);
            $(thisElement).trigger("submit");
        });
    };
})(jQuery);

8、分页的按钮栏封装,主要是控制上一页、下一页,暂时称为page.jsp

<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${not empty pageFinder.data}">
<div align="center">
&nbsp;&nbsp;<a href="javascript:void(0);" onclick="goFirstPage()">首页</a>
&nbsp;&nbsp;<a href="javascript:void(0);" onclick="goPrePage()">上一页</a>
&nbsp;&nbsp;<a href="javascript:void(0);" onclick="goNextPage()">下一页</a>
&nbsp;&nbsp;<a href="javascript:void(0);" onclick="goLastPage()">末页</a>&nbsp;
第${pageFinder.page }页&nbsp;共&nbsp;${pageFinder.lastPage }&nbsp;页,
每页&nbsp;${pageFinder.pageSize }&nbsp;项
</div>
<script type="text/javascript">
    var page = "${pageFinder.page }";
    var lastPage = "${pageFinder.lastPage}";
    //首页
    function goFirstPage(){
        if(page != "1"){
            createQueryPageHidden("1");
        }
    }

    //上一页
    function goPrePage(){
        if(parseInt(page) - 1 >= 1){
            createQueryPageHidden(parseInt(page) - 1);
        }
    }
   
    //下一页
    function goNextPage(){
        if(parseInt(page) + 1 <= parseInt(lastPage)){
            createQueryPageHidden(parseInt(page) + 1);
        }
    }

    //末页
    function goLastPage(){
        if(parseInt(page) != parseInt(lastPage)){
            createQueryPageHidden(lastPage);
        }
    }

    function createQueryPageHidden(value){
        var queryFormId = "${param.formId}";
        var queryPage = document.getElementById("queryPage");
        if(queryPage == null){
            $("#" + queryFormId).append("<input type='hidden' name='page' id='queryPage' value='" + value + "' />");
        }else{
            $("#queryPage").val(value);
        }
        $("#" + queryFormId).trigger("submit");
    }
</script>
</c:if>

9、把javabean类给忘了,这里贴上代码补充下

package com.demo.page;

public class Person {

 private int id;//编号
 private String name;//名称
 private String sex;//性别

 public Person(){
  
 }
 
 public Person(int id,String name,String sex){
  this.id = id;
  this.name = name;
  this.sex = sex;
 }
 
 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getSex() {
  return sex;
 }

 public void setSex(String sex) {
  this.sex = sex;
 }

}

/****************************************************************************************************************************************/

代码就这些了,没什么难度,最值得说的就是非 js + json,非js迭代table数据,而是jsp代码迭代集合,如果不知所云,两个可能,1、我没说清楚,2、你没这么思考过,不知道实现这个东西的常规实现。

现在贴上效果图吧,无图无真相。

日志说完了,高端在哪里呢,我觉得就是第6段代码,这段代码看似很平常,其实。。。?

补充一点:

今天上午给一些功能的查询列表页面添加 “重置”按钮的功能,普通jsp查询分页,每次提交后,都刷新页面,然后再将该回显的文本框回显,下拉框选中,此时的重置按钮,重置的状态时onload页面之后,js代码执行完之后的一个状态,而非未点击查询按钮时的状态,即初始化进入页面的一个状态,文本框为空白,下拉框选中的是 “请选择”,或者“全部”,需要特殊处理,而ajax方式的查询,就能狠方便的解决这种问题,直接一个rest按钮。

 点赞


 发表评论

当前回复:作者

 评论列表


留言区