分页查询

分页查询将数据库中庞大的数据分段显示,每页显示用户自定义的行数,提高用户体验度,最主要的是如果一次性从服务器磁盘中读出全部数据到内存,有内存溢出的风险

真假分页

假分页: 其原理还是将所有的数据读到内存中,翻页从内存中读取数据, 优点: 实现简单,性能高 缺点:如果数据大容易造成内存溢出
真分页: 每次翻页从数据库查询数据(即磁盘) , 优点 : 不容易造成内存溢出 缺点: 实现复杂,性能相对低一些

分页效果

一般分页的功能包括: 首页 上一页 下一页 末页 当前是多少页 总共多少页 一共多少行数据 跳转到第几页 每页多少条数据 我们需要将这个数据查询出来封装到一个对象中,体现了封装思想,也节省了很多复杂代码

分页需要传递的参数

需要用户传入的参数:
currentPage: 当前页,跳转到第几页, 第一次访问,我们创建一个对象,默认值是1
pageSize: 每页显示多少行数据, 第一次我们也给个默认值 比如10条

分页需要展示的数据

1.当前页的货品信息
2.首页是第几页
3.上一页是第几页
4.下一页是第几页
5.一共有多少页,和末页的值是一样的
6.数据一共有多少条(行)
7.当前是第几页
8.每页显示多少条信息

分页需要展示的数据的来源

来源于用户上传: 当前页 , 每页显示多少条数据
来源于数据库查询 : 数据总条数 , 每一页需要展示的商品信息
来源于根据上面的已知信息计算 : 总页数 , 上一页 , 下一页

书写从数据库查询的sql语句

第一条sql 查询数据库中有多少条数据,COUNT后面不能有空格

SELECT COUNT(*) FROM 表名

第二条sql 根据传入的参数查询第几页,一页多少条数据的结果集

# 第一个 ?:从哪一个索引的数据开始查询(默认从 0 开始)
# 第二个 ?:查询多少条数据
SELECT * FROM 表名 LIMIT ?, ?

接下来分析第二条 SQL 中两个 ? 取值来源:
假设 product 表中有 21 条数据,每页分 5 条数据:
查询第一页数据:SELECT * FROM product LIMIT 0, 5
查询第二页数据:SELECT * FROM product LIMIT 5, 5
查询第三页数据:SELECT * FROM product LIMIT 10, 5
查询第四页数据:SELECT * FROM product LIMIT 15, 5
通过寻找规律发现:第一个 ? 取值来源于 (currentPage - 1) * pageSize;第二个 ? 取值来源于
pageSize,即都来源于用户传递的分页参数。

总页数,上一页和下一页

// 优先计算总页数
int totalPage = rows % pageSize == 0 ? rows / pageSize : rows / pageSize   1;
//上一页等于当前页-1,但不能超过1页界限
int prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1;
//下一页等于当前页 1,但不能超过总页数界限
int nextPage = currentPage   1 <= totalPage ? currentPage   1 : totalPage;

分页查询实现

访问流程:

封装需要展示的数据

如果不封装数据,每个数据都需要存到作用域中,数据太分散,不方便统一管理

/**
* 封装结果数据(某一页的数据)
*/
@Getter
public class PageResult<T> {
    // 两个用户的输入
    private int currentPage; // 当前页码
    private int pageSize; // 每页显示的条数
    // 两条 SQL 语句执行的结果
    private int totalCount; // 总条数
    private List<T> data; // 当前页结果集数据
    // 三个程序计算的数据
    private int prevPage; // 上一页页码
    private int nextPage; // 下一页页码
    private int totalPage; // 总页数/末页页码
    // 分页数据通过下面构造期封装好
    public PageResult(int currentPage, int pageSize, int totalCount, List<T>
    data) {
        this.currentPage = currentPage;
        this.pageSize = pageSize;
        this.totalCount = totalCount;
        this.data = data;
        // 计算三个数据
        this.totalPage = totalCount % pageSize == 0 ? totalCount / pageSize :
        totalCount / pageSize   1;
        this.prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1;
        this.nextPage = currentPage   1 <= this.totalPage ? currentPage   1 :
        this.totalPage;
    }
}

持久层DAO

Mybatis提供的操作方法只能传入一个参数执行SQL任务,而我们现在查询某一页的数据,需要知道是第几页和每页多少条数据这两个参数,所以我们需要将这两个参数封装在一个对象里面
编写一个类(起名叫查询对象类)来封装这些查询数据

@Setter
@Getter
/**
* 封装分页查询需要的两个请求传入的分页参数
*/
public class QueryObject {
    private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值)
    private int pageSize = 3; // 每页显示条数(需要给默认值)
}

再书写持久层DAO接口和实现类

//DAO接口提供两个根据查询对象的查询方法
int queryForCount();
List<Product> queryForList(QueryObject qo);
//DAO实现类
@Override
//查询数据库总数据条数
public int queryForCount() {
    SqlSession session = MyBatisUtil.getSession();
    int totalCount =
    session.selectOne("cn.xxx.mapper.ProductMapper.queryForCount");
    session.close();
    return totalCount;
}
@Override
//查询某一页的结果集
public List<Product> queryForList(QueryObject qo) {
    SqlSession session = MyBatisUtil.getSession();
    List<Product> products =
    session.selectList("cn.xxx.mapper.ProductMapper.queryForList",qo);
    session.close();
    return products;
}

修改productMapper.xml

<select id="queryForCount" resultType="int">
SELECT COUNT(*) FROM product
</select>
<select id="queryForList" resultType="cn.xxx.domain.Product">
SELECT * FROM product LIMIT #{start}, #{pageSize}
</select>

修改QueryObject.java

给这个类增加getStart方法,返回根据当前页,每页大小需要从数据库从第几行开始显示

@Setter
@Getter
/**
* 封装分页查询需要的两个请求传入的分页参数
*/
public class QueryObject {
    private int currentPage = 1; // 当前页码,要跳转到哪一页的页码(需要给默认值)
    private int pageSize = 3; // 每页显示条数(需要给默认值)
    // 用于 Limit 子句第一个 ? 取值
    public int getStart(){
        return (currentPage - 1) * pageSize;
    }
}

业务层ProductService

调用持久层DAO完成数据的查询,并将多个数据封装到一个对象中

//IProductService接口
public interface IProductService {
    /**
    * 完成查询某一页的业务逻辑功能
    */
    PageResult<Product> query(QueryObject qo);
}
//Service实现类
public class ProductServiceImpl implements IProductService {
    private IProductDAO productDAO = new ProductDAOImpl();
    @Override
    public PageResult<Product> query(QueryObject qo) {
        // 调用 DAO 查询数据数量
        int totalCount = productDAO.queryForCount();
        // 为了性能加入判断,若查询的数据数量为 0,说明没有数据,返回返回空集合,即集合中没有
        元素
        if(totalCount == 0){
            return new PageResult(qo.getCurrentPage(), qo.getPageSize(),
            totalCount, Collections.emptyList());
        }
        // 执行到这里代表有数据,查询当前页的结果数据
        List<Product> products = productDAO.queryForList(qo);
        return new PageResult(qo.getCurrentPage(), qo.getPageSize(), totalCount,
        products);
    }
}

前台分页功能实现

1.必须先完成业务层组件,保证后台测试通过。
2.遵循 MVC 思想。
3.浏览器发出分页请求参数(去往第几页/每页多少条数据),在 Servlet 中接收这些参数,并封装
4.到 QueryObject 对象,调用 Service 中分页查询方法(query)。
5.把得到的分页查询结果对象(PageResult)共享在请求作用域中,跳转到 JSP,显示即可。
6.修改 JSP 页面,编写出分页条信息(分页条中的信息来源于 PageResult 对象)。

修改ProductServlet.java和展示jsp

1.获取页面请求参数,判断是查询操作,调用查询方法,获取分页参数
2.将参数封装成查询对象QueryObject
3.调用业务层方法查询某一页数据
4.将查询出来的结果存到作用域中
5.转发到展示页面jsp
6.在jsp从作用域中将结果取出来响应到浏览器

//创建业务层对象
private IProductService productService = new ProductServiceImpl();

protected void list(HttpServletRequest req, HttpServletResponse resp) throws
ServletException, IOException {
    QueryObject qo = new QueryObject();
    // 获取请求参数 currentPage,并转型封装
    String currentPage = req.getParameter("currentPage");
    if(StringUtil.hasLength(currentPage)) {
        qo.setCurrentPage(Integer.valueOf(currentPage));
    }
    // 获取请求参数 pageSize,并转型封装
    String pageSize = req.getParameter("pageSize");
    if(StringUtil.hasLength(pageSize)) {
        qo.setPageSize(Integer.valueOf(pageSize));
    }
    // 调用业务层方法来处理请求查询某一页数据
    PageResult<Product> pageResult = productService.query(qo);
    // 把数据共享给 list.jsp
    req.setAttribute("pageResult", pageResult);
    // 控制跳转到 list.jsp 页面
    req.getRequestDispatcher("/WEB-INF/views/product/list.jsp").forward(req,
    resp);
}

修改jsp文件,使用JSTL EL获取作用域中的数据

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>产品列表</title>
        <script type="text/javascript">
            window.onload = function () {
                var trClzs = document.getElementsByClassName("trClassName");
                for(var i = 0; i < trClzs.length; i  ){
                    trClzs[i].onmouseover = function () {
                        console.log(1);
                        this.style.backgroundColor = "gray";
                    }
                    trClzs[i].onmouseout = function () {
                        console.log(2);
                        this.style.backgroundColor = "";
                    }
                }
            }
            // 分页 JS
            function changePageSize() {
                document.forms[0].submit();
            }
        </script>
    </head>
    <body>
        <a href="/replaceImg.jsp" rel="external nofollow" ><img src="${USER_IN_SESSION.headImg}" title="更换头
        像"/></a><br/>
        <a href="/product?cmd=input" rel="external nofollow" >添加</a>
        <form action="/product">
            <table border="1" cellspacing="0" cellpadding="0" width="80%">
                <tr>
                    <th>编号</th>
                    <th>货品名</th>
                    <th>分类编号</th>
                    <th>零售价</th>
                    <th>供应商</th>
                    <th>品牌</th>
                    <th>折扣</th>
                    <th>进货价</th>
                    <th>操作</th>
                </tr>
                <c:forEach var="product" items="${pageResult.data}" varStatus="status">
                    <tr class="trClassName">
                        <td>${status.count}</td>
                        <td>${product.productName}</td>
                        <td>${product.dir_id}</td>
                        <td>${product.salePrice}</td>
                        <td>${product.supplier}</td>
                        <td>${product.brand}</td>
                        <td>${product.cutoff}</td>
                        <td>${product.costPrice}</td>
                        <td>
                            <a href="/product?cmd=delete&id=${product.id}" rel="external nofollow" >删除</a>
                            <a href="/product?cmd=input&id=${product.id}" rel="external nofollow" >修改</a>
                        </td>
                    </tr>
                </c:forEach>
                <tr align="center">
                    <td colspan="9">
                        <a href="/product?currentPage=1" rel="external nofollow" >首页</a>
                        <a href="/product?currentPage=${pageResult.prevPage}" rel="external nofollow" >上一页</a>
                        <a href="/product?currentPage=${pageResult.nextPage}" rel="external nofollow" >下一页</a>
                        <a href="/product?currentPage=${pageResult.totalPage}" rel="external nofollow" >尾页</a>
                        当前第 ${pageResult.currentPage} / ${pageResult.totalPage} 页
                        一共 ${pageResult.totalCount} 条数据
                        跳转到<input type="number" onchange="changePageSize()"
                        name="currentPage" value="${pageResult.currentPage}" style="width: 60px;"页
                        每页显示
                        <select name="pageSize" onchange="changePageSize()">
                            <option value="3" ${pageResult.pageSize == 3 ? 'selected' : ''}> 3 </option>
                            <option value="5" ${pageResult.pageSize == 5 ? 'selected' : ''}> 5 </option>
                            <option value="8" ${pageResult.pageSize == 8 ? 'selected' : ''}> 8 </option>
                        </select>条数据
                    </td>
                </tr>
            </table>
        </form>
    </body>
</html>

常见问题

若开始翻页操作成功,翻了几页不能翻了,只能重启tomcat才能翻,问题: DAO中没有关闭SqlSession对象

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持Devmax。

Java实现分页查询功能的更多相关文章

  1. ios – UIScrollView的平滑自定义分页

    我在UIScrollView中有两个(可能更多)视图,并希望使用分页.当我尝试使用UIScrollView的默认分页选项时出现问题,因为视图具有不同的宽度,无法正确分页.所以我已经实现了一个有效的自定义分页代码.但是,当滚动较慢时,它不会按预期运行.(它回到没有动画的原始位置.)以下是我目前通过uiscrollviewdelegate进行自定义分页的方法我想要的是:是)我有的:解决方法尝试下面的自

  2. ios – 使用子视图控制器分页滚动视图

    使用分页实现水平滚动视图的最佳做法是什么,每页有一个视图控制器?由于iOS5具有用于视图控制器容器/包含的API,因此PageControl示例仍然是实现此功能的最佳方式吗?

  3. 可可触摸 – 启用预览和分页的UICollectionView

    在AppStore中显示搜索结果时,我正在尝试模仿苹果公司的功能.(参考:http://searchengineland.com/apple-app-search-shows-only-one-result-at-a-time-133818)它显示像卡中的详细应用程序信息,并且它被分页.当中间的一个活动卡片和滚动视图的分页行为仍然完整时,我被困在如何使上一张和第二张卡片显示.我已经尝试使用UICo

  4. ios – 启用了内容插入的UIScrollView分页工作很奇怪

    我创建了具有内容插入的UIScrollView.第一次,scrollView.contentOffset.x为-160.0但是奇怪的问题是当我点击scrollView(黄色区域)时,内容偏移x值将重置为0并显示为这样.我尝试过几次,但是点击滚动视图会将内容偏移量重置为0.我该如何防止这种情况?解决方法UIScrollView分页通过滚动与scrollView宽度相同的页面(在您的情况下为480个宽

  5. UIKit框架-高级控件Swift版本: 10.UIWebView方法/属性详解

    前面我们已经讲解完了UINavigationController的一些常用属性以及方法,现在让我们来看看一个关于网络的UIWebView.1.UIWebView的常用属性常用类型2.UIWebView的代理方法3.代码示范首先我们要使用storyBoard布局界面关联控件遵守代理协议自定义UIWebVIew实现代理方法在ViewDidLoad方法中实现PS:UIWebView继承与UIView,并

  6. swift+storyboard+UIImageview入门

    更新记录:该Storyboard教程由CarolineBegbie更新iOS8和Swift相关内容。Storyboard是最先在iOS5引入的一项振奋人心的特性,大幅缩减构建App用户界面所需的时间。要介绍Storyboard是什么,我打算从这张图讲起。这就是使用Storyboard的力量。Storyboard通过新的原型表项和静态表项特性,让处理表视图的工作更加轻松。Storyboard使自动布局更易用。接下来我们看一下Storyboard,点击项目浏览器中的Main.storyboard就可以在Int

  7. 使用RxSwift进行分页API调用

    如何实现这一点的任何建议将非常感谢…

  8. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  9. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  10. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

随机推荐

  1. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  2. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  4. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  5. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  6. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  7. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  8. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  9. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. Spring JdbcTemplate执行数据库操作详解

    JdbcTemplate是Spring框架自带的对JDBC操作的封装,目的是提供统一的模板方法使对数据库的操作更加方便、友好,效率也不错,这篇文章主要介绍了Spring JdbcTemplate执行数据库操作,需要的朋友可以参考下

返回
顶部