JavaWeb分页了解一下

JavaWeb分页功能的实现


虽然现在有很多框架可以很简单的实现分页这个功能,但是我觉的对于初学者来说,还是很有必要学习自己手动实现分页这个功能,更好的理解分页的原理,编程最重要的就是思想.

1 思路分析

在写代码之前我们得分析怎样实现分页,把思路分析清楚了,写起代码来才能游刃有余.我们来看看分页的效果.

![image]

这就是我们要实现的效果从效果图中我们可以看到,要把数据按照我们希望的方式展示,我么能的到的数据有

totalPage 总页数

currentPage 当前页数

pageSize 每页显示的数据条数

totalSize 总的数据条数

还有就是每页显示的数据条数,是需要我们从后台时时传过来的,那我们可以把这些每页显示的数据封装到一个JavaBean中,然后把它存到域对象中,最后展示到前端页面.

如果上面的这些数据我们一个一个的从后台去取的话,操作起来太麻烦了,于是我们想,前台不就是需要这些数据吗?那我们可以把这些数据有封装到一个PageBean对象身上,到时候把它页存到域对象中,然后到jsp页面展示出来不就行了吗,对吧?

List<T> 用于存放每页要显示的数据的list

扫描二维码关注公众号,回复: 1031567 查看本文章
创建Product Bean用来封装从数据库中的到的数据
  package bean;
  ​
  import java.io.Serializable;
  import java.util.Date;
  ​
  public class Product implements Serializable{
   
      private static final long serialVersionUID = 2078432725470146037L;
      //商品pid
      private String pid;
      
      //商品名称
   private String pname;   //市场价格  private Double market_price;   //商城价格  private Double shop_price;   //商品图片  private String pimage;   //商品上架时间  private String pdate;   //商品描述  private String pdesc;   public String getPid() {   return pid;  }  public void setPid(String pid) {   this.pid = pid;  }  public String getPname() {   return pname;  }  public void setPname(String pname) {   this.pname = pname;  }  public Double getMarket_price() {   return market_price;  }  public void setMarket_price(Double market_price) {   this.market_price = market_price;  }  public Double getShop_price() {   return shop_price;  }  public void setShop_price(Double shop_price) {   this.shop_price = shop_price;  }  public String getPimage() {   return pimage;  }  public void setPimage(String pimage) {   this.pimage = pimage;  }  public String getPdate() {   return pdate;  }  public void setPdate(String pdate) {   this.pdate = pdate;  }  public String getPdesc() {   return pdesc;  }  public void setPdesc(String pdesc) {   this.pdesc = pdesc;  }  public static long getSerialversionuid() {   return serialVersionUID;  }  @Override  public String toString() {   return "Product [pid=" + pid + ", pname=" + pname + ", market_price=" + market_price + ", shop_price="     + shop_price + ", pimage=" + pimage + ", pdate=" + pdate + ", pdesc=" + pdesc + "]";  }   }
创建PageBean用来封装前台页面需要的数据
  
  package bean;
  ​
  import java.io.Serializable;
  import java.util.List;
  ​
  public class PageBean implements Serializable{
      
      private static final long serialVersionUID = 1L;
      //当页要显示的商品集合
      private List<Product> list;
      //当前页数
   private int currentPage;   //每页显示数据条数  private int pageSize;   //总页数  private int totalPage;   //总条数  private Long totalSize;       //每页要显示的数据  public List<Product> getList() {   return list;  } ​  public void setList(List<Product> list) {   this.list = list;  } ​  public int getCurrentPage() {   return currentPage;  } ​  public void setCurrentPage(int currentPage) {   this.currentPage = currentPage;  } ​  public int getPageSize() {   return pageSize;  } ​  public void setPageSize(int pageSize) {   this.pageSize = pageSize;  } ​  public int getTotalPage() {   return totalPage;  } ​  public void setTotalPage(int totalPage) {   this.totalPage = totalPage;  } ​  public Long getTotalSize() {   return totalSize;  } ​  public void setTotalSize(Long totalSize) {   this.totalSize = totalSize;  } ​  @Override  public String toString() {   return "PageBean [list=" + list + ", currentPage=" + currentPage + ", pageSize=" + pageSize + ", totalPage="     + totalPage + ", totalSize=" + totalSize + "]";  }   }
在Dao层操作数据库,完成数据的封装
  
  package dao;
  ​
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.util.List;
  ​
  import org.apache.commons.dbutils.QueryRunner;
  import org.apache.commons.dbutils.handlers.BeanHandler;
  import org.apache.commons.dbutils.handlers.BeanListHandler;
  import org.apache.commons.dbutils.handlers.ScalarHandler;
  ​
  import com.sun.org.apache.bcel.internal.generic.NEW;
  ​
  import bean.Product;
  import utils.C3P0Utils;
  import utils.DBUtils;
  import utils.TransctionManager;
  ​
  public class ProductDao {
  ​
      /**
       * 每页显示的商品集合
       * 
       * @param pageSize
       * @param currentPage
   * @throws SQLException  */  public List<Product> pageProduct(int currentPage, int pageSize) throws SQLException {   int a = (currentPage - 1) * pageSize;   QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());   String sql = "select * from product limit ?,?";   List<Product> list = runner.query(sql, new BeanListHandler<>(Product.class),a,pageSize);   return list;  }  /**  * 查询总记录数  */  public Long queryProductCount() throws SQLException {   QueryRunner runner = new QueryRunner(C3P0Utils.getDataSource());   String sql = "select count(*) from product";   Long count = (Long) runner.query(sql, new ScalarHandler());   return count;    } ​ }
在Service层完成业务逻辑
  
  package service;
  ​
  import java.sql.SQLException;
  import java.util.List;
  ​
  import bean.PageBean;
  import bean.Product;
  import dao.ProductDao;
  import utils.TransctionManager;
  ​
  public class ProductService {
   
      /**
       * 分页查询所有商品
       */
      public PageBean pageQuery(int currentPage) {
       // 封装PageBean   /**   * 分别获取到: 当前页 每页显示数据条数 每页要显示的商品集合 总页数 总数据条数   */   PageBean bean = new PageBean();   // 当前页   bean.setCurrentPage(currentPage);   // 每页显示数据条数   int pageSize = 5;   bean.setPageSize(pageSize);   // 每页要显示的商品集合   ProductDao dao = new ProductDao();   try {    List<Product> products = dao.pageProduct(currentPage, pageSize);    bean.setList(products); ​    // 总数据条数    Long totalSize = dao.queryProductCount();    bean.setTotalSize(totalSize);    // 总页数    int totalPage = 0;    totalPage = (int) (totalSize / pageSize);    if (totalSize % pageSize != 0) { ​     totalPage++;    }    bean.setTotalPage(totalPage);   } catch (SQLException e) {    e.printStackTrace();   }   return bean;  } ​ }

在Servlet中编写控制代码

  
  package servlet;
  ​
  import java.io.IOException;
  import java.io.PrintWriter;
  import java.io.Writer;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.List;
  import java.util.Map;
  import java.util.UUID;
  ​
  import javax.servlet.ServletException;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  ​
  import org.apache.commons.beanutils.BeanUtils;
  ​
  import bean.PageBean;
  import bean.Product;
  import service.ProductService;
  import utils.DateUtil;
  ​
  /**
   * 用来处理分页的Servlet,利用反射技术实现动态获取前台调用的方法,这里使用反射技术是为了增    强代码的可维护性.
  如果不使用反射技术,那么我们要么只能时针对前台的每个请求我们都写一个Servlet,或者使用if{}else if 来判断前台传过来的方法名
   */
  public class BigServlet extends HttpServlet {
      private static final long serialVersionUID = 1L;
  ​
      protected void doGet(HttpServletRequest request, HttpServletResponse response)
              throws ServletException, IOException {
    // 解决中文乱码问题   request.setCharacterEncoding("utf-8");   response.setContentType("text/html;charset=utf-8"); ​   String methods = request.getParameter("method");   //通过反射技术获取servlet字节码文件对象,创建对象然后调用方法,注意:一个servlet只有只有一个对象   Class<? extends BigServlet> clazz = this.getClass();   try {    Method method = clazz.getMethod(methods, HttpServletRequest.class,HttpServletResponse.class);    method.invoke(this,request,response);   } catch (Exception e) {    e.printStackTrace();   } ​  } ​  protected void doPost(HttpServletRequest request, HttpServletResponse response)    throws ServletException, IOException {   doGet(request, response);  }  /**  * 分页查询  */  public void page(HttpServletRequest request, HttpServletResponse response)    throws IOException, ServletException {   //获取请求参数   int currentPage = Integer.parseInt(request.getParameter("currentPage"));   //调用业务层的方法获取pageBean   ProductService service=new ProductService();   PageBean bean=service.pageQuery(currentPage);     //把数据存入域对象中   HttpSession session = request.getSession();   session.setAttribute("page",bean);   response.sendRedirect(request.getContextPath()+"/page.jsp");  } }
C3P0连接池工具类
  
  package utils;
  ​
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  ​
  import javax.sql.DataSource;
  ​
  import com.mchange.v2.c3p0.ComboPooledDataSource;
  ​
  public class C3P0Utils {
  /**
   * c3p0连接池工具类
   */
      
      private static ComboPooledDataSource dataSource;
      
      static {
       dataSource=new ComboPooledDataSource();  }   public static DataSource getDataSource() {     return dataSource;  }   public static Connection getConnection() {   Connection con=null;   try {    con= dataSource.getConnection();   } catch (SQLException e) {    System.out.println(e);       throw new RuntimeException("数据库链接异常,请联系技术人员");   }   return con;  }   public static void close(ResultSet resultSet,PreparedStatement ps,Connection con) {     if (resultSet!=null) {    try {     resultSet.close();    } catch (Exception e) {     System.out.println(e);    }   }     if (ps!=null) {    try {     ps.close();    } catch (Exception e) {     System.out.println(e);    }   }     if (con!=null) {    try {     con.close();    } catch (Exception e) {     System.out.println(e);    }   }  } }
用于封装数据的工具类(这个可以用commons-dbutils-1.4.jar代替),这个工具类可以自己封装,新手建议自己封装一下
  
  package utils;
  ​
  import java.lang.reflect.Method;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.ResultSetMetaData;
  import java.sql.SQLException;
  import java.util.ArrayList;
  import java.util.List;
  ​
  import javax.management.RuntimeErrorException;
  import javax.sql.DataSource;
  ​
  public class DBUtils {
      /**
       * 操作数据库的工具类
       */
      private DataSource dataSource;
  ​
      public DBUtils(DataSource dataSource) {
  ​
    this.dataSource = dataSource;  } ​  // 增删改方法  public int update(String sql, Object[] params) {   PreparedStatement ps = null;   int num = 0;   // 注册驱动,获得链接   Connection con = C3P0Utils.getConnection();   // 获取执行对象   try {    ps = con.prepareStatement(sql);    // 设置?处参数    if (params != null) {     for (int i = 1; i <= params.length; i++) { ​      ps.setObject(i, params[i - 1]);     }    }    num = ps.executeUpdate();   } catch (SQLException e) { ​    System.out.println(e); ​    throw new RuntimeException("数据库链接异常,请联系技术人员");   }   // 关闭资源   C3P0Utils.close(null, ps, con);   return num;  } ​  // 操作数据实现查询多条数据功能  public <E> List<E> query(String sql, Object[] params, Class<E> clazz) {   PreparedStatement ps = null;   List<E> list = null;   ResultSet set = null;   // 1注册驱动,获取链接   Connection con = C3P0Utils.getConnection();   try {    // 2后去执行对象    ps = con.prepareStatement(sql);    // 设置?处参数    if (params != null) {     for (int i = 1; i <= params.length; i++) { ​      ps.setObject(i, params[i - 1]);     }    }    // 利用ps动态获取所有字段名    ResultSetMetaData metaData = ps.getMetaData();    // 利用字节码文件对象获取clazz对象中所有的方法    Method[] methods = clazz.getMethods();    // 3执行sql语句,处理结果集    set = ps.executeQuery();    // 遍历结果集,并把结果集封装到对象中,再把每对象封装到集合中    // 创建一个集合用于封装每个对象    list = new ArrayList<>();    while (set.next()) {     // 创建对象用于封装每条数据     E e = clazz.newInstance();     // 遍历metaData获取每一个字段名     for (int i = 1; i <= metaData.getColumnCount(); i++) {      String columnName = metaData.getColumnName(i);      // 根据列明,获取每一列数据      Object object = set.getObject(columnName);      // 遍历所有方法,找出setxx()的方法      for (Method method : methods) {       String name = method.getName();       if (name.equalsIgnoreCase("set" + columnName)) { ​        method.invoke(e, object);       }      }     }     list.add(e);    }   } catch (Exception e) { ​    System.out.println(e); ​    throw new RuntimeException("数据库链接异常,请联系技术人员");   }   // 关闭资源   C3P0Utils.close(set, ps, con);   return list;  } ​  // 操作数据实现查询一条数据  public <E> E queryBean(String sql, Object[] params, Class clazz) {   PreparedStatement ps = null;   ResultSet resultSet = null;   E e = null;   // 1注册驱动,获得链接   Connection con = C3P0Utils.getConnection();   // 2获取执行对象   try {    ps = con.prepareStatement(sql);    // 设置?处参数    if (params != null) {     for (int i = 1; i <= params.length; i++) { ​      ps.setObject(i, params[i - 1]);     }    }    // 动态获取ps字段集    ResultSetMetaData metaData = ps.getMetaData();    // 同字节码文件对象获取所有方法    Method[] methods = clazz.getMethods();    // 3.执行sql语句    resultSet = ps.executeQuery();    // 4.处理结果集,把数据封装到JavaBean对象中    while (resultSet.next()) {     // 创建用于封装数据JavaBean对象     e = (E) clazz.newInstance();     // 获取每一列列明     for (int i = 1; i <= metaData.getColumnCount(); i++) {      String columnName = metaData.getColumnName(i);      // 获取每一列数据      Object object = resultSet.getObject(columnName);      // 遍历所有方法,找出setxxx的方法,然后为每个字段赋值      for (Method method : methods) {       String name = method.getName();       if (name.equalsIgnoreCase("set" + columnName)) { ​        method.invoke(e, object);       }      }     }    }   } catch (Exception ex) { ​    System.out.println(ex); ​    throw new RuntimeException("数据读取异常,请联系技术人员");   } ​   // 5.释放资源   C3P0Utils.close(resultSet, ps, con);   return e;  } ​  // 实现操作一个字段的查询  public Object queryScalar(String sql, Object[] params) {   PreparedStatement ps = null;   ResultSet resultSet = null;   Object object=null;   // 1注册驱动,获得链接   Connection con = C3P0Utils.getConnection();   // 2获取执行对象   try {    ps = con.prepareStatement(sql);    // 设置?处参数    if (params != null) {     for (int i = 1; i <= params.length; i++) { ​      ps.setObject(i, params[i - 1]);     }    }    // 动态获取ps字段集    ResultSetMetaData metaData = ps.getMetaData();    //3.执行sql语句    resultSet = ps.executeQuery();    //4.处理结果集,获取到每一个字段对应的值       while (resultSet.next()) {         for (int i = 1; i <= metaData.getColumnCount(); i++) {      String columnName = metaData.getColumnName(i);      object = resultSet.getObject(columnName);     }    }   }catch (Exception e) {       System.out.println(e);   }   //5.释放资源   C3P0Utils.close(resultSet, ps, con);     return object;  } }

连接池配置文件

c3p0-config.xml

  
  <?xml version="1.0" encoding="UTF-8"?>
  <c3p0-config>
      <default-config>
          <property name="user">root</property>
          <property name="password">root</property>
    <property name="driverClass">com.mysql.jdbc.Driver</property>   <property name="jdbcUrl">jdbc:mysql:///数据库名</property>  </default-config> </c3p0-config> 
web.xml配置
  
  <?xml version="1.0" encoding="UTF-8"?>
  <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
    <display-name>Day22_1</display-name>
    <welcome-file-list>
      <welcome-file>index.html</welcome-file>
      <welcome-file>index.htm</welcome-file>
      <welcome-file>index.jsp</welcome-file>
      <welcome-file>default.html</welcome-file>
      <welcome-file>default.htm</welcome-file>
      <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
     
    <servlet>
      <description></description>
      <display-name>BigServlet</display-name>
      <servlet-name>BigServlet</servlet-name>
      <servlet-class>servlet.BigServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>BigServlet</servlet-name>
      <url-pattern>/big</url-pattern>
    </servlet-mapping>
  </web-app>
前台页面 page.jsp

因为我们把我们需要的数据都封装到了PageBean对象中,PageBean对象又在session中,我们只需要取出域对象中的数据放在我们需要放的地方即可.

  
  <%@ page language="java" contentType="text/html; charset=UTF-8"
      pageEncoding="UTF-8"%>
  <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Insert title here</title>
  </head>
  <body>
      <h5>欢迎使用~</h5>
      <table border="1" cellspacing="0" align="center" width="80%">
          <tr>
     <th>商品id</th>    <th>商品图片</th>    <th>商品名称</th>    <th>市场价格</th>    <th>商城价格</th>    <th>上架日期</th>    <th>商品描述</th>   </tr>   <c:forEach items="${page.list }" var="p">    <tr>     <td>${p.pid }</td>     <td><img alt="" src="${p.pimage }" width="100px" height="100px">     </td>     <td>${p.pname }</td>     <td>${p.market_price }</td>     <td>${p.shop_price }</td>     <td>${p.pdate }</td>     <td>${p.pdesc }</td>    </tr>   </c:forEach>   <tr align="center">    <td colspan="7">总共 ${page.totalPage } 页 |当前是第 ${page.currentPage }     页 | 每页显示 ${page.pageSize } 条数据|总共有 ${page.totalSize } 条数据</td>   </tr>   <tr align="center">    <td colspan="7">     <%--判断是否是首页,如果是则显示上一页,首页 --%>     <c:if test="${page.currentPage!=1 }">      <a href="${pageContext.request.contextPath }/big?method=page&currentPage=1">首页</a>      <a href="${pageContext.request.contextPath }/big?method=page&currentPage=${page.currentPage-1}">上一页</a>     </c:if>    <c:forEach begin="1" end="${page.pageSize }"      var="i">      <%--判断是否是当前页,若是当前页加以区别 --%>      <c:if test="${i==page.currentPage }">       <a>${i }</a>      </c:if>      <%--正常显示第i页 --%>      <c:if test="${i!=page.currentPage }">       <a href="${pageContext.request.contextPath }/big?method=page&currentPage=${i}">${i }</a>      </c:if>     </c:forEach>     <%--判断是否是尾页,如果是则显示下一页,尾页 --%>     <c:if test="${page.currentPage!=page.pageSize }">      <a href="${pageContext.request.contextPath }/big?method=page&currentPage=${page.currentPage+1}">下一页</a>      <a href="${pageContext.request.contextPath }/big?method=page&currentPage=${page.pageSize}">尾页</a>     </c:if>     </td>   </tr>  </table> </body> </html>

==温馨提醒:==

  
  我所用的开发环境为:win10 ,tomcat7,jdk 1.8
  用到类库
  c3p0-0.9.1.2.jar
  commons-dbutils-1.4.jar(如果自己封装dbUtil则可不用)
  commons-logging-1.1.1.jar
  jstl.jar
  mysql-connector-java-5.1.39-bin.jar
  standard.jar

==数据库数据准备==

  
  create database page;
  use page;
  create table `product` (
      `pid` varchar (96) primary key,
      `pname` varchar (150),
      `market_price` double ,
      `shop_price` double ,
      `pimage` varchar (600),
   `pdate` date ,  `pdesc` varchar (765) ); INSERT INTO `product` VALUES('1','小米 4c 标准版','1399','1299','products/1/c_0001.jpg','2015-11-02','小米 4c 标准版 全网通 白色 移动联通电信4G手机 双卡双待'); INSERT INTO `product` VALUES('10','华为 Ascend Mate7','2699','2599','products/1/c_0010.jpg','2015-11-02','华为 Ascend Mate7 月光银 移动4G手机 双卡双待双通6英寸高清大屏,纤薄机身,智能超八核,按压式指纹识别!!选择下方“移动老用户4G飞享合约”,无需换号,还有话费每月返还!'); INSERT INTO `product` VALUES('11','vivo X5Pro','2399','2298','products/1/c_0014.jpg','2015-11-02','移动联通双4G手机 3G运存版 极光白【购机送蓝牙耳机+蓝牙自拍杆】新升级3G运行内存·双2.5D弧面玻璃·眼球识别技术'); INSERT INTO `product` VALUES('12','努比亚(nubia)My 布拉格','1899','1799','products/1/c_0013.jpg','2015-11-02','努比亚(nubia)My 布拉格 银白 移动联通4G手机 双卡双待【嗨11,下单立减100】金属机身,快速充电!布拉格相机全新体验!'); INSERT INTO `product` VALUES('13','华为 麦芒4','2599','2499','products/1/c_0012.jpg','2015-11-02','华为 麦芒4 晨曦金 全网通版4G手机 双卡双待金属机身 2.5D弧面屏 指纹解锁 光学防抖'); INSERT INTO `product` VALUES('14','vivo X5M','1899','1799','products/1/c_0011.jpg','2015-11-02','vivo X5M 移动4G手机 双卡双待 香槟金【购机送蓝牙耳机+蓝牙自拍杆】5.0英寸大屏显示·八核双卡双待·Hi-Fi移动KTV'); INSERT INTO `product` VALUES('15','Apple iPhone 6 (A1586)','4399','4288','products/1/c_0015.jpg','2015-11-02','Apple iPhone 6 (A1586) 16GB 金色 移动联通电信4G手机长期省才是真的省!点击购机送费版,月月送话费,月月享优惠,畅享4G网络,就在联通4G!');

猜你喜欢

转载自www.cnblogs.com/weolwy/p/9091087.html