上一章我们整理了无条件的分页查询,实现过程较为简单。今天带来的是条件查询之后的内容进行分页。
先上效果图:
如何实现这个效果呢?先看我的目录结构
首先说一下思路,在上一篇博客实现的内容上我们需要加一些点功能:第一、多条件查询,我们如何在多个条件选择后得到我们想要的结果。第二、多条件查询结果后
点击下一页如何带着上一次的查询条件。第三、在删除之后,如何回到之前的页面,如何在删除最后一页最后一条数据后自动跳到上一页。
第一步:JavaBean
第一个是Stu,这个用来封装学生的信息,第二个是PageBean,用来封装显示页面的属性,包括当前页码pc、总页数tp(这个不需要手动设置,直接用tr/ps 判断即可得到)、总记录数tr(满足条件的数据总记录数)、每页的记录条数ps、装多个Stu的beanList(当前页的记录 ),在上一次的基础上加了一个 url属性,主要解决的是,多条件查询得到结果后,切换页面条件得以保留,防止条件丢失。
package com.jie.bean;
public class Stu {
private int id;
private String name;
private String sex;
private int age;
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;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Stu [age=" + age + ", id=" + id + ", name=" + name + ", sex="
+ sex + "]";
}
}
package com.jie.bean;import java.util.List;public class PageBean <T>{ private int pc;//当前页码 private int tp;//总页数 private int tr;//总记录数 private int ps;//每页记录数 private List<T> beanList;//当前页的记录 private String url;//url后的条件 public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public int getPc() { return pc; } public void setPc(int pc) { this.pc = pc; } public int getTp() { tp = tr/ps; return tr%ps==0?tp:tp+1; } public int getTr() { return tr; } public void setTr(int tr) { this.tr = tr; } public int getPs() { return ps; } public void setPs(int ps) { this.ps = ps; } public List<T> getBeanList() { return beanList; } public void setBeanList(List<T> beanList) { this.beanList = beanList; } }
第二步:我们先来看看dao层
多条件查询查询后,总记录数就不在是之前的了,而是我们满足条件之后的记录数。这时我们就需要考虑怎么获取现在的记录数。当页面输入的数据时在Servlet中被封
装成一个Stu对象。而当我们页面没有输入条件时,它的属性就为空或者为零,默认为全部查询。所以我们这里会做一个判断,如果满足条件我们就在whereSql语句用
StringBuilder的append()方法把条件添加进去,而后面的参数赋值我用了一个List集合,满足条件就把参数加到集合中,然后把它转化为数组。然后通过DBUtils的ScalarHandler
结果集得到总记录数(tr)。而后面pc(当前页码)进行了一个判断,当pc(当前页码)>tb(总页数),即当前页大于总页数时pb赋值给pc,这里在删除最后一页最后一条数据
后自动跳到上一页时起作用。最后通过pc(当前页码)、ps(每页记录数)得到分页条件 limit (pc-1)*ps,ps, 然后拼凑前面的sql语句(查询条件),组成最终的sql语句,查询得到
BeanListHandler结果集,赋值给beanList(当前页的记录),设置给pb(PageBeand对象),并返回给servlet层。
package com.jie.dao;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import com.jie.bean.PageBean;
import com.jie.bean.Stu;
import com.jie.utils.JdbcUtils;
public class StuDao {
public PageBean<Stu> query(Stu s,int pc,int ps) throws SQLException{
//创建pb
PageBean<Stu> pb = new PageBean<Stu>();
//设置已有条件 ps
pb.setPs(ps);
//设置tr
QueryRunner qr = new QueryRunner();
Connection conn = JdbcUtils.getConnection();
StringBuilder cntSql = new StringBuilder("select count(*) from stu");
StringBuilder whereSql = new StringBuilder(" where 1=1");
List<Object> params = new ArrayList<Object>();
int id = s.getId();
if(id!=0){
whereSql.append(" and id like ?");
params.add("%" +id+ "%");
}
String name = s.getName();
if(name!=null && !name.trim().isEmpty()){
whereSql.append(" and name like ?");
params.add("%" +name+ "%");
}
String sex = s.getSex();
if(sex!=null && !sex.trim().isEmpty()){
whereSql.append(" and sex=?");
params.add(sex);
}
int age = s.getAge();
if(age!=0){
whereSql.append(" and age like ?");
params.add("%" +age+ "%");
}
Number num =(Number)qr.query(conn,cntSql.append(whereSql).toString(), new ScalarHandler<Object>(), params.toArray());
int tr = num.intValue();
pb.setTr(tr);
//当删除最后一页时进行判断 跳转前一页
pc = pc>pb.getTp()?pb.getTp():pc;
pb.setPc(pc);
// 得到beanList
StringBuilder sql = new StringBuilder("select * from stu");
StringBuilder limitSql = new StringBuilder(" limit ?,?");
params.add((pc-1)*ps);
params.add(ps);
List<Stu> benaList = qr.query(conn, sql.append(whereSql).append(limitSql).toString(), new BeanListHandler<Stu>(Stu.class), params.toArray());
pb.setBeanList(benaList);
conn.close();
return pb;
}
public void delete(int id) throws SQLException {
QueryRunner qr = new QueryRunner();
Connection conn = JdbcUtils.getConnection();
String sql = "delete from stu where id=?";
Object[] param = {id};
qr.update(conn, sql, param);
conn.close();
}
}
第三步:Servlet
这里我们用了一个BaseServlet,然后用一个StuServlet去继承它,用反射的原理进行方法调用。在Servlet调用dao的query方法得到了PageBean对象 pb,在Servlet中我加了一getUrl方法,获取了项目路径+Servlet路径+queryString的部分内容(条件截取),这个Url就得到了上一次查询条件的绝对路径和条件参数,然后保设置 PageBean的对象pb中,最后把pb保存在request域中,转发回index.jsp。而后面的delete方法,一样的先截取上次的查询条件,然后转发到查询页面,回到上次查询的页码。
package com.jie.servlet;
import java.io.IOException;
import java.sql.SQLException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jie.bean.PageBean;
import com.jie.bean.Stu;
import com.jie.dao.StuDao;
public class StuServlet extends BaseServlet {
private static final long serialVersionUID = 1L;
StuDao dao = new StuDao();
public void query(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Stu s = new Stu();
String id = request.getParameter("id");
if (id != null && !id.trim().isEmpty()) {
s.setId(Integer.parseInt(id));
}
String name = request.getParameter("name");
if (name != null && !name.trim().isEmpty()) {
s.setName(name);
}
String sex = request.getParameter("sex");
if (sex != null && !sex.trim().isEmpty()) {
s.setSex(sex);
}
String age = request.getParameter("age");
if (age != null && !age.trim().isEmpty()) {
s.setAge(Integer.parseInt(age));
}
int pc = Integer.parseInt(request.getParameter("pc"));
int ps = 10;
StuDao dao = new StuDao();
try {
PageBean<Stu> pb = dao.query(s, pc, ps);
pb.setUrl(getUrl(request));
request.setAttribute("pb", pb);
request.getRequestDispatcher("/index.jsp").forward(request,
response);
} catch (SQLException e) {
e.printStackTrace();
}
}
public String getUrl(HttpServletRequest request) {
String contextPath = request.getContextPath();
String servletPath = request.getServletPath();
String queryString = request.getQueryString();
int index = queryString.indexOf("&pc=");
String url = contextPath + servletPath + "?"
+ queryString.substring(0, index);
return url;
}
public void delete(HttpServletRequest request, HttpServletResponse response)
throws NumberFormatException, SQLException, ServletException,
IOException {
String id = request.getParameter("id");
dao.delete(Integer.parseInt(id));
int index = request.getQueryString()
.indexOf("/StuServlet?method=query");
String url = request.getQueryString().substring(index);
System.out.println(url);
request.getRequestDispatcher(url).forward(request, response);
}
}
package com.jie.servlet;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class BaseServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//获取参数,根据参数调用的方法
String methodName = request.getParameter("method");
if(methodName==null||methodName.trim().isEmpty()) {
throw new RuntimeException("没有传递参数,无法确定调用的方法");
}
//得到当前类的对象
Class clazz = this.getClass();
Method method = null;
try {
method = clazz.getMethod(methodName,HttpServletRequest.class, HttpServletResponse.class);
} catch (Exception e) {
e.printStackTrace();
}
//调用方法
try {
method.invoke(this, request,response);
} catch (Exception e) {
e.printStackTrace(); } }}
最后:我们来看看JSP页面
我们导入JSTL标签库,然后用forEach循环,遍历pb(PageBean对象)的值,我把上一页,下一页,页码等的超链值都换成了${pb.url}+pc,从而达到了保留条件的目的。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
<style type="text/css">
body{
background:rgb(230,230,230);
}
table td{
width:100px;
height: 30px;
text-align: center;
}
.menu{
width:520px;
height:40px;
text-align:center;
line-height:40px;
}
</style>
</head>
<body>
<form action="StuServlet" method="get">
<input type="hidden" name="method" value="query">
用户ID:<input type="text" name="id" />
姓名:<input type="text" name="name"/>
性别:<select name="sex">
<option value="">请选择性别</option>
<option value="男">男</option>
<option value="女">女</option>
</select>
年龄:<input type="text" name="age"/>
<input type="hidden" name="pc" value="1"/>
<input type="submit"/><br/>
</form>
<table border="1" cellspacing="0">
<c:forEach items="${pb.beanList}" var="Stu">
<tr>
<td>${Stu.id }</td>
<td>${Stu.name }</td>
<td>${Stu.sex }</td>
<td>${Stu.age }</td>
<td><a href="StuServlet?method=delete&id=${Stu.id }&queryUrl=${pb.url}&pc=${pb.pc}"/>删除</a></td>
</tr>
</c:forEach>
</table>
<div class="menu">
<a href="${pb.url}&pc=1">首页</a>
<c:if test="${pb.pc>1}">
<a href="${pb.url}&pc=${pb.pc-1}">上一页</a>
</c:if>
<c:choose>
<%--当总页数小于5 --%>
<c:when test="${pb.tp<=5}">
<c:set var="begin" value="1"></c:set>
<c:set var="end" value="${pb.tp}"></c:set>
</c:when>
<%--总页数大于5 --%>
<c:otherwise>
<c:set var="begin" value="${pb.pc-2}"></c:set>
<c:set var="end" value="${pb.pc+2}"></c:set>
<%--头溢出 --%>
<c:if test="${begin<1}">
<c:set var="begin" value="1"></c:set>
<c:set var="end" value="5"></c:set>
</c:if>
<%--尾溢出 --%>
<c:if test="${end>pb.tp}">
<c:set var="begin" value="${pb.tp-4}"></c:set>
<c:set var="end" value="${pb.tp}"></c:set>
</c:if>
</c:otherwise>
</c:choose>
<%--遍历循环页码表 --%>
<c:forEach var="i" begin="${begin}" end="${end}">
<c:choose>
<c:when test="${i eq pb.pc}">
${i }
</c:when>
<c:otherwise>
<a href="${pb.url}&pc=${i }">${i }</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${pb.pc<pb.tp}">
<a href="${pb.url}&pc=${pb.pc+1}">下一页</a>
</c:if>
<a href="${pb.url}&pc=${pb.tp }">尾页</a>
${pb.pc}/${pb.tp}
</div>
</body>
</html>
备注:数据库连接用的c3po
工具类
package com.jie.utils;c3p0配置文件
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcUtils {
//配置文件的默认配置 必须给出c3p0-config.xml
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
/**
* 使用连接池返回一个连接对象
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
return dataSource.getConnection();
}
/**
* 返回连接池
* @return
*/
public static DataSource getDataSoutce(){
return dataSource;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<!-- 连接四大参数配置 -->
<property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">123</property>
<!-- 池参数配置 -->
<property name="acquireIncrement">3</property>
<property name="initialPoolSize">10</property>
<property name="minPoolSize">2</property>
<property name="maxPoolSize">10</property>
</default-config>
</c3p0-config>