“纯真”ajax和Servlet实现jsp页面“无刷新”分页显示[含模糊查询和绑定事件]
首先说明使用的jar包和开发工具
三个jar包实现,分别是:fastjson-1.2.13.jar , jstl.jar 和 standard.jar。
附上下载路径 https://download.csdn.net/download/hupersan/11157286
开发工具:mysclipse 8.5、JDK1.7
数据库:MySql5.6
整体实现标题所述的效果除了实体类和dao包以及jsp页面仅使用了一个js和两个Servlet
重点讲解一下实现思路
- 首先Page是一个封装的实体类,里面有四个参数,在这里直接上代码不做过多解释。
// 四个参数
private int currentPage; // 当前页码
private int totalCount; // 数据总条数
private int totalPage; // 总页数
private int pageSize; // 每页数据量
对以上四个参数进行封装,下文所有涉及到Page相关的都是指这四个参数。
- 接下来进入正题,如果要使用无框架达到无刷新的分页效果,涉及到三个界面的数据交互,jsp,js和Servlet。首先排除jsp界面,为了达到无刷新的效果我固定了jsp的table格式,好在js页面对每一个tr里td的内容进行替换,以此来实现一个无刷新的分页效果,jsp关键部分,代码如下:
<table class="selectTable">
<tr>
<th width="3%"><input type="checkbox"/></th>
<th width="3%">商品编号</th>
<th width="10%">商品名称</th>
<th width="10%">商品类型</th>
<th width="10%">商品单价</th>
<th width="10%">商品总数量</th>
<th width="10%">操作</th>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
</table>
<input type="button" value="首页" name="first"/>
<input type="button" value="上一页" name="up"/>
<span class="showPage">1/1</span> 页
<input type="button" value="下一页" name="down"/>
<input type="button" value="尾页" name="last"/>
转到第<input type="text" name="number"/>页
<input type="button" name="jump" value="跳转"/>
在这里我设置的默认每页数据条数是5,所以就要搭五个tr。th中以百分数设置宽度,是为了固定每一个列的宽窄(所有列相加就是100%这样方便计算和使用)。
- 在jsp页面固定了table之后,就要在js和Servlet两者中选择一个进行页面的Page和数据内容的交互,由于Servlet属于服务器端,js属于客户端小脚本,为了减轻服务器的工作量,所以选择在js页面进行相对而言更繁重的相关数据操作。
接下来考虑到分页显示信息的两部分变量,Page和页面显示的信息数据,于是使用了两个Servlet。
一个PageServlet用来接收js传输过来的信息并返回Page相关信息转换后的的Json字符串,在js中进行回调。
PageServlet,代码如下:
// 得到每页显示的数据量
Integer pageSize = Integer.valueOf(request.getParameter("pageSize"));
String input = request.getParameter("input");// 获得用户模糊查询使用的输入内容
//多态实体化impl
Item_FrameDao id = new Item_FrameDaoImpl();
// 声明总条数
int counts;
//对应impl中的两个sql语句
if (input == null || input == "") {
counts = id.sumItem_FrameDao();// 总条数
} else {
counts = id.sumItem_FrameDao(input);// 总条数
}
// 再获得总页数
int totalPage= 1;
if (counts % pageSize == 0) {
totalPage= counts / pageSize;
} else {
totalPage = counts / pageSize + 1;
}
// 将数据存入实体类
Page pa = new Page();
pa.setTotalCount(counts);
pa.setTotalPage(totalPage);
// 将实体类转换为json串
String json = JSON.toJSONString(pa);
// 回调
out.print(json);
以上为手写的万能查询方法,c3p0同理,不做展示。
js中的代码:
$(document).ready(function() {
var currentPage = 1;// 当前页码
var totalPage = 1;// 总页码
var pageSize = 5;// 每页显示的数据量
var pageCount = 1;// 数据库总条数
var input="";//用户输入
// 传pageSize,得到pageCount和totalPage(模糊查询传送用户输入)
$.post("PageServlet", "pageSize=" + pageSize+"&input="+input, function(servletPage) {
var pa = $.parseJSON(servletPage);
totalPage = pa.totalPage;// 总页码
pageCount = pa.totalCount;// 总条数
showPage();// 显示页码
pageInfo();// 直接获取数据
});
// 显示*/*
function showPage() {
if(pageCount%pageSize==0){
currentPage=pageCount/pageSize;
}
//避免出现0/0的情况
if(pageCount==0){
totalPage=1;
}
//避免出现0/0的情况
if(currentPage==0){
currentPage=1;
}
//如果当前页码大于总页码,就将当前页码重新赋值为总页码
if(currentPage>totalPage){currentPage=totalPage};
//显示出?/?的状态
$(".showPage").text(currentPage + "/" + totalPage);
}
// 获取分页数据
function pageInfo() {
//如果不选中table替换td内容或元素的话,就会出现问题,比如说12条数据显示完第13行不是空行,而是接着显示前面的据替换在第13行和接下来的空行的位置
$(".selectTable tr td").html(" ");
$.post("FenYeServlet", "currentPage="+currentPage+"&pageSize="+pageSize+"&input="+input, function(pageJson) {
var fenYe = $.parseJSON(pageJson);
if (fenYe == "[]") {
return;
}
var num = 1;// 表格的行号
$(fenYe).each(function() {
//其中num代表第几行,td:eq(?)代表当前行的第几个列,html表示替换标签样式,txt表示替换文本内容
$("tr:eq("+num+")").children("td:eq(0)").html("<input type='checkbox' class='item' value='"+this.cid+"'/>");
$("tr:eq("+num+")").children("td:eq(1)").text((currentPage-1)*pageSize+num);//序号
$("tr:eq("+num+")").children("td:eq(2)").text(this.cname);//商品名称
$("tr:eq("+num+")").children("td:eq(3)").text(this.itemtype);//商品类型
$("tr:eq("+num+")").children("td:eq(4)").text(this.num);//商品单价
$("tr:eq("+num+")").children("td:eq(5)").text(this.price);//商品总数量
//a标签中的href='javascript:void(0)'表示让a标签走一个空方法,指向一个死链接
$("tr:eq("+num+")").children("td:eq(6)").html("<a href='SelectUpDateServlet?cid="+this.cid+"' class='update'>修改</a>/<a href='javascript:void(0)' class='del'>下架</a>");//操作
num++;// 序号+1
});//循环结束
//这里需要为下架绑定点击事件,否则下架按钮就算设置了点击事件也不会有反应,修改跳转servlet无需绑定事件
$(".del").on("click",function() {
//得到checkbox的value也就是选中商品对应的数据库id
var id = $(this).parents("tr").find(".item").val().trim();
var isSure = confirm("您确定要下架该商品?");
if (isSure == false) {
return;
}
delItem(id);
})
});
}
//下架商品的方法
function delItem(id){
$.post("DelItem_FrameServlet", "cid=" + id, function(data) {
if (data == "true") {
alert("下架成功!");
//获得总条数和总页数,PageServlet
$.post("PageServlet","pageSize="+pageSize+"&input="+input,function(data){
//jQuery提供了parseJSON(),将普通文本转换为json串。
var pa=$.parseJSON(data);
//从数据库返回总条数和总页数
totalCount=pa.totalCount;
totalPage=pa.totalPage;
if(totalCount==pageSize){
//如果总条数等于每页显示的数据量,就触发首页的点击事件
$('input[name=first]').trigger("click");//trigger中文含义“触发”
}else if(totalCount%pageSize==0){
//如果总条数余每页显示的数据量等等于0,就触发上一页的点击事件
$('input[name=up]').trigger("click");
}
showPage();
});
pageInfo();//调用分页方法
} else {
alert("下架失败!");
}
});
}
})
上述操作中对a标签使用 href=‘javascript:void(0)’ 的含义是,让超链接去执行一个js函数,而不是去跳转到一个地址,而void(0)表示一个空的方法,也就是不执行js函数,仅仅表示一个死链接。
另一个FenYeServlet则用来接收js传输过来的信息时并返回页面显示的数据相关信息转换后的Json字符串,在js中进行回调。
FenYeServlet,代码如下:
// 获得当前页码和每页显示的数据量
Integer currentPage = Integer.valueOf(request.getParameter("currentPage"));// 当前页码
Integer pageSize = Integer.valueOf(request.getParameter("pageSize"));// 每页显示的数据量
String input = request.getParameter("input");// 获得用户输入
// 得到分页信息
Item_FrameDao if = new Item_FrameDaoImpl();
//声明集合
List<Item_Frame> gList= if.FenYe(input, currentPage, pageSize);
// 转换为json串
String json = JSON.toJSONString(gList);
// 回调
out.print(json);
如果数据中含有时间类型,可以在将集合转换为json字符串向js传的时候调用JSON.toJSONStringWithDateFormat(集合,“日期格式”);将时间格式转换过来。
以上代码中,获取数据集合的impl方法如下:
/**
* 根据用户输入进行模糊查询
* @return
*/
public List<Item_Frame> FenYe(String input, int currentPage,int pageSize) {
String sql = "select * from item_Frame where cname like ? order by cid desc limit ?,?;";
return BaseDao.getEntityList(sql, Item_Frame.class, "%" + input+ "%", (currentPage - 1) * pageSize,pageSize);
}
以上代码的返回值BaseDao部分代码如下:
//实体类列表
public static <T> List<T> getEntityList(String sql, Class<T> cla,Object... objects) {
Connection con = getCon();
PreparedStatement ps = null;
ResultSet rs = null;
List<T> lists = new ArrayList<T>();
try {
ps = con.prepareStatement(sql);
if (objects != null) {
for (int i = 0; i < objects.length; i++) {
ps.setObject(i + 1, objects[i]);
}
}
rs = ps.executeQuery();
while (rs.next()) {
T entity = cla.newInstance();
Field[] fields = cla.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
field.set(entity, rs.getObject(field.getName()));
}
lists.add(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
close(con, ps, rs);
}
return lists;
}
以上为手写的返回实体类列表方法,但有一个小缺陷。比如类型转换的时候数据库是int类型,实体类的类型就必须要设成long,这是使用反射的一个缺陷,不过不影响接下来的操作,不做过多的解释。c3p0同理,不做展示。
js中的代码:
//模糊查询点击事件
$(".moCha").click(function() {
currentPage=1;
input = $(".qingzaicisousuo").val().trim();
$.post("PageServlet", "pageSize=" + pageSize+"&input="+input, function(servletPage) {
var pa = $.parseJSON(servletPage);
totalPage = pa.totalPage;// 总页码
pageCount = pa.totalCount;// 总条数
showPage();// 显示页码
});
pageInfo();// 直接获取数据!!!注意展示数据并没有在post里直接调用而是在外面调用
})//结束
以上就是js的模糊查询点击事件中的分页操作,当触发点击事件时,为当前页面重新赋初始值(有必要)!接收用户的输入,传入PageServlet获取相关信息,回调并解析json串,设置总页码和总条数,调用显示页码的方法,post结束!在post外调用pageInfo()方法!否则PageServlet会报空异常,控制台会提醒是转换异常,因为空值是没办法用Integer.valueOf()方法转换的,会报转换异常但是实际错误并不在转换上,而是内部调用的方法中还包括调用其他方法就会导致空值。
附上效果图:
还有上一页、下一页、首页、尾页、?/?和跳转的功能实现,其中显示 ?/? 的js代码在上文中有出现,这里不重复展示,直接上代码:
// “上一页”点击事件
$("input[name=up]").click(function() {
// 当前页码-1
if (currentPage == 1) {
currentPage = 1;
return;
} else {
currentPage--;
showPage();// 显示页码
pageInfo();// 直接获取数据
}
})// 上一页结束
// “下一页”点击事件
$("input[name=down]").click(function() {
// 当前页码+1
if (currentPage == totalPage) {
return;
} else {
currentPage++;
showPage();// 显示页码
pageInfo();// 直接获取数据
}
})// 下一页结束
//“首页”点击事件
$("input[name=first]").click(function() {
//防止首页时点击首页事件时重新替换
if(currentPage ==1){
return;
}
// 当前页码=1
currentPage=1;
showPage();// 显示页码
pageInfo();// 直接获取数据
})// 首页结束
// “尾页”点击事件
$("input[name=last]").click(function() {
//防止尾页时点击尾页事件时重新替换
if(currentPage == totalPage){
return;
}
// 当前页码=总页数
currentPage = totalPage;
if (currentPage > totalPage) {
currentPage = totalPage;
return;
} else {
showPage();// 显示页码
pageInfo();// 直接获取数据
}
})//尾页结束
//“跳转”点击事件
// 点击跳转按钮时对输入跳转页面的数字进行判断
$("input[name=jump]").click(function() {
// 获得跳转页面框输入的数字
var num = $("input[name=number]").val().trim();
var pre =/^\d*$/; //正则表达式,返回boolean类型
if(pre.test(num)==false){
alert("请输入正确的数字!");
$("input[name=number]").val("");
return;
}
if(num>totalPage){
alert("不能超出当前页!");
$("input[name=number]").val("");
return;
}
if(num<1){
alert("跳转页码不能小于1!");
$("input[name=number]").val("");
return;
}
currentPage=num;
$(".showPage").text(currentPage + "/" + totalPage);
pageInfo();// 直接获取数据
})// 跳转结束
至此,使用纯ajax和Servlet的数据交互实现JavaWeb无刷新分页显示含模糊查询结束,第一次发博客,欢迎大家多提建议。
by 琥珀酱~