通用分页实现

为什么要通用分页?

1) 为了提高查询性能及节约网络流量,每次只查询指定的记录数,而不是全部,在数量比较大时很有用
2)当点击下一页或指定页面的数据时,将带着所有的查询条件,再次执行查询

最终效果展示:

 

图解

 效果展示

实现思路:(理解)

怎么封装一个通用分页查询方法,先编写一个查询sql语句,将查询条件与分页实体放入做为方法的参数。

判断是否需要分页

1.不分页,直接查询,先遍历,然后返回结果集

2.分页,查询总页数,如果总记录为0,直接返回空的结果集,如果不为0,先编写需要显示分页条数的sql语句,然后查询当前页的数据,返回当前页的结果集(1~10页)。

 封装一个分页信息实体,因为我们后面需要用它的属性

package com.zking.utils;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import com.mysql.jdbc.StringUtils;
public class PageBean {
	
	/**
	 * 页码
	 */
	private int page = 1;

	/**
	 * 每页显示的记录数
	 */
	private int rows = 10;

	/**
	 * 总记录数
	 */
	private int total = 0;

	/**
	 * 是否分页
	 */
	private boolean pagination = false;
	
	/**
	 * 记录查询的url,以便于点击分页时再次使用
	 */
	private String url;
	
	/**
	 * 存放请求参数,用于生成隐藏域中的元素
	 */
	private Map<String,String[]> parameterMap;
	
	/**
	 * 根据传入的Request初始化分页对象
	 * @param request
	 */
	public void setRequest(HttpServletRequest request) {
		
		if(!StringUtils.isNullOrEmpty(request.getParameter("page"))) {
			this.page = Integer.valueOf(request.getParameter("page"));
		}
		if(!StringUtils.isNullOrEmpty(request.getParameter("rows"))) {
			this.rows = Integer.valueOf(request.getParameter("rows"));
		}
		if(!StringUtils.isNullOrEmpty(request.getParameter("pagination"))) {
			this.pagination = Boolean.valueOf(request.getParameter("pagination"));
		}
		
		this.url = request.getRequestURI();
		this.parameterMap = request.getParameterMap();
		
		request.setAttribute("pageBean", this);
	}


	public int getPage() {
		return page;
	}


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


	public int getRows() {
		return rows;
	}


	public void setRows(int rows) {
		this.rows = rows;
	}


	public int getTotal() {
		return total;
	}


	public void setTotal(int total) {
		this.total = total;
	}

	public boolean isPagination() {
		return pagination;
	}

	public void setPagination(boolean pagination) {
		this.pagination = pagination;
	}
	
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public Map<String, String[]> getParameterMap() {
		return parameterMap;
	}

	public void setParameterMap(Map<String, String[]> parameterMap) {
		this.parameterMap = parameterMap;
	}

	//计算起始行号
	public int getStartIndex() {
		if(this.page > this.getTotalPage()) { 
			this.page = this.getTotalPage();
		}
		if(this.page < 1) {
			this.page = 1;
		}
		return (this.page - 1) * this.rows;
	}
	
	//获取总页数
	public int getTotalPage() {
		if (this.getTotal() % this.rows == 0) {
			return this.getTotal() / this.rows;
		} else {
			return this.getTotal() / this.rows + 1;
		}
	}

	//上一页
	public int getPreviousPage() {
		return this.page - 1 > 0 ? this.page - 1 : 1;
	}
	
	//下一页
	public int getNextPage() {
		return this.page + 1 > getTotalPage() ? getTotalPage() : this.page + 1;
	}

}

版本一

public List<Book> queryBook(String bname,PageBean pb){
		String sql="select * from t_book";
		
		if(!StringUtils.isNullOrEmpty(bname)) {
			sql+=" where bname like ?";
		}
		
		List<Book> list=new ArrayList<>();
		Connection con=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		//false || true 或者,一个为真即为真,后续不再计算,一个为假再计算右边的表达式。
		//true && true  与,先计算左边的,如果左边的不满足,后续将不再计算;如果满足,必须要满足两个才行
		if(pb ==null ||  !pb.isPagination()) {//不分页
			try {
				con=DBUtil.getConection();
				ps=con.prepareStatement(sql);
				
				/**
				 * 由于mysql数据库自动添加成以下sql
				 * select * from t_book where bname like '%strName%';
				 * 所以这里不用转义"%";
				 */
				if(!StringUtils.isNullOrEmpty(bname)) {
					ps.setObject(1, "%"+bname+"%");
				}
				
				rs=ps.executeQuery();
				while (rs.next()) {
					Book b=new Book();
					b.setBid(rs.getInt(1));
					b.setBname(rs.getString(2));
					b.setPrice(rs.getDouble(3));
					list.add(b);
				}
				return list;
			} catch (Exception e) {
				e.printStackTrace();
			}
		}else {
			try{//需要分页
			//总页面
			String countsql="select count(*) from ("+sql+") p";
			con=DBUtil.getConection();
			ps=con.prepareStatement(countsql);
			
			if(!StringUtils.isNullOrEmpty(bname)) {
				ps.setObject(1, bname+"%");
			}
			
			rs=ps.executeQuery();
			if(rs.next()) {
				pb.setTotal(rs.getInt(1));
			}
			
			if(pb.getTotal()<=0) {//无记录
				return list;
			}
			//查询当前页的数据
			String pageql=sql+" limit "+pb.getStartIndex()+","+pb.getRows();
			ps=con.prepareStatement(pageql);
			if(!StringUtils.isNullOrEmpty(bname)) {
				ps.setObject(1, bname+"%");
			}
			rs=ps.executeQuery();
			while (rs.next()) {
				Book b=new Book();
				b.setBid(rs.getInt(1));
				b.setBname(rs.getString(2));
				b.setPrice(rs.getDouble(3));
				list.add(b);
			}
		}catch(Exception e){
		e.printStackTrace();
		}finally {
			DBUtil.closeDB(rs, ps, con);
		}
		}
		return list;
	}

版本二:

通用查询思路

将sql语句,参数,分页对象,转换器做为参数传入该方法,判断是否需要分页,

如果需要,编写sql(显示条数)查询当前页的数据,将数据结果集转换成对象,显示当前页面;

如果不需要,执行查询,直接返回结果集。

public class BaseDao {
/*
	 * 转换接口:
	 * 我不知道怎么将数据库结果集转换成对象,我需要covert该接口帮我进行转换。
	 * 
	 */
	public interface IConvert<T>{

	public List<T> convert(ResultSet rs) throws SQLException;
	}
	
	public final <T> List<T> query(
			String sql,//sql
			Object[] params,//参数
			PageBean pb,//分页对象
			IConvert<T> convert//转换器
			){
		
		List<T> list=new ArrayList<>();
		Connection con=null;
		PreparedStatement ps=null;
		ResultSet rs=null;
		
		/**
		 * ||条件或  只要满足第一个条件,后面的条件就不再判断
		 * && 条件与 	要满足第一个条件与第二条件
		 */
		if(pb ==null ||  !pb.isPagination()) {//不分页
			try {
				con=DBUtil.getConection();
				ps=con.prepareStatement(sql);
				
				/*
				 * 循环Object[]数组,将参数一个个放入sql
				 */
				int i=1;
				for (Object param : params) {
					ps.setObject(i, param);
					i++;
				}
				
				rs=ps.executeQuery();
				//将查询到数据库结果集转换成对象
				list=convert.convert(rs);
				return list;
			} catch (Exception e) {
				e.printStackTrace();
			}finally {
				DBUtil.closeDB(rs, ps, con);
			}
	}else {
		try{//需要分页
		//总页面
		String countsql="select count(*) from ("+sql+") p";
		con=DBUtil.getConection();
		ps=con.prepareStatement(countsql);
		
		int i=1;
		for (Object param : params) {
			ps.setObject(i, param);
			i++;
		}
		
		rs=ps.executeQuery();
		if(rs.next()) {
			pb.setTotal(rs.getInt(1));
		}
		
		if(pb.getTotal()<=0) {//无记录
			return list;
		}
		//查询当前页的数据
		String pageql=sql+" limit "+pb.getStartIndex()+","+pb.getRows();
		ps=con.prepareStatement(pageql);
		
		int j=1;
		for (Object param : params) {
			ps.setObject(j, param);
			j++;
		}
		rs=ps.executeQuery();
		
		list=convert.convert(rs);
		
	}catch(Exception e){
	e.printStackTrace();
	}finally {
		DBUtil.closeDB(rs, ps, con);
	}
	}
		
	return list;
}
}

测试类

public class Bookdao extends BaseDao{
/**
	 * @param bname 查询关键字
	 * @param pb 分页对象	
	 * @return
	 */
	public List<Book> getbook(String bname,PageBean pb){
		String sql="select * from t_book";
		List<Object> params=new ArrayList<>();
		if(!StringUtils.isNullOrEmpty(bname)) {//判断字符串是否为空引用或者值为空的方法
			sql+=" where bname like ?";
			params.add(bname+"%");//添加查询条件
		}
		
		//params.toArray()当使用Arraylist数组,可以获取一个实际的数组
		/**
		 * 子类继承父类后,this对象表达的意思,主要看this调用的是那个类的方法。如果指定父类方法,就表示调用父类方法
		 * 如果指定子类方法,就表示调用子类方法
		 */
		List<Book> list=this.query(sql, params.toArray(), pb, new IConvert<Book>() {
			@Override
			public List<Book> convert(ResultSet rs) throws SQLException {
				List<Book> list = new ArrayList<>();
				while (rs.next()) {
					Book b=new Book();
					b.setBid(rs.getInt(1));
					b.setBname(rs.getString(2));
					b.setPrice(rs.getDouble(3));
					list.add(b);
				}
				return list;
			}
		});
		return list;
	}

    public static void main(String[] args) {
	Bookdao bs=new Bookdao();
	PageBean pageBean = new PageBean();
	System.out.println(pageBean.isPagination());//结果:flase
	pageBean.setPagination(true);
	List<Book> queryBook = bs.getbook("",pageBean );
	System.out.println(queryBook);
}
}

注意事项:

||条件或  只要满足第一个条件,后面的条件就不再判断
&& 条件与     要满足第一个条件与第二条件

转换接口:

作用:我不知道怎么将数据库结果集转换成对象,我需要covert该接口帮我进行转换。

代码展示

 public interface IConvert<T>{
    
	public List<T> convert(ResultSet rs) throws SQLException;

	}


public final <T> List<T> query(
			String sql,//sql
			Object[] params,//参数
			PageBean pb,//分页对象
			IConvert<T> convert//转换器
			){
	    //将查询到数据库结果集转换成对象
				list=convert.convert(rs);
}

this对象

public class Bookdao extends BaseDao{

	/**
	 *
	 * @param bname 查询关键字
	 * @param pb 分页对象	
	 * @return
	 */
	public List<Book> getbook(String bname,PageBean pb){
		String sql="select * from t_book";
		List<Object> params=new ArrayList<>();
		if(!StringUtils.isNullOrEmpty(bname)) {//判断字符串是否为空引用或者值为空的方法
			sql+=" where bname like ?";
			params.add(bname+"%");//添加查询条件
		}
		
		//params.toArray()当使用Arraylist数组,可以获取一个实际的数组
		List<Book> list=this.query(sql, params.toArray(), pb, new IConvert<Book>() {
			@Override
			public List<Book> convert(ResultSet rs) throws SQLException {
						return list;
			}
		});
		return list;
	}

this子类继承父类后,this对象表达的意思,主要看this调用的是那个类的方法。如果指定父类方法,就表示调用父类方法;如果指定子类方法,就表示调用子类方法。

公用代码

  • 只要是分页,就会统计总记录数,而总记录数的统计是在业务sql外封装了一个select count(*)是有规律可循的,可以通用

  • 只要是分页,则封装分页sql也是有规律可循的(在业务sql后加limit子句即可),可以通用

 Book页面


	<h2>学生信息</h2>

	<form action="<%=request.getContextPath()%>/BookServlet" method="post">
		<input type="text" name="bname"> <input type="submit"
			value="查询">
	</form>

	<!--如果该集合为空,就将servlet数据加载到页面  -->
	<c:if test="${empty list }">
	<jsp:forward page="/BookServlet"></jsp:forward>
	</c:if> 
	<table border="1" style="width: 100%" >
		<tr>
			<td>编号</td>
			<td>书名</td>
			<td>价格</td>
		</tr>

		<c:forEach items="${list }" var="b">
			<tr>
				<td>${b.bid }</td>
				<td>${b.bname }</td>
				<td>${b.price }</td>
			</tr>
		</c:forEach>
	</table>

	 <div style="text-align: right; width:98%;">
		第${pageBean.page}页&nbsp;&nbsp;&nbsp;
		共${pageBean.totalPage}条记录&nbsp;&nbsp;&nbsp;
		<a href="javascript:goPage(1)">首页</a>&nbsp;&nbsp;&nbsp;
		<a href="javascript:goPage(${pageBean.previousPage })">上页</a>&nbsp;&nbsp;&nbsp; 
		<a href="javascript:goPage(${pageBean.nextPage })">下页</a>&nbsp;&nbsp;&nbsp; 
		<a href="javascript:goPage(${pageBean.totalPage })">尾页</a>&nbsp;&nbsp;&nbsp;
		第<input type="text" size="2" id="pageNumber" onkeyup="toPage(event,this.value)" /> 
		<a href="#">GO</a>
	</div>
	
	<!-- 用于分页的隐藏表单 -->
	<form action="${pageBean.url}" id="pagingForm" method="post">
		<input type="hidden" name="page" value="${pageBean.page}"/>
		<!-- 先只考虑本功能的查询参数,没有考虑公用性(不同功能的参数不同) -->
		<input type="hidden" name="bname" value="<%=request.getParameter("bname")%>"/>
	</form> 
	
	<script type="text/javascript">
 	function goPage(pageNum){
		let form=document.getElementById("pagingForm");
		form.page.value=pageNum;
		form.submit();
	}
 	
 	/**
 	*键盘点击事件
 	*event事件对象
 	*/
 	function toPage(e,pageNumber){
 		 if(e.keyCode == 13){//回车键的阿斯特吗值
 			goPage(pageNumber);
 		 } 
 	}
 	
	</script> 

与数据库交互的BookServlet

@WebServlet("/BookServlet")
public class BookServlet extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
	PageBean pb=new PageBean();
	pb.setRows(5);
	pb.setPagination(true);
	pb.setRequest(request);//PageBean保存的
	
	String bname=request.getParameter("bname");
	
	Bookdao b=new Bookdao();
	List<Book> list = b.query1Book(bname,pb);
	
	request.setAttribute("list", list);

	request.getRequestDispatcher("Book.jsp").forward(request, response);
	}

}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值