java中實現(xiàn)分頁的幾種常見方式總結
1. 前言
無論是自我學習中,還是在工作中,固然會遇到與前端搭配實現(xiàn)分頁的功能,發(fā)現(xiàn)有幾種方式,特此記錄一下。
2. 先說結論
- 分頁功能直接交給前端實現(xiàn)(根據(jù)業(yè)務場景且僅僅只能用于數(shù)據(jù)量少的情況)。即后端不做任何數(shù)據(jù)的限制,直接把全部數(shù)據(jù)返回給前端,前端通過組件實現(xiàn)分頁,篩選等功能。請不要輕視該方式,好處即只需要前后端交互一次。
- 使用數(shù)據(jù)庫SQL的限制條件,即給搜索語句加上條件,限制查詢出來的數(shù)據(jù)個數(shù):
- mysql數(shù)據(jù)庫是使用 limit n,m 從第n個開始,往后取m個(注 不包括第n個數(shù)據(jù))
- oracle數(shù)據(jù)庫是使用 OFFSET n ROWS FETCH NEXT m ROWS ONLY 從第n行開始,往后取m行(注 不包括第n行數(shù)據(jù))
- oracle的可以查看這篇文章:oracle中將數(shù)據(jù)進行排序之后,獲取前幾行數(shù)據(jù)的寫法(rownum、fetch方式)
- 使用List集合的截取功能實現(xiàn),即將數(shù)據(jù)都查到內存中List集合,在內存中找到要的數(shù)據(jù)。當然有人說這種方式還不如第二點,但請具體情況具體分析,有可能需求要的數(shù)據(jù),是從數(shù)據(jù)庫中查詢不到的,需要將原始數(shù)據(jù)查到內存加工處理數(shù)據(jù)之后得到,才能進行分頁處理。(同理,該方法,只能根據(jù)需求且數(shù)據(jù)量少的情況)
- 使用優(yōu)秀的插件PageHelper,真的很不錯。
3. 例子
1. 數(shù)據(jù)庫SQL的限制條件(limit、fetch)
先說結論:
mysql寫法: SELECT * FROM user2 LIMIT (#{pageNum} - 1) * #{pageSize}, #{pageSize} oracle寫法: SELECT * FROM user2 OFFSET (#{pageNum} - 1) * #{pageSize} ROWS FETCH NEXT #{pageSize} ROWS ONLY
直接看代碼:
@Mapper public interface PageTestDao { // 查數(shù)據(jù) // start:從第幾條開始,向后要數(shù)據(jù) // pageSize:一頁多少條數(shù)據(jù) List<UserEntity> getUserInfoByParams(@Param("nameParam") String name, @Param("start") int start, @Param("pageSize") int pageSize); // 返回總條數(shù) int getCountByParams(@Param("nameParam") String name); }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.csdn2.page_test.dao.PageTestDao"> <sql id="nameCondition"> <where> <if test="nameParam != null and nameParam != ''"> name like CONCAT('%', #{nameParam}, '%') </if> </where> </sql> <select id="getUserInfoByParams" resultType="com.example.csdn2.page_test.entity.UserEntity"> SELECT * FROM user2 <include refid="nameCondition" /> LIMIT #{start}, #{pageSize} </select> <select id="getCountByParams" resultType="int"> SELECT COUNT(*) FROM user2 <include refid="nameCondition" /> </select> </mapper>
@Service @RequiredArgsConstructor public class PageTestService { private final PageTestDao pageTestDao; public PageResponse<UserEntity> getPageTest(UserRequest userRequest) { final List<UserEntity> userEntityList = pageTestDao.getUserInfoByParams(userRequest.getNameParam(), userRequest.getStart(), userRequest.getPageSize()); final int total = pageTestDao.getCountByParams(userRequest.getNameParam()); return new PageResponse<>(userEntityList, total); } }
// 若分頁的需求很多,可把分頁相關的參數(shù)抽出來 @Data public class PageRequest { // 第幾頁 private int pageNum; // 每頁幾行數(shù)據(jù) private int pageSize; // 計算從第幾行開始 // 無論是limit、還是fetch 都是從某一行數(shù)據(jù)開始,向后取 pageSize 條數(shù)據(jù) public int getStart() { if (pageNum <= 0) { return 0; } return (pageNum - 1) * pageSize; } } // 入參 @EqualsAndHashCode(callSuper = true) @Data public class UserRequest extends PageRequest { // 搜索參數(shù) private String nameParam; } // 返回實體類,因為分頁需要返回總條數(shù),前端好做下標第幾頁 @Data @AllArgsConstructor public class PageResponse<T> { private List<T> data; // 總條數(shù) private int total; }
@RestController @RequiredArgsConstructor public class PageTestController { private final PageTestService pageTestService; @PostMapping("/page-test") public PageResponse<UserEntity> getPageTest(@RequestBody UserRequest userRequest){ return pageTestService.getPageTest(userRequest); } }
2. 使用List集合的截取功能實現(xiàn)
1.先看一下List的截取
// 從第幾個下標,到第幾個下標 List<E> subList(int fromIndex, int toIndex);
public void test_ListSub() { // 創(chuàng)建模擬數(shù)據(jù),字符串 0-9的集合 final List<String> list = IntStream.range(0, 10) .mapToObj(i -> i + "") .collect(Collectors.toList()); System.out.println(list); // 截取從下標0到5的數(shù)據(jù) System.out.println(list.subList(0, 5)); // 截取從下標3到5的數(shù)據(jù) System.out.println(list.subList(3, 5)); }
2.回歸上述分頁例子,代碼改成如下:
dao層 不加 limit 條件
SELECT * FROM user2 name like CONCAT('%', #{nameParam}, '%')
server層:
public PageResponse<UserEntity> getPageTestByListSub(UserRequest userRequest) { final List<UserEntity> allData = pageTestDao.getUserInfoByParamsNoLimit(userRequest.getNameParam()); // 下標開始 final int start = userRequest.getStart(); // 下標結束 final int end = start + userRequest.getPageSize(); // 截取數(shù)據(jù) final List<UserEntity> userEntityList = allData.subList(start, end); final int total = pageTestDao.getCountByParams(userRequest.getNameParam()); return new PageResponse<>(userEntityList, total); }
3. 插件PageHelper
1.其實PageHelper官網中有詳細的文檔以及例子:https://pagehelper.github.io/docs/howtouse/
2.下面例子只是講其與springboot結合的核心內容,即快速開發(fā):
3.引入相關jar包坐標到pom.xml中
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency>
4.dao層的sql不需要加 Limit 條件(因為PageHelper會自動幫忙加的)
SELECT * FROM user2 name like CONCAT('%', #{nameParam}, '%')
5.service層修改如下:
public PageInfo<UserEntity> getPageTest(UserRequest userRequest) { // 告訴PageHelper數(shù)據(jù)要從第幾頁,每頁多少條數(shù)據(jù) // 注:一定要在select查詢語句之前使用該方法,否則無效 PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize()); // 查詢sql final List<UserEntity> userEntityList = pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam()); // 返回dto,使用插件自帶的PageInfo return new PageInfo<>(userEntityList); // 上述邏輯還可以簡寫為: // return PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize()) // .doSelectPageInfo(() -> pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam())); }
6.結果如下(與之前查詢結果一致,沒問題):
{
"total": 9,
"list": [
{
"name": "4a",
"pwd": "D"
},
{
"name": "5a",
"pwd": "E"
},
{
"name": "6a",
"pwd": "F"
}
],
"pageNum": 2,
"pageSize": 3,
"size": 3,
"startRow": 4,
"endRow": 6,
"pages": 3,
"prePage": 1,
"nextPage": 3,
"isFirstPage": false,
"isLastPage": false,
"hasPreviousPage": true,
"hasNextPage": true,
"navigatePages": 8,
"navigatepageNums": [
1,
2,
3
],
"navigateFirstPage": 1,
"navigateLastPage": 3
}
7.為什么說該插件很優(yōu)秀呢,查看PageInfo的返回參數(shù),核心內容:
// 當前頁 private int pageNum; // 每頁的數(shù)量 private int pageSize; // 當前頁的數(shù)量 private int size; // 總記錄數(shù) private long total; // 總頁數(shù) private int pages; // 結果集 private List<T> list; // 以下內容都是其自動幫生成的 // 對于前端來說極其友好,前端分頁功能的全部參數(shù)都包含了 // 前一頁的頁碼 private int prePage; // 下一頁的頁碼 private int nextPage; // 是否為第一頁 private boolean isFirstPage = false; // 是否為最后一頁 private boolean isLastPage = false; // 是否有前一頁 private boolean hasPreviousPage = false; // 是否有下一頁 private boolean hasNextPage = false; // 導航條上的第一頁的頁碼 private int navigateFirstPage; // 導航條上的第一頁的頁碼 private int navigateLastPage;
8.查看PageHelper執(zhí)行了什么sql語句
總結
到此這篇關于java中實現(xiàn)分頁的幾種常見方式的文章就介紹到這了,更多相關java實現(xiàn)分頁方式內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
springboot serverEndpoint導致@resource注解不生效
在SpringBoot中,@Resource注解用于注入依賴,本文主要介紹了springboot serverEndpoint導致@resource注解不生效,具有一定的參考價值,感興趣的可以了解一下2023-12-12Java String源碼分析并介紹Sting 為什么不可變
這篇文章主要介紹了Java String源碼分析并介紹Sting 為什么不可變的相關資料,需要的朋友可以參考下2017-02-02Java 使用POI生成帶聯(lián)動下拉框的excel表格實例代碼
本文通過實例代碼給大家分享Java 使用POI生成帶聯(lián)動下拉框的excel表格,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友參考下吧2017-09-09JavaSE static final及abstract修飾符實例解析
這篇文章主要介紹了JavaSE static final及abstract修飾符實例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06Java Optional解決空指針異??偨Y(java 8 功能)
這篇文章主要介紹了Java Optional解決空指針異??偨Y(java 8 功能),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11Spring MVC 請求參數(shù)綁定實現(xiàn)方式
Spring MVC 是一個用于構建 Web 應用程序的框架,它提供了一種方便的方式來處理 HTTP 請求和響應,Spring MVC 提供了多種方式來實現(xiàn)請求參數(shù)綁定,本文結合實例代碼給大家介紹的非常詳細,需要的朋友跟隨小編一起看看吧2023-09-09基于springboot bean的實例化過程和屬性注入過程
這篇文章主要介紹了基于springboot bean的實例化過程和屬性注入過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11