JavaWeb分页功能的实


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


1 思路分析


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

效果图

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

totalPage 总页数

currentPage 当前页数

pageSize 每页显示的数据条数

totalSize 总的数据条数

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

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

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


创建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!');


猜你喜欢

转载自blog.csdn.net/luo609630199/article/details/80457898