MyBatis的分頁查詢需要手動實現,MyBatis並沒有提供現成的分頁功能。接下來跟着本文章來一步一步實現它。
1.需求明確
首先要明確分頁查詢SQL語句怎麼寫:
SELECT * FROM `user` LIMIT startIndex,count
startIndex:指定從第哪一條條記錄開始查詢(不包含當前記錄,即實際是從startIndex+1開始的)
count: 指定查詢多少條數據
- count是人爲指定的,即需要一頁顯示多少條數據。
- startIndex是程序計算出來的,取決於當前查詢的頁數和每頁的記錄數。計算方式是:(當前要查詢的頁碼-1)* 每頁要查詢的記錄數。
此外,還需要得到總記錄數,總頁數。這些可能都是需要在前端顯示的。
2.編寫Page類
新建page包並在包下新創建Page類,代碼如下:
package com.yky.springboot.page;
import java.util.List;
public class Page<T> {
//每頁顯示的記錄數
private int lineSize = 5;
//總記錄數
private long totalRecord;
//用戶指定的頁數
private int currentPage;
//起始位置
private long startIndex;
//總頁數
int pageCount;
List<T> list;
public Page(int currentPage, long totalRecord, int lineSize) {
this.currentPage = currentPage;
this.totalRecord = totalRecord;
this.lineSize = lineSize;
//計算出pageCount
this.pageCount = (int) ((totalRecord % lineSize) != 0 ? ((totalRecord / lineSize) + 1) : (totalRecord / lineSize));
//計算出起始位置,注意,從0下標開始
this.startIndex = (currentPage - 1) * lineSize;
}
public long getStartIndex() {
return (currentPage - 1) * lineSize;
}
public void setStartIndex(long startIndex) {
this.startIndex = startIndex;
}
public int getLineSize() {
return lineSize;
}
public void setLineSize(int lineSize) {
this.lineSize = lineSize;
}
public long getTotalRecord() {
return totalRecord;
}
public void setTotalRecord(long totalRecord) {
this.totalRecord = totalRecord;
}
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getPageCount() {
return pageCount;
}
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
@Override
public String toString() {
return "Page{" +
"lineSize=" + lineSize +
", totalRecord=" + totalRecord +
", currentPage=" + currentPage +
", pageCount=" + pageCount +
", list=" + list +
'}';
}
}
Page類的構造方法需要傳入三個參數,分別是:
- currentPage:當前要查詢的頁碼
- totalRecord:符合查詢條件的總記錄數
- lineSize:每頁顯示的最大記錄數
通過傳入這三個參數可以算出:
- pageCount:總頁數
- startIndex:當前頁SQL語句查詢的開始下標
3.編寫Dao層查詢數據
Dao層需要針對兩個查詢接口進行編寫,一是查詢符合條件的總記錄數,二是查詢符合條件的具體記錄。
Mapper接口代碼:
/**
* 根據查詢條件獲取總記錄數
* 在這裏直接傳一個user對象
* 使用user.name進行模糊查詢
* 使用user.phone進行精確查詢
* @param user
* @return
*/
Long getTotalRecord(@Param("u") User user);
/**
* 根據查詢條件獲取總記錄數
* 在這裏直接傳一個user對象
* 使用user.name進行模糊查詢
* 使用user.phone進行精確查詢
* @param page
* @param user
* @return
*/
List<User> selectPage(@Param("p") Page page, @Param("u") User user);
xml映射文件代碼
<select id="getTotalRecord" resultType="java.lang.Long">
SELECT COUNT(1) FROM `user`
<where>
<if test="u.name != null and u.name != ''">
name LIKE CONCAT('%',#{u.name},'%')
</if>
<if test="u.phone != null and u.phone != ''">
AND phone = #{u.phone}
</if>
</where>
</select>
<select id="selectPage" resultType="com.yky.springboot.entities.User">
SELECT * FROM `user`
<where>
<if test="u.name != null and u.name != ''">
name LIKE CONCAT('%',#{u.name},'%')
</if>
<if test="u.phone != null and u.phone != ''">
AND phone = #{u.phone}
</if>
</where>
LIMIT #{p.startIndex},#{p.lineSize}
</select>
測試
@Test
void pageMapperTest() {
User user = new User();
user.setName("小");
//查詢第一頁
Long totalRecord = userMapper.getTotalRecord(user);
Page page = new Page(1, totalRecord, 3);
List<User> userList = userMapper.selectPage(page, user);
System.out.println("totalRecord" + totalRecord);
System.out.println("userList:" + userList);
//查詢第二頁
Page page1 = new Page(2, totalRecord, 3);
userList = userMapper.selectPage(page1, user);
System.out.println("userList:" + userList);
//使用phone條件查詢
User user1 = new User();
user1.setPhone("18888888888");
totalRecord = userMapper.getTotalRecord(user1);
Page page2 = new Page(1, totalRecord, 3);
userList = userMapper.selectPage(page, user1);
System.out.println("totalRecord" + totalRecord);
System.out.println("userList:" + userList);
}
運行結果
4.編寫Service層得到分頁數據
dao層在上一步我們已經寫好了,接下來就是在service整合dao層的兩個查詢了。
在這裏service層要做的事情有:
- 調用dao層的getTotalRecord獲得符合條件的總記錄數
- 將上一步得到的總記錄數封裝到Page對象中
- 調用dao層的selectPage方法查詢數據
- 將查詢到的數據封裝到Page對象中
在service包下新創建UserService.java文件代碼如下(注意:這裏只定義接口,具體實現不再這裏):
public interface UserService {
/**
* 分頁查詢
* @param currentPage 當前頁碼
* @param lineSize 每頁數據個數
* @param user user對象
* @return
*/
Page<User> getPageData(int currentPage, int lineSize, User user);
}
在service.impl包下新建文件UserServiceImpl.java代碼如下(這裏寫接口的具體實現):
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public Page<User> getPageData(int currentPage, int lineSize, User user) {
//得到符合條件的總記錄數
Long totalRecord = userMapper.getTotalRecord(user);
//構建page對象
Page<User> page = new Page<>(currentPage,totalRecord,lineSize);
//分頁查詢
List<User> userList = userMapper.selectPage(page, user);
//將查詢結果封裝到page裏
page.setList(userList);
return page;
}
}
該類實現了UserService接口,至此Service層代碼就寫好了。
5.HTTP接口獲取分頁數據實戰
接下來就是編寫Controller層,前端傳遞分頁條件,後端返回對應的數據。在controller包下新創建UserController.java文件,並添加以下代碼
@Controller
@RequestMapping(value = "/user")
public class UserController {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private UserService userService;
@PostMapping(value = "/{currentPage}/{lineSize}")
@ResponseBody
public Page<User> list(@RequestBody User user, @PathVariable("currentPage") Integer currentPage, @PathVariable("lineSize") Integer lineSize) {
Page<User> page = userService.getPageData(currentPage, lineSize, user);
System.out.println(page);
return page;
}
}
在這裏頁碼和單頁數據大小通過PathValue傳入,篩選條件通過JSON對象傳入,接口返回JSON字符串。
利用Postman進行測試
查詢第一頁數據,篩選條件是name中含有“小”字。
查詢第二頁數據
後話:爲了更規範,在這裏可以自定義一個Result對象,將page對象封裝到Result對象中,最後將Result對象返回給前端。
{
"code":200,
"message":"OK",
"data":{
"lineSize": 3,
"totalRecord": 5,
"currentPage": 2,
"startIndex": 3,
"pageCount": 2,
"list": [
{
"id": 4,
"name": "小張",
"phone": "15555555555",
"birthday": "2020-03-16T06:37:25.000+0000"
},
{
"id": 5,
"name": "小劉",
"phone": "12345678",
"birthday": "2020-03-16T06:48:08.000+0000"
}
]
}
}