Mybatis-Plus分页查询

Mybatis-Plus分页插件解读

官方地址

  1. 引入依赖
<!--        mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
  1. 引入分页插件(官方推荐的最新引入方式):
  @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //DbType  数据库类型
        PaginationInnerInterceptor page = new PaginationInnerInterceptor(DbType.MYSQL);
        //单次查询最大的数量   如果我查10条,返回还是5条。
        page.setMaxLimit(5L);
        //溢出总页数后是否做处理(默认不做,true表示做处理,回到首页) false  继续请求
        page.setOverflow(false);
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //设置数据库类型为mysql
        interceptor.addInnerInterceptor(page);
        return interceptor;
    }
  • PaginationInnerInterceptor :自动分页插件

属性:
在这里插入图片描述
常用的数据库类型DbType.mysql等,详细请见官方文档。

  • MybatisPlusInterceptor:MP插件主体,addInnerInterceptor返回值为Interceptor接口,mybatis的其他插件都是其实现类。
  • 通过他们的命名我们可知,他们都是一些拦截器
    在这里插入图片描述
分页查询条件准备
分页查询5要素

分页查询的条件
current:当前页
size:当前页显示数据条数
records:返回数据
total:数据库数据总量
pages:总页数
当然,也缺少不了数据的排序方式。

MP提供的分页条件类

Page
在这里插入图片描述
IPage接口
Page实现了IPage接口
通过这两个默认方法我们可知,查询时,如果当前页数<=1,那么默认从第0页开始查,如果>=1,则从传入页数-1开始查。
在这里插入图片描述

自定义的分页条件类

虽然MP给我们提供了丰富的分页查询接口,但是由于功能过于繁多,正常开发中我们很少用到,所以适合我们的才是最好的。我这里提供了一个自定义的查询条件接口,满足自己作品的使用。

在这里,我们默认从第一页开始查询数据。
并且排序方式[{‘column’: ‘create_time’,‘asc’: false},{‘column’: ‘name’,‘asc’: "true}]
默认是按照,创建时间倒序的方式[{‘column’: ‘create_time’,‘asc’: false}]

@Data
@ApiModel(value = "分页", description = "orders传参实例:[{'column': 'create_time','asc': false},{'column': 'name','asc': " +
        "true}]")
public class PageVO {
    /**
     * 当前页
     */
    @ApiModelProperty(value = "当前页")
    private Integer current;

    /**
     * 当前页显示数据的条数
     */
    @ApiModelProperty(value = "当前页显示数据的条数")
    private Integer size;

    /**
     * 获取排序信息,排序的字段和正反序
     */
    @ApiModelProperty(value = "排序方式。(默认【创建时间倒序】:[{'column': 'create_time','asc': false}])。",
            notes = "例子:[{'column': 'create_time','asc': false},{'column':'name','asc': true}]"
    )
    private String orders;

    /**
     * 当前页默认值为1
     */
    public Integer getCurrent() {
        return current = (current == null || current <= 0) ? 1 : current;
    }

    /**
     * 每页大小默认为10
     */
    public Integer getSize() {
        return size = (size == null || size == 0) ? 10 : size;
    }

    public Integer obtainRealCurrent() {
        return current;
    }

    public Integer obtainRealSize() {
        return size;
    }

    /**
     * description:将orders(json数组字符串)转为List
     * Date: 2020/11/22 16:43
     */
    public List<OrderItem> generateOrderList() {
        List<OrderItem> orderItemList = new ArrayList<>();
        if (StrUtil.isBlank(getOrders())) {
            orderItemList.add(OrderItem.desc("create_time"));
        } else {
            try {
                orderItemList = JSONArray.parseArray(orders, OrderItem.class);
            } catch (Exception e) {
                throw new BadRequestException("分页排序参数orders不合法,请传正确的参数格式——['column':'','asc':'true/false']");
            }
        }
        return orderItemList;
    }

    /**
     * description:根据pageVO构建分页查询IPage
     * @return IPage查询条件
     * Date: 2020/11/22 17:19
     */
    public <K> IPage<K> buildPage() {
        Page<K> page = new Page<>(getCurrent(), getSize());
        page.addOrder(generateOrderList());
        return page;
    }
}

案例一:使用MP提供的mapper进行分页查询

分页查询所有学生信息

controller

    public Result<Object> getAllStudent(Page studentPage) {
        IPage<StudentDTO> allStudents = studentService.selectPageStudent(studentPage);
        return Result.success(allStudents);
    }

service

    @Override
    public IPage<StudentDTO> selectPageStudent(Page studentIPage) {
        //设置返回的分页查询结果。由于我们要返回DTO类型的数据,分页查询时,我们只能查Student类型数据,所有我们需要重新封装查询结果
        IPage<StudentDTO> returnPage = studentIPage;
        IPage<Student> studentPage = studentMapper.selectPage(studentIPage, null);
        List<Student> students = studentPage.getRecords();
        List<StudentDTO> studentsDTO = studentMapStruct.toDto(students);
        returnPage.setRecords(studentsDTO);
        return returnPage;
    }

returnPage结果:

  "data": {
    "records": [
      {
        "id": 1,
        "name": "张浩琦"
      },
      {
        "id": 2,
        "name": "张武"
      },
      {
        "id": 3,
        "name": "花花"
      },
      {
        "id": 4,
        "name": "花花"
      },
      {
        "id": 5,
        "name": "花花"
      }
    ],
    "total": 21,
    "size": 5,
    "current": 1,
    "orders": [],
    "optimizeCountSql": true,
    "hitCount": false,
    "countId": null,
    "maxLimit": null,
    "searchCount": true,
    "pages": 5

案例二:使用MP提供的mapper进行模糊分页查询

分页查询所有的项目信息

controller

 @ApiOperation("分页查询所有项目基本信息")
    @GetMapping
    public Result<Object> query(AppQueryCriteria criteria, PageVO pageVO) {
        log.info(StrUtil.format("【查询所有项目基本信息 /api/app】操作人id:{},项目查询条件 criteria:{},分页pageVo:{}", SecurityUtils.getCurrentUserId(), criteria, pageVO));
        IPage<AppDTO> app = appService.queryAll(criteria, pageVO, true);
        return Result.success(app);
    }

AppQueryCriteria 为查询条件
在这里插入图片描述
service

   @Override
    @Transactional(rollbackFor = Exception.class)
    public IPage<AppDTO> queryAll(AppQueryCriteria criteria, PageVO pageVO) {
        //创建结果存储
        IPage<AppDTO> returnPage = pageVO.buildPage();
        //判断查询条件是否为全空,全空的话就进行默认查询。这个true可以忽略,业务需求。
        if (judgeObjectIsAllNull(criteria, true)) {
            IPage<App> appPage = appMapper.selectPage(pageVO.buildPage(), new LambdaQueryWrapper<App>().eq(App::getEnabled, true));
            List<AppDTO> appDtos = appMapStruct.toDto(appPage.getRecords());
            returnPage.setRecords(appDtos).setTotal(appPage.getTotal());
            log.info(StrUtil.format("【查询所有项目基本信息】默认查询。操作人id:{},项目信息:{}", SecurityUtils.getCurrentUserId(),
                    appDtos));
            return returnPage;
        }
        //条件查询        produceWrapper(criteria)为条件构造器的生成方法
        IPage<App> page = appMapper.selectPage(pageVO.buildPage(), produceWrapper(criteria));
        List<AppDTO> appDtoList = appMapStruct.toDto(page.getRecords());
        BeanUtil.copyProperties(page, returnPage);
        returnPage.setRecords(appDtoList);
        log.info(StrUtil.format("【查询所有项目基本信息】条件查询。操作人id:{},项目信息:{}", SecurityUtils.getCurrentUserId(),
                appDtoList));
        return returnPage;
    }

我们创建了returnPage,用来存储返回的结果。
returnPage结果:其中包含分页的5要素

 "data": {
    "records": [
      {
        "appId": 63,
        "name": "123"
      },
      {
        "appId": 62,
        "name": "123"
      }
    ],
    "total": 50,
    "size": 2,
    "current": 1,
    "orders": [
      {
        "column": "create_time",
        "asc": false
      }
    ],
    "optimizeCountSql": true,
    "hitCount": false,
    "countId": null,
    "maxLimit": null,
    "searchCount": true,
    "pages": 25

附代码:
1.判断对象属性是否为全空
enabled属性表示的是否可用,可忽略。

public boolean judgeObjectIsAllNull(Object obj, Boolean enabled) {
        Field[] declaredFields = ReflectUtil.getFields(obj.getClass());
        boolean isAllNull = true;
        String en = "enabled";
        //判断对象是否为全空
        for (Field field : declaredFields) {
            if (ObjectUtil.isNotNull(ReflectUtil.getFieldValue(obj, field))) {
                if (enabled) {
                    if (!field.getName().equals(en)) {
                        isAllNull = false;
                        break;
                    }
                } else {
                    isAllNull = false;
                    break;
                }

            }
        }
        return isAllNull;
    }

2.条件构造器生成方法

public LambdaQueryWrapper<App> produceWrapper(AppQueryCriteria criteria) {
        LambdaQueryWrapper<App> wrapper = Wrappers.lambdaQuery();
        //查询是否可用的项目
        wrapper.eq(App::getEnabled, ObjectUtil.isNull(criteria.getEnabled()) ? true : criteria.getEnabled());
        if (StrUtil.isNotBlank(criteria.getName())) {
            wrapper.like(App::getName, criteria.getName());
        }
        if (ObjectUtil.isNotNull(criteria.getBeginTime())) {
            //如果有开始时间,默认从开始到现在
            wrapper.between(App::getBeginTime, criteria.getBeginTime(), ObjectUtil.isNotNull(criteria.getEndTime()) ? criteria.getEndTime() : LocalDateTime.now());
        }
        return wrapper;
    }

案例三:自定义mapper模糊分页查询

根据项目名称和项目状态来模糊查询项目信息
在这里插入图片描述

controller

	@ApiOperation("大盘查询所有项目信息,项目信息,人员信息")
    @GetMapping("detail/all")
    public Result<Object> selectAppByName(AppNameQueryCriteria criteria, PageVO pageVO) {
        log.info(StrUtil.format("【大盘查询所有项目信息 /api/app/detail/all】操作人id:{},项目查询条件 criteria:{},分页pageVo:{}", SecurityUtils.getCurrentUserId(), criteria, pageVO));
        IPage<AppBigViewDTO> appBigView = appService.selectAppByName(criteria, pageVO, true);
        return Result.success(appBigView);
    }

查询条件:AppNameQueryCriteria

@Data
public class AppNameQueryCriteria {
    @ApiModelProperty(value = "项目名称")
    private String name;
    @ApiModelProperty(value = "状态:开发中(0)、开发完成(1)、暂停开发(2)、持续维护中(3)、未开始(4)")
    private Integer status;
}

service

    @Override
    @Transactional(rollbackFor = Exception.class)
    public IPage<AppBigViewDTO> selectAppByName(AppNameQueryCriteria criteria, PageVO pageVO, boolean b) {
        //查询条件全空
        IPage<AppBigViewDTO> returnPage = pageVO.buildPage();
        //默认查询
        if (judgeObjectIsAllNull(criteria, false)) {
            List<AppBigViewDTO> apps = appMapper.selectAppByName(pageVO.buildPage(), new LambdaQueryWrapper<>());
            returnPage.setRecords(apps).setTotal(apps.size());
            log.info(StrUtil.format("【查询成功】。操作人id:{},项目信息:{}", SecurityUtils.getCurrentUserId(), apps));
            return returnPage;
        }
        //条件查询
        LambdaQueryWrapper<App> wrapper = Wrappers.lambdaQuery();
        if (ObjectUtil.isNotNull(criteria.getName())) {
            wrapper.like(App::getName, criteria.getName());
        }
        if (ObjectUtil.isNotNull(criteria.getStatus())) {
            wrapper.eq(App::getStatus, criteria.getStatus());
        }
        List<AppBigViewDTO> apps = appMapper.selectAppByName(pageVO.buildPage(), wrapper);
        returnPage.setRecords(apps).setTotal(apps.size());
        log.info(StrUtil.format("【查询成功】。操作人id:{},项目信息:{}", SecurityUtils.getCurrentUserId(), apps));
        return returnPage;
    }

mapper

@Select("<script>" +
            "SELECT a.app_id ,a.name,a.begin_time ,a.end_time,a.finish_time,a.status " +
            "FROM mnt_app a " +
            "<where>" +
            "${ew.SqlSegment} AND is_deleted=false" +
            "</where>" +
            "</script>")
    @Results(id = "appMap", value = {
            @Result(column = "app_id", property = "id"),
            @Result(column = "name", property = "appName"),
            @Result(column = "begin_time", property = "beginTime"),
            @Result(column = "end_time", property = "endTime"),
            @Result(column = "finish_time", property = "finishTime"),
            @Result(property = "appUsers", column = "app_id", many = @Many(select = "marchsoft.modules.system.mapper.SystemMapper.selectUserByAppId"))
    })
    List<AppBigViewDTO> selectAppByName(IPage<AppUserBaseDTO> appUser, @Param(Constants.WRAPPER) LambdaQueryWrapper<App> wrapper);

注意:当自定义mapper进行模糊分页查询时,需要在mapper层的接口形参条件构造器前添加 @Param(Constants.WRAPPER) 不然的话我们的分页条件是传递不过来的,并且还要在sql添加分页条件的位置添加 ${ew.SqlSegment},他会将分页条件生成在添加的地方。
执行的SQL

SELECT a.app_id, a.name, a.begin_time, a.end_time, a.finish_time, a.status FROM mnt_app a WHERE 
(name LIKE '%测试%') AND is_deleted = false ORDER BY create_time DESC LIMIT 1 

注意:
除了 ${ew.SqlSegment} 外,还有一个 ${ew.customSqlSegment},他们的区别是前者直接 like “%测试%”,后者是where like “%测试%”,会自动帮我们生成一个where关键字,在写动态sql时,一定要多加注意。

如果我们写一个简单的sql的模糊分页,我们使用,${ew.customSqlSegment},可以不写where。

@Select("<script>" +
            "SELECT a.app_id ,a.name,a.begin_time ,a.end_time,a.finish_time,a.status " +
            "FROM mnt_app a " +
            "${ew.customSqlSegment} AND is_deleted=false" +
            "</script>")

返回结果

{
  "data": {
    "records": [
      {
        "id": 60,
        "appName": "测试now6",
        "status": 1,
        "beginTime": 1612800000000,
        "endTime": 1614268800000,
        "finishTime": null,
        "appUsers": [
          {
            "userId": 7,
            "name": "啊啊",
            "avatarPath": ""
          }
        ]
      }
    ],
    "total": 1,
    "size": 1,
    "current": 1,
    "orders": [
      {
        "column": "create_time",
        "asc": false
      }
    ],
    "optimizeCountSql": true,
    "hitCount": false,
    "countId": null,
    "maxLimit": null,
    "searchCount": true,
    "pages": 1
  }
}

Mybatis关联查询

mybatis为我们提供了一对一,一对多,以及多对多的查询方式,来方便我们的查询。
优点:

  1. sql精简化,避免繁杂查询语句的书写
  2. sql复用能力大大增强

案例一:一对一查询(原生mybais)

查询员工所在部门

entity
在这里插入图片描述

service

        UserBaseDTO userBaseDTO = systemMapper.selectUserJoinAppByUserId(userId);

mapper
1. 主句

    @Select({"SELECT u.id ,u.nick_name,u.`avatar_path`,u.`phone`\n" +
            "FROM sys_user u \n" +
            "WHERE u.`id`=#{userId}"})
    //字段名和属性名不相等时,要映射。avatar_path其实会自动转化的,写不写都可以。
    @Results({
    		@Result(column = "id", property = "id",
            @Result(column = "nick_name", property = "name"),
            @Result(column = "avatar_path", property = "avatarPath"),
            @Result(column = "id",property = "dept",one=@One(select = "marchsoft.modules.system.mapper.SystemMapper.selectDeptByUserId"))
              })
    UserBaseDTO selectUserJoinAppByUserId(Long userId);

注意:

  1. 一对一或一对多查询时,传入字句的条件,即上句中的id必须加属性映射@Result(column = “id”, property = “id”,)不然主句接收的id为null
  2. 一对一或一对多查询时,column的id指向的是 @Result(column = “id”, property =
    “id”)column中的id。
  3. 如果我们查询时,使用as,即u.id as userId,那么@Result(column =
    “id”, property = “id”)应该换成@Result(column = “userId”, property =
    “id”)。
    @Result(column = “id”,property = “dept”,one=@One(select = “marchsoft.modules.system.mapper.SystemMapper.selectDeptByUserId”))
    })中的column也应该随着切换
  4. @Result主要做数据库字段和实体对象的名称映射的,如果两者一样,或者数据库user_id,实体类userId,是可以省略的。

在这里插入图片描述

2. 子句

    @Select("SELECT d.`name`" +
            "FROM sys_dept d,sys_user u\n" +
            "WHERE u.id=#{userId} AND u.`dept_id`=d.`id`\n")
    String selectDeptByUserId(Long userId);

案例二: 一对多查询 (@Many)

查询某个项目的参与人员(一个项目有多个参与人员)

entity
在这里插入图片描述

service

        List<AppBigViewDTO> apps = appMapper.selectAppByName(pageVO.buildPage(), new LambdaQueryWrapper<>());

mapper

主句:

    @Select("<script>" +
            "SELECT a.app_id ,a.name,a.begin_time ,a.end_time,a.finish_time,a.status " +
            "FROM mnt_app a " +
            "<where>" +
            "${ew.SqlSegment} AND is_deleted=false" +
            "</where>" +
            "</script>")
    @Results(id = "appMap", value = {
            @Result(column = "app_id", property = "id"),
            @Result(column = "name", property = "appName"),
            @Result(column = "begin_time", property = "beginTime"),
            @Result(column = "end_time", property = "endTime"),
            @Result(column = "finish_time", property = "finishTime"),
            @Result(property = "appUsers", column = "app_id", many = @Many(select = "marchsoft.modules.system.mapper.SystemMapper.selectUserByAppId"))
    })
    List<AppBigViewDTO> selectAppByName(IPage<AppUserBaseDTO> appUser, @Param(Constants.WRAPPER) LambdaQueryWrapper<App> wrapper);

子句:

    @Select({"SELECT u.id ,u.nick_name,u.`avatar_path`",
            "FROM mnt_app a,sys_user u, sys_users_roles_apps sa",
            "WHERE a.`app_id`=#{appId}",
            "AND a.`app_id`=sa.`app_id`",
            "AND sa.`user_id`=u.`id`",
            "GROUP BY a.`app_id`,u.id,u.`nick_name`"})
    @Results({
            @Result(column = "id", property = "userId"),
            @Result(column = "nick_name", property = "name"),
            @Result(column = "avatar_path", property = "avatarPath")
    })
    Set<AppUserBaseDTO> selectUserByAppId(Long appId);

案例三: 一对一查询(封装的查询注解@ Query)

查询某个人的基本信息(部门信息在另外一张表)

entity
在这里插入图片描述

service

        UserBaseDTO userBaseDTO = systemMapper.selectUserJoinAppByUserId(userId);

mapper

1. 主句

    @Select({"SELECT u.id ,u.nick_name,u.`avatar_path`,u.`phone`\n" +
            "FROM sys_user u \n" +
            "WHERE u.`id`=#{userId}"})
    @Results({
            @Result(column = "id", property = "id"),
            @Result(column = "nick_name", property = "name"),
            @Result(column = "avatar_path", property = "avatarPath"),
    })
    @Queries({
            @Query(column = "id", property = "dept", select = "marchsoft.modules.system.mapper.SystemMapper.selectDeptByUserId"),
    })
    UserBaseDTO selectUserJoinAppByUserId(Long userId);

注意:

  1. 封装的@Query,一对一查询时,column指向的是 @Result(column = “id”, property =
    “id”)中的property中的id,这与@One是有区别的。
  2. 不论一对一查,还是一对多查,都可以直接使用@Query。
  3. @One和@Many中的column与数据库中的字段名称对应,@Query与实体类中的属性名称对应。

在这里插入图片描述

2. 子句

    @Select("SELECT d.`name`" +
            "FROM sys_dept d,sys_user u\n" +
            "WHERE u.id=#{userId} AND u.`dept_id`=d.`id`\n")
    String selectDeptByUserId(Long userId);

案例四 一对多查询 (封装的@Query)

查询某个项目的参与人员

entity
在这里插入图片描述

service

        List<AppBigViewDTO> apps = appMapper.selectAppByName(pageVO.buildPage(), new LambdaQueryWrapper<>());

mapper

主句:

    @Select("<script>" +
            "SELECT a.app_id ,a.name,a.begin_time ,a.end_time,a.finish_time,a.status " +
            "FROM mnt_app a " +
            "<where>" +
            "${ew.SqlSegment} AND is_deleted=false" +
            "</where>" +
            "</script>")
    @Results(id = "appMap", value = {
            @Result(column = "app_id", property = "id"),
            @Result(column = "name", property = "appName"),
            @Result(column = "begin_time", property = "beginTime"),
            @Result(column = "end_time", property = "endTime"),
            @Result(column = "finish_time", property = "finishTime"),
    })
    @Queries({
		@Query(column = "id", property = "appUsers",
                   select = "marchsoft.modules.system.mapper.SystemMapper.selectUserByAppId")
  })
    List<AppBigViewDTO> selectAppByName(IPage<AppUserBaseDTO> appUser, @Param(Constants.WRAPPER) LambdaQueryWrapper<App> wrapper);

子句:

    @Select({"SELECT u.id ,u.nick_name,u.`avatar_path`",
            "FROM mnt_app a,sys_user u, sys_users_roles_apps sa",
            "WHERE a.`app_id`=#{appId}",
            "AND a.`app_id`=sa.`app_id`",
            "AND sa.`user_id`=u.`id`",
            "GROUP BY a.`app_id`,u.id,u.`nick_name`"})
    @Results({
            @Result(column = "id", property = "userId"),
            @Result(column = "nick_name", property = "name"),
            @Result(column = "avatar_path", property = "avatarPath")
    })
    Set<AppUserBaseDTO> selectUserByAppId(Long appId);

案例五: 一对多查询传递多个参数(特殊情况@Many)

我们正常进行一对一或一对多查询时,一般只需要传递一个子表的主键id,就能够查出来相应的数据。上面我们举得例子都是这样进行的。如: @Result(property = "appUsers", column = "app_id", many = @Many(select = "marchsoft.modules.system.mapper.SystemMapper.selectUserByAppId")) }),我们就只传递了一个app_id,但是我们在复杂(变态)的业务中,很可能会出现需要传递多个参数才能查出子表的内容。

方式很简单,column用一个大括号包裹即可。

@Result(column = "{userId=userId,appId=app_id}", property = "roles", many = @Many(select = "marchsoft.modules.system.mapper.SystemMapper.selectRoleByUserAndAppId"))

同样,子表接收时,接收的参数也应该是两个,一个userId,一个appId。

xml 一对多查询

一张考卷对应多条配置信息,通过试卷id获取试卷详情及配置。

实体类:
考卷

@Data
@ApiModel(value = "试卷")
public class ExaminationPapersDTO implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "主键id")
    private Long id;

    @ApiModelProperty(value = "试卷名称")
    private String paperName;

    @ApiModelProperty(value = "试卷类型(0固定试卷,1随机试卷)")
    private Integer paperType;

    @ApiModelProperty(value = "试卷总题量")
    private Integer questionNumber;

    @ApiModelProperty(value = "试卷总分值")
    private Integer paperScore;

    @ApiModelProperty(value = "判断题数量")
    private Integer checkQuestionNumber;

    @ApiModelProperty(value = "判断题单题分数")
    private Integer checkQuestionScore;

    @ApiModelProperty(value = "单选题数量")
    private Integer schoiceQuestionNumber;

    @ApiModelProperty(value = "单选题单题分数")
    private Integer schoiceQuestionScore;

    @ApiModelProperty(value = "多选题数量")
    private Integer dchoiceQuestionNumber;

    @ApiModelProperty(value = "多选题单题分数")
    private Integer dchoiceQuestionScore;

    @ApiModelProperty(value = "考试开始时间")
    private String examinationBeaginDate;

    @ApiModelProperty(value = "考试开始时间段")
    private String examinationBeaginScope;

    @ApiModelProperty(value = "考试结束时间")
    private String examinationEndDate;

    @ApiModelProperty(value = "考试结束时间段")
    private String examinationEndScope;

    @ApiModelProperty(value = "应考人数")
    private Integer numberOfCandidates;

    @ApiModelProperty(value = "已考人数")
    private Integer numberOfExaminees;

    @ApiModelProperty(value = "试卷状态(0待考试,1考试中,2已结束)")
    private Integer paperState;

    @ApiModelProperty(value = "考试配置信息")
    List<ExaminationConfDTO> examinationConfs;

}

配置

@Data
@ApiModel("考试配置信息")
public class ExaminationConfDTO {
    private Long examinationPapersId;
    private Integer questionType;
    private Integer questionNumber;
    private Integer knowledgeId;
    private Integer singleScore;
}

查询:

//试卷
    <select id="selectPageAndConf" resultMap="paperAllMes">
        SELECT t1.*
        FROM tb_examination_papers t1
        WHERE t1.id = #{pageId}
          AND t1.del_flag = 0;
    </select>

//试卷配置
    <select id="selectPageConfs" resultType="io.renren.modules.question.dto.save.ExaminationConfDTO">
        SELECT t1.*
        FROM tb_exam_conf t1
        WHERE t1.examination_papers_id = #{id}
    </select>

//字段映射   
    <resultMap id="paperAllMes" type="io.renren.modules.question.dto.save.ExaminationPapersDTO">
        <id property="id" column="id" /> // 必须加,否则id为null
        <collection property="examinationConfs" ofType="io.renren.modules.question.dto.save.ExaminationConfDTO"
                    column="id" select="io.renren.modules.question.dao.ExaminationPapersDao.selectPageConfs">
        </collection>
    </resultMap>

参考文章:MyBatis一对多关联查询

参考Blog

xml文件使用:

  1. mybatis关联查询问题(一对多、多对一)
  2. Mybatis的一对多(collection)和一对一(association)查询
  3. mybatis学习网站
  4. 多表关联查询
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐