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