Spring?Boot?集成PageHelper的使用方法
前言:
項(xiàng)目中數(shù)據(jù)分頁(yè)是一個(gè)很常見的需求,目前大部分項(xiàng)目都會(huì)使用pagehelper進(jìn)行分頁(yè),那么在使用的過程中是否考慮如下問題?
一、基本集成
引入jar包
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper.version}</version> </dependency>
Yml配置文件中添加相關(guān)配置
pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql
封裝相關(guān)分頁(yè)方法
分頁(yè)參數(shù)類 public class PageParam<T> implements Serializable { private static final long serialVersionUID = -7916211163897873899L; private int pageNum=1; private int pageSize=10; //條件參數(shù) private T param; //排序字段 private String orderBy; public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public T getParam() { return param; } public void setParam(T param) { this.param = param; } public String getOrderBy() { return orderBy; } public void setOrderBy(String orderBy) { //需要注意sql注入 this.orderBy = orderBy; } } 分頁(yè)結(jié)果類 public class PagedList<T> implements Serializable { private static final long serialVersionUID = -1253790062865437768L; private int pageNum = 1; private List<T> data = null; private int pageCount = 0; private int recordCount = -1; private int pagingType = 0; private int pageSize; private String orderBy; /** * @return the pageSize */ public int getPageSize() { return pageSize; } /** * @param pageSize * the pageSize to set */ public void setPageSize(int pageSize) { if (pageSize <= 0) { return; } this.pageSize = pageSize; } /** * @return the pageCount */ public int getPageCount() { return pageCount; } /** * @param pageCount * the pageCount to set */ public void setPageCount(int pageCount) { if (pageCount <= 0) { return; } this.pageCount = pageCount; } /** * @return the recordCount */ public int getRecordCount() { return recordCount; } /** * @param recordCount * the recordCount to set */ public void setRecordCount(int recordCount) { this.recordCount = recordCount; calcPageCount(); } private void calcPageCount() { if (this.recordCount < 0) { return; } int tmp = this.recordCount % getPageSize(); this.pageCount = (tmp == 0 ? (this.recordCount / getPageSize()) : (this.recordCount / getPageSize() + 1)); if (this.pageNum > this.pageCount && this.pageCount != 0) { this.pageNum = this.pageCount; } this.pageNum = this.pageCount; } public void setData(List<T> data) { this.data = data; if (ObjectUtil.isNotEmpty(data) && this.recordCount == -1) { this.recordCount = data.size(); } } public List<T> getData() { return data; } /** * @return the pagingType */ public int getPagingType() { return pagingType; } /** * @param pagingType * the pagingType to set */ public void setPagingType(int pagingType) { this.pagingType = pagingType; } public void setOrderBy(String orderBy) { this.orderBy = orderBy; } public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public String getOrderBy() { return orderBy; } } 分頁(yè)工具類 public class PageUtils implements Serializable { private static final long serialVersionUID = 377943433889798799L; public static <T> PagedList<T> exportPagedList(PageParam<T> pageParam) { PagedList<T> pl = new PagedList<T>(); // pagesize int pageSize = pageParam.getPageSize(); if (pageSize <= 0) { pageSize = 10; } else { pl.setPageSize(pageSize); } int pageNum = pageParam.getPageNum(); pl.setPageNum(pageNum); String orderBy= pageParam.getOrderBy(); if(StringUtil.isNotEmpty(orderBy)) { //防止sql注入 String orderBySql=SQLFilter.sqlInject(orderBy); pl.setOrderBy(orderBySql); } return pl; } public static <T>PagedList<T> toPageList(PageInfo<T> spage) { PagedList<T> pagedList = new PagedList<T>(); pagedList.setPageSize((int) spage.getPageSize()); pagedList.setPageNum((int) spage.getPageNum()); pagedList.setRecordCount((int) spage.getTotal()); pagedList.setData(spage.getList()); pagedList.setPageCount((int) spage.getPages()); return pagedList; } }
示例代碼
@PostMapping("getPageList") public Result getPageList(@RequestBody PageParam<TUser> pageParm) { //接收參數(shù) PagedList<TUser> pl =PageUtils.exportPagedList(pageParm); return Result.success(userService.queryPageList(pl, pageParm.getParam())); } public PagedList<TUser> queryPageList(PagedList<TUser> page,TUser user) { PageInfo<TUser> pageInfo= PageHelper.startPage(page).doSelectPageInfo(()-> list(user)); //轉(zhuǎn)換結(jié)果 return PageUtils.toPageList(pageInfo); }
前段傳入?yún)?shù)
{ ????"pageSize":10, ????"pageNum":"1", //查詢條件 ?????"param":{ ?????????"name":"張三210001" ????}, //排序字段 ????"orderBy":"age?desc" }
執(zhí)行結(jié)果
2022-04-15 22:26:39.914 [http-nio-9090-exec-9] DEBUG [613920d89eb54bfd8601c93ec8572dcf] c.s.f.m.UserMapper.queryPageList - ==> Preparing: SELECT * FROM t_user u LEFT JOIN t_user_role ur ON ur.userOid = u.oid WHERE name = ? order by age desc LIMIT ?
2022-04-15 22:26:39.919 [http-nio-9090-exec-9] DEBUG [613920d89eb54bfd8601c93ec8572dcf] c.s.f.m.UserMapper.queryPageList - ==> Parameters: 張三210001(String), 10(Integer)
2022-04-15 22:26:40.267 [http-nio-9090-exec-9] DEBUG [613920d89eb54bfd8601c93ec8572dcf] c.s.f.m.UserMapper.queryPageList - <== Total: 1
基礎(chǔ)的分頁(yè)查詢已經(jīng)發(fā)完成了,下面解答上面的問題的方法
二、分頁(yè)中的排序字段如何防止SQL注入問題
對(duì)于前段傳入的排序字段,我們需要進(jìn)行SQL過濾處理,關(guān)于這個(gè)問題其實(shí)在上述的分頁(yè)封裝類中已經(jīng)進(jìn)行了解決
示例代碼:
public class SQLFilter { public static String sqlInject(String str) { if (StringUtil.isBlank(str)) { return null; } // 去掉'|"|;|\字符 str = StringUtil.replace(str, "'", ""); str = StringUtil.replace(str, "\"", ""); str = StringUtil.replace(str, ";", ""); str = StringUtil.replace(str, "\\", ""); // 轉(zhuǎn)換成小寫 str = str.toLowerCase(); // 非法字符 String[] keywords = { "master", "truncate", "insert", "select", "delete", "update", "declare", "alert", "drop" }; // 判斷是否包含非法字符 for (String keyword : keywords) { if (str.indexOf(keyword) != -1) { throw new SysException("包含非法字符"); } } return str; } }
三、復(fù)雜的SQL分頁(yè)語(yǔ)句
復(fù)雜的SQL分頁(yè)語(yǔ)句,需要自定義SQL的count語(yǔ)句如何實(shí)現(xiàn)呢?
PageHelper實(shí)現(xiàn)分頁(yè),默認(rèn)是查詢自定義的count語(yǔ)句是否存在,如果存在就用自定義的語(yǔ)句,否則就在外層包裝查詢的語(yǔ)句,而自定義count語(yǔ)句只需要在在查詢語(yǔ)句名稱后面添加_COUNT即可。例如
查詢集合的語(yǔ)句名稱為queryPageList
,那么查詢count的語(yǔ)句為queryPageList_COUNT
,返回Long類型即可。
<select id="queryPageList_COUNT" resultType="java.lang.Long"> select count(1) from t_user u left join t_user_role ur on ur.userOid=u.oid <where> <if test="name != null">name=#{name}</if> </where> </select>
四、分頁(yè)失效的常見的場(chǎng)景有哪些?
1.pageHelper分頁(yè)查詢有個(gè)特殊的要求,查詢下sql語(yǔ)句一定要緊跟在分頁(yè)查詢的后面,否則分頁(yè)查詢會(huì)失效。之前采用的如下寫法容易失效,建議采用java8的寫法
PageHelper.startPage(pagedList.getPageNum(),pagedList.getPageSize()); //緊跟分頁(yè)查詢后面 List<TUser> list = list(user); PageInfo<TUser> pageInfo =new PageInfo<>(list); return PageUtils.toPageList(pageInfo);
2.注意pagehelper的reasonable 默認(rèn)為false,遇到查詢頁(yè)數(shù)大于總頁(yè)數(shù)時(shí),出現(xiàn)分頁(yè)失敗
pagehelper的reasonable 默認(rèn)為false,遇到查詢頁(yè)數(shù)大于總頁(yè)數(shù)時(shí),查詢?yōu)榭眨划?dāng)reasonable設(shè)置為true時(shí),遇到查詢頁(yè)數(shù)大于總頁(yè)數(shù)時(shí),查詢最后一頁(yè)數(shù)據(jù);
3.PageHelper先開啟分頁(yè),后對(duì)list數(shù)據(jù)操作將會(huì)導(dǎo)致分頁(yè)錯(cuò)誤
示例代碼:
public PageInfo<TUserVO> getUserPageList(int pageNum, int pageSize) { PageHelper.startPage(pageNum,pageSize); List<TUserVO> tUserVOsByView = userMapper.getUserList(); List<TUserVO> TUserVOs = new ArrayList<>(); for (TUserVO TUserVO : tUserVOsByView) { TUserVO TUserVOSingle = new TUserVO(); TUserVOSingle.setHdId(TUserVO.getHdId()); TUserVOs.add(TUserVOSingle); } PageInfo<TUserVO> pageViewInfo = new PageInfo<>(TUserVOs); return pageViewInfo; }
4.PageHelper先對(duì)list數(shù)據(jù)操作,后開啟分頁(yè),將會(huì)導(dǎo)致分頁(yè)失效
示例代碼:
public PageInfo<TUserVO> getUserPageList(int pageNum, int pageSize) { List<TUserVO> tUserVOsByView = userMapper.getUserList(); List<TUserVO> TUserVOs = new ArrayList<>(); for (TUserVO TUserVO : tUserVOsByView) { TUserVO TUserVOSingle = new TUserVO(); TUserVOSingle.setHdId(TUserVO.getHdId()); } PageHelper.startPage(pageNo,pageSize); PageInfo<TUserVO> pageViewInfo = new PageInfo<>(TUserVOs); return pageViewInfo; }
大家需要注意下,抽時(shí)間可以去驗(yàn)證下結(jié)果。
五、大表數(shù)據(jù)PageHelper分頁(yè)性能如何
PageHelper 對(duì)于大表查詢數(shù)據(jù)量越大,性能越差,這是因?yàn)镻ageHelper分頁(yè)是自動(dòng)在sql語(yǔ)句后面拼接limit沒有進(jìn)行相關(guān)的優(yōu)化,一旦數(shù)據(jù)大,性能就比較慢。
例如:
優(yōu)化前SQL語(yǔ)句:
SELECT d.* FROM tag_detail d LIMIT 10000000,10
查詢的時(shí)間大概需要10秒左右,執(zhí)行速度比較慢。
優(yōu)化后SQL語(yǔ)句:
SELECT d.* FROM tag_detail d INNER JOIN (SELECT oid FROM tag_detail LIMIT 10000000,10) t ON d.oid= t.oid;
子查詢先通過分頁(yè)查詢主鍵字段,然后進(jìn)行關(guān)聯(lián)查詢,經(jīng)過優(yōu)化后,查詢時(shí)間大概為1秒左右。性能大幅度提升。
總結(jié):
本文講解了PageHelper的基本的使用和相關(guān)的問題,這些都是我從實(shí)際的項(xiàng)目中總結(jié)出來的問題以及相關(guān)的解決方案,大家在使用的時(shí)候要特別注意,不要放同樣的錯(cuò)誤。
到此這篇關(guān)于Spring Boot 集成PageHelper的使用方法的文章就介紹到這了,更多相關(guān)Spring Boot 集成PageHelper內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
IntelliJ IDEA中properties文件顯示亂碼問題的解決辦法
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA中properties文件顯示亂碼問題的解決辦法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10JAVA TIMER簡(jiǎn)單用法學(xué)習(xí)
Timer類是用來執(zhí)行任務(wù)的類,它接受一個(gè)TimerTask做參數(shù)2013-07-07一文吃透Spring?Cloud?gateway自定義錯(cuò)誤處理Handler
這篇文章主要為大家介紹了一文吃透Spring?Cloud?gateway自定義錯(cuò)誤處理Handler方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Java導(dǎo)出Excel統(tǒng)計(jì)報(bào)表合并單元格的方法詳解
我們?cè)谌粘>幊踢^程中,總是會(huì)碰見導(dǎo)出相關(guān)表格信息的需求,所以就讓我們一起來學(xué)習(xí)一下,這篇文章主要給大家介紹了關(guān)于Java導(dǎo)出Excel統(tǒng)計(jì)報(bào)表合并單元格的相關(guān)資料,需要的朋友可以參考下2021-10-10Java編程之多線程死鎖與線程間通信簡(jiǎn)單實(shí)現(xiàn)代碼
這篇文章主要介紹了Java編程之多線程死鎖與線程間通信簡(jiǎn)單實(shí)現(xiàn)代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10