數據庫樹形結構,正反遍歷html
--從Root往樹末梢遞歸java
select level ,identity,pid from table_namenode
start with identity=475數據庫
connect by prior identity = pidjson
--從末梢往樹ROOT遞歸api
select level ,identity,pid,yylevel from table_namemybatis
start with identity=542app
connect by prior pid = identityide
做用: 函數
connect by主要用於父子,祖孫,上下級等層級關係的查詢
語句:
{ CONNECT BY [ NOCYCLE ] condition [AND condition]... [ START WITH condition ]
| START WITH condition CONNECT BY [ NOCYCLE ] condition [AND condition]...}
解釋:
start with: 指定起始節點的條件
connect by: 指定父子行的條件關係
prior: 查詢父行的限定符,格式: prior column1 = column2 or column1 = prior column2 and ... ,
nocycle: 若數據表中存在循環行,那麼不添加此關鍵字會報錯,添加關鍵字後,便不會報錯,但循環的兩行只會顯示其中的第一條
循環行: 該行只有一個子行,並且子行又是該行的祖先行
connect_by_iscycle: 前置條件:在使用了nocycle以後才能使用此關鍵字,用於表示是不是循環行,0表示否,1 表示是
connect_by_isleaf: 是不是葉子節點,0表示否,1 表示是
level: level僞列,表示層級,值越小層級越高,level=1爲層級最高節點
MySQL沒有提供相似函數,只能經過在程序或存儲過程當中利用遞歸的方式進行實現
定義菜單類
public class Menu {
// 菜單id
private String id;
// 菜單名稱
private String name;
// 父菜單id
private String parentId;
// 菜單url
private String url;
// 菜單圖標
private String icon;
// 菜單順序
private int order;
// 子菜單
private List<Menu> childMenus;
// ... 省去getter和setter方法以及toString方法
}
根據這個類定義數據庫,並插入菜單數據
DROP TABLE IF EXISTS `jrbac_menu`;
CREATE TABLE `jrbac_menu` (
`id` varchar(32) NOT NULL COMMENT '主鍵id,uuid32位',
`name` varchar(64) NOT NULL COMMENT '菜單名稱',
`parent_id` varchar(32) DEFAULT NULL COMMENT '父菜單id',
`url` varchar(64) DEFAULT NULL COMMENT '訪問地址',
`icon` varchar(32) DEFAULT NULL COMMENT '菜單圖標',
`order` tinyint(4) DEFAULT '0' COMMENT '菜單順序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='菜單表';
-- ----------------------------
-- Records of jrbac_menu
-- ----------------------------
INSERT INTO `jrbac_menu` VALUES ('1', 'Forms', null, 'forms.html', 'fa fa-edit', '0');
INSERT INTO `jrbac_menu` VALUES ('2', 'UI Elements', null, '', 'fa fa-wrench', '1');
INSERT INTO `jrbac_menu` VALUES ('3', 'Buttons', '2', 'buttons.html', '', '0');
INSERT INTO `jrbac_menu` VALUES ('4', 'Icons', '2', 'icons.html', null, '1');
INSERT INTO `jrbac_menu` VALUES ('5', 'Multi-Level Dropdown', '', '', 'fa fa-sitemap', '2');
INSERT INTO `jrbac_menu` VALUES ('6', 'Second Level Item', '5', 'second.html', null, '0');
INSERT INTO `jrbac_menu` VALUES ('7', 'Third Level', '5', null, '', '1');
INSERT INTO `jrbac_menu` VALUES ('8', 'Third Level Item', '7', 'third.html', null, '0');
爲了演示,咱們把可展開的沒有作完,僅僅插入幾條數據能出效果就能夠了。
測試方法與遞歸方法
private final Gson gson = new GsonBuilder().disableHtmlEscaping().create();
@Test
public void testQueryMenuList() {
// 原始的數據
List<Menu> rootMenu = menuDao.queryMenuList(null);
// 查看結果
for (Menu menu : rootMenu) {
System.out.println(menu);
}
// 最後的結果
List<Menu> menuList = new ArrayList<Menu>();
// 先找到全部的一級菜單
for (int i = 0; i < rootMenu.size(); i++) {
// 一級菜單沒有parentId
if (StringUtils.isBlank(rootMenu.get(i).getParentId())) {
menuList.add(rootMenu.get(i));
}
}
// 爲一級菜單設置子菜單,getChild是遞歸調用的
for (Menu menu : menuList) {
menu.setChildMenus(getChild(menu.getId(), rootMenu));
}
Map<String,Object> jsonMap = new HashMap<>();
jsonMap.put("menu", menuList);
System.out.println(gson.toJson(jsonMap));
}
/**
* 遞歸查找子菜單
*
* @param id
* 當前菜單id
* @param rootMenu
* 要查找的列表
* @return
*/
private List<Menu> getChild(String id, List<Menu> rootMenu) {
// 子菜單
List<Menu> childList = new ArrayList<>();
for (Menu menu : rootMenu) {
// 遍歷全部節點,將父菜單id與傳過來的id比較
if (StringUtils.isNotBlank(menu.getParentId())) {
if (menu.getParentId().equals(id)) {
childList.add(menu);
}
}
}
// 把子菜單的子菜單再循環一遍
for (Menu menu : childList) {// 沒有url子菜單還有子菜單
if (StringUtils.isBlank(menu.getUrl())) {
// 遞歸
menu.setChildMenus(getChild(menu.getId(), rootMenu));
}
} // 遞歸退出條件
if (childList.size() == 0) {
return null;
}
return childList;
}
menuDao.queryMenuList(null);查找的結果是一條一條的數據
meuDao
package com.jrbac.dao;
import java.util.List;
import com.jrbac.entity.LoginUser;
import com.jrbac.entity.Menu;
public interface MenuDao {
/**
* 查找用戶的菜單
* @param loginUser
* @return
*/
public List<Menu> queryMenuList(LoginUser loginUser);
}
mybatis
<?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.jrbac.dao.MenuDao">
<select id="queryMenuList" resultType="Menu">
SELECT
id,`name`,parent_id,url,icon,`order`
FROM
jrbac_menu ORDER BY `order` ASC
</select>
</mapper>
建立表
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for t_areainfo
-- ----------------------------
DROP TABLE IF EXISTS `t_areainfo`;
CREATE TABLE `t_areainfo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`level` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
`parentId` int(11) DEFAULT NULL,
`status` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of t_areainfo
-- ----------------------------
INSERT INTO `t_areainfo` VALUES ('1', '0', '中國', '0', '0');
INSERT INTO `t_areainfo` VALUES ('2', '0', '華北區', '1', '0');
INSERT INTO `t_areainfo` VALUES ('3', '0', '華南區', '1', '0');
INSERT INTO `t_areainfo` VALUES ('4', '0', '北京', '2', '0');
INSERT INTO `t_areainfo` VALUES ('5', '0', '海淀區', '4', '0');
INSERT INTO `t_areainfo` VALUES ('6', '0', '豐臺區', '4', '0');
INSERT INTO `t_areainfo` VALUES ('7', '0', '朝陽區', '4', '0');
INSERT INTO `t_areainfo` VALUES ('8', '0', '北京XX區1', '4', '0');
INSERT INTO `t_areainfo` VALUES ('9', '0', '北京XX區2', '4', '0');
INSERT INTO `t_areainfo` VALUES ('10', '0', '北京XX區3', '4', '0');
INSERT INTO `t_areainfo` VALUES ('11', '0', '北京XX區4', '4', '0');
INSERT INTO `t_areainfo` VALUES ('12', '0', '北京XX區5', '4', '0');
INSERT INTO `t_areainfo` VALUES ('13', '0', '北京XX區6', '4', '0');
INSERT INTO `t_areainfo` VALUES ('14', '0', '北京XX區7', '4', '0');
INSERT INTO `t_areainfo` VALUES ('15', '0', '北京XX區8', '4', '0');
INSERT INTO `t_areainfo` VALUES ('16', '0', '北京XX區9', '4', '0');
INSERT INTO `t_areainfo` VALUES ('17', '0', '北京XX區10', '4', '0');
INSERT INTO `t_areainfo` VALUES ('18', '0', '北京XX區11', '4', '0');
存儲過程建立
FIND_IN_SET函數說明
FIND_IN_SET(str,strlist)
str 要查詢的字符串
strlist 字段名 參數以","分隔 如 (1,2,6,8)
查詢字段(strlist)中包含(str)的結果,返回結果爲null或記錄
select * from treenodes where FIND_IN_SET(id, '1,2,3,4,5');
使用find_in_set函數一次返回多條記錄
id 是一個表的字段,而後每條記錄分別是id等於1,2,3,4,5的時候
有點相似in (集合)
select * from treenodes where id in (1,2,3,4,5);
調用方式
select queryChildrenAreaInfo(2);
select * from t_areainfo where FIND_IN_SET(id, queryChildrenAreaInfo(2));