當(dāng)Mybatis遇上目錄樹超全完美解決方案
相信你也遇到過這種場(chǎng)景,判斷二級(jí)目錄屬于哪個(gè)一級(jí)目錄,一個(gè)員工屬于哪個(gè)上級(jí)員工領(lǐng)導(dǎo)…
當(dāng)Mybatis
遇上目錄樹,有哪些解決方法?
一般來(lái)說,有
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)文章
java中計(jì)算字符串長(zhǎng)度的方法及u4E00與u9FBB的認(rèn)識(shí)
字符串采用unicode編碼的方式時(shí),計(jì)算字符串長(zhǎng)度的方法找出UNICODE編碼中的漢字的代表的范圍“\u4E00” 到“\u9FBB”之間感興趣的朋友可以參考本文,或許對(duì)你有所幫助2013-01-01使用Maven Archetype插件構(gòu)建Maven工程原型模板的實(shí)例
下面小編就為大家分享一篇使用Maven Archetype插件構(gòu)建Maven工程原型模板的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助2017-12-12SpringBoot配置連接兩個(gè)或多個(gè)數(shù)據(jù)庫(kù)的常用方法
在Spring Boot應(yīng)用中連接多個(gè)數(shù)據(jù)庫(kù)或數(shù)據(jù)源可以使用多種方式,本文講給大家介紹兩種常用的方法:使用Spring Boot官方支持的多數(shù)據(jù)源配置和使用第三方庫(kù)實(shí)現(xiàn)多數(shù)據(jù)源,文章通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08Spring Cloud Feign內(nèi)部實(shí)現(xiàn)代碼細(xì)節(jié)
Feign 的英文表意為“假裝,偽裝,變形”, 是一個(gè)http請(qǐng)求調(diào)用的輕量級(jí)框架,可以以Java接口注解的方式調(diào)用Http請(qǐng)求,而不用像Java中通過封裝HTTP請(qǐng)求報(bào)文的方式直接調(diào)用。接下來(lái)通過本文給大家分享Spring Cloud Feign內(nèi)部實(shí)現(xiàn)代碼細(xì)節(jié),感興趣的朋友一起看看吧2021-05-05利用Java實(shí)現(xiàn)調(diào)用http請(qǐng)求
在實(shí)際開發(fā)過程中,我們經(jīng)常需要調(diào)用對(duì)方提供的接口或測(cè)試自己寫的接口是否合適。本文就為大家準(zhǔn)備了幾個(gè)java調(diào)用http請(qǐng)求的幾種常見方式,需要的可以參考一下2022-08-08Java圖片處理 (文字水印、圖片水印、縮放、補(bǔ)白)代碼實(shí)例
這篇文章主要介紹了Java圖片處理 (文字水印、圖片水印、縮放、補(bǔ)白)代碼實(shí)例,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-06-06Java AOP動(dòng)態(tài)代理詳細(xì)介紹
AOP是一種設(shè)計(jì)思想,是軟件設(shè)計(jì)領(lǐng)域中的面向切面編程,它是面向?qū)ο缶幊痰囊环N補(bǔ)充和完善。本文將用Java實(shí)現(xiàn)AOP代理的三種方式,需要的可以參考一下2022-08-08