当Mybatis遇上目录树超全完美解决方案

网友投稿 218 2023-01-19

当Mybatis遇上目录树超全完美解决方案

相信你也遇到过这种场景,判断二级目录属于哪个一级目录,一个员工属于哪个上级员工领导…

当Mybatis遇上目录树,有哪些解决方法?

一般来说,有xml直接实现和java代码递归赋值实现。

方式一:xml直接实现

这里列出category数据表数据

表结构如下

type表示分类类型,也就是目录级别,1表示一级目录,3表示三级目录

大家就不要关注数据类型规范了,比如这里id应该bigint,type明明可以tinyint之类的,我抓我看到的例子直接讲解。

目录为甜点/蛋糕的id为1,而蛋糕和点心的father_id为1,目录为饼干/膨化的id为2,饼干、薯片、虾条的father_id就是2,一级目录id对应二级子目录的father_id,这就是所属对应关系,可以理解为父子关系。

实体类是mybatis-generator插件自动生成的

public class Category {

private Integer id;

private String name;

private Integer type;

private Integer fatherId;

private String logo;

private String slogan;

private String catImage;

private String bgColor;

//=====篇幅原因,省掉Getter和Setter方法======

......

}

一般我们看到的商城,鼠标放到一级分类目录就会展示出二级分类目录。我们的需求是当鼠标移动到一级分类,我们需要提供二级分http://类和三级分类。

这里贴出需要返回给前端的聚合模型view object数据

/**

* 二级分类VO

*/

public class CategoryVO {

private Integer id;

private String name;

private String type;

private Integer fatherId;

oLdUPxY// 三级分类vo list

private List subCatList;

//=====篇幅原因,省掉Getter和Setter方法======

......

}

public class SubCategoryVO {

private Integer subId;

private String subName;

private String subType;

private Integer subFatherId;

//=====篇幅原因,省掉Getter和Setter方法======

......

}

这就涉及到自连接查询子目录的技巧了,我们试试查找father_id是1的子分类数据,也就是查询甜点/蛋糕分类下面的二级和三级分类,执行如下语句

SELECT

f.id AS id,

f.`name` AS `name`,

f.type AS type,

f.father_id AS fatherId,

c.id AS subId,

c.`name` AS subName,

c.type AS subType,

c.father_id AS subFatherId

FROM

category f

LEFT JOIN category c ON f.id = c.father_id

WHERE

f.father_id = 1

结果如下

可以看到二级分类为蛋糕、点心时,有哪些对应的三级分类可以提供给前端,便于展示。

我这里分为CategoryVO、SubCategoryVO ,而不是把所有属性放在一个VO,是为了便于理解。如果不用List集合,而把所有属性放在一个VO,前端收到的数据形式和你此时在数据库查询出来的一样,有多条蛋糕记录,底下对应着不同具体食品,这让前端不好处理也不符合逻辑,正常逻辑应该是只有一个蛋糕分类,然后这个分类里面有数组去装着蛋糕对应子分类才对。

这里其实只用一个CategoryVO里面也可以处理,在后面第二种方式用java代码处理多级目录时,你会看到我只用了一个CategoryVO就能处理。

注意,二级分类的实体类CategoryVO有个

private List subCatList;

这个subCatList是为了存放三级分类的vo list,在xml中三级分类用了collection对应这个list

SELECT

f.id as id,

f.`name` as `name`,

f.type as type,

f.father_id as fatherId,

c.id as subId,

c.`name` as subName,

c.type as subType,

c.father_id as subFatherId

FROM

category f

LEFT JOIN

category c

on

f.id = c.father_id

WHERE

f.father_id = #{rootCatId}

首先让前端展示在首页的一级分类,前端调用一级分类接口,我们只需要查询type为1的数据返回给前端,鼠标移动到一级分类,就调用获取子分类的接口,前端传入对应一级分类的id给后端,后端将这个id作为father_id去查询子分类。最后我们可以调用getSubCatList来得到所有目录。

@Transactional(propagation = Propagation.SUPPORTS)

@Override

public List getSubCatList(Integer rootCatId) {

return categoryMapperCustom.getSubCatList(rootCatId);

}

最后数据就是这样,如下

{

"status": 200,

"msg": "OK",

"data": [{

"id": 11,

"name": "蛋糕",

"type": "2", <==================type=2表示二级目录

"fatherId": 1,

"subCatList": [{

"subId": 37,

"subName": "蒸蛋糕",

"subType": "3", <================subType=3表示3级目录

"subFatherId": 11

}, {

"subId": 38,

"subName": "软面包",

"subType": "3",

"subFatherId": 11

}, {

"subId": 39,

"subName": "脱水蛋糕",

"subType": "3",

"subFatherId": 11

}, {

"subId": 40,

"subName": "马卡龙",

"subType": "3",

"subFatherId": 11

}, {

"subId": 41,

"subName": "甜甜圈",

"subType": "3",

"subFatherId": 11

}, {

"subId": 42,

"subName": "三明治",

"subType": "3",

"subFatherId": 11

}, {

"subId": 43,

"subName": "铜锣烧",

"subType": "3",

"subFatherId": 11

}]

}, {

"id": 12,

"name": "点心",

"type": "2",

"fatherId": 1,

"subCatList": [{

"subId": 44,

"subName": "肉松饼",

"subType": "3",

"subFatherId": 12

}, {

"subId": 45,

"subName": "华夫饼",

"subType": "3",

"subFatherId": 12

}, {

"subId": 46,

"subName": "沙琪玛",

"subType": "3",

"subFatherId": 12

}, {

"subId": 47,

"subName": "鸡蛋卷",

"subType": "3",

"subFatherId": 12

}, {

"subId": 48,

"subName": "蛋饼",

"subType": "3",

"subFatherId": 12

}, {

"subId": 49,

"subName": "凤梨酥",

"subType": "3",

"subFatherId": 12

}, {

"subId": 50,

"subName": "手撕面包",

"subType": "3",

"subFatherId": 12

}]

}]

}

方式二:java代码递归处理二级三级目录

此刻我换一个数据库例子,但是还是和上面一个处理一级二级三级分类的例子一样

数据表如下

表结构如下

和上一个例子大同小异,type依然表示目录级别

此刻需要返回给前端的VO如下,此刻我只写了一个CategoryVO,没有写子VO,可以对比前一种方式看看,道理都是一样的。

public class CategoryVO {

private Integer id;

private String name;

private Integer type;

private Integer parentId;

private Integer orderNum;

private Date createTime;

private Date updateTime;

private List childCategory = new ArrayList<>();

//=====篇幅原因,省掉Getter和Setter方法======

......

}

@Override

public List listCategoryForCustomer(Integer parentId) {

ArrayList categoryVOList = new ArrayList<>();

recursivelyFindCategories(categoryVOList, parentId);

return categoryVOList;

}

// 以该parentId对应的目录为根节点,查询下面所有子目录信息,categoryVOList是要返回给前端展示的聚合模型数据

private void recursivelyFindCategories(List categoryVOList, Integer parentId) {

// 递归获取所有子类别,并组合成为一个"目录树"

List list= categoryMapper.selectCategoriesByParentId(parentId); // 通过父id查询子分类

if (!CollectionUtils.isEmpty(list)) {

for (int i = 0; i < list.size(); ++i) {

Category category = list.get(i);

CategoryVO categoryVO = new CategoryVO();

BeanUtils.copyProperties(category, categoryVO);

categoryVOList.add(categoryVO);

// 这里当前目录id作为下一次的父id,查询有没有对应的子目录,getChildCategory()方法是返回定义的List childCategory

recursivelyFindCategories(categoryVO.getChildCategory(), categoryVO.getId());

}

}

}

XML文件如下:

......

id, `name`, `type`, parent_id, order_num, create_time, update_time

select

from category

where parent_id = #{parentId}

......

我们手动查询模拟一下递归的过程,首先查询parent_id为3的二级分类

select *

from category

where parent_id = 3

结果递归查询的时候,又会发现parent_id=4时还有数据,即还有三级分类,我们手动查询试试

select *

from category

where parent_id = 4

示例数据如下:

{

"status": 10000,

"msg": "SUCCESS",

"data": [

{

"id": 4,

"name": "橘子橙子",

"type": 2, <=================代表二级目录

"parentId": 3,

"orderNum": 1,

"createTime": "2019-12-17T17:17:00.000+0000",

"updateTime": "2019-12-28T08:25:10.000+0000",

"childCategory": [ <===============代表还有三级目录

{

"id": 19,

"name": "果冻橙",

"type": 3,

"parentId": 4,

"orderNum": 1,

"createTime": "2019-12-17T17:17:00.000+0000",

"updateTime": "2020-02-10T16:37:02.000+0000",

"childCategory": []

}

]

},

{

"id": 11,

"name": "草莓",

"type": 2,

"parentId": 3,

"orderNum": 2,

"createTime": "2019-12-17T17:17:00.000+0000",

"updateTime": "2019-12-28T07:44:42.000+0000",

"childCategory": []

},

{

"id": 12,

"name": "奇异果",

"type": 2,

"parentId": 3,

"orderNum": 3,

"createTime": "2019-12-17T17:17:00.000+0000",

"updateTime": "2019-12-28T08:25:12.000+0000",

"childCategory": []

},

{

"id": 14,

"name": "车厘子",

"type": 2,

"parentId": 3,

"orderNum": 4,

"createTime": "2019-12-17T17:17:00.000+0000",

"updateTime": "2019-12-28T08:25:12.000+0000",

"childCategory": []

},

{

"id": 28,

"name": "其他水果",

"type": 2,

"parentId": 3,

"orderNum": 4,

"createTime": "2019-12-17T17:17:00.000+0000",

"updateTime": "2019-12-28T08:25:12.000+0000",

"childCategory": []

}

]

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:手机验证码短信接口api(手机验证码短信接口发送失败)
下一篇:小程序 豆瓣电影api(新电影小程序)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~