内容纲要
企业微信通讯录组装树备份,可直接拷贝使用
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;
}