一、前言
無論是自我學(xué)習(xí)中,還是在工作中,固然會遇到與前端搭配實現(xiàn)分頁的功能,發(fā)現(xiàn)有幾種方式,特此記錄一下。
二、實現(xiàn)方式
2.1、分頁功能直接交給前端實現(xiàn)
這種情況也是有的,(根據(jù)業(yè)務(wù)場景且僅僅只能用于數(shù)據(jù)量少的情況)。即后端不做任何數(shù)據(jù)的限制,直接把全部數(shù)據(jù)返回給前端,前端通過組件實現(xiàn)分頁,篩選等功能。請不要輕視該方式,好處即只需要前后端交互一次。
2.2、數(shù)據(jù)庫SQL的限制條件
即給搜索語句加上條件,限制查詢出來的數(shù)據(jù)個數(shù)。(這里不同數(shù)據(jù)庫可能sql語句寫法不一樣)
- 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ù)進(jìn)行排序之后,獲取前幾行數(shù)據(jù)的寫法(rownum、fetch方式)
2.3、使用List集合的截取功能實現(xiàn)?
即將數(shù)據(jù)都查到內(nèi)存中List集合,在內(nèi)存中找到要的數(shù)據(jù)。當(dāng)然有人說這種方式還不如第二點,但請具體情況具體分析,有可能需求要的數(shù)據(jù),是從數(shù)據(jù)庫中查詢不到的,需要將原始數(shù)據(jù)查到內(nèi)存加工處理數(shù)據(jù)之后得到,才能進(jìn)行分頁處理。(同理,該方法,只能根據(jù)需求且數(shù)據(jù)量少的情況)。
2.4、插件PageHelper
使用優(yōu)秀的插件PageHelper,真的很不錯。
如果想詳細(xì)了解PageHelper插件的,可以訪問:如何使用分頁插件
2.5、SpringData?
SpringData我還沒用過,這里就不展開詳細(xì)說明了,后期如果業(yè)務(wù)使用到了,會更新到這篇文章。
三、詳細(xì)介紹
分頁功能交給前端實現(xiàn)的這里就不展示了,比較我們標(biāo)題是后端實現(xiàn)分頁功能。
3.1、數(shù)據(jù)庫SQL的限制條件(limit,fetch)
sql語句
mysql寫法:
SELECT * FROM user2
LIMIT (#{pageNum} - 1) * #{pageSize}, #{pageSize}
oracle寫法:
SELECT * FROM user2
OFFSET (#{pageNum} - 1) * #{pageSize} ROWS FETCH NEXT #{pageSize} ROWS ONLY
Dao層(也可以叫Mapper層)
@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);
}
Mapper.xml
<?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實現(xiàn)層
@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);
}
}
PageRequest
// 若分頁的需求很多,可把分頁相關(guān)的參數(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;
}
}
UserRequest
// 入?yún)?@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRequest extends PageRequest {
// 搜索參數(shù)
private String nameParam;
}
PageResponse
我這邊只返回給前端查詢的某頁數(shù)據(jù)、和一共多少條數(shù)據(jù),如果前端需要知道可以分多少頁,需要前端自己計算一下,當(dāng)然后端其實也可以計算,只需要添加一個參數(shù)和一個方法。
// 返回實體類,因為分頁需要返回總條數(shù),前端好做下標(biāo)第幾頁
@Data
@AllArgsConstructor
public class PageResponse<T> {
private List<T> data;
// 總條數(shù)
private int total;
}
Controller層
@RestController
@RequestMapping("/pageTest")
public class PageTestController {
private final PageTestService pageTestService;
@PostMapping("/page-test")
public PageResponse<UserEntity> getPageTest(@RequestBody UserRequest userRequest){
return pageTestService.getPageTest(userRequest);
}
}
運行結(jié)果
3.2、使用List集合的截取功能(subList())實現(xiàn)
先看一下List的截取
// 從第幾個下標(biāo),到第幾個下標(biāo)
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);
// 截取從下標(biāo)0到5的數(shù)據(jù)
System.out.println(list.subList(0, 5));
// 截取從下標(biāo)3到5的數(shù)據(jù)
System.out.println(list.subList(3, 5));
}
回歸上述分頁例子,代碼改成如下:
dao層 不加 limit 條件
SELECT * FROM user2
name like CONCAT('%', #{nameParam}, '%')
server層
public PageResponse<UserEntity> getPageTestByListSub(UserRequest userRequest) {
final List<UserEntity> allData = pageTestDao.getUserInfoByParamsNoLimit(userRequest.getNameParam());
// 下標(biāo)開始
final int start = userRequest.getStart();
// 下標(biāo)結(jié)束
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.3、插件PageHelper
這是一個特別好用的分頁插件。
其實PageHelper官網(wǎng)中有詳細(xì)的文檔以及例子:https://pagehelper.github.io/docs/howtouse/
下面例子只是講其與springboot結(jié)合的核心內(nèi)容,即快速開發(fā):
引入相關(guān)jar包坐標(biāo)到pom.xml中
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
配置項目application.yml文件
#bybatis分頁插件配置
pagehelper:
helper-dialect: mysql #數(shù)據(jù)庫
reasonable: true
support-methods-arguments: true
params: count=countSql
3.3.1、案例1?
前端所需要的數(shù)據(jù)就是數(shù)據(jù)庫中表的數(shù)據(jù)
dao層的sql不需要加 Limit 條件(因為PageHelper會自動幫忙加的)
SELECT * FROM user2
name like CONCAT('%', #{nameParam}, '%')
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()));
}
結(jié)果如下(與之前查詢結(jié)果一致,沒問題)
{
"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
}
3.3.2、案例2
前端所需要的數(shù)據(jù)不只是數(shù)據(jù)庫中表的數(shù)據(jù),還有一些需要Java代碼邏輯計算得到的數(shù)據(jù)。那么上面的PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize());就失效了。
public PageInfo<UserEntityResp> getPageTest(UserRequest userRequest) {
//分頁類的創(chuàng)建
PageInfo<UserEntityResp> res = new PageInfo<>();
// 查詢sql
List<UserEntity> userEntityList =
pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam());
//對userEntityList中的數(shù)據(jù)進(jìn)行了一些算法操作,改變了原來從數(shù)據(jù)庫中查詢到的數(shù)據(jù)
//或者以什么排序等等操作,最終得到result
List<UserEntityResp> result = ..... ;
int total = result.size();
//注意:這里的start,end是需要通過userRequest.getPageNum(), userRequest.getPageSize()
//計算得到的
Double index = (Double)Math.ceil(total * 1.0 / userRequest.getPageSize());
if (index.intValue()>=userRequest.getPage()){
start = (userRequest.getPage() - 1) * userRequest.getPageSize();
end = Math.min(start + userRequest.getPageSize(), total);
} else{
start = 0;
end = total;
}
List<InterfaceConfirmTimeResp> pageList = result.subList(start, end);
//將分頁相關(guān)對象的屬性設(shè)置
res.setList(pageList);
res.setTotal(result.size());
res.setPageNum(userRequest.getPage());
res.setPageSize(userRequest.getPageSize());
res.setPages((int)Math.ceil(result.size()*1.0/userRequest.getPageSize()));
return res;
}
這是通過PageHelp插件中的PageInfo類和List中的subList()方法實現(xiàn)的,其實一般這種情況用的也是比較多的。
3.3.3、為什么PageHelp插件優(yōu)秀
為什么說該插件很優(yōu)秀呢,查看PageInfo的返回參數(shù),核心內(nèi)容:
// 當(dāng)前頁
private int pageNum;
// 每頁的數(shù)量
private int pageSize;
// 當(dāng)前頁的數(shù)量
private int size;
// 總記錄數(shù)
private long total;
// 總頁數(shù)
private int pages;
// 結(jié)果集
private List<T> list;
// 以下內(nèi)容都是其自動幫生成的
// 對于前端來說極其友好,前端分頁功能的全部參數(shù)都包含了
// 前一頁的頁碼
private int prePage;
// 下一頁的頁碼
private int nextPage;
// 是否為第一頁
private boolean isFirstPage = false;
// 是否為最后一頁
private boolean isLastPage = false;
// 是否有前一頁
private boolean hasPreviousPage = false;
// 是否有下一頁
private boolean hasNextPage = false;
// 導(dǎo)航條上的第一頁的頁碼
private int navigateFirstPage;
// 導(dǎo)航條上的第一頁的頁碼
private int navigateLastPage;
查看PageHelper執(zhí)行了什么sql語句
3.3.4、spring結(jié)合mybatis整合PageHelper框架
Spring整合:導(dǎo)入pom.xml
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.1.2</version>
</dependency>
配置項目配置文件(我在spring和mybatis整合的配置文件中配置的,如果在mybatis核心配置文件中配置,百度一下)
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 依賴數(shù)據(jù)源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 注冊加載myBatis映射文件 -->
<property name="mapperLocations">
<array>
<value>classpath*:com/yyz/mapper/*Mapper.xml</value>
</array>
</property>
<!-- PageHelper分頁配置 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--使用下面的方式配置參數(shù),一行配置一個,后面會有所有的參數(shù)介紹 -->
<value>
<!--helperDialect屬性來指定分頁插件使用哪種方言。-->
helperDialect=mysql
<!--分頁合理化參數(shù),設(shè)置為true時,pageNum<=0時會查詢第一頁,pageNum>pages(超過總數(shù)時),會查詢最后一頁。-->
reasonable=true
<!--為了支持startPage(Object params)方法,增加了該參數(shù)來配置參數(shù)映射,用于從對象中根據(jù)屬性名取值,
可以配置 pageNum,pageSize,count,pageSizeZero,reasonable-->
params=count=countSql
<!--支持通過Mapper接口參數(shù)來傳遞分頁參數(shù),默認(rèn)值false,分頁插件會從查詢方法的參數(shù)值中,自動根據(jù)上面 params 配
置的字段中取值,查找到合適的值時就會自動分頁。-->
supportMethodsArguments=true
<!--默認(rèn)值為 false。設(shè)置為 true 時,允許在運行時根據(jù)多數(shù)據(jù)源自動識別對應(yīng)方言的分頁-->
autoRuntimeDialect=true
</value>
</property>
</bean>
</array>
</property>
<!-- 給數(shù)據(jù)庫實體起別名 -->
<property name="typeAliasesPackage" value="com.yyz.entity;"/>
</bean>
以上就是Java實現(xiàn)分頁的幾種方式,希望對你有所幫助,如果有其它方式可以在評論區(qū)留言?。?!文章來源:http://www.zghlxwxcb.cn/news/detail-783819.html
參考文章:java中實現(xiàn)分頁的常見幾種方式_java 分頁-CSDN博客文章來源地址http://www.zghlxwxcb.cn/news/detail-783819.html
到了這里,關(guān)于【Java 干貨教程】Java實現(xiàn)分頁的幾種方式詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!