本文对比了前端一次性加载与后端分页的性能差异,重点解析后端同步分页中搜索条件丢失的问题及Session解决方案。随后深入讲解基于Ajax的异步分页实现,通过全局变量保存搜索状态,解决了刷新页面后搜索条件重置的痛点,提供了完整的代码逻辑与优化思路。
分页技术概述
分页技术主要划分为后端分页与前端分页两种模式。
前端分页的局限性
前端分页
前端分页的核心逻辑是将所有数据一次性从服务器获取至客户端,随后利用JavaScript在本地进行分页展示。这种方式存在明显缺陷:假设数据库表dbgoods中存储了99999万条数据,若执行查询语句
select *from dbgoods where 1=1 并将结果集通过List<goods>list 进行接收,服务端需将海量数据传输至前端。这不仅导致巨大的下载流量(增加成本),还会给服务器带来沉重的处理压力。
后端分页与同步实现
后端分页
后端分页策略要求每次请求仅查询当前页的数据。以MySQL数据库为例,若需查询从第一条开始的后8条记录,具体操作如下:
select * from dbgoods order by id limit 0,8;
后端同步分页
其实现原理是设计一个Bean对象来封装分页相关的信息,
public class PageBean{
private long total; //总记录数
private List<T> list; //结果集
private int pageNum; // 第几页
private int pageSize; // 每页记录数
private int pages; // 总页数
private int size; // 当前页的数量 <= pageSize,该属性来自ArrayList的size属性
在首次加载页面时,系统默认加载第一页的分页数据:

需要特别注意的是
以往在编写SQL语句以获取总记录数时,常见的做法是:
select *from dbgoods ;
//用Lits<goods> lists去存储 得到的数据,如果数据有几万条,
//为了得到一个数字,去开辟这么大的空间,实属浪费
PageBean page=new PageBean();
page.setTotal=lists.size();
实际上,更规范的实现方式应为:
select count(*) from dbgoods where 1=1 ;
//查询语句返回的是一个表的总记录数,int型,
//where 1==1是为了查询搜索,做sql语句拼接
同步分页的实现流程为:从JSP界面传递currentpage参数至Servlet,Servlet通过request对象获取该参数,经DAO层查询数据库后,将数据返回并跳转至JSP界面展示。
从浏览器视角看,界面交互路径为:jsp--->servlet----->jsp(发生页面跳转),这种体验并不友好。
若界面包含搜索框,在执行搜索分页时,点击搜索按钮后,待数据传回JSP界面,页面已完全刷新,导致搜索框内的文本内容丢失。为解决此问题,需在点击搜索时将文本框的值一并放入request请求中发送给Servlet,再由Servlet传递至新的JSP页面。这一过程实现起来极为繁琐。

同步分页搜索条件处理方案
针对上述问题,主要有两种解决思路:
(1)构建两个界面布局相同的页面:一个用于展示全量数据的分页,另一个用于展示搜索结果的分页。当点击查询时,获取数据后由另一个页面(其下一页点击事件指向执行搜索逻辑)进行显示。
(2)利用Session存储:当点击搜索查询时,将搜索条件保存至Session中。点击下一页时,判断Session值:若为空,则执行全量数据的下一页逻辑;若不为空,则取出Session值作为查询条件,执行带有搜索条件的分页语句。此方法较为繁琐,且Session的销毁机制难以精确控制,容易引发Bug。
综上所述,采用同步方式实现分页功能,往往伴随诸多不便与体验缺陷。
Ajax异步分页实现与优化
Ajax异步分页
//jsp界面一个函数,传递查询页码,绘制表格
function InitTable(currentpage)
{
$.ajax({
type:"get",
url:"CustomServlet?type=search¤tpage="+currentpage,
async:true,
dataType:"json",
success:function(data)
{
DrawTable(data); //绘制表格
}
});
}
function DrawTable(data) //根据传递过来的json绘制表格
{
//给总页数赋值
$("#custom_all").text(data.pagelist.total);
//给当前页赋值
$("#custom_currunt_page").text(data.pagelist.pageNum);
//给总页数赋值
$("#custom_all_page").text(data.pagelist.pages);
var _th="<th><input id='cb_all' type='checkbox'></th>"
+"<th>ID</th>"
+"<th>客户名称</th>"
+"<th>公司名称</th>"
+"<th>联系人</th>"
+"<th>性别</th>"
+"<th>联系电话</th>"
+"<th>手机</th>"
+"<th>QQ</th>"
+"<th>电子邮箱</th>"
+"<th>通讯地址</th>"
+"<th>创建时间</th>";
document.getElementsByTagName("tbody")[0].innerHTML=_th;
for(var i=0;i<data.pagelist.list.length;i++)
{
var customerCreatetime= format(data.pagelist.list[i].customerCreatetime, 'yyyy-MM-dd');
var _tr=document.createElement('tr');
msg="<td><input type='checkbox'></td><td>"+data.pagelist.list[i].customerId+"</td><td>"+data.pagelist.list[i].customerName+"</td><td>"+data.pagelist.list[i].customerCompanyname+"</td><td>"+data.pagelist.list[i].customerContactname+"</td><td>"+data.pagelist.list[i].customerSex+"</td><td>"+data.pagelist.list[i].customerTelephone+"</td><td>"+data.pagelist.list[i].customerPhone+"</td><td>"+data.pagelist.list[i].customerQq+"</td><td>"+data.pagelist.list[i].customerEmail+"</td><td>"+data.pagelist.list[i].customerAddress+"</td><td>"+customerCreatetime+"</td>"
_tr.innerHTML=msg;
document.getElementsByTagName("tbody")[0].appendChild(_tr);
}
}
在初次加载页面时,默认调用初始化函数:
//初始化表格
InitTable(1);
需要特别强调的是,接下来的内容是核心重点:
在执行搜索操作时,定义一个名为mydata的全局变量,其作用域覆盖整个页面。
var mydata="";
接下来查看点击搜索按钮的事件处理代码:
btns.eq(1).click( //搜索按钮点击事件
function()
{
//custom_dialog_form是搜索的form表单,将其搜索条件序列化后赋值给一个全局变量 mydata=$("#custom_dialog_form").serialize();
$.ajax({
type:"post",
url:"CustomServlet?type=search¤tpage=1",
async:true,
dataType:"json",
data:mydata, //传递数据
success:function(data)
{
DrawTable(data);
$("#custom_dialog").css("display","none");
}
});
}
);
针对同步分页中搜索后下一页仍访问全量数据的问题,异步方案提供了更好的解决思路:
function InitTable(currentpage) //无搜索条件下的查询,传递一个页码
{
$.ajax({
type:"get",
url:"CustomServlet?type=search¤tpage="+currentpage,
async:true,
dataType:"json",
success:function(data)
{
DrawTable(data);
}
});
}
function InitTableSearch(currentpage)//有搜索添加的查询,传递页码
{
$.ajax({
type:"post",
url:"CustomServlet?type=search¤tpage="+currentpage,
async:true,
dataType:"json",
data:mydata,
success:function(data)
{
DrawTable(data);
$("#custom_dialog").css("display","none");
}
});
}
//下一页
$("#custom_btn_next").click(
function ()
{
var currentpage=$("#custom_currunt_page").text(); //获取页面的当前页的值
var pages=$("#custom_all_page").text(); //获取总页数
currentpage++;
if(currentpage<=pages)
{
if(mydata=="") //判断全局变量mydata是否为空,空表示没有进行搜索查询
{
InitTable(currentpage);
}
else
{
InitTableSearch(currentpage); //进行条件搜索
}
}
});
由于采用异步刷新机制,全局变量mydata中保存有搜索条件数据。即使用户手动刷新页面导致重新加载,mydata初始化为空,从而默认执行无条件搜索语句。这一机制巧妙解决了搜索与显示全部数据下一页之间的冲突,上一页、首页及尾页的逻辑同理可通。
总结
以上介绍了JS分页的实现方法,涵盖同步与异步两种模式,希望能为读者提供帮助。如有任何疑问,欢迎留言,小编会及时回复!