Java實(shí)現(xiàn)分頁(yè)查詢(xún)功能
分頁(yè)查詢(xún)
分頁(yè)查詢(xún)將數(shù)據(jù)庫(kù)中龐大的數(shù)據(jù)分段顯示,每頁(yè)顯示用戶(hù)自定義的行數(shù),提高用戶(hù)體驗(yàn)度,最主要的是如果一次性從服務(wù)器磁盤(pán)中讀出全部數(shù)據(jù)到內(nèi)存,有內(nèi)存溢出的風(fēng)險(xiǎn)
真假分頁(yè)
假分頁(yè): 其原理還是將所有的數(shù)據(jù)讀到內(nèi)存中,翻頁(yè)從內(nèi)存中讀取數(shù)據(jù), 優(yōu)點(diǎn): 實(shí)現(xiàn)簡(jiǎn)單,性能高 缺點(diǎn):如果數(shù)據(jù)大容易造成內(nèi)存溢出
真分頁(yè): 每次翻頁(yè)從數(shù)據(jù)庫(kù)查詢(xún)數(shù)據(jù)(即磁盤(pán)) , 優(yōu)點(diǎn) : 不容易造成內(nèi)存溢出 缺點(diǎn): 實(shí)現(xiàn)復(fù)雜,性能相對(duì)低一些
分頁(yè)效果
一般分頁(yè)的功能包括: 首頁(yè) 上一頁(yè) 下一頁(yè) 末頁(yè) 當(dāng)前是多少頁(yè) 總共多少頁(yè) 一共多少行數(shù)據(jù) 跳轉(zhuǎn)到第幾頁(yè) 每頁(yè)多少條數(shù)據(jù) 我們需要將這個(gè)數(shù)據(jù)查詢(xún)出來(lái)封裝到一個(gè)對(duì)象中,體現(xiàn)了封裝思想,也節(jié)省了很多復(fù)雜代碼
分頁(yè)需要傳遞的參數(shù)
需要用戶(hù)傳入的參數(shù):
currentPage: 當(dāng)前頁(yè),跳轉(zhuǎn)到第幾頁(yè), 第一次訪問(wèn),我們創(chuàng)建一個(gè)對(duì)象,默認(rèn)值是1
pageSize: 每頁(yè)顯示多少行數(shù)據(jù), 第一次我們也給個(gè)默認(rèn)值 比如10條
分頁(yè)需要展示的數(shù)據(jù)
1.當(dāng)前頁(yè)的貨品信息
2.首頁(yè)是第幾頁(yè)
3.上一頁(yè)是第幾頁(yè)
4.下一頁(yè)是第幾頁(yè)
5.一共有多少頁(yè),和末頁(yè)的值是一樣的
6.數(shù)據(jù)一共有多少條(行)
7.當(dāng)前是第幾頁(yè)
8.每頁(yè)顯示多少條信息
分頁(yè)需要展示的數(shù)據(jù)的來(lái)源
來(lái)源于用戶(hù)上傳: 當(dāng)前頁(yè) , 每頁(yè)顯示多少條數(shù)據(jù)
來(lái)源于數(shù)據(jù)庫(kù)查詢(xún) : 數(shù)據(jù)總條數(shù) , 每一頁(yè)需要展示的商品信息
來(lái)源于根據(jù)上面的已知信息計(jì)算 : 總頁(yè)數(shù) , 上一頁(yè) , 下一頁(yè)
書(shū)寫(xiě)從數(shù)據(jù)庫(kù)查詢(xún)的sql語(yǔ)句
第一條sql 查詢(xún)數(shù)據(jù)庫(kù)中有多少條數(shù)據(jù),COUNT后面不能有空格
SELECT COUNT(*) FROM 表名
第二條sql 根據(jù)傳入的參數(shù)查詢(xún)第幾頁(yè),一頁(yè)多少條數(shù)據(jù)的結(jié)果集
# 第一個(gè) ?:從哪一個(gè)索引的數(shù)據(jù)開(kāi)始查詢(xún)(默認(rèn)從 0 開(kāi)始) # 第二個(gè) ?:查詢(xún)多少條數(shù)據(jù) SELECT * FROM 表名 LIMIT ?, ?
接下來(lái)分析第二條 SQL 中兩個(gè) ? 取值來(lái)源:
假設(shè) product 表中有 21 條數(shù)據(jù),每頁(yè)分 5 條數(shù)據(jù):
查詢(xún)第一頁(yè)數(shù)據(jù):SELECT * FROM product LIMIT 0, 5
查詢(xún)第二頁(yè)數(shù)據(jù):SELECT * FROM product LIMIT 5, 5
查詢(xún)第三頁(yè)數(shù)據(jù):SELECT * FROM product LIMIT 10, 5
查詢(xún)第四頁(yè)數(shù)據(jù):SELECT * FROM product LIMIT 15, 5
通過(guò)尋找規(guī)律發(fā)現(xiàn):第一個(gè) ? 取值來(lái)源于 (currentPage - 1) * pageSize;第二個(gè) ? 取值來(lái)源于
pageSize,即都來(lái)源于用戶(hù)傳遞的分頁(yè)參數(shù)。
總頁(yè)數(shù),上一頁(yè)和下一頁(yè)
// 優(yōu)先計(jì)算總頁(yè)數(shù) int totalPage = rows % pageSize == 0 ? rows / pageSize : rows / pageSize + 1; //上一頁(yè)等于當(dāng)前頁(yè)-1,但不能超過(guò)1頁(yè)界限 int prevPage = currentPage - 1 >= 1 ? currentPage - 1 : 1; //下一頁(yè)等于當(dāng)前頁(yè)+1,但不能超過(guò)總頁(yè)數(shù)界限 int nextPage = currentPage + 1 <= totalPage ? currentPage + 1 : totalPage;
分頁(yè)查詢(xún)實(shí)現(xiàn)
訪問(wèn)流程:
封裝需要展示的數(shù)據(jù)
如果不封裝數(shù)據(jù),每個(gè)數(shù)據(jù)都需要存到作用域中,數(shù)據(jù)太分散,不方便統(tǒng)一管理
/** * 封裝結(jié)果數(shù)據(jù)(某一頁(yè)的數(shù)據(jù)) */ @Getter public class PageResult<T> { ?? ?// 兩個(gè)用戶(hù)的輸入 ?? ?private int currentPage; // 當(dāng)前頁(yè)碼 ?? ?private int pageSize; // 每頁(yè)顯示的條數(shù) ?? ?// 兩條 SQL 語(yǔ)句執(zhí)行的結(jié)果 ?? ?private int totalCount; // 總條數(shù) ?? ?private List<T> data; // 當(dāng)前頁(yè)結(jié)果集數(shù)據(jù) ?? ?// 三個(gè)程序計(jì)算的數(shù)據(jù) ?? ?private int prevPage; // 上一頁(yè)頁(yè)碼 ?? ?private int nextPage; // 下一頁(yè)頁(yè)碼 ?? ?private int totalPage; // 總頁(yè)數(shù)/末頁(yè)頁(yè)碼 ?? ?// 分頁(yè)數(shù)據(jù)通過(guò)下面構(gòu)造期封裝好 ?? ?public PageResult(int currentPage, int pageSize, int totalCount, List<T> ?? ?data) { ?? ??? ?this.currentPage = currentPage; ?? ??? ?this.pageSize = pageSize; ?? ??? ?this.totalCount = totalCount; ?? ??? ?this.data = data; ?? ??? ?// 計(jì)算三個(gè)數(shù)據(jù) ?? ??? ?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提供的操作方法只能傳入一個(gè)參數(shù)執(zhí)行SQL任務(wù),而我們現(xiàn)在查詢(xún)某一頁(yè)的數(shù)據(jù),需要知道是第幾頁(yè)和每頁(yè)多少條數(shù)據(jù)這兩個(gè)參數(shù),所以我們需要將這兩個(gè)參數(shù)封裝在一個(gè)對(duì)象里面
編寫(xiě)一個(gè)類(lèi)(起名叫查詢(xún)對(duì)象類(lèi))來(lái)封裝這些查詢(xún)數(shù)據(jù)
@Setter @Getter /** * 封裝分頁(yè)查詢(xún)需要的兩個(gè)請(qǐng)求傳入的分頁(yè)參數(shù) */ public class QueryObject { ?? ?private int currentPage = 1; // 當(dāng)前頁(yè)碼,要跳轉(zhuǎn)到哪一頁(yè)的頁(yè)碼(需要給默認(rèn)值) ?? ?private int pageSize = 3; // 每頁(yè)顯示條數(shù)(需要給默認(rèn)值) }
再書(shū)寫(xiě)持久層DAO接口和實(shí)現(xiàn)類(lèi)
//DAO接口提供兩個(gè)根據(jù)查詢(xún)對(duì)象的查詢(xún)方法 int queryForCount(); List<Product> queryForList(QueryObject qo); //DAO實(shí)現(xiàn)類(lèi) @Override //查詢(xún)數(shù)據(jù)庫(kù)總數(shù)據(jù)條數(shù) public int queryForCount() { ?? ?SqlSession session = MyBatisUtil.getSession(); ?? ?int totalCount = ?? ?session.selectOne("cn.xxx.mapper.ProductMapper.queryForCount"); ?? ?session.close(); ?? ?return totalCount; } @Override //查詢(xún)某一頁(yè)的結(jié)果集 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
給這個(gè)類(lèi)增加getStart方法,返回根據(jù)當(dāng)前頁(yè),每頁(yè)大小需要從數(shù)據(jù)庫(kù)從第幾行開(kāi)始顯示
@Setter @Getter /** * 封裝分頁(yè)查詢(xún)需要的兩個(gè)請(qǐng)求傳入的分頁(yè)參數(shù) */ public class QueryObject { ?? ?private int currentPage = 1; // 當(dāng)前頁(yè)碼,要跳轉(zhuǎn)到哪一頁(yè)的頁(yè)碼(需要給默認(rèn)值) ?? ?private int pageSize = 3; // 每頁(yè)顯示條數(shù)(需要給默認(rèn)值) ?? ?// 用于 Limit 子句第一個(gè) ? 取值 ?? ?public int getStart(){ ?? ??? ?return (currentPage - 1) * pageSize; ?? ?} }
業(yè)務(wù)層ProductService
調(diào)用持久層DAO完成數(shù)據(jù)的查詢(xún),并將多個(gè)數(shù)據(jù)封裝到一個(gè)對(duì)象中
//IProductService接口 public interface IProductService { ?? ?/** ?? ?* 完成查詢(xún)某一頁(yè)的業(yè)務(wù)邏輯功能 ?? ?*/ ?? ?PageResult<Product> query(QueryObject qo); } //Service實(shí)現(xiàn)類(lèi) public class ProductServiceImpl implements IProductService { ?? ?private IProductDAO productDAO = new ProductDAOImpl(); ?? ?@Override ?? ?public PageResult<Product> query(QueryObject qo) { ?? ??? ?// 調(diào)用 DAO 查詢(xún)數(shù)據(jù)數(shù)量 ?? ??? ?int totalCount = productDAO.queryForCount(); ?? ??? ?// 為了性能加入判斷,若查詢(xún)的數(shù)據(jù)數(shù)量為 0,說(shuō)明沒(méi)有數(shù)據(jù),返回返回空集合,即集合中沒(méi)有 ?? ??? ?元素 ?? ??? ?if(totalCount == 0){ ?? ??? ??? ?return new PageResult(qo.getCurrentPage(), qo.getPageSize(), ?? ??? ??? ?totalCount, Collections.emptyList()); ?? ??? ?} ?? ??? ?// 執(zhí)行到這里代表有數(shù)據(jù),查詢(xún)當(dāng)前頁(yè)的結(jié)果數(shù)據(jù) ?? ??? ?List<Product> products = productDAO.queryForList(qo); ?? ??? ?return new PageResult(qo.getCurrentPage(), qo.getPageSize(), totalCount, ?? ??? ?products); ?? ?} }
前臺(tái)分頁(yè)功能實(shí)現(xiàn)
1.必須先完成業(yè)務(wù)層組件,保證后臺(tái)測(cè)試通過(guò)。
2.遵循 MVC 思想。
3.瀏覽器發(fā)出分頁(yè)請(qǐng)求參數(shù)(去往第幾頁(yè)/每頁(yè)多少條數(shù)據(jù)),在 Servlet 中接收這些參數(shù),并封裝
4.到 QueryObject 對(duì)象,調(diào)用 Service 中分頁(yè)查詢(xún)方法(query)。
5.把得到的分頁(yè)查詢(xún)結(jié)果對(duì)象(PageResult)共享在請(qǐng)求作用域中,跳轉(zhuǎn)到 JSP,顯示即可。
6.修改 JSP 頁(yè)面,編寫(xiě)出分頁(yè)條信息(分頁(yè)條中的信息來(lái)源于 PageResult 對(duì)象)。
修改ProductServlet.java和展示jsp
1.獲取頁(yè)面請(qǐng)求參數(shù),判斷是查詢(xún)操作,調(diào)用查詢(xún)方法,獲取分頁(yè)參數(shù)
2.將參數(shù)封裝成查詢(xún)對(duì)象QueryObject
3.調(diào)用業(yè)務(wù)層方法查詢(xún)某一頁(yè)數(shù)據(jù)
4.將查詢(xún)出來(lái)的結(jié)果存到作用域中
5.轉(zhuǎn)發(fā)到展示頁(yè)面jsp
6.在jsp從作用域中將結(jié)果取出來(lái)響應(yīng)到瀏覽器
//創(chuàng)建業(yè)務(wù)層對(duì)象 private IProductService productService = new ProductServiceImpl(); protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ?? ?QueryObject qo = new QueryObject(); ?? ?// 獲取請(qǐng)求參數(shù) currentPage,并轉(zhuǎn)型封裝 ?? ?String currentPage = req.getParameter("currentPage"); ?? ?if(StringUtil.hasLength(currentPage)) { ?? ??? ?qo.setCurrentPage(Integer.valueOf(currentPage)); ?? ?} ?? ?// 獲取請(qǐng)求參數(shù) pageSize,并轉(zhuǎn)型封裝 ?? ?String pageSize = req.getParameter("pageSize"); ?? ?if(StringUtil.hasLength(pageSize)) { ?? ??? ?qo.setPageSize(Integer.valueOf(pageSize)); ?? ?} ?? ?// 調(diào)用業(yè)務(wù)層方法來(lái)處理請(qǐng)求查詢(xún)某一頁(yè)數(shù)據(jù) ?? ?PageResult<Product> pageResult = productService.query(qo); ?? ?// 把數(shù)據(jù)共享給 list.jsp ?? ?req.setAttribute("pageResult", pageResult); ?? ?// 控制跳轉(zhuǎn)到 list.jsp 頁(yè)面 ?? ?req.getRequestDispatcher("/WEB-INF/views/product/list.jsp").forward(req, ?? ?resp); }
修改jsp文件,使用JSTL+EL獲取作用域中的數(shù)據(jù)
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> ?? ?<head> ?? ??? ?<title>產(chǎn)品列表</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 = ""; ?? ??? ??? ??? ??? ?} ?? ??? ??? ??? ?} ?? ??? ??? ?} ?? ??? ??? ?// 分頁(yè) 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>編號(hào)</th> ?? ??? ??? ??? ??? ?<th>貨品名</th> ?? ??? ??? ??? ??? ?<th>分類(lèi)編號(hào)</th> ?? ??? ??? ??? ??? ?<th>零售價(jià)</th> ?? ??? ??? ??? ??? ?<th>供應(yīng)商</th> ?? ??? ??? ??? ??? ?<th>品牌</th> ?? ??? ??? ??? ??? ?<th>折扣</th> ?? ??? ??? ??? ??? ?<th>進(jìn)貨價(jià)</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" >首頁(yè)</a> ?? ??? ??? ??? ??? ??? ?<a href="/product?currentPage=${pageResult.prevPage}" rel="external nofollow" >上一頁(yè)</a> ?? ??? ??? ??? ??? ??? ?<a href="/product?currentPage=${pageResult.nextPage}" rel="external nofollow" >下一頁(yè)</a> ?? ??? ??? ??? ??? ??? ?<a href="/product?currentPage=${pageResult.totalPage}" rel="external nofollow" >尾頁(yè)</a> ?? ??? ??? ??? ??? ??? ?當(dāng)前第 ${pageResult.currentPage} / ${pageResult.totalPage} 頁(yè) ?? ??? ??? ??? ??? ??? ?一共 ${pageResult.totalCount} 條數(shù)據(jù) ?? ??? ??? ??? ??? ??? ?跳轉(zhuǎn)到<input type="number" onchange="changePageSize()" ?? ??? ??? ??? ??? ??? ?name="currentPage" value="${pageResult.currentPage}" style="width: 60px;"頁(yè) ?? ??? ??? ??? ??? ??? ?每頁(yè)顯示 ?? ??? ??? ??? ??? ??? ?<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>條數(shù)據(jù) ?? ??? ??? ??? ??? ?</td> ?? ??? ??? ??? ?</tr> ?? ??? ??? ?</table> ?? ??? ?</form> ?? ?</body> </html>
常見(jiàn)問(wèn)題
若開(kāi)始翻頁(yè)操作成功,翻了幾頁(yè)不能翻了,只能重啟tomcat才能翻,問(wèn)題: DAO中沒(méi)有關(guān)閉SqlSession對(duì)象
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
為什么wait和notify必須放在synchronized中使用
這篇文章主要介紹了為什么wait和notify必須放在synchronized中使用,文章圍繞主題的相關(guān)問(wèn)題展開(kāi)詳細(xì)介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考以參考一下2022-05-05springboot集成本地緩存Caffeine的三種使用方式(小結(jié))
本文主要介紹了springboot集成本地緩存Caffeine的三種使用方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06詳解Java中字符串緩沖區(qū)StringBuffer類(lèi)的使用
StringBuffer與String類(lèi)似,只不過(guò)StringBuffer在進(jìn)行字符串處理時(shí)不生成新的對(duì)象,下面我們就來(lái)詳解Java中字符串緩沖區(qū)StringBuffer類(lèi)的使用:2016-06-06Spring Boot中@value的常見(jiàn)用法及案例
@Value注解是Spring框架中強(qiáng)大且常用的注解之一,本文主要介紹了SpringBoot中@value的常見(jiàn)用法及案例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-09-09解決新版 Idea 中 SpringBoot 熱部署不生效的問(wèn)題
這篇文章主要介紹了解決新版 Idea 中 SpringBoot 熱部署不生效的問(wèn)題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08