JavaWeb中Mysql数据库分页

数据库分页原理

在Mysql数据库中提供了分页语句:
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数。LIMIT 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初始记录行的偏移量是 0(而不是 1): 为了与 PostgreSQL 兼容,MySQL 也支持句法: LIMIT # OFFSET #。

LIMIT子句可以用来限制由SELECT语句返回过来的数据数量,它有一个或两个参数,如果给出两个参数, 第一个参数指定返回的第一行在所有数据中的位置,从0开始(注意不是1),第二个参数指定最多返回行数。例如:
select * from table WHERE … LIMIT 10; #返回前10行
select * from table WHERE … LIMIT 0,10; #返回前10行
select * from table WHERE … LIMIT 10,20; #返回第10-20行数据

在实际设计中,我们会发现分页具有多个属性,分别是页码(pageIndex)、页大小(pageSize)、从数据库中查询的数据总条数(totalSize)、以及用来存放每页查询的数据的集合(list)。(当然也包括页总数(pageCount),不过页总数可以通过(totalSize/pageSize)来获取),所以我们可以设计一个PageBean对象类封装。
具体代码如下:

import java.util.List;

public class PageBean<T>{
    /**
     * 页码
     */
    private int pageNum;
    /**
     * 页大小
     */
    private  int pageSize;
    /**
     * 数据总数
     */
    private long totalSize;
    /**
     * 总页数
     */
    private int pageCount;
    /**
     * 页面数据
     */
    private List<T> data;

    public PageBean() {
    }

    public PageBean(int pageNum, int pageSize, long totalSize,  List<T> data) {
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        this.totalSize = totalSize;
        pageCount= (int) (totalSize%pageSize==0?totalSize/pageSize:totalSize/pageSize+1);
        this.data = data;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public long getTotalSize() {
        return totalSize;
    }

    public void setTotalSize(long totalSize) {
        this.totalSize = totalSize;
    }

    public int getPageCount() {
        return pageCount;
    }

    public void setPageCount(int pageCount) {
        this.pageCount = pageCount;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "PageBean{" +
                "pageNum=" + pageNum +
                ", pageSize=" + pageSize +
                ", totalSize=" + totalSize +
                ", pageCount=" + pageCount +
                ", data=" + data +
                '}';
    }
}

现在有一个学生表,需要实现在页面上显示并使用分页。首先创建一个Student类,属性与员工表属性保持一致即可。
tb_emp数据表结构:
在这里插入图片描述

  • sid:学生学号
  • sname:学生姓名
  • age:学生年龄
  • gender:学生性别
  • date:入学日期(由于接收的日期是字符串格式,在存入数据库中会和数据库中的date类型字段不匹配,抛出异常,所以我们可以转换,使用simpledateformate,这里我使用beanutils工具类中提供的转换工具ConverUtils完成转换)
 ConvertUtils.register(new Converter() {
            @Override
            public <T> T convert(Class<T> aClass, Object o) {
                if(o!=null){
                        if(o instanceof  String){
                            String string=(String)o;
                            SimpleDateFormat[] sdf={new SimpleDateFormat("yyyy-MM-dd HH:MM:ss"),new SimpleDateFormat("yyyy-MM-dd"),new SimpleDateFormat("yyyy/MM/dd HH:MM:ss"),new SimpleDateFormat("yyyy/MM/dd")};
                            for (SimpleDateFormat format : sdf) {
                                try {
                                    return  (T)format.parse(string);
                                } catch (ParseException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                }
                return null;
            }
        }, Date.class);
  • banlance(这个属性没什么用,只是我用来测试ThreadLocal时用的)
    Student代码:
public class Student {
    private  String sid;
    private  String sname;
    private Integer age;
    private  String gender;

    public Student() {
    }

    public Student(String sid, String sname, Integer age, String gender) {
        this.sid = sid;
        this.sname = sname;
        this.age = age;
        this.gender = gender;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid='" + sid + '\'' +
                ", sname='" + sname + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

有了这些java域对象后,我们实现DAO层的工作,主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此。设计一个StudentDao接口,在写一个该接口的实现类StudentDaoImpl。在这里我使用Dbutils工具类以及DruidDateSource连接池。
要使用Dbutils工具类,需要导入commons-dbutils-1.6.jar包,数据库连接池导入druid-1.1.5.jar包
mysql数据库连接导入mysql-connector-java-5.1.7-bin.jar, 版本根据自己开发环境自行选择。

  • StudentDao接口
import java.util.List;

public interface StudentDao {
    /**
     *分页
     * @param pageNum  页码
     * @param pageSize  页大小
     * @return
     */
    List<Student> findByPage(int pageNum,int pageSize);
    void add(Student student);
    long getCount();
}
  • StudentDaoImpl
public class StudentDaoImpl implements StudentDao {

    @Override
    public List<Student> findByPage(int pageNum, int pageSize) {
        QueryRunner qr=new QueryRunner(DataSourceUtils.getDateSource());
        try {
           return  qr.query("select *from stu order by sid limit ?,?", new BeanListHandler<>(Student.class),(pageNum-1)*pageSize,pageSize);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public void add(Student student) {
        QueryRunner qr=new QueryRunner(DataSourceUtils.getDateSource());
        Object[] params={student.getSid(),student.getSname(),student.getAge(),student.getGender()};
        try {
            qr.update("insert into stu values (?,?,?,?)", params);
        } catch (SQLException e) {
            e.printStackTrace();
            throw  new RuntimeException("添加失败", e);
        }
    }

    @Override
    public long getCount() {
        QueryRunner qr=new QueryRunner(DataSourceUtils.getDateSource());
        try {
           return qr.query("select count(*)  from stu", new ScalarHandler<>());
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }
}

实现dao层代码后,接下来就是实现业务层代码,由于业务相对较少,所以业务层代码会相对简单。设计一个StudentService业务接口以及实现类

  • StudentService接口
public interface StudentService {
    /**
     *
     * @param pageNum
     * @param pageSize
     * @return 返回PageBean对象
     */
    PageBean<Student> findPage(int pageNum,int pageSize);
}
  • 实现类StudentServiceImpl
import java.util.List;

public class StudentServiceImpl implements StudentService {
    private StudentDao studentDao=new StudentDaoImpl();
    @Override
    public PageBean<Student> findPage(int pageNum, int pageSize) {
        List<Student> data = studentDao.findByPage(pageNum, pageSize);
        long count = studentDao.getCount();
        PageBean<Student> pageBean=new PageBean<>(pageNum, pageSize, count, data);
        return pageBean;
    }
}

业务层写完后,可以实现View(视图层),额,界面比较丑。界面要想实现数据的展示,那么jsp界面必须能够接收数据,所以这里要借助EL表达式以及jstl标签库。

  • stulist.jsp实现代码:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>学生信息界面</title>
    <style>
        td {
            border: 1px solid gray;
            text-align: center;
        }
        table {
            border: 1px solid gray;
        }
    </style>
</head>
<body>
<h2 align="center">学生信息</h2>
<table style=" margin: auto; width: 600px;height: 400px" cellspacing="0" cellpadding="3px" >
    <tr style="background: aquamarine">
        <th>学生ID</th>
        <th>学生姓名</th>
        <th>学生年龄</th>
        <th>学生性别</th>
    </tr>
    <c:forEach var="stu" items="${pages.data}">
        <tr>
        <td>${stu.sid}</td>
        <td>${stu.sname}</td>
        <td>${stu.age}</td>
        <td>${stu.gender}</td>
        </tr>
    </c:forEach>
</table>
<div align="center">
    <a href="${pageContext.request.contextPath}/stulist?pageNum=1&pageSize=${pages.pageSize}" style="font-size: large">首页</a>
    <a href="${pageContext.request.contextPath}/stulist?pageNum=${pages.pageNum-1}&pageSize=${pages.pageSize}" style="font-size: large">上一页</a>
    <a href="${pageContext.request.contextPath}/stulist?pageNum=${pages.pageNum+1<pages.pageCount?pages.pageNum+1:pages.pageCount}&pageSize=${pages.pageSize}" style="font-size: large">下一页</a>
    <a href="${pageContext.request.contextPath}/stulist?pageNum=${pages.pageCount}&pageSize=${pages.pageSize}" style="font-size: large">尾页</a>
</div>
</body>
</html>

最后就是使用servlet来实现数据传递到jsp页面
*StuListServlet

@WebServlet(name = "StuListServlet", value = "/stulist")
public class StuListServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset:utf-8");
        String pageNum = request.getParameter("pageNum");
        String pageSize = request.getParameter("pageSize");
        int pn=1;
        int ps=5;
        if(!StringUtils.isEmpty(pageNum)) {
            pn = Integer.parseInt(pageNum);
            if (pn < 1)
                pn = 1;
        }
        if(!StringUtils.isEmpty(pageSize)) {
            ps = Integer.parseInt(pageSize);
            if(ps<1){
                ps=5;
            }
        }
        StudentService studentService=new StudentServiceImpl();
        PageBean<Student> pages = studentService.findPage(pn, ps);
        request.setAttribute("pages", pages);
        request.getRequestDispatcher("/stulist.jsp").forward(request, response);
    }

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

到这里,分页显示学生信息的基本需求已经完成了,看一下最终效果吧
在这里插入图片描述


版权声明:本文为qq_39308401原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。