JavaEE的分页方法

时间:2023-01-31 12:47:29
  • 分页基本概述
    • 什么是分页查询?
      • 将数据按页分配,每一页显示固定数量的数据
    • 为什么使用分页查询?
      • 利于页面布局,且显示的效率高!!
    • 两种分页实现方式:
      • 物理分页:
        • 使用数据库的分页功能,一次只查询一页数据;
      • 逻辑分页:
        • 一次查出全部数据,然后由程序控制取出需要的数据;
  • 分页关键点
    • 分页SQL语句;
    • 后台处理: dao/service/servlet/JSP
  • 物理分页的功能设计
    • PageCustomer分页对象:
      • pageIndex(从1开始)
      • pageSize(每页多少条数据)
      • totalSize(总共多少条)
      • totalPage(总共多少页)
      • List<Customer>(这页的数据)
    • 点击第2页连接,把pageIndex=2发送给Servlet
      • Servlet调用service
      • service执行分页业务,调用dao
      • dao进行数据库分页操作,返回Page分页对象
  • 实现步骤
    • 环境准备
      • 引入jar文件及引入配置文件
        • 数据库驱动包
        • C3P0连接池jar文件 及 配置文件
        • DbUtis组件:
          • 公用类: JdbcUtils.java
    • 先设计:PageBean.java
    • Dao接口设计/实现: 2个方法
    • Service/servlet
    • JSP
  • 示例1
    • 表示分页的domain

public classPageCustomer{

private intpageIndex;//第几页

private intpageSize;//每页的数据

private inttotalSize;//一共有多少数据

private inttotalPage;//一共多少页

privateList<Customer>customerList;//查询页的数据

publicPageCustomer(intpageIndex,intpageSize) {

if(pageIndex< 1) {

this.pageIndex=1;

}else{

this.pageIndex=pageIndex;

}

if(pageSize< 1) {

this.pageSize=1;

}else{

this.pageSize=pageSize;

}

}

//get,set

}

  • 分页Servlet

public class PageCustomerServletextends HttpServlet{

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException{

this.doPost(request, response);

}

  

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException{

response.setContentType("text/html");

  

try{

int pageIndex= 1;//当前第几页

int pageSize= 10;//每页的数据

String pageIndexStr= request.getParameter("pageIndex");

String pageSizeStr= request.getParameter("pageSize");

//为了程序健壮性和容错性,如果 request.getParameter("pageIndex");

//没有查到数据,那么还有默认值int pageIndex = 1;

//如果查到了数据,就直接用查到的数据,替代默认值

try{

pageIndex= Integer.parseInt(pageIndexStr);

pageSize= Integer.parseInt(pageSizeStr);

}catch(Exception e) {

  

}

  

//以当前页和每页的数据构造出一个分页类

PageCustomer pageCustomer=new PageCustomer(pageIndex, pageSize);

//以这个分页类为参数,传递给DAO,获取这个页数的数据集合

ObjectFactory.getCustomerService().page(pageCustomer);

//将页数,和该页的数据个数传递给JSP

request.setAttribute("pageCustomer", pageCustomer);

//将存放有该页面的人员信息集合,传递给JSP

request.setAttribute("customerList",pageCustomer.getCustomerList());

//数据查询完毕之后,就跳转到分页显示页面

request.getRequestDispatcher("pageCustomer.jsp").forward(request,response);

}catch(Exception e) {

response.getWriter().print("分页查询出错:"+ e.getMessage());

}

}

}

  • 工厂类,快速获取Service对象

public class ObjectFactory{

private static DataSource dataSource;

private static CustomerService customerService;

private static CustomerDao customerDao;

static{

dataSource=new ComboPooledDataSource();

customerService=new CustomerService();

customerDao=new CustomerDaoImpl();

}

public static DataSource getDataSource() {

return dataSource;

}

public static CustomerService getCustomerService() {

return customerService;

}

public static CustomerDao getCustomerDao() {

return customerDao;

}

}

  • 后台Service

public class CustomerService{

/**

*Servlet传递来的有关于分页查询的数据传递给DAO

*

*@param pageCustomer

*/

public void page(PageCustomer pageCustomer)throws Exception{

ObjectFactory.getCustomerDao().page(pageCustomer);

}

}

  • 接口DAO

public interface CustomerDao{

void page(PageCustomer pageCustomer)throws SQLException;

}

  • 实现DAO的实现类

public class CustomerDaoImplimplements CustomerDao{

/**

*根据Servlet传递来的分页数据,在数据库中进行分页查找

*/

public void page(PageCustomer pageCustomer)throws SQLException{

//mysql的分页语法:select * from customer limit begin,size;

//先执行分页语句查询,获取当前页,和该页有多少数据

int begin=(pageCustomer.getPageIndex()- 1)* pageCustomer.getPageSize()+ 1;

QueryRunner run=new QueryRunner(ObjectFactory.getDataSource());

  

List<Customer> customer= run.query("select * from customer limit ?,?"

,new BeanListHandler<Customer>(Customer.class)

,begin

,pageCustomer.getPageSize());

  

pageCustomer.setCustomerList(customer);

  

//使用聚合函数查看一共有多少数据

long totalSize= run.query("select count(*) from customer",new ScalarHandler<Long>());

pageCustomer.setTotalSize((int) totalSize);

  

/*根据全部的数据来分页.用当前全部数据(totalSize)乘以每页数据(PageSize),来获取需要分多少页

但是除法会舍去余数,所以我们加上一个9,比如我们有99条数据,应该是分10,前9页是每页10条,最后一页是9

加上一个9就是108条数据,其中9条是空的。这样除以10(也就是每页10条数据),就分了10,舍去了余数8,也就得到了最后一页只有9个数据的效果,每页20条数据就减去19。也就是说,我们的总数据需要加上(PageSize-1)条数据。这里只能加9,结果加8,如果总数据的余数是1,则凑不够一页。如果加10,又多了一页空白页*/

int totalPage=(

pageCustomer.getTotalSize()

+ pageCustomer.getPageSize()

- 1)

/ pageCustomer.getPageSize();

  

pageCustomer.setTotalPage(totalPage);

}

}

  • 实例分页JSP

<div>

<ahref="PageCustomerServlet?pageIndex=1&pageSize=10">首页</a>

<!--分页条,如果当前页数不为1的话才会显示上一页的选项 -->

<c:iftest="${pageCustomer.pageIndex!=1}">

<ahref="PageCustomerServlet?pageIndex=${pageCustomer.pageIndex-1 }&pageSize=10">上一页</a>

</c:if>

<%//根据分页类对分页条动态添加一个页数链接

PageCustomer pageCustomer=(PageCustomer)request.getAttribute("pageCustomer");//获得分页类

int pageIndex=pageCustomer.getPageIndex();//获得当前页

int begin=pageIndex-3;//当前页减去一个数字,就是当前页前面的页数

if(begin<1){//如果前面的页数小于1,就让它等于1

begin=1;

}

int end=pageIndex+2;

if(end>pageCustomer.getTotalPage()){

end=pageCustomer.getTotalPage();

}

//根据开始页和结束页来循环动态添加页数

for(int i=begin;i<=end;i++){

//如果循环到的页数与当前页相等,说明用户正在当前页,就直接输出一个数组,而不是链接

if(i==pageIndex){

out.print(i);

}else{

%>

<ahref="PageCustomerServlet?pageIndex=<%= i%>&pageSize=10"><%= i%></a>

<%

}

}

%>

<c:iftest="${pageCustomer.pageIndex!=pageCustomer.totalPage}">

<ahref="PageCustomerServlet?pageIndex=${pageCustomer.pageIndex+1 }&pageSize=10">下一页</a>

</c:if>

<ahref="PageCustomerServlet?pageIndex=${pageCustomer.totalPage }&pageSize=10">尾页</a>

</div>

</div>

  • 示例2
    • 工具类

/**

*工具类

* 1.初始化C3P0连接池

* 2.创建DbUtils核心工具类对象

*/

public class JdbcUtils{

/**

* 1.初始化C3P0连接池

*/

private static DataSource dataSource;

static{

dataSource=new ComboPooledDataSource();

}

/**

* 2.创建DbUtils核心工具类对象

*/

public static QueryRunner getQueryRuner(){

//创建QueryRunner对象,传入连接池对象

//在创建QueryRunner对象的时候,如果传入了数据源对象;

//那么在使用QueryRunner对象方法的时候,就不需要传入连接对象;

//会自动从数据源中获取连接(不用关闭连接)

returnnew QueryRunner(dataSource);

}

}

  • 封装分页的参数

/**

*封装分页的参数

*/

public class PageBean<T>{

private int currentPage= 1;//当前页,默认显示第一页

private int pageCount= 4;//每页显示的行数(查询返回的行数),默认每页显示4

private int totalCount;//总记录数

private int totalPage;//总页数 =总记录数 / 每页显示的行数 (+ 1)

private List<T> pageData;//分页查询到的数据

//返回总页数

public int getTotalPage() {

if(totalCount% pageCount == 0) {

totalPage= totalCount/ pageCount;

}else{

totalPage= totalCount/ pageCount + 1;

}

return totalPage;

}

//get,set,构造函数略

}

  • domain类

/**

* 1.实体类设计 (因为用了DbUtils组件,属性要与数据库中字段一致)

*/

public class Employee{

private int empId;//员工id

private String empName;//员工名称

private int dept_id;//部门id

//get,set

}

  • dao

//2.数据访问层,接口设计

public interface IEmployeeDao{

/**

*分页查询数据

*/

public void getAll(PageBean<Employee> pb);

/**

*查询总记录数

*/

public int getTotalCount();

}

  • dao实现类

/**

* 2.数据访问层实现

*/

public class EmployeeDaoimplements IEmployeeDao{

@Override

public void getAll(PageBean<Employee> pb) {

//2.查询总记录数;设置到pb对象中

int totalCount=this.getTotalCount();

pb.setTotalCount(totalCount);

/*

*问题: jsp页面,如果当前页为首页,再点击上一页报错!

*如果当前页为末页,再点下一页显示有问题!

*解决:

* 1.如果当前页 <= 0;当前页设置当前页为1;

* 2.如果当前页 >最大页数;当前页设置为最大页数

*/

//判断

if(pb.getCurrentPage()<=0) {

pb.setCurrentPage(1);//把当前页设置为1

}else if(pb.getCurrentPage()> pb.getTotalPage()){

pb.setCurrentPage(pb.getTotalPage());//把当前页设置为最大页数

}

//1.获取当前页: 计算查询的起始行、返回的行数

int currentPage= pb.getCurrentPage();

int index=(currentPage-1)* pb.getPageCount();//查询的起始行

int count= pb.getPageCount();//查询返回的行数

//3.分页查询数据;把查询到的数据设置到pb对象中

String sql="select * from employee limit ?,?";

try{

//得到Queryrunner对象

QueryRunner qr= JdbcUtils.getQueryRuner();

//根据当前页,查询当前页数据(一页数据)

List<Employee> pageData= qr.query(sql,new BeanListHandler<Employee>(Employee.class), index, count);

//设置到pb对象中

pb.setPageData(pageData);

}catch(Exception e) {

throw new RuntimeException(e);

}

}

@Override

public int getTotalCount() {

String sql="select count(*) from employee";

try{

//创建QueryRunner对象

QueryRunner qr= JdbcUtils.getQueryRuner();

//执行查询, 返回结果的第一行的第一列

Long count= qr.query(sql,new ScalarHandler<Long>());

return count.intValue();

}catch(Exception e) {

throw new RuntimeException(e);

}

}

}

  • service接口层

//3.业务逻辑层接口设计

public interface IEmployeeService{

/**

*分页查询数据

*/

public void getAll(PageBean<Employee> pb);

}

  • service实现层

//3.业务逻辑层,实现

public classEmployeeServiceimplementsIEmployeeService {

//创建Dao实例

privateIEmployeeDaoemployeeDao= new EmployeeDao();

@Override

public voidgetAll(PageBean<Employee>pb) {

try{

employeeDao.getAll(pb);

}catch(Exceptione) {

throw newRuntimeException(e);

}

}

}

  • Servlet

/**

* 4.控制层开发

*/

public class IndexServletextends HttpServlet{

//创建Service实例

private IEmployeeService employeeService=new EmployeeService();

//跳转资源

private String uri;

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException{

try{

//1.获取"当前页"参数; (第一次访问当前页为null)

String currPage= request.getParameter("currentPage");

//判断

if(currPage==null ||"".equals(currPage.trim())){

currPage="1";//第一次访问,设置当前页为1;

}

//转换

int currentPage= Integer.parseInt(currPage);

//2.创建PageBean对象,设置当前页参数; 传入service方法参数

PageBean<Employee> pageBean=new PageBean<Employee>();

pageBean.setCurrentPage(currentPage);

//3.调用service

employeeService.getAll(pageBean);//pageBean已经被dao填充了数据】

//4.保存pageBean对象,到request域中

request.setAttribute("pageBean", pageBean);

//5.跳转

uri="/WEB-INF/list.jsp";

}catch(Exception e) {

e.printStackTrace();//测试使用

//出现错误,跳转到错误页面;给用户友好提示

uri="/error/error.jsp";

}

request.getRequestDispatcher(uri).forward(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException{

this.doGet(request, response);

}

}

  • JSP

<html>

<head>

<title>分页查询数据</title>

<metahttp-equiv="pragma"content="no-cache">

<metahttp-equiv="cache-control"content="no-cache">

<metahttp-equiv="expires"content="0">

</head>

 

<body>

<tableborder="1"width="80%"align="center"cellpadding="5"cellspacing="0">

<tr>

<td>序号</td>

<td>员工编号</td>

<td>员工姓名</td>

</tr>

<!--迭代数据 -->

<c:choose>

<c:whentest="${not emptyrequestScope.pageBean.pageData}">

<c:forEachvar="emp"items="${requestScope.pageBean.pageData}"varStatus="vs">

<tr>

<td>${vs.count }</td>

<td>${emp.empId }</td>

<td>${emp.empName }</td>

</tr>

</c:forEach>

</c:when>

<c:otherwise>

<tr>

<tdcolspan="3">对不起,没有你要找的数据</td>

</tr>

</c:otherwise>

</c:choose>

 

<tr>

<tdcolspan="3"align="center">

当前${requestScope.pageBean.currentPage }/${requestScope.pageBean.totalPage }&nbsp;&nbsp;

 

<ahref="${pageContext.request.contextPath }/index?currentPage=1">首页</a>

<ahref="${pageContext.request.contextPath }/index?currentPage=${requestScope.pageBean.currentPage-1}">上一页</a>

<ahref="${pageContext.request.contextPath }/index?currentPage=${requestScope.pageBean.currentPage+1}">下一页</a>

<ahref="${pageContext.request.contextPath }/index?currentPage=${requestScope.pageBean.totalPage}">末页</a>

</td>

</tr>

</table>

</body>

</html>

  • web.xml

<servlet>

<servlet-name>IndexServlet</servlet-name>

<servlet-class>cn.itcast.servlet.IndexServlet</servlet-class>

</servlet>

<servlet-mapping>

<servlet-name>IndexServlet</servlet-name>

<url-pattern>/index</url-pattern>

</servlet-mapping>

<welcome-file-list>

<welcome-file>index.jsp</welcome-file>

</welcome-file-list>