03【若依框架解讀】Tree樹形結構的控制(選單,部門)

如何在3年拿到50K發表於2020-12-06

背景

若依管理框架中包含了不少選單樹和許可權樹的控制,主要實現的方式是遞迴,比較容易閱讀和理解。構建屬性結構本身是開發中非常常見的場景。掌握後非常容易在工作中使用。

屬性結構控制

  1. 後端返回列表,前端控制
  2. 後端直接返回

處理方法

1. 根據角色獲取部門

介面:/roleDeptTreeselect/{roleId}

查詢角色具有的部門許可權
deptCheckStrictly模式下只查詢子選單

    <select id="selectDeptListByRoleId" resultType="Integer">
		select d.dept_id
		from sys_dept d
            left join sys_role_dept rd on d.dept_id = rd.dept_id
        where rd.role_id = #{roleId}
            <if test="deptCheckStrictly">
              and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId})
            </if>
		order by d.parent_id, d.order_num
	</select>

2. 獲取部門下拉樹

介面:/system/dept/treeselect

step1 : 獲取部門列表

  List<SysDept> depts = deptService.selectDeptList(dept);

step2: 構建樹形結構(重點)

deptService.buildDeptTreeSelect(depts)

生成樹形結構

  1. 獲取傳入部門列表中的頂級部門
  2. 遍歷頂級部門獲取每個部門的子部門列表
    1. 獲取子部門列表
    2. 遞迴遍歷子部門列表,獲取每個子部門的子部門列表
    3. 退出條件:當前部門沒有子部門
 /**
     * 構建前端所需要樹結構
     * 
     * @param depts 部門列表
     * @return 樹結構列表
     */
    @Override
    public List<SysDept> buildDeptTree(List<SysDept> depts)
    {
        List<SysDept> returnList = new ArrayList<SysDept>();
        //儲存所有的dept_id
        List<Long> tempList = new ArrayList<Long>();
        for (SysDept dept : depts)
        {
            tempList.add(dept.getDeptId());
        }
        for (Iterator<SysDept> iterator = depts.iterator(); iterator.hasNext();)
        {
            SysDept dept = (SysDept) iterator.next();
            // 如果是頂級節點, 遍歷該父節點的所有子節點
            <!--// 如果一個部門的父節點不在templist中,說明這個部門在當前資料集中是頂級部門,否則說明該部門是子部門-->
            <!--注:不是所有的樹都是從root部門,也可能是某個葉子節點遍歷的樹形結構-->
            if (!tempList.contains(dept.getParentId()))
            {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty())
        {
            returnList = depts;
        }
        return returnList;
    }

遞迴獲取子部門列表樹形結構

  1. 獲取子部門列表
  2. 遞迴遍歷子部門列表,獲取每個子部門的子部門列表
  3. 退出條件:當前部門沒有子部門
    /**
     * 遞迴列表
     */
    private void recursionFn(List<SysDept> list, SysDept t)
    {
        // 得到子節點列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList)
        {
            if (hasChild(list, tChild))
            {
                recursionFn(list, tChild);
            }
        }
    }

獲取子部門

  • 入參:部門列表+部門
  • 輸出:查詢部門的所有子部門列表
    /**
     * 得到子節點列表
     */
    private List<SysDept> getChildList(List<SysDept> list, SysDept t)
    {
        List<SysDept> tlist = new ArrayList<SysDept>();
        Iterator<SysDept> it = list.iterator();
        while (it.hasNext())
        {
            SysDept n = (SysDept) it.next();
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue())
            {
                tlist.add(n);
            }
        }
        return tlist;
    }

每個函式只做一件簡單的事情

/**
     * 判斷是否有子節點
     */
    private boolean hasChild(List<SysDept> list, SysDept t)
    {
        return getChildList(list, t).size() > 0 ? true : false;
    }

最終統一格式

    /**
     * 構建前端所需要下拉樹結構
     * 
     * @param depts 部門列表
     * @return 下拉樹結構列表
     */
    @Override
    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts)
    {
        List<SysDept> deptTrees = buildDeptTree(depts);
        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

相關文章