當(dāng)Mybatis遇上目錄樹超全完美解決方案
相信你也遇到過這種場(chǎng)景,判斷二級(jí)目錄屬于哪個(gè)一級(jí)目錄,一個(gè)員工屬于哪個(gè)上級(jí)員工領(lǐng)導(dǎo)…
當(dāng)Mybatis遇上目錄樹,有哪些解決方法?
一般來(lái)說(shuō),有
xml直接實(shí)現(xiàn)和java代碼遞歸賦值實(shí)現(xiàn)。
方式一:xml直接實(shí)現(xiàn)
這里列出category數(shù)據(jù)表數(shù)據(jù)

表結(jié)構(gòu)如下

type表示分類類型,也就是目錄級(jí)別,1表示一級(jí)目錄,3表示三級(jí)目錄
大家就不要關(guān)注數(shù)據(jù)類型規(guī)范了,比如這里id應(yīng)該bigint,type明明可以tinyint之類的,我抓我看到的例子直接講解。
目錄為甜點(diǎn)/蛋糕的id為1,而蛋糕和點(diǎn)心的father_id為1,目錄為餅干/膨化的id為2,餅干、薯片、蝦條的father_id就是2,一級(jí)目錄id對(duì)應(yīng)二級(jí)子目錄的father_id,這就是所屬對(duì)應(yīng)關(guān)系,可以理解為父子關(guān)系。
實(shí)體類是mybatis-generator插件自動(dòng)生成的
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方法======
......
}
一般我們看到的商城,鼠標(biāo)放到一級(jí)分類目錄就會(huì)展示出二級(jí)分類目錄。我們的需求是當(dāng)鼠標(biāo)移動(dòng)到一級(jí)分類,我們需要提供二級(jí)分類和三級(jí)分類。

這里貼出需要返回給前端的聚合模型view object數(shù)據(jù)
/**
* 二級(jí)分類VO
*/
public class CategoryVO {
private Integer id;
private String name;
private String type;
private Integer fatherId;
// 三級(jí)分類vo list
private List<SubCategoryVO> subCatList;
//=====篇幅原因,省掉Getter和Setter方法======
......
}
public class SubCategoryVO {
private Integer subId;
private String subName;
private String subType;
private Integer subFatherId;
//=====篇幅原因,省掉Getter和Setter方法======
......
}
這就涉及到自連接查詢子目錄的技巧了,我們?cè)囋嚥檎?code>father_id是1的子分類數(shù)據(jù),也就是查詢甜點(diǎn)/蛋糕分類下面的二級(jí)和三級(jí)分類,執(zhí)行如下語(yǔ)句
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
結(jié)果如下

可以看到二級(jí)分類為蛋糕、點(diǎn)心時(shí),有哪些對(duì)應(yīng)的三級(jí)分類可以提供給前端,便于展示。
我這里分為CategoryVO、SubCategoryVO ,而不是把所有屬性放在一個(gè)VO,是為了便于理解。如果不用List集合,而把所有屬性放在一個(gè)VO,前端收到的數(shù)據(jù)形式和你此時(shí)在數(shù)據(jù)庫(kù)查詢出來(lái)的一樣,有多條蛋糕記錄,底下對(duì)應(yīng)著不同具體食品,這讓前端不好處理也不符合邏輯,正常邏輯應(yīng)該是只有一個(gè)蛋糕分類,然后這個(gè)分類里面有數(shù)組去裝著蛋糕對(duì)應(yīng)子分類才對(duì)。

這里其實(shí)只用一個(gè)CategoryVO里面也可以處理,在后面第二種方式用java代碼處理多級(jí)目錄時(shí),你會(huì)看到我只用了一個(gè)CategoryVO就能處理。
注意,二級(jí)分類的實(shí)體類CategoryVO有個(gè)
private List<SubCategoryVO> subCatList;
這個(gè)subCatList是為了存放三級(jí)分類的vo list,在xml中三級(jí)分類用了collection對(duì)應(yīng)這個(gè)list
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.me.mapper.CategoryMapperCustom" >
<resultMap id="myCategoryVO" type="com.me.pojo.vo.CategoryVO">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="type" property="type"/>
<!--
column一定要在sql語(yǔ)句中找到,property一定要在對(duì)應(yīng)實(shí)體類中找到
因?yàn)閟ql用as寫了別名,所以column才能用fatherId,如果不用別名,還是得寫father_id
-->
<result column="fatherId" property="fatherId"/>
<!--
collection 標(biāo)簽:用于定義關(guān)聯(lián)的list集合類型的封裝規(guī)則
property:對(duì)應(yīng)三級(jí)分類的list屬性名
ofType:集合的類型,三級(jí)分類的vo
-->
<collection property="subCatList" ofType="com.me.pojo.vo.SubCategoryVO">
<id column="subId" property="subId"/>
<result column="subName" property="subName"/>
<result column="subType" property="subType"/>
<result column="subFatherId" property="subFatherId"/>
</collection>
</resultMap>
<select id="getSubCatList" resultMap="myCategoryVO" parameterType="int">
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}
</select>
</mapper>
首先讓前端展示在首頁(yè)的一級(jí)分類,前端調(diào)用一級(jí)分類接口,我們只需要查詢type為1的數(shù)據(jù)返回給前端,鼠標(biāo)移動(dòng)到一級(jí)分類,就調(diào)用獲取子分類的接口,前端傳入對(duì)應(yīng)一級(jí)分類的id給后端,后端將這個(gè)id作為father_id去查詢子分類。最后我們可以調(diào)用getSubCatList來(lái)得到所有目錄。
@Transactional(propagation = Propagation.SUPPORTS)
@Override
public List<CategoryVO> getSubCatList(Integer rootCatId) {
return categoryMapperCustom.getSubCatList(rootCatId);
}
最后數(shù)據(jù)就是這樣,如下
{
"status": 200,
"msg": "OK",
"data": [{
"id": 11,
"name": "蛋糕",
"type": "2", <==================type=2表示二級(jí)目錄
"fatherId": 1,
"subCatList": [{
"subId": 37,
"subName": "蒸蛋糕",
"subType": "3", <================subType=3表示3級(jí)目錄
"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": "點(diǎn)心",
"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代碼遞歸處理二級(jí)三級(jí)目錄
此刻我換一個(gè)數(shù)據(jù)庫(kù)例子,但是還是和上面一個(gè)處理一級(jí)二級(jí)三級(jí)分類的例子一樣
數(shù)據(jù)表如下

表結(jié)構(gòu)如下

和上一個(gè)例子大同小異,type依然表示目錄級(jí)別
此刻需要返回給前端的VO如下,此刻我只寫了一個(gè)CategoryVO,沒有寫子VO,可以對(duì)比前一種方式看看,道理都是一樣的。
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<CategoryVO> childCategory = new ArrayList<>();
//=====篇幅原因,省掉Getter和Setter方法======
......
}
@Override
public List<CategoryVO> listCategoryForCustomer(Integer parentId) {
ArrayList<CategoryVO> categoryVOList = new ArrayList<>();
recursivelyFindCategories(categoryVOList, parentId);
return categoryVOList;
}
// 以該parentId對(duì)應(yīng)的目錄為根節(jié)點(diǎn),查詢下面所有子目錄信息,categoryVOList是要返回給前端展示的聚合模型數(shù)據(jù)
private void recursivelyFindCategories(List<CategoryVO> categoryVOList, Integer parentId) {
// 遞歸獲取所有子類別,并組合成為一個(gè)"目錄樹"
List<Category> 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);
// 這里當(dāng)前目錄id作為下一次的父id,查詢有沒有對(duì)應(yīng)的子目錄,getChildCategory()方法是返回定義的List<CategoryVO> childCategory
recursivelyFindCategories(categoryVO.getChildCategory(), categoryVO.getId());
}
}
}
XML文件如下:
......
<resultMap id="BaseResultMap" type="com.me.mall.model.pojo.Category">
<id column="id" jdbcType="INTEGER" property="id" />
<result column="name" jdbcType="VARCHAR" property="name" />
<result column="type" jdbcType="INTEGER" property="type" />
<result column="parent_id" jdbcType="INTEGER" property="parentId" />
<result column="order_num" jdbcType="INTEGER" property="orderNum" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
</resultMap>
<sql id="Base_Column_List">
id, `name`, `type`, parent_id, order_num, create_time, update_time
</sql>
<select id="selectCategoriesByParentId" parameterType="int" resultMap="BaseResultMap">
select <include refid="Base_Column_List"/>
from category
where parent_id = #{parentId}
</select>
......
我們手動(dòng)查詢模擬一下遞歸的過程,首先查詢parent_id為3的二級(jí)分類
select * from category where parent_id = 3

結(jié)果遞歸查詢的時(shí)候,又會(huì)發(fā)現(xiàn)parent_id=4時(shí)還有數(shù)據(jù),即還有三級(jí)分類,我們手動(dòng)查詢?cè)囋?/p>
select * from category where parent_id = 4

示例數(shù)據(jù)如下:
{
"status": 10000,
"msg": "SUCCESS",
"data": [
{
"id": 4,
"name": "橘子橙子",
"type": 2, <=================代表二級(jí)目錄
"parentId": 3,
"orderNum": 1,
"createTime": "2019-12-17T17:17:00.000+0000",
"updateTime": "2019-12-28T08:25:10.000+0000",
"childCategory": [ <===============代表還有三級(jí)目錄
{
"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": "車?yán)遄?,
"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": []
}
]
}
到此這篇關(guān)于當(dāng)Mybatis遇上目錄樹有哪些解決方法的文章就介紹到這了,更多相關(guān)Mybatis目錄樹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring實(shí)戰(zhàn)之方法級(jí)別緩存用法示例
這篇文章主要介紹了Spring實(shí)戰(zhàn)之方法級(jí)別緩存用法,結(jié)合實(shí)例形式分析了spring方法級(jí)別緩存配置、屬性文件、領(lǐng)域模型及相關(guān)使用技巧,需要的朋友可以參考下2020-01-01
Java對(duì)List進(jìn)行排序的兩種實(shí)現(xiàn)方法
這篇文章主要給大家介紹了關(guān)于Java對(duì)List進(jìn)行排序的兩種實(shí)現(xiàn)方法,第一種是實(shí)體類自己實(shí)現(xiàn)比較,第二種是借助比較器進(jìn)行排序,下面開一起看看詳細(xì)的介紹吧,有需要的朋友們可以參考借鑒。2016-12-12
log4j2動(dòng)態(tài)修改日志級(jí)別及拓展性使用詳解
這篇文章主要介紹了log4j2動(dòng)態(tài)修改日志級(jí)別及拓展性使用詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2018-11-11
org.springframework.web.client.ResourceAccessException資源訪問錯(cuò)誤
本文主要介紹了org.springframework.web.client.ResourceAccessException資源訪問錯(cuò)誤的解決方法,首先需要分析異常的詳細(xì)信息,以確定具體的錯(cuò)誤原因,感興趣的可以了解一下2024-05-05

