使用Mybatis生成樹(shù)形菜單的方法詳解
開(kāi)發(fā)中我們難免會(huì)遇到各種樹(shù)形結(jié)構(gòu)展示的場(chǎng)景。比如用戶登錄系統(tǒng)后菜單的展示,某些大型購(gòu)物網(wǎng)站商品的分類(lèi)展示等等,反正開(kāi)發(fā)中會(huì)遇到各種樹(shù)形展示的功能,這些功能大概處理的思路都是一樣的,所以本文就總結(jié)一下樹(shù)形結(jié)構(gòu)的代碼生成,在開(kāi)發(fā)的時(shí)候套用這種結(jié)構(gòu)就可以了。
好了正文開(kāi)始,首先相關(guān)的SQL腳本【MYSQL】提供給你(包吃包住包SQL)
DDL語(yǔ)句:
CREATE TABLE `student`.`SYS_menu`( `ID` INT(10) NOT NULL AUTO_INCREMENT, `name` VARCHAR(200) NOT NULL, `permissions` VARCHAR(1000), `url` VARCHAR(200), `description` VARCHAR(2000), `icon_cls` VARCHAR(2000), `pid` INT(10), `status` INT(2), `resource_type` INT(2), `sort` INT(6), `create_time` TIMESTAMP, `update_time` TIMESTAMP, PRIMARY KEY (`ID`) ) ENGINE=INNODB CHARSET=utf8;
初始化語(yǔ)句:
INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('主菜單',NULL,NULL,'數(shù)據(jù)主菜單',NULL,0,1,1,NOW(),NOW(),NULL) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單1',NULL,NULL,'菜單1',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='主菜單') a ),1,1,NOW(),NOW(),1) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單2',NULL,NULL,'菜單2',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='主菜單') a ),1,1,NOW(),NOW(),2) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單3',NULL,NULL,'菜單3',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='主菜單') a ),1,1,NOW(),NOW(),3) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單1.1',NULL,NULL,'菜單1的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單1') a ),1,1,NOW(),NOW(),1) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單1.2',NULL,NULL,'菜單1的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單1') a ),1,1,NOW(),NOW(),2) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單1.3',NULL,NULL,'菜單1的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單1') a ),1,1,NOW(),NOW(),3) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單2.1',NULL,NULL,'菜單2的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單2') a ),1,1,NOW(),NOW(),1) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單2.2',NULL,NULL,'菜單2的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單2') a ),1,1,NOW(),NOW(),2) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單2.3',NULL,NULL,'菜單2的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單2') a ),1,1,NOW(),NOW(),3) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單3.1',NULL,NULL,'菜單3的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單3') a ),1,1,NOW(),NOW(),1) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單3.2',NULL,NULL,'菜單3的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單3') a ),1,1,NOW(),NOW(),2) ; INSERT INTO SYS_MENU(NAME,permissions,url,description,icon_cls,pid,STATUS,resource_type,create_time,update_time,SORT) VALUES('菜單3.3',NULL,NULL,'菜單3的子菜單',NULL,(SELECT * FROM (SELECT id FROM SYS_MENU WHERE NAME='菜單3') a ),1,1,NOW(),NOW(),3)
數(shù)據(jù)結(jié)構(gòu)一般就是上面得那樣,只是初始化得數(shù)據(jù)按照你開(kāi)發(fā)得需求初始化。
然后就是創(chuàng)建簡(jiǎn)單得項(xiàng)目,好了那我就貼出相關(guān)得代碼,這些大家開(kāi)發(fā)得時(shí)候可以根據(jù)需求進(jìn)行嵌套使用。
// entity @Data @TableName("sys_menu") public class SysMenu implements Serializable { private static final long serialVersionUID = 1L; @TableId private Integer id; private String name; private String permissions; private String url; private String description; private String iconCls; private Integer pid; private Integer status; private Integer resourceType; private Integer sort; private Date createTime; private Date updateTime; /** * 此處為了簡(jiǎn)單我就不新建DTO對(duì)象了, * 加一個(gè)children屬性,注意如果不是數(shù)據(jù)庫(kù)的字段一定要 * 加下面d額那個(gè)注解 */ @TableField(exist=false) private List<SysMenu> children; }
// mapper接口,很簡(jiǎn)單沒(méi)有多余代碼 public interface SysMenuDao extends BaseMapper<SysMenu> { }
mapper 文件也是沒(méi)有多余的代碼,使用Mybatis-Plus特有的就行
其中下面的resultMap也可以去掉。
<mapper namespace="io.renren.mapper.SysMenuDao"> <!-- 可根據(jù)自己的需求,是否要使用 --> <resultMap type="io.renren.domain.SysMenu" id="sysMenuMap"> <result property="id" column="ID"/> <result property="name" column="name"/> <result property="permissions" column="permissions"/> <result property="url" column="url"/> <result property="description" column="description"/> <result property="iconCls" column="icon_cls"/> <result property="pid" column="pid"/> <result property="status" column="status"/> <result property="resourceType" column="resource_type"/> <result property="sort" column="sort"/> <result property="createTime" column="create_time"/> <result property="updateTime" column="update_time"/> </resultMap> </mapper>
// service 主要的邏輯代碼就在這里。 public interface SysMenuService extends IService<SysMenu> { List<SysMenu> getMenuTree(); } @Service("sysMenuService") public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenu> implements SysMenuService { @Autowired private SysMenuDao sysMenuDao ; @Override public List<SysMenu> getMenuTree() { //查詢出所有菜單 List<SysMenu> sysMenus = sysMenuDao.selectList(null); //2、組裝成樹(shù)形結(jié)構(gòu) //2.1)、找到所有的一級(jí)菜單 List<SysMenu> level1Menus = sysMenus.stream().filter(sysMenu -> sysMenu.getPid() == 0 ).map((menu) -> { menu.setChildren(getChildrens(menu, sysMenus)); return menu; // 排序 }).sorted((menu1, menu2) -> { return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort()); }).collect(Collectors.toList()); return level1Menus; } //遞歸查找所有菜單的子菜單,主要就是用了這個(gè)遞歸查詢。 // 我也都寫(xiě)了相關(guān)的注釋。 private List<SysMenu> getChildrens(SysMenu root, List<SysMenu> all) { List<SysMenu> children = all.stream().filter(sysMenu -> { return sysMenu.getPid() == root.getId(); }).map(sysMenu -> { //1、找到子菜單 sysMenu.setChildren(getChildrens(sysMenu, all)); return sysMenu; }).sorted((menu1, menu2) -> { //2、菜單的排序 return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort()); }).collect(Collectors.toList()); return children; }
有的小伙伴可能會(huì)說(shuō),博主我們項(xiàng)目使用的jdk7 。上面的代碼使用不了啊,這篇文章對(duì)我來(lái)說(shuō)不合適啊。好了安排上,既然寫(xiě)文章我就要寫(xiě)的明明白白,下面是不使用Stream流完成的功能。
List<SysMenu> getMenuTreeVerLowJava8() ; @Override public List<SysMenu> getMenuTreeVerLowJava8() { List<SysMenu> sysMenus = sysMenuDao.selectList(null); List<SysMenu> tree = new ArrayList<>(); for (SysMenu sysmenu: sysMenus) { if (sysmenu.getPid()==0){ tree.add(getChildrens02(sysmenu,sysMenus)) ; } } return tree; } /** * 不使用stream的遞歸調(diào)用 * @param list * @return */ private SysMenu getChildrens02(SysMenu sysMenu, List<SysMenu> list) { List<SysMenu> children = new ArrayList<SysMenu>(); for (SysMenu sysMenu2 : list) { if (sysMenu2.getPid() == sysMenu.getId()) { // 遞歸調(diào)用 SysMenu result = getChildrens02(sysMenu2, list); children.add(result); } } sysMenu.setChildren(children); return sysMenu; }
使用Java7的菜單樹(shù)我沒(méi)有進(jìn)行排序,Java7的排序使用起來(lái)也很簡(jiǎn)單,相信大家開(kāi)發(fā)的時(shí)候都使用過(guò),大家可以自行完成排序。生成的樹(shù)形結(jié)構(gòu)太多我就不貼出來(lái)了肯定是正確的。
開(kāi)發(fā)中就是需要這種記錄,為什么呢,當(dāng)你沒(méi)看到這篇文章你寫(xiě)一個(gè)樹(shù)形結(jié)構(gòu)的代碼可能需要一天,而你點(diǎn)一下關(guān)注,后面開(kāi)發(fā)中你遇到這種功能的開(kāi)發(fā)一個(gè)小時(shí)應(yīng)該就能搞定并且還沒(méi)有問(wèn)題,極大的提高了開(kāi)發(fā)效率,領(lǐng)導(dǎo)看到你效率那么高應(yīng)該也會(huì)很高興,說(shuō)不定升職加薪就在眼前。點(diǎn)點(diǎn)關(guān)注何樂(lè)而不為呢?生活中也一樣,你同樣需要記錄總結(jié),這樣你應(yīng)該也越走越順,比如你今天上班路上遇到一個(gè)坑,你記住了。下次走過(guò)這里你就會(huì)避開(kāi)這個(gè)坑,路也越走越順了。
到此這篇關(guān)于使用Mybatis生成樹(shù)形菜單的方法詳解的文章就介紹到這了,更多相關(guān)Mybatis樹(shù)形菜單內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaWeb中的filter過(guò)濾敏感詞匯案例詳解
敏感詞、文字過(guò)濾是一個(gè)網(wǎng)站必不可少的功能,本篇文章主要介紹了JavaWeb中的filter過(guò)濾敏感詞匯案例,具有一定的參考價(jià)值,有需要的可以了解一下,2016-11-11Java編程實(shí)現(xiàn)提取文章中關(guān)鍵字的方法
這篇文章主要介紹了Java編程實(shí)現(xiàn)提取文章中關(guān)鍵字的方法,較為詳細(xì)的分析了Java提取文章關(guān)鍵字的原理與具體實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11JDK17、JDK19、JDK1.8輕松切換(無(wú)坑版,小白也可以看懂!)
在做不同的java項(xiàng)目時(shí)候,因項(xiàng)目需要很可能來(lái)回切換jdk版本,下面這篇文章主要介紹了JDK17、JDK19、JDK1.8輕松切換的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-02-02Java對(duì)接ansible自動(dòng)運(yùn)維化平臺(tái)方式
這篇文章主要介紹了Java對(duì)接ansible自動(dòng)運(yùn)維化平臺(tái)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04java中double類(lèi)型運(yùn)算結(jié)果異常的解決方法
下面小編就為大家?guī)?lái)一篇java中double類(lèi)型運(yùn)算結(jié)果異常的解決方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12springboot使用外置tomcat啟動(dòng)方式
這篇文章主要介紹了springboot使用外置tomcat啟動(dòng)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11Java解析zip文件,并識(shí)別壓縮包里面的文件轉(zhuǎn)換成可操作的IO流方式
這篇文章主要介紹了Java解析zip文件,并識(shí)別壓縮包里面的文件轉(zhuǎn)換成可操作的IO流方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容
QSV是一種加密的視頻文件格式。是愛(ài)奇藝公司研發(fā)的一種視頻文件格式,這篇文章主要為大家介紹了如何利用Java實(shí)現(xiàn)提取QSV文件視頻內(nèi)容,感興趣的可以了解一下2023-03-03Spring?Boot中的微信支付全過(guò)程(小程序)
微信支付是企業(yè)級(jí)項(xiàng)目中經(jīng)常使用到的功能,作為后端開(kāi)發(fā)人員,完整地掌握該技術(shù)是十分有必要的。今天通過(guò)本文給大家介紹Spring?Boot中的微信支付全過(guò)程,感興趣的朋友一起看看吧2022-05-05