企业微信通讯录组装树Demo

企业微信通讯录组装树Demo

企业微信通讯录组装树备份,可直接拷贝使用

package com.xxxx.server.pmo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.xxxx.mes.common.core.utils.BeanCopyUtils;
import com.xxxx.server.pmo.dao.OrganizationalDepartmentMapper;
import com.xxxx.server.pmo.domain.entity.OrganizationalDepartment;
import com.xxxx.server.pmo.domain.entity.OrganizationalUser;
import com.xxxx.server.pmo.domain.vo.CommonVoTree;
import com.xxxx.server.pmo.domain.vo.OrganizationalDepartmentVo;
import com.xxxx.server.pmo.domain.vo.OrganizationalDepartmentVoTree;
import com.xxxx.server.pmo.domain.vo.OrganizationalSyncVo;
import com.xxxx.server.pmo.feign.WeChatApiFeign;
import com.xxxx.server.pmo.service.IOrganizationalDepartmentService;
import com.xxxx.server.pmo.service.IOrganizationalUserService;
import io.seata.common.util.CollectionUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Service
public class OrganizationalDepartmentServiceImpl extends ServiceImpl<OrganizationalDepartmentMapper, OrganizationalDepartment> implements IOrganizationalDepartmentService {

    private final String corpId = "xxxxx";

    private final String corpSecret = "xxxxxx";

    @Resource
    IOrganizationalUserService organizationalUserService;

    @Resource
    WeChatApiFeign weChatApiFeign;

    /**
     * @return boolean
     * @description: 同步企业微信的组织结构到数据库
     * @date: 2022/12/2
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrganizationalSyncVo syncOrganizationalStructureToUinFor() {
        List<Map<String, Object>> organizationalStructures = this.getOrganizationalStructureDetail();
        List<OrganizationalDepartmentVo> voList = this.copyWeChatModuleToVo(organizationalStructures);

        List<OrganizationalDepartmentVo> roundVoList = Lists.newArrayList();
        voList.forEach(item -> roundVoList.addAll(this.roundOrganizationalToDataBase(item, Lists.newArrayList())));

        List<OrganizationalUser> userList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(roundVoList)) {
            roundVoList.forEach(p -> {
                if (CollectionUtils.isNotEmpty(p.getUserList())) {
                    userList.addAll(p.getUserList());
                }
            });
        }

        OrganizationalSyncVo syncVo = new OrganizationalSyncVo();

        if (CollectionUtils.isNotEmpty(roundVoList)) {
            this.addOrUpdateDepartment(roundVoList, syncVo);
            this.addOrUpdateUser(userList, syncVo);
        }

        return syncVo;
    }

    private void addOrUpdateDepartment(List<OrganizationalDepartmentVo> roundVoList, OrganizationalSyncVo syncVo) {
        List<OrganizationalDepartment> originDepartmentList = this.list();
        List<OrganizationalDepartment> insertDepartmentList = Lists.newArrayList();
        Map<String, OrganizationalDepartment> originDepartmentMap = originDepartmentList.stream().collect(Collectors.toMap(OrganizationalDepartment::getId, p -> p));
        roundVoList.forEach(p -> {
            if (!originDepartmentMap.containsKey(p.getId())) {
                p.setDivisionStatus(true);
                insertDepartmentList.add(p);
            }
        });
        originDepartmentList.addAll(insertDepartmentList);
        syncVo.setNewDepartmentCount(insertDepartmentList.size());

        List<OrganizationalDepartment> disableDepartmentList = Lists.newArrayList();
        Map<String, OrganizationalDepartmentVo> newDepartmentMap = roundVoList.stream().collect(Collectors.toMap(OrganizationalDepartmentVo::getId, p -> p));
        originDepartmentList.forEach(p -> {
            if (!newDepartmentMap.containsKey(p.getId()) && p.getDivisionStatus()) {
                p.setDivisionStatus(false);
                disableDepartmentList.add(p);
            }
        });
        syncVo.setDisableDepartmentCount(disableDepartmentList.size());

        List<OrganizationalDepartmentVo> departmentVoList = BeanCopyUtils.copyList(originDepartmentList, OrganizationalDepartmentVo.class);

        OrganizationalDepartmentVoTree tree = new OrganizationalDepartmentVoTree(departmentVoList);

        departmentVoList = tree.builTree();

        List<OrganizationalDepartment> updateDepartmentList = Lists.newArrayList();

        this.renderDivisionCompany(departmentVoList, "", updateDepartmentList);

        //this.saveOrUpdateBatch(originDepartmentList);
        this.saveOrUpdateBatch(updateDepartmentList);
    }

    private void renderDivisionCompany(List<OrganizationalDepartmentVo> departmentVoList, String divisionCompany, List<OrganizationalDepartment> newDepartmentList) {
        departmentVoList.forEach(item -> {
            if ("0".equals(item.getParentId()) || "1".equals(item.getParentId())) {
                item.setDivisionCompany(item.getDivisionName());
                newDepartmentList.add(item);

                if (CollectionUtils.isNotEmpty(item.getChildren())) {
                    this.renderDivisionCompany(item.getChildren(), item.getDivisionName(), newDepartmentList);
                }
            } else {
                item.setDivisionCompany(divisionCompany);
                newDepartmentList.add(item);

                if (CollectionUtils.isNotEmpty(item.getChildren())) {
                    this.renderDivisionCompany(item.getChildren(), divisionCompany, newDepartmentList);
                }
            }
        });
    }

    private void addOrUpdateUser(List<OrganizationalUser> newUserList, OrganizationalSyncVo syncVo) {
        List<OrganizationalUser> originUserList = organizationalUserService.list();
        List<OrganizationalUser> insertUserList = Lists.newArrayList();
        Map<String, OrganizationalUser> originUserMap = originUserList.stream().collect(Collectors.toMap(OrganizationalUser::getId, p -> p));

        // 需要打标识的部门(本体)
        Map<String, String> isUpdateDeptMap = Maps.newHashMap();
        newUserList.forEach(p -> {
            if (!originUserMap.containsKey(p.getId())) {
                p.setStatus(true);
                insertUserList.add(p);
                String isUpdateDeptNum = isUpdateDeptMap.get(p.getDepartmentId());
                if (StringUtils.isNotBlank(isUpdateDeptNum)) {
                    isUpdateDeptMap.put(p.getDepartmentId(), (Integer.parseInt(isUpdateDeptNum) + 1) + "");
                } else {
                    isUpdateDeptMap.put(p.getDepartmentId(), "1");
                }
            }
        });
        originUserList.addAll(insertUserList);
        syncVo.setNewUserCount(insertUserList.size());

        List<String> departmentIds = isUpdateDeptMap.keySet().stream().collect(Collectors.toList());
        // 是否更新部门变动标识
        if (CollectionUtils.isNotEmpty(departmentIds)) {
            List<OrganizationalDepartment> departmentList = this.listByIds(departmentIds);
            Map<String, String> isUpdateParentDeptMap = Maps.newHashMap();
            departmentList.forEach(p -> {
                String isUpdateDeptNum = isUpdateDeptMap.get(p.getId());
                p.setIsUpdate(isUpdateDeptNum);

                String isUpdateParentDeptNum = isUpdateParentDeptMap.get(p.getParentId());
                if (StringUtils.isNotBlank(isUpdateParentDeptNum)) {
                    isUpdateParentDeptMap.put(p.getParentId(), (Integer.parseInt(isUpdateParentDeptNum) + Integer.parseInt(isUpdateDeptNum)) + "");
                } else {
                    isUpdateParentDeptMap.put(p.getParentId(), isUpdateDeptNum);
                }
            });
            // 更新本部门
            this.saveOrUpdateBatch(departmentList);

            List<String> parentDepartmentIds = isUpdateParentDeptMap.keySet().stream().collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(parentDepartmentIds)) {
                List<OrganizationalDepartment> parentDepartmentList = this.listByIds(parentDepartmentIds);
                parentDepartmentList.forEach(p -> {
                    p.setIsUpdate(isUpdateParentDeptMap.get(p.getId()));
                });
                // 更新父级部门
                this.saveOrUpdateBatch(parentDepartmentList);
            }
        }

        List<OrganizationalUser> disableUserList = Lists.newArrayList();
        Map<String, OrganizationalUser> newDepartmentMap = newUserList.stream().collect(Collectors.toMap(OrganizationalUser::getId, p -> p));
        originUserList.forEach(p -> {
            if (!newDepartmentMap.containsKey(p.getId()) && p.getStatus()) {
                p.setStatus(false);
                disableUserList.add(p);
            }
        });
        syncVo.setDisableUserCount(disableUserList.size());

        organizationalUserService.saveOrUpdateBatch(originUserList);
    }

    private List<OrganizationalDepartmentVo> roundOrganizationalToDataBase(OrganizationalDepartmentVo vo, List<OrganizationalDepartmentVo> voList) {
        voList.add(vo);
        if (CollectionUtils.isNotEmpty(vo.getChildren())) {
            vo.getChildren().forEach(item -> this.roundOrganizationalToDataBase(item, voList));
        }
        return voList;
    }

    /**
     * @return List<Object>
     * @description: 查询基础组织结构
     * @date: 2022/12/2
     */
    @Override
    public List<Map<String, Object>> getOrganizationalStructureExcludeUser() {
        return this.getOrganizationalStructureByParam("USER");
    }

    /**
     * @return List<Object>
     * @description: 查询组织结构详情(包括用户)
     * @date: 2022/12/2
     */
    @Override
    public List<Map<String, Object>> getOrganizationalStructureDetail() {
        return this.getOrganizationalStructureByParam(null);
    }

    /**
     * @return List<Object>
     * @description: 查询基础组织结构 - 数据库
     * @date: 2022/12/2
     */
    @Override
    public List<OrganizationalDepartmentVo> getOrganizationalExcludeUserByUinFor() {
        return this.getOrganizationalByParamByUinFor("USER");
    }

    /**
     * @return List<Object>
     * @description: 查询组织结构详情(包括用户) - 数据库
     * @date: 2022/12/2
     */
    @Override
    public List<OrganizationalDepartmentVo> getOrganizationalDetailByUinFor() {
        return this.getOrganizationalByParamByUinFor(null);
    }

    private List<OrganizationalDepartmentVo> getOrganizationalByParamByUinFor(String excludeType) {
        List<OrganizationalDepartment> departmentList = this.list();
        List<OrganizationalDepartmentVo> departmentVoList = BeanCopyUtils.copyList(departmentList, OrganizationalDepartmentVo.class);
        OrganizationalDepartmentVoTree tree = new OrganizationalDepartmentVoTree(departmentVoList);

        departmentVoList = tree.builTree();
        if ("USER".equals(excludeType)) {
            return departmentVoList;
//            List<OrganizationalDepartmentVo> departmentVoList = Lists.newArrayList();
//            BeanUtils.copyProperties(departmentVoList, departmentList);
//            return BeanUtils.copyProperties(confVo, busPage);
        }

        List<OrganizationalUser> userList = organizationalUserService.list(new QueryWrapper<>());
        return this.initUserListToModule(departmentVoList, userList);
    }

    private List<OrganizationalDepartmentVo> copyWeChatModuleToVo(List<Map<String, Object>> weChatModuleList) {
        List<OrganizationalDepartmentVo> resultList = Lists.newArrayList();

        weChatModuleList.forEach((module) -> {
            OrganizationalDepartmentVo vo = new OrganizationalDepartmentVo();
            vo.setId(module.get("id").toString());
            vo.setDivisionName(module.get("name").toString());
            vo.setDivisionStatus(true);
            vo.setParentId(module.get("parentid").toString());
            List<Map<String, Object>> userList = (List<Map<String, Object>>) module.get("userList");

            if (CollectionUtils.isNotEmpty(userList)) {
                List<OrganizationalUser> userVoList = userList.stream().map(userItem -> {
                    OrganizationalUser user = new OrganizationalUser();
                    user.setId(userItem.get("userid").toString());
                    user.setName(userItem.get("name").toString());
                    user.setStatus(true);
                    user.setDepartmentId(vo.getId());
                    return user;
                }).collect(Collectors.toList());

                if (CollectionUtils.isNotEmpty(userVoList)) {
                    vo.setUserList(userVoList);
                }
            }

            List<Map<String, Object>> children = (List<Map<String, Object>>) module.get("children");
            if (CollectionUtils.isNotEmpty(children)) {
                vo.setChildren(this.copyWeChatModuleToVo(children));
            }

            resultList.add(vo);
        });

        return resultList;
    }

    private List<OrganizationalDepartmentVo> initUserListToModule(List<OrganizationalDepartmentVo> departmentVoList, List<OrganizationalUser> userList) {
        for (OrganizationalDepartmentVo organizationalDepartmentVo : departmentVoList) {
            organizationalDepartmentVo.setDivisionStatus(null);
            organizationalDepartmentVo.setCreateBy(null);
            organizationalDepartmentVo.setCreateTime(null);
            organizationalDepartmentVo.setUpdateBy(null);
            organizationalDepartmentVo.setUpdateTime(null);
            organizationalDepartmentVo.setParams(null);
            organizationalDepartmentVo.setUserList(userList.stream().filter(p -> p.getDepartmentId().equals(organizationalDepartmentVo.getId())).collect(Collectors.toList()));
            if (CollectionUtils.isNotEmpty(organizationalDepartmentVo.getChildren())) {
                organizationalDepartmentVo.setChildren(this.initUserListToModule(organizationalDepartmentVo.getChildren(), userList));
            }
        }
        return departmentVoList;
    }

    private List<Map<String, Object>> getOrganizationalStructureByParam(String excludeType) {
        String accessToken = weChatApiFeign.fetchAccessTokenByQYWeChat(corpId, corpSecret).get("access_token").toString();

        // 获取所有部门列表
        List<Map<String, Object>> departmentBaseList = (List<Map<String, Object>>) weChatApiFeign.fetchDepartmentBaseListV2("1", accessToken).get("department");

        CommonVoTree tree = new CommonVoTree(departmentBaseList);

        List<Map<String, Object>> departmentBaseTree = tree.builTree();

        if ("USER".equals(excludeType)) {
            return departmentBaseTree;
        }

        Map<String, Object> result = this.fetchSyncUserMap(departmentBaseList, accessToken);

        return this.renderDepartmentUserDetailTree(departmentBaseTree, result);
    }

    public Map<String, Object> fetchSyncUserMap(List<Map<String, Object>> departmentBaseList, String accessToken) {
        long begin = System.currentTimeMillis();
        // 自定义一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        // 循环创建10个CompletableFuture
        List<CompletableFuture<DepartmentUsersMap>> collect = departmentBaseList.stream().map(item -> {
            CompletableFuture<DepartmentUsersMap> future = CompletableFuture
                    .supplyAsync(() -> {
                                String departmentId = item.get("id").toString();
                                List<Object> userList = (List<Object>) weChatApiFeign.fetchDepartmentUsers(departmentId, accessToken).get("userlist");
                                DepartmentUsersMap departmentUsersMap = new DepartmentUsersMap();
                                departmentUsersMap.setDepartmentId(departmentId);
                                departmentUsersMap.setUserList(userList);
                                return departmentUsersMap;
                            }, executorService
                    )
                    // 如果这里不处理异常,那么异常会在所有任务完成后抛出,小伙伴可自行测试
                    .exceptionally(Error -> {
                        Error.printStackTrace();
                        return null;
                    });
            return future;
        }).collect(Collectors.toList());
        // List列表转成CompletableFuture的Array数组,使其可以作为allOf()的参数
        // 使用join()方法使得主线程阻塞,并等待所有并行线程完成
        CompletableFuture.allOf(collect.toArray(new CompletableFuture[]{})).join();
        System.out.println("最终耗时" + (System.currentTimeMillis() - begin) + "毫秒");
        executorService.shutdown();

        Map<String, Object> result = Maps.newHashMap();

        collect.stream().forEach(future -> {
            DepartmentUsersMap departmentUsersMap = future.join();
            result.put(departmentUsersMap.getDepartmentId(), departmentUsersMap.getUserList());
        });

        return result;
    }

    private List<Map<String, Object>> renderDepartmentUserDetailTree(List<Map<String, Object>> departmentBaseList, Map<String, Object> departmentUsersMap) {
        if (CollectionUtils.isEmpty(departmentBaseList)) {
            return departmentBaseList;
        }
        List<Map<String, Object>> newTree = Lists.newArrayList();
        for (Map<String, Object> department : departmentBaseList) {
            Map<String, Object> detailMap = Maps.newLinkedHashMap();
            detailMap.putAll(department);
            List<Map<String, Object>> userList = (List<Map<String, Object>>) departmentUsersMap.get(department.get("id").toString());
            if (CollectionUtils.isNotEmpty(userList)) {
                detailMap.put("userList", userList);
            }

            List<Map<String, Object>> children = (List<Map<String, Object>>) detailMap.get("children");
            if (CollectionUtils.isNotEmpty(children)) {
                detailMap.put("children", this.renderDepartmentUserDetailTree(children, departmentUsersMap));
            }
            newTree.add(detailMap);
        }
        return newTree;
    }

}

@Data
class DepartmentUsersMap {

    String departmentId;

    List<Object> userList;
}