package com.ytkj.rose.util; import org.springframework.util.StringUtils; import javax.validation.constraints.NotNull; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Set; public class TreeUtils { /** * 集合转树结构 * * @param collection 目标集合 * @param clazz 集合元素类型 * @return 转换后的树形结构 */ public static <T> Collection<T> toTree(@NotNull Collection<T> collection, @NotNull Class<T> clazz) { return toTree(collection, null, null, null, clazz); } /** * 集合转树结构 * * @param collection 目标集合 * @param id 节点编号字段名称 * @param parent 父节点编号字段名称 * @param children 子节点集合属性名称 * @param clazz 集合元素类型 * @return 转换后的树形结构 */ public static <T> Collection<T> toTree(@NotNull Collection<T> collection, String id, String parent, String children, @NotNull Class<T> clazz) { try { if (collection == null || collection.isEmpty()) return null;// 如果目标集合为空,直接返回一个空树 if (StringUtils.isEmpty(id)) id = "id"; // 如果被依赖字段名称为空则默认为id if (StringUtils.isEmpty(parent)) parent = "parent"; // 如果依赖字段为空则默认为parent if (StringUtils.isEmpty(children)) children = "children"; // 如果子节点集合属性名称为空则默认为children // 初始化根节点集合, 支持 Set 和 List Collection<T> roots; if (collection.getClass().isAssignableFrom(Set.class)) { roots = new HashSet<>(); } else { roots = new ArrayList<>(); } // 获取 id 字段, 从当前对象或其父类 Field idField; try { idField = clazz.getDeclaredField(id); } catch (NoSuchFieldException e1) { idField = clazz.getSuperclass().getDeclaredField(id); } // 获取 parentId 字段, 从当前对象或其父类 Field parentField; try { parentField = clazz.getDeclaredField(parent); } catch (NoSuchFieldException e1) { parentField = clazz.getSuperclass().getDeclaredField(parent); } // 获取 children 字段, 从当前对象或其父类 Field childrenField; try { childrenField = clazz.getDeclaredField(children); } catch (NoSuchFieldException e1) { childrenField = clazz.getSuperclass().getDeclaredField(children); } // 设置为可访问 idField.setAccessible(true); parentField.setAccessible(true); childrenField.setAccessible(true); // 找出所有的根节点 for (T c : collection) { Object parentId = parentField.get(c); if (isRootNode(parentId)) { roots.add(c); } } // 从目标集合移除所有根节点 collection.removeAll(roots); // 遍历根节点, 依次添加子节点 for (T root : roots) { addChild(root, collection, idField, parentField, childrenField); } // 关闭可访问 idField.setAccessible(false); parentField.setAccessible(false); childrenField.setAccessible(false); return roots; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } /** * 为目标节点添加孩子节点 * * @param node 目标节点 * @param collection 目标集合 * @param idField ID 字段 * @param parentField 父节点字段 * @param childrenField 字节点字段 */ private static <T> void addChild(@NotNull T node, @NotNull Collection<T> collection, @NotNull Field idField, @NotNull Field parentField, @NotNull Field childrenField) throws IllegalAccessException { Object id = idField.get(node); Collection<T> children = (Collection<T>) childrenField.get(node); // 如果子节点的集合为 null, 初始化孩子集合 if (children == null) { if (collection.getClass().isAssignableFrom(Set.class)) { children = new HashSet<>(); } else children = new ArrayList<>(); } for (T t : collection) { Object o = parentField.get(t); if (id.equals(o)) { // 将当前节点添加到目标节点的孩子节点 children.add(t); // 重设目标节点的孩子节点集合,这里必须重设,因为如果目标节点的孩子节点是null的话,这样是没有地址的,就会造成数据丢失,所以必须重设,如果目标节点所在类的孩子节点初始化为一个空集合,而不是null,则可以不需要这一步,因为java一切皆指针 childrenField.set(node, children); // 递归添加孩子节点 addChild(t, collection, idField, parentField, childrenField); } } } /** * 判断是否是根节点, 判断方式为: 父节点编号为空或为 0, 则认为是根节点. 此处的判断应根据自己的业务数据而定. * @param parentId 父节点编号 * @return 是否是根节点 */ private static boolean isRootNode(Object parentId) { boolean flag = false; if (parentId == null) { flag = true; } else if (parentId instanceof String && (StringUtils.isEmpty(parentId) || parentId.equals("0"))) { flag = true; } else if (parentId instanceof Integer && Integer.valueOf(0).equals(parentId)) { flag = true; } return flag; } }
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
bean:
package com.ytkj.rose.bean;
import java.util.ArrayList;
import java.util.List;
public class TMenu {
    private Integer id;
    private Integer pid;
    private String name;
    private String icon;
    private String url;
    private List<TMenu> children=new ArrayList<>();
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Integer getPid() {
        return pid;
    }
    public void setPid(Integer pid) {
        this.pid = pid;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getIcon() {
        return icon;
    }
    public void setIcon(String icon) {
        this.icon = icon;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public List<TMenu> getChildren() {
        return children;
    }
    public void setChildren(List<TMenu> children) {
        this.children = children;
    }
    @Override
    public String toString() {
        return "TMenu{" +
                "id=" + id +
                ", pid=" + pid +
                ", name=‘" + name + ‘\‘‘ +
                ", icon=‘" + icon + ‘\‘‘ +
                ", url=‘" + url + ‘\‘‘ +
                ", children=" + children +
                ‘}‘;
    }
}
controller:
@RequestMapping("/main")
    public String main(HttpSession session) {
        logger.debug("跳转到主面");
      
        List<TMenu> menuList=tMenuService.getMenuAll();
        session.setAttribute("menuList",menuList);
        
        return "main";
    }
service:
package com.ytkj.rose.service;
import com.ytkj.rose.bean.TMenu;
import java.util.List;
public interface TMenuService {
    List<TMenu> getMenuAll();
}
serviceImpl
package com.ytkj.rose.service.impl;
import com.ytkj.rose.bean.TMenu;
import com.ytkj.rose.mapper.TMenuMapper;
import com.ytkj.rose.service.TMenuService;
import com.ytkj.rose.util.TreeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class TMenuServiceImpl implements TMenuService {
    Logger logger= LoggerFactory.getLogger(TAdminServiceImpl.class);
    @Autowired
    TMenuMapper tMenuMapper;
    @Override
    public List<TMenu> getMenuAll() {
        List<TMenu> list = tMenuMapper.selectAll();
        Collection<TMenu> tMenus = TreeUtils.toTree(list, "id", "pid", "children", TMenu.class);
        logger.debug("菜单={}",tMenus);
        return (List<TMenu>) tMenus;
    }
}
mapper:
package com.ytkj.rose.mapper;
import com.ytkj.rose.bean.TMenu;
import java.util.List;
public interface TMenuMapper {
    List<TMenu> selectAll();
}
mapper.xml
<?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.ytkj.rose.mapper.TMenuMapper"> <select id="selectAll" resultType="com.ytkj.rose.bean.TMenu" > select * from t_menu </select> </mapper>
jsp页面:
<%--
  Created by IntelliJ IDEA.
  User: 3600X
  Date: 2020/2/29
  Time: 14:53
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div class="col-sm-3 col-md-2 sidebar" style="top: 52px">
    <div class="tree">
        <ul style="padding-left:0px;" class="list-group">
            <c:forEach items="${menuList}" var="parent">
                <c:if test="${empty parent.children}">
                    <li class="list-group-item tree-closed">
                        <a href="${PATH}/${parent.url}"><i class="glyphicon glyphicon-dashboard"></i>${parent.name}</a>
                    </li>
                </c:if>
                <c:if test="${not empty parent.children}">
                    <li class="list-group-item tree-closed">
                        <span><i class="${parent.icon}"></i> ${parent.name}<span class="badge" style="float:right">${parent.children.size()}</span></span>
                        <ul style="margin-top:10px;display:none;">
                            <c:forEach items="${parent.children}" var="child">
                                <li style="height:30px;">
                                    <a href="${PATH}/${child.url}"><i class="glyphicon glyphicon-user"></i> ${child.name}</a>
                                </li>
                            </c:forEach>
                        </ul>
                    </li>
                </c:if>
            </c:forEach>
        </ul>
    </div>
</div>
页面效果:

原文:https://www.cnblogs.com/yscec/p/12386835.html