MyBatis教程[4]----手寫分頁


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"
	        }
	    ]
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章