Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities.

0 foreword

Since the organization tree is common in projects, and the function is basically the same, so organize the relevant implementation encountered before, keep updating the relevant implementation ah.

1 Organization tree structure (recursive implementation)

1 Department Organization

@Data
public class Org {
    
    @apiModelProperty (value = "department ID")
    private String orgId;

    @apiModelProperty (value = "department name ")
    private String orgName;

    @apiModelProperty (value = "parent department ID")
    private String parentOrgId;
    
    / /... There are other fields such as org_path org_level
}
Copy the code

2 Organize tree classes

@Data
public class OrgTreeNode {
    private String id;
    private String label;
    private String parentId;
    private Boolean disabled;
    private String isLeaf;
    private String isHidden;
    private String orgPath;
    private String ownerUserIds;
    private String ownerUserNames;
    private int sortNo;
    private Object data;

    private List<OrgTreeNode> children;

    public void addChildren(OrgTreeNode orgTree) {
        if (children == null) {
            children = new ArrayList<>();
        }
        children.add(orgTree);
    }

    public void addChildrens(List<OrgTreeNode> orgTreeList) {
        if (children == null) {
            children = newArrayList<>(); } children.addAll(orgTreeList); }}Copy the code

3 Tree tool classes

@Slf4j
public class OrgTreeMenuUtil {

    /* * order */
    public Comparator<OrgTreeNode> order(a) {
        return (o1, o2) -> {
            if(o1.getSortNo() ! = o2.getSortNo()) {return o1.getSortNo() - o2.getSortNo();
            }
            return 0;
        };
    }

    public List<OrgTreeNode> findTree(List<OrgTreeNode> allMenu, String rootNode) {
        List<OrgTreeNode> rootMenu = new ArrayList<>();
        try {
            / / the root node
            for (OrgTreeNode nav : allMenu) {
                // rootNode is the rootNode
                if(rootNode.equals(nav.getParentId())) { rootMenu.add(nav); }}// Sort by order of the Menu class
            rootMenu.sort(order());
            // Set the submenu for the root menu. GetClild is called recursively
            for (OrgTreeNode nav : rootMenu) {
                // Get all children under the root node using the getChild method
                List<OrgTreeNode> childList = getChild(nav.getId(), allMenu);
                // Set child nodes for the root node
                nav.setChildren(childList);
            }
            // Outputs the constructed menu data
            return rootMenu;
        } catch (Exception e) {
            log.error(e.getMessage());
            returnCollections.emptyList(); }}/** * get the child node *@paramId Id of the parent node *@paramAllMenu List of all menus *@returnUnder each root node, all submenu lists */
    public List<OrgTreeNode> getChild(String id,List<OrgTreeNode> allMenu){
        / / submenu
        List<OrgTreeNode> childList = new ArrayList<OrgTreeNode>();
        for (OrgTreeNode nav : allMenu) {
            // Iterate over all nodes and compare the parent id of all menus with the id of the root node passed in
            // Equal: indicates the child node of the root node.
            if(id.equals(nav.getParentId())){ childList.add(nav); }}/ / recursion
        for (OrgTreeNode nav : childList) {
            nav.setChildren(getChild(nav.getId(), allMenu));
        }
        / / sorting
        childList.sort(order()); 
        // If there are no children under the node, return an empty List (recursive exit)
        if (CollectionUtils.isEmpty(childList)){
            return new ArrayList<OrgTreeNode>();
        }
        returnchildList; }}Copy the code

4 Instructions

First, all department information is queried and converted into OrgTreeNode objects. Then, the findTree method of the OrgTreeMenuUtil utility class is called and passed in the OrgTreeNode object and the organization root node. Utility classes use recursion to encapsulate organizational structure.

In addition, when editing org_path and org_level, for the modification of sub-departments, modify org_path :(== separator is recommended, use /== as little as possible, such as: Alibaba, Purchasing Department, mobile phone Business Department)

1 Use the original path and the upper-level path to perform fuzzy query and query all sub-departments.

2 Cut out the first half of the path and add the latest prefix.

3 Update the org_PATH field of all subdepartments.

For org_level modification :(for example, Alibaba, purchasing Department and mobile phone business department are the third-level departments)

1 This field depends on the org_PATH field. See whether the delimiter in the org_PATH field can be split into several parts.

2 Organization tree structure (non-recursive implementation)

1 Department Organization

@Data
public class Org {
    
    @apiModelProperty (value = "department ID")
    private String orgId;

    @apiModelProperty (value = "department name ")
    private String orgName;

    @apiModelProperty (value = "parent department ID")
    private String orgParentId;
    
    @apiModelProperty (value = "subdepartment set ")
    private List<Org> children;
    
    / /... There are other fields such as org_path org_level
}
Copy the code

2 Tree tool classes

@Slf4j
public class OrgTreeMenuUtil {
    
    /** * Generate organization tree **@param list 
     * @paramRoot Indicates the root node ID *@return* /
    public List<Org> getTree(List<Org> list, String root) {
        List<Org> orgList = new ArrayList<>();
        Map<String, Org> parentObjs = new HashMap<>();
        // Find all the first level menus
        for (Org org : list) { 
            if (org.getOrgParentId().equals(root)) {
                orgList.add(org);
            }
            // Record all menu ids and corresponding entities
            parentObjs.put(org.getOrgId(), org);
        }
 
        // Add each organization to the child set of the parent organization
        for (Org org : list) {
            // If it is a first-level menu, there is no need to find its parent
            if (org.getOrgParentId().equals(root)) {
                continue;
            }
            // Each organization finds its immediate parent and joins the parent's child set
            Org parentObj = parentObjs.get(org.getOrgParentId());

            // If there is no suborganization set, create a new collection and add the suborganization
            if (Objects.isNull(parentObj.getChildren())) {
                parentObj.setChildren(new ArrayList<>());
            }
            parentObj.getChildren().add(org);
        }
        returnorgList; }}Copy the code

With the method of space for time, the encapsulation of the organization tree is completed directly through two traversals without cyclic recursion.

3 Tree structure of departments and personnel

1 Organize user objects

@Data
public class OrgDropdownListRes {
    private String id;
    private String pId;
    private String isLeaf;
    private String value;
    private String title;
    private List<Person> persons;
}
Copy the code

2 User Object

@Data
public class Person {
    private String id;
    private String username;
    private String password;
    private String orgId;
    private Integer gender;
}
Copy the code

3 Department set and user set merge code

	    private List<OrgDropdownListRes> convertOrg(List<Org> orgList, List<Person> personList) {
        List<OrgDropdownListRes> resList = Lists.newArrayList();
        orgList.forEach(o -> {
            OrgDropdownListRes res = new OrgDropdownListRes();
            res.setId(o.getOrgId());
            res.setPId(o.getParentOrgId());
            res.setValue(o.getOrgId());
            res.setTitle(o.getOrgName());
            res.setIsLeaf(SysConstants.IS_LEAF_1.equals(o.getIsLeaf()));
            if(! CollectionUtils.isEmpty(personList)) { Map<String, List<Person>> stringListMap = personList.stream().collect(Collectors.groupingBy(Person::getOrgId)); res.setPersons(stringListMap.getOrDefault(o.getOrgId(), Collections.emptyList())); } resList.add(res); });return resList;
    }
Copy the code

Query all departments and all personnel (based on department ID and enterprise ID), turn personnel set into map structure through Stream, traverse department, and set user data.