问题描述
我们知道MyBatisPlus的分页插件是操作对应的表来查询的,如果要展示的数据跨表,该如何查询展示?
场景模拟
假设有两张表菜品表和分类表,而展示菜品时,不但需要菜品信息,还要需要分类表的分类名称
需要用菜品表记录的分类表的category_id来查询分类表的分类名称
sql代码如下:
#分类表
CREATE TABLE `category` (
`id` BIGINT(20) NOT NULL COMMENT '主键',
`type` INT(11) DEFAULT NULL COMMENT '类型 1 菜品分类 2 套餐分类',
`name` VARCHAR(64) COLLATE utf8_bin NOT NULL COMMENT '分类名称',
`sort` INT(11) NOT NULL DEFAULT '0' COMMENT '顺序',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`update_time` DATETIME NOT NULL COMMENT '更新时间',
`create_user` BIGINT(20) NOT NULL COMMENT '创建人',
`update_user` BIGINT(20) NOT NULL COMMENT '修改人',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_category_name` (`name`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='菜品及套餐分类';
#菜品表
CREATE TABLE `dish` (
`id` BIGINT(20) NOT NULL COMMENT '主键',
`name` VARCHAR(64) COLLATE utf8_bin NOT NULL COMMENT '菜品名称',
`category_id` BIGINT(20) NOT NULL COMMENT '菜品分类id',
`price` DECIMAL(10,2) DEFAULT NULL COMMENT '菜品价格',
`code` VARCHAR(64) COLLATE utf8_bin NOT NULL COMMENT '商品码',
`image` VARCHAR(200) COLLATE utf8_bin NOT NULL COMMENT '图片',
`description` VARCHAR(400) COLLATE utf8_bin DEFAULT NULL COMMENT '描述信息',
`status` INT(11) NOT NULL DEFAULT '1' COMMENT '0 停售 1 起售',
`sort` INT(11) NOT NULL DEFAULT '0' COMMENT '顺序',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`update_time` DATETIME NOT NULL COMMENT '更新时间',
`create_user` BIGINT(20) NOT NULL COMMENT '创建人',
`update_user` BIGINT(20) NOT NULL COMMENT '修改人',
`is_deleted` INT(11) NOT NULL DEFAULT '0' COMMENT '是否删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `idx_dish_name` (`name`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='菜品管理';
对应的两个表的实体类
/**
* 分类
*/
@Data
public class Category implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//类型 1 菜品分类 2 套餐分类
private Integer type;
//分类名称
private String name;
//顺序
private Integer sort;
//创建时间
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//更新时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
//创建人
@TableField(fill = FieldFill.INSERT)
private Long createUser;
//修改人
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
/**
菜品
*/
@Data
public class Dish implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
//菜品名称
private String name;
//菜品分类id
private Long categoryId;
//菜品价格
private BigDecimal price;
//商品码
private String code;
//图片
private String image;
//描述信息
private String description;
//0 停售 1 起售
private Integer status;
//顺序
private Integer sort;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
//是否删除
private Integer isDeleted;
}
解决方案:
建立一个新的实体类对象,将要返回的属性都写上面,其实就是继承菜品类再扩展一个分类名字
专业的术语称之为dto类,一般将此类型的类专一放在dto包下
新建的dto类如下:
@Data public class DishDto extends Dish {//继承了Dish说明属性都继承过来了 //下面的属性名称因为前端的分类的name就是categoryName //所以我这里返回的属性名称也要是categoryName,名字要一一对应的 private String categoryName; } 前端的这个属性的代码 <el-table-column prop="categoryName" label="菜品分类" ></el-table-column>
然后进行业务层基于MyBatisPlus的分页插件进行封装展示
下面代码讲解:
步骤1、先当成单表分页,将对应的菜品类分页查询的Page分页对象查询出来
步骤2、将菜品类分页对象的值,赋值给新建的dto类的分页对象
赋值步骤:
打开Page源码可知,只有List类型的属性records是分装展示的信息,其它的都一样。
步骤1、拷贝除了分装展示的信息属性records值之外的所有属性,使用现成的拷贝属性的工具类BeanUtils,该工具类是Springboot提供的,具体调用的方法BeanUtils.copyProperties(被拷贝的对象,接收的对象,拷贝忽略属性的字符串);
步骤2、菜品分页对象的分装展示的信息属性records在拷贝的基础上使用菜品中的分类id属性查询出对应的分类名称,并存入新的dto类里,最后放在对应的dto类的分页对象,然后进行dto类的分页对象的返回实现业务!
代码如下:
/** * 菜品信息分页查询 * @param page * @param pageSize * @param name * @return */ @GetMapping("/page") public R<Page> page(int page,int pageSize,String name){ //构造分页构造器对象 Page<Dish> pageInfo = new Page<>(page, pageSize); LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>(); //如果name是空就直接查询全部,如果name不为空,就执行由name筛选条件的sql语句 queryWrapper.like(name != null,Dish::getName,name); queryWrapper.orderByDesc(Dish::getUpdateTime);//按更新时间排序 dishService.page(pageInfo,queryWrapper); //对象拷贝,因为没有categoryName,所以要把分页的信息查询过来后,所有信息都拷贝到Page<DishDto> Page<DishDto> dishDtoPage = new Page<>();//创建这个分页对象 BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");//除了里面的records属性将信息全部拷贝一份 List<Dish> records = pageInfo.getRecords();//将对应分装分页类的封装属性的List拿到,然后慢慢赋值 List<DishDto> list = new ArrayList(); for(Dish item: records){ Long categoryId = item.getCategoryId();//找到List中每一个CategoryId Category category = categoryService.getById(categoryId);//Category表中进行查询 String categoryName = category.getName();//找到对应Category表中的分类名称 DishDto dishDto = new DishDto(); dishDto.setCategoryName(categoryName);//先添加CategoryName属性的值 BeanUtils.copyProperties(item,dishDto);//将dish的属性全部拷贝进去 list.add(dishDto);//最后将封装好的对象全部添加到对应的List中 } dishDtoPage.setRecords(list); return R.success(dishDtoPage); }