首页/文章列表/文章详情

树形结构工具类

编程知识2032024-09-25评论

  前言

  日常开发中,树形结构的数据是比较常见的一种数据结构,比如系统菜单、组织机构、数据字典等,有时候需要后端把数据转成树形结构再返回给前端,对此特意封装通用树形结构工具类

  封装了以下方法:

  根据父id,递归获取所有子节点,转为树结构

 

  根据子id,递归获取所有父节点,转为树结构

 

  拼接 union sql脚本,根据查询查询条件、id字段名、pid字段名,拼接出sql

   

  依赖hutool

        <!-- hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.18</version>
        </dependency>

 

  完整代码

packagecn.huanzi.qch.util;importcn.hutool.core.bean.BeanUtil;importjava.util.ArrayList;importjava.util.Comparator;importjava.util.List;/** * 树形结构工具类 */publicclassTreeUtil{/** * 根据父id,递归获取所有子节点,转为树结构 * * @param idFieldName id字段名称 * @param pIdFieldName pid字段名称 * @param childrenFieldName children字段名称 * @param pxFieldName px字段名称 * @param pId 父节点id * @param allList 所有菜单列表 * @return每个根节点下,所有子菜单列表*/publicstatic <M> List<M> toTreeByParentId(String idFieldName, String pIdFieldName, String childrenFieldName, String pxFieldName,String pId, List<M>allList){//子节点 List<M> childList = newArrayList<>(allList.size());for(int i = 0; i < allList.size(); i++) { M model =allList.get(i);//遍历所有节点将节点的父id与传过来的根节点的id比较//父节点id字段,例如:pidif (BeanUtil.getFieldValue(model,pIdFieldName).equals(pId)){ childList.add(model); //删除,减少下次循环次数 allList.remove(i); i--; } } //递归for (M model : childList) { //主键字段,例如:id,子节点字段,例如:children BeanUtil.setFieldValue(model,childrenFieldName,TreeUtil.toTreeByParentId(idFieldName,pIdFieldName,childrenFieldName,pxFieldName,String.valueOf(BeanUtil.getFieldValue(model,idFieldName)), allList)); } //排序字段,例如:px,如果不需要排序可以注释if(null != pxFieldName && !pxFieldName.isEmpty()){ childList.sort(Comparator.comparingInt(m -> Integer.parseInt(String.valueOf(BeanUtil.getFieldValue(m, pxFieldName))))); //排序}//底层节点的子节点赋空值,节省内存空间if(childList.size() <= 0){ childList =null; } return childList; } publicstatic <M> List<M> toTreeByParentId(String pId, List<M>allList){//设置一下默认值returnTreeUtil.toTreeByParentId("id","pid","children","px",pId,allList); } /** * 根据子id,递归获取所有父节点,转为树结构 * * @param idFieldName id字段名称 * @param pIdFieldName pid字段名称 * @param childrenFieldName children字段名称 * @param cId 子节点id * @param allList 所有菜单列表 * @return每个根节点下,所有子菜单列表*/publicstatic <M> M toTreeByChildrenId(String idFieldName, String pIdFieldName, String childrenFieldName,String cId, List<M>allList){returnTreeUtil.toTreeByChildrenId(idFieldName,pIdFieldName,childrenFieldName,null,cId,allList); } privatestatic <M> M toTreeByChildrenId(String idFieldName, String pIdFieldName, String childrenFieldName,M parent,String cId, List<M>allList){//父节点 M newParent = null;for(int i = 0; i < allList.size(); i++) { M model =allList.get(i);//相等说明:找出当前节点if (BeanUtil.getFieldValue(model,idFieldName).equals(cId)){ newParent =model;//设置子节点if(parent != null){ ArrayList<M> childList = newArrayList<>(1); childList.add(parent); BeanUtil.setFieldValue(newParent,childrenFieldName, childList); } //删除,减少下次循环次数 allList.remove(i); i--;break; } } //父节点为空,则说明为顶层节点 String menuParentId = newParent == null ?"" : String.valueOf(BeanUtil.getFieldValue(newParent,pIdFieldName)); if("".equals(menuParentId)){return parent; } //父节点递归 newParent =TreeUtil.toTreeByChildrenId(idFieldName,pIdFieldName,childrenFieldName,newParent,menuParentId,allList);return newParent; } publicstatic <M> M toTreeByChildrenId(String cId, List<M>allList){//设置一下默认值return TreeUtil.toTreeByChildrenId("id","pid","children",null,cId,allList); } /** * 拼接 union sql脚本,根据查询查询条件、id字段名、pid字段名,拼接出sql * @param select 查询字段,例如: select id * @param tableName 表名,例如 sys_dept * @param initWhere 查询条件,例如:pid = '-1' * @param idField id字段名 * @param pidField pid字段名 * @param maxLevel 拼接最大层级 * @returnunion拼接好的sql脚本*/publicstatic String getParentSql(String select, String tableName, String initWhere, String idField, String pidField, int maxLevel) { return getUnionSql(select,tableName,initWhere,idField,pidField,maxLevel); } publicstatic String getChildSql(String select, String tableName, String initWhere, String idField, String pidField, int maxLevel) { return getUnionSql(select,tableName,initWhere,pidField,idField,maxLevel); } privatestatic String getUnionSql(String select, String tableName, String initWhere, String whereIn, String selectIn, int maxLevel) { StringBuilder stringBuilder =new StringBuilder(select); stringBuilder.append(" from").append(tableName).append(" where 1=1");if(null != initWhere && !initWhere.isEmpty()) { stringBuilder.append(" and").append(initWhere); } String tmp = String.format("from %s where %s", tableName, initWhere); for(int i = 0; i < maxLevel; ++i) { tmp = String.format(" from %s where %s in ( select %s %s)", tableName, whereIn, selectIn, tmp); stringBuilder.append(" union").append(select).append(tmp); } return stringBuilder.toString(); }}
TreeUtil

 

  完整main测试

/** * 测试 */publicstaticvoid main(String[] args) { ArrayList<Menu> list = newArrayList<>(); list.add(newMenu("1","-1","系统管理",1)); list.add(newMenu("11","1","菜单维护",1)); list.add(newMenu("12","1","角色维护",2)); list.add(newMenu("13","1","系统安全",3)); list.add(newMenu("131","13","日志管理",1)); list.add(newMenu("12","-1","用户管理",2));//备份list List<Menu> list1 = BeanUtil.copyToList(list, Menu.class); List<Menu> menus = TreeUtil.toTreeByParentId("-1", list); System.out.println(menus); Menu menu = TreeUtil.toTreeByChildrenId("131", list1); System.out.println(menu); String sql = TreeUtil.getChildSql("select id","lp_sys_menu","pid = '-1'","id","pid", 3); System.out.println(sql); } /** * 测试菜单类 */publicstaticclass Menu { private String id; //节点idprivate String pid; //父节点idprivate List<Menu> children; //子节点privateintpx;//排序字段private String menuName; //菜单名称public Menu() { } public Menu(String id, String pid, String name, int px) { this.id =id;this.pid =pid;this.menuName =name;this.px = px; } public String getId() { return id; } publicvoid setId(String id) { this.id = id; } public String getPid() { return pid; } publicvoid setPid(String pid) { this.pid = pid; } publicList<Menu> getChildren() { return children; } publicvoidsetChildren(List<Menu> children) { this.children = children; } publicint getPx() { return px; } publicvoidsetPx(int px) { this.px = px; } public String getMenuName() { return menuName; } publicvoid setMenuName(String menuName) { this.menuName = menuName; } @Override public String toString() { return"Menu{" +"id='" + id + '\'' +", pid='" + pid + '\'' +", children=" + children +", px=" + px +", menuName='" + menuName + '\'' + '}'; } }
View Code

 

  效果展示

[Menu{id='1', pid='-1', children=[Menu{id='11', pid='1', children=null, px=1, menuName='菜单维护'}, Menu{id='12', pid='1', children=null, px=2, menuName='角色维护'}, Menu{id='13', pid='1', children=[Menu{id='131', pid='13', children=null, px=1, menuName='日志管理'}], px=3, menuName='系统安全'}], px=1, menuName='系统管理'}, Menu{id='12', pid='-1', children=null, px=2, menuName='用户管理'}]Menu{id='1', pid='-1', children=[Menu{id='13', pid='1', children=[Menu{id='131', pid='13', children=null, px=1, menuName='日志管理'}], px=3, menuName='系统安全'}], px=1, menuName='系统管理'}select id from lp_sys_menu where 1=1 and pid = '-1' union select id from lp_sys_menu where pid in ( select id from lp_sys_menu where pid = '-1') union select id from lp_sys_menu where pid in ( select id from lp_sys_menu where pid in ( select id from lp_sys_menu where pid = '-1')) union select id from lp_sys_menu where pid in ( select id from lp_sys_menu where pid in ( select id from lp_sys_menu where pid in ( select id from lp_sys_menu where pid = '-1')))

 

  原数据

   根据父id,递归获取所有子节点,转为树结构

   根据子id,递归获取所有父节点,转为树结构

   拼接 union sql脚本,根据查询查询条件、id字段名、pid字段名,拼接出sql

SELECTidFROMlp_sys_menuWHERE1=1ANDpid='-1'UNIONSELECTidFROMlp_sys_menuWHEREpidIN(SELECTidFROMlp_sys_menuWHEREpid='-1')UNIONSELECTidFROMlp_sys_menuWHEREpidIN(SELECTidFROMlp_sys_menuWHEREpidIN(SELECTidFROMlp_sys_menuWHEREpid='-1' ) )UNIONSELECTidFROMlp_sys_menuWHEREpidIN(SELECTidFROMlp_sys_menuWHEREpidIN(SELECTidFROMlp_sys_menuWHEREpidIN(SELECTidFROMlp_sys_menuWHEREpid='-1' ) ) )

 

 

  后记

  树形结构工具类暂时先记录到这,后续再进行补充

 

博客园

这个人很懒...

用户评论 (0)

发表评论

captcha