Mybatis Plus 使用学习十一 再说分页之自定义查询的分页

在前面的章节已经演示过基于Mybatis Plus自带的查询方法实现分页查询,但是有时候如果我的查询特别复杂,要自己写sql,类似于mybatis在xml中写sql,这时该如何分页呢,我们这一节就来演示一下。

我们先来回顾一下在第二节使用的分页方式。

/**
     * 根据 entity 条件,查询全部记录(并翻页)
     *
     * @param page         分页查询条件(可以为 RowBounds.DEFAULT)
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    <E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

这个方法是基于生成的mapper,掉用selectPage方法,并传入条件参数,来完成查询。

我们自定义的分页查询其实和这个写法类似。

1、在Classz的mapper中,定义一个联查方法

package com.itzhimei.mybatis.plus.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.itzhimei.mybatis.plus.model.Classz;
import com.itzhimei.mybatis.plus.model.ClasszAndStudent;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * @Auther: www.itzhimei.com
 * @Description:
 */
public interface ClasszMapper extends BaseMapper<Classz> {

    /**
     * 关联查询
     * @return
     */
    @Select("select a.*,b.id stdId,b.cid, b.name stdName from classz a ,student b where a.id = b.cid and a.id = 1")
    List<ClasszAndStudent> selectClassAndStudentsForPage(IPage page);

}

这个查询方法的惨呼就是IPage page,我这里没有使用泛型,因为我只需要用page的最基本的功能,就是当前页码、每页记录数、总记录数、总页数等这些和分页相关的参数。

这样定义的方法,能够让我即自定义查询,又带有分页,且代码量也并不多。

2、定义结果eneity:ClasszAndStudent

package com.itzhimei.mybatis.plus.model;

import lombok.Data;

/**
 * @Auther: www.itzhimei.com
 * @Description: 班级和学生entity
 */

@Data
public class ClasszAndStudent {
    private Long id;
    private String name;

    private Long stdId;
    private Long cid;
    private String stdName;
}

3、测试

package com.itzhimei.mybatis.plus.test;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itzhimei.mybatis.plus.mapper.ClasszMapper;
import com.itzhimei.mybatis.plus.mapper.StudentMapper;
import com.itzhimei.mybatis.plus.model.ClasszAndStudent;
import com.itzhimei.mybatis.plus.model.Student;
import com.itzhimei.mybatis.plus.model.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.List;

/**
 * @Auther: www.itzhimei.com
 * @Description:
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class ClassStudentTest {

    @Autowired
    private ClasszMapper classzMapper;

    @Test
    public void testSelectPage() {
        IPage page =new Page<User>(1, 1);
        List<ClasszAndStudent> classzs = classzMapper.selectClassAndStudentsForPage(page);
        classzs.forEach(System.out::println);
    }
}

在测试方法中,我定义了分页对象Page,设置了页码和每页数据条数,demo中设置的是第一页的一条记录。

4、输出

==>  Preparing: SELECT COUNT(1) FROM classz a, student b WHERE a.id = b.cid AND a.id = 1 
==> Parameters: 
<==    Columns: COUNT(*)
<==        Row: 2
==>  Preparing: select a.*,b.id stdId,b.cid, b.name stdName from classz a ,student b where a.id = b.cid and a.id = 1 limit ? 
==> Parameters: 1(Long)
<==    Columns: ID, NAME, STDID, CID, STDNAME
<==        Row: 1, 一年一班, 1, 1, 小明
<==      Total: 1

我们从日志输出可以看出,总记录2条,当前查询了一条。

我手动完成一个翻页,也就是继续查询第二页数据,demo中的page做一些修改。

IPage page =new Page<User>(2, 1);

输出

==>  Preparing: SELECT COUNT(1) FROM classz a, student b WHERE a.id = b.cid AND a.id = 1 
==> Parameters: 
<==    Columns: COUNT(*)
<==        Row: 2
==>  Preparing: select a.*,b.id stdId,b.cid, b.name stdName from classz a ,student b where a.id = b.cid and a.id = 1 limit ? offset ? 
==> Parameters: 1(Long), 1(Long)
<==    Columns: ID, NAME, STDID, CID, STDNAME
<==        Row: 1, 一年一班, 2, 1, 小欧
<==      Total: 1

这里可以看到结果从“小明”变为了“小欧”,分页成功。

补充:

如果自定义查询有条件怎么办?

也很简单,在mapper定义的方法中再添加一个参数,例如:

List<ClasszAndStudent> selectClassAndStudentsForPage(IPage page, ClassCondition condition);

这里的ClassCondition condition,就可以作为一个参数实体,拼装条件。

上面demo中mapper的方法,是返回的List<实体>,你可能会问,page信息怎么返回,办法就是在Service层来处理。

    @Autowired
    ClasszMapper classzMapper;

    public IPage<ClasszAndStudent> selectClassAndStudentsForPage(Page page, ClassCondition condition) {
        IPage<ClasszAndStudent> result = new Page<>();
        List<ClasszAndStudent> list = classzMapper.selectClassAndStudentsForPage(page, condition);
        result.setRecords(list);
        return result;
    }

这就是分页结果的返回方式,这里其实和第二节的使用方式是一样的,都是返回的是IPage<实体>对象,只是这里是手动赋值。