✨ Introducing new features. 支持企业微信组织 用户结构同步

This commit is contained in:
lbw committed 2022-04-25 16:41:34 +08:00
1 parent 5e80065d46
commit 92e20524bc
9 files changed
+415 -370

No files matched your search

+6 -1
View File
@@ -27,7 +27,7 @@
<sqlserver.version>8.4.1.jre8</sqlserver.version>
<dm.version>8.1.2.79</dm.version>
<swagger.core.version>1.5.22</swagger.core.version>
<mp.weixin.version>4.2.0</mp.weixin.version>
<mp.weixin.version>4.3.0</mp.weixin.version>
<ijpay.version>2.8.0</ijpay.version>
<groovy.version>3.0.3</groovy.version>
<jsoup.version>1.13.1</jsoup.version>
@@ -233,6 +233,11 @@
<artifactId>weixin-java-mp</artifactId>
<version>${mp.weixin.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
<version>${mp.weixin.version}</version>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-common</artifactId>
@@ -90,4 +90,14 @@ public interface ErrorCodes {
*/
String SYS_APP_PHONE_UNREGISTERED = "sys.app.phone.unregistered";
/**
* 企微调用接口错误
*/
String SYS_CONNECT_CP_DEPT_SYNC_ERROR = "sys.connect.cp.dept.sync.error";
/**
* 企微调用接口错误
*/
String SYS_CONNECT_CP_USER_SYNC_ERROR = "sys.connect.cp.user.sync.error";
}
@@ -3,22 +3,17 @@ sys.user.query.error=\u83B7\u53D6\u5F53\u524D\u7528\u6237\u4FE1\u606F\u5931\u8D2
sys.user.import.succeed=\u7528\u6237\u5BFC\u5165\u6210\u529F\uFF0C\u9ED8\u8BA4\u5BC6\u7801\u4E3A\u624B\u673A\u53F7
sys.user.username.existing={0} \u7528\u6237\u540D\u5DF2\u5B58\u5728
sys.user.userInfo.empty={0} \u7528\u6237\u4FE1\u606F\u4E3A\u7A7A
sys.dept.deptName.inexistence={0} \u90E8\u95E8\u540D\u79F0\u4E0D\u5B58\u5728
sys.post.postName.inexistence={0} \u5C97\u4F4D\u540D\u79F0\u4E0D\u5B58\u5728
sys.post.nameOrCode.existing={0} {1} \u5C97\u4F4D\u540D\u6216\u5C97\u4F4D\u7F16\u7801\u5DF2\u7ECF\u5B58\u5728
sys.role.roleName.inexistence={0} \u89D2\u8272\u540D\u79F0\u4E0D\u5B58\u5728
sys.role.nameOrCode.existing={0} {1} \u89D2\u8272\u540D\u6216\u89D2\u8272\u7F16\u7801\u5DF2\u7ECF\u5B58\u5728
sys.param.delete.system=\u7CFB\u7EDF\u5185\u7F6E\u53C2\u6570\u4E0D\u80FD\u5220\u9664
sys.param.config.error={0} \u7CFB\u7EDF\u53C2\u6570\u914D\u7F6E\u9519\u8BEF
sys.menu.delete.existing=\u83DC\u5355\u542B\u6709\u4E0B\u7EA7\u4E0D\u80FD\u5220\u9664
sys.app.sms.often=\u9A8C\u8BC1\u7801\u53D1\u9001\u8FC7\u9891\u7E41
sys.app.phone.unregistered={0} \u624B\u673A\u53F7\u672A\u6CE8\u518C
sys.dict.delete.system=\u7CFB\u7EDF\u5185\u7F6E\u5B57\u5178\u9879\u76EE\u4E0D\u80FD\u5220\u9664
sys.dict.update.system=\u7CFB\u7EDF\u5185\u7F6E\u5B57\u5178\u9879\u76EE\u4E0D\u80FD\u4FEE\u6539
sys.connect.cp.dept.sync.error=\u83B7\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u90E8\u95E8\u5217\u8868\u5931\u8D25
sys.connect.cp.user.sync.error=\u83B7\u53D6\u4F01\u4E1A\u5FAE\u4FE1\u7528\u6237\u5217\u8868\u5931\u8D25
+161 -162
View File
@@ -19,171 +19,170 @@
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-upms</artifactId>
<version>4.3.0</version>
</parent>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-upms</artifactId>
<version>4.3.0</version>
</parent>
<artifactId>pigx-upms-biz</artifactId>
<packaging>jar</packaging>
<artifactId>pigx-upms-biz</artifactId>
<packaging>jar</packaging>
<description>pigx 通用用户权限管理系统业务处理模块</description>
<description>pigx 通用用户权限管理系统业务处理模块</description>
<dependencies>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- ojdbc8 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<!--PG-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!--mssql-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<!--upms api、model 模块-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-upms-api</artifactId>
</dependency>
<!--日志处理-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-log</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-data</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-swagger</artifactId>
</dependency>
<!--文件系统-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-oss</artifactId>
</dependency>
<!--注册中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--配置中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--spring security 、oauth、jwt依赖-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-security</artifactId>
</dependency>
<!--XSS 安全过滤-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-xss</artifactId>
</dependency>
<!--支持动态路由配置 -->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-gateway</artifactId>
</dependency>
<!--sentinel 依赖-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-sentinel</artifactId>
</dependency>
<!--路由控制-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-gray</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- cas sdk -->
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>${cas.sdk.version}</version>
</dependency>
<!--新版api-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dingtalk</artifactId>
<version>${dingtalk.version}</version>
</dependency>
<!--旧版api,新版api未包含全部的服务端API的产品能力-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>${dingtalk.old.version}</version>
</dependency>
<!--web 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>
<dependencies>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- ojdbc8 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
</dependency>
<!--PG-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!--mssql-->
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
</dependency>
<!--upms api、model 模块-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-upms-api</artifactId>
</dependency>
<!--日志处理-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-log</artifactId>
</dependency>
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-data</artifactId>
</dependency>
<!--swagger-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-swagger</artifactId>
</dependency>
<!--文件系统-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-oss</artifactId>
</dependency>
<!--注册中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--配置中心客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--spring security 、oauth、jwt依赖-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-security</artifactId>
</dependency>
<!--XSS 安全过滤-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-xss</artifactId>
</dependency>
<!--支持动态路由配置 -->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-gateway</artifactId>
</dependency>
<!--sentinel 依赖-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-sentinel</artifactId>
</dependency>
<!--路由控制-->
<dependency>
<groupId>com.pig4cloud</groupId>
<artifactId>pigx-common-gray</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!-- druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!-- cas sdk -->
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>${cas.sdk.version}</version>
</dependency>
<!--旧版api,新版api未包含全部的服务端API的产品能力-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>${dingtalk.old.version}</version>
</dependency>
<!--企业微信-->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-cp</artifactId>
</dependency>
<!--web 模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--undertow容器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.xlsx</exclude>
<exclude>**/*.xls</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.xlsx</include>
<include>**/*.xls</include>
</includes>
</resource>
</resources>
</build>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.xlsx</exclude>
<exclude>**/*.xls</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.xlsx</include>
<include>**/*.xls</include>
</includes>
</resource>
</resources>
</build>
</project>
@@ -40,15 +40,6 @@ public class ConnectController {
return R.ok();
}
/**
* 同步钉钉角色
* @return
*/
@PostMapping("/sync/ding/role")
public R syncRole() {
return R.ok(connectService.syncDingRole());
}
/**
* 同步钉钉部门
* @return
@@ -64,16 +55,7 @@ public class ConnectController {
*/
@PostMapping("/sync/cp/user")
public R syncCpUser() {
return R.ok();
}
/**
* 同步企微角色
* @return
*/
@PostMapping("/sync/cp/role")
public R syncCpRole() {
return R.ok();
return connectService.syncCpUser();
}
/**
@@ -82,7 +64,7 @@ public class ConnectController {
*/
@PostMapping("/sync/cp/dept")
public R syncCpDept() {
return R.ok();
return connectService.syncCpDept();
}
}
@@ -1,5 +1,7 @@
package com.pig4cloud.pigx.admin.service;
import com.pig4cloud.pigx.common.core.util.R;
/**
* @author lengleng
* @date 2022/4/22
@@ -8,11 +10,6 @@ package com.pig4cloud.pigx.admin.service;
*/
public interface ConnectService {
/**
* 同步钉钉角色
*/
Boolean syncDingRole();
/**
* 同步钉钉部门
*/
@@ -21,6 +18,18 @@ public interface ConnectService {
/**
* 同步钉钉用户
*/
Boolean syncDingUser(Long deptId);
R syncDingUser(Long deptId);
/**
* 同步企微部门
* @return
*/
R<Boolean> syncCpDept();
/**
* 同步企微用户
* @return
*/
R<Boolean> syncCpUser();
}
@@ -2,7 +2,6 @@ package com.pig4cloud.pigx.admin.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
@@ -10,24 +9,43 @@ import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.pig4cloud.pigx.admin.api.entity.*;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiUserListidRequest;
import com.dingtalk.api.request.OapiV2DepartmentListsubRequest;
import com.dingtalk.api.request.OapiV2UserGetRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiUserListidResponse;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.pig4cloud.pigx.admin.api.dto.UserDTO;
import com.pig4cloud.pigx.admin.api.entity.SysDept;
import com.pig4cloud.pigx.admin.api.entity.SysSocialDetails;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.admin.mapper.SysSocialDetailsMapper;
import com.pig4cloud.pigx.admin.service.*;
import com.pig4cloud.pigx.admin.service.ConnectService;
import com.pig4cloud.pigx.admin.service.SysDeptService;
import com.pig4cloud.pigx.admin.service.SysUserService;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.constant.enums.LoginTypeEnum;
import com.pig4cloud.pigx.common.core.exception.ErrorCodes;
import com.pig4cloud.pigx.common.core.util.MsgUtils;
import com.pig4cloud.pigx.common.core.util.R;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.api.impl.WxCpServiceImpl;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.config.impl.WxCpDefaultConfigImpl;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 互联平台实现
@@ -45,91 +63,16 @@ public class ConnectServiceImpl implements ConnectService {
private final SysSocialDetailsMapper sysSocialDetailsMapper;
private final SysRoleService sysRoleService;
private final SysDeptService sysDeptService;
private final SysUserService sysUserService;
private final SysUserRoleService sysUserRoleService;
private String getDingAccessToken() {
SysSocialDetails dingTalk = sysSocialDetailsMapper.selectOne(Wrappers.<SysSocialDetails>lambdaQuery()
.eq(SysSocialDetails::getType, LoginTypeEnum.dingtalk.getType()));
DingTalkClient client = new DefaultDingTalkClient(SecurityConstants.DING_OLD_GET_TOKEN);
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(dingTalk.getAppId());
request.setAppsecret(dingTalk.getAppSecret());
request.setHttpMethod(HttpMethod.GET.name());
try {
OapiGettokenResponse response = client.execute(request);
return response.getAccessToken();
}
catch (Exception e) {
log.error("调用钉钉异常", e);
}
return null;
}
/**
* 同步钉钉角色
*
* @link https://open.dingtalk.com/document/orgapp-server/obtains-a-list-of-enterprise-roles
*/
@SneakyThrows
@Override
public Boolean syncDingRole() {
// 分页偏移量
long offset = 0L;
// 是否还有非同步的数据
boolean hasMore;
// 数据库中现有的角色
List<SysRole> roleList = sysRoleService.list(Wrappers.emptyWrapper());
// 钉钉同步过来的角色
List<SysRole> insertRole = new LinkedList<>();
do {
DingTalkClient client = new DefaultDingTalkClient(SecurityConstants.DING_OLD_ROLE_URL);
OapiRoleListRequest req = new OapiRoleListRequest();
// 分页查询,默认分页20条
req.setSize(2L);
req.setOffset(offset);
OapiRoleListResponse rsp = client.execute(req, getDingAccessToken());
offset += req.getSize();
JSONObject result = JSONUtil.parseObj(rsp.getBody());
JSONObject resultStr = result.getJSONObject("result");
hasMore = resultStr.get("hasMore", Boolean.class);
List<JSONObject> list = resultStr.get("list", List.class);
// 处理返回的数据
List<SysRole> collect = list.stream().flatMap(
(Function<JSONObject, Stream<JSONObject>>) item -> ((List<JSONObject>) item.get("roles")).stream())
.filter(role -> roleList.stream().noneMatch(db -> db.getRoleName().equals(role.get("name"))))
.map(role -> {
SysRole sysRole = new SysRole();
sysRole.setRoleId(Convert.toLong(role.get("id")));
sysRole.setRoleCode(String.format("ROLE_DING_%s", Convert.toStr(role.get("id"))));
sysRole.setRoleCode(PinyinUtil.getPinyin(Convert.toStr(role.get("name"))));
sysRole.setRoleName(Convert.toStr(role.get("name")));
return sysRole;
}).collect(Collectors.toList());
insertRole.addAll(collect);
}
while (hasMore);
// 保存到数据库中
return sysRoleService.saveBatch(insertRole);
}
/**
* 同步钉钉部门
*
* @see <a href=
* "https://open.dingtalk.com/document/orgapp-server/obtain-the-department-list-v2"/>
* @return Boolean
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean syncDingDept() {
OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
req.setDeptId(1L);
@@ -152,6 +95,187 @@ public class ConnectServiceImpl implements ConnectService {
return Boolean.TRUE;
}
/**
* 同步部门下的钉钉用户
* @param deptId 部门ID
* @return R
*/
@SneakyThrows
@Override
@Transactional(rollbackFor = Exception.class)
public R syncDingUser(Long deptId) {
// 数据库中现有用户
List<SysUser> users = sysUserService.list(Wrappers.emptyWrapper());
String token = getDingAccessToken();
// 查询部门下的用户id列表
DingTalkClient client = new DefaultDingTalkClient(SecurityConstants.DING_DEPT_USERIDS_URL);
OapiUserListidRequest req = new OapiUserListidRequest();
req.setDeptId(deptId);
OapiUserListidResponse rsp = client.execute(req, token);
JSONObject jsonObject = JSONUtil.parseObj(rsp.getBody());
JSONObject result = jsonObject.getJSONObject("result");
if (result == null) {
return R.ok();
}
List<String> useridList = result.get("userid_list", List.class);
// 查询用户详情
for (String userid : useridList) {
DingTalkClient userClient = new DefaultDingTalkClient(SecurityConstants.DING_USER_INFO_URL);
OapiV2UserGetRequest userGetRequest = new OapiV2UserGetRequest();
userGetRequest.setUserid(userid);
OapiV2UserGetResponse userGetResponse = userClient.execute(userGetRequest, token);
JSONObject userResult = JSONUtil.parseObj(userGetResponse.getBody());
JSONObject userObj = JSONUtil.parseObj(userResult.get("result"));
boolean exist = users.stream().anyMatch(user -> user.getPhone().equals(userObj.getStr("mobile")));
if (exist) {
log.info("用户已存在 {}", userid);
continue;
}
// 用户部门信息
JSONArray deptOrders = userObj.getJSONArray("dept_order_list");
JSONObject deptInfo = (JSONObject) deptOrders.get(0);
// 用户信息
UserDTO userDTO = new UserDTO();
userDTO.setDeptId(Convert.toLong(deptInfo.get("dept_id")));
userDTO.setAvatar(userObj.getStr("avatar"));
userDTO.setUsername(userObj.getStr("mobile"));
userDTO.setPhone(userObj.getStr("mobile"));
userDTO.setNickname(userObj.getStr("nickname"));
userDTO.setName(userObj.getStr("name"));
userDTO.setEmail(userObj.getStr("email"));
// 初始化密码为 手机号
userDTO.setPassword(userObj.getStr("mobile"));
sysUserService.saveUser(userDTO);
}
return R.ok();
}
/**
* 同步企微部门
* @return R
*/
@Override
@Transactional(rollbackFor = Exception.class)
public R<Boolean> syncCpDept() {
WxCpService wxCpService = new WxCpServiceImpl();
wxCpService.setWxCpConfigStorage(getCpConfig());
List<WxCpDepart> departList;
try {
departList = wxCpService.getDepartmentService().list(null);
}
catch (WxErrorException e) {
log.error("获取企业微信部门列表失败", e);
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_CONNECT_CP_DEPT_SYNC_ERROR));
}
if (CollUtil.isEmpty(departList)) {
return R.ok();
}
// 数据库中现有的部门
List<SysDept> deptList = sysDeptService.list(Wrappers.emptyWrapper());
departList.stream()
.filter(depart -> deptList.stream().noneMatch(sysDept -> depart.getName().equals(sysDept.getName())))
.map(dept -> {
SysDept sysDept = new SysDept();
sysDept.setName(dept.getName());
sysDept.setDeptId(dept.getId());
sysDept.setParentId(dept.getParentId());
sysDept.setSortOrder(dept.getOrder().intValue());
return sysDept;
}).forEach(sysDeptService::saveDept);
return R.ok();
}
/**
* 同步企微用户
* @return R
*/
@Override
public R<Boolean> syncCpUser() {
WxCpService wxCpService = new WxCpServiceImpl();
wxCpService.setWxCpConfigStorage(getCpConfig());
List<WxCpUser> cpUserList;
try {
cpUserList = wxCpService.getUserService().listByDepartment(0L, true, 0);
}
catch (WxErrorException e) {
log.error("获取企业微信用户列表失败", e);
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_CONNECT_CP_USER_SYNC_ERROR));
}
if (CollUtil.isEmpty(cpUserList)) {
return R.ok();
}
// 系统原有用户
List<SysUser> userList = sysUserService.list(Wrappers.emptyWrapper());
for (WxCpUser cpUser : cpUserList) {
boolean exist = userList.stream().anyMatch(user -> user.getPhone().equals(cpUser.getMobile()));
if (exist) {
log.info("用户已存在跳过 {}", cpUser);
continue;
}
UserDTO user = new UserDTO();
user.setUsername(cpUser.getMobile());
user.setName(cpUser.getName());
user.setDeptId(cpUser.getDepartIds()[0]);
user.setEmail(cpUser.getEmail());
user.setPhone(cpUser.getMobile());
user.setAvatar(cpUser.getAvatar());
// 初始化密码为 手机号
user.setPassword(cpUser.getMobile());
sysUserService.saveUser(user);
}
return R.ok();
}
private String getDingAccessToken() {
SysSocialDetails dingTalk = sysSocialDetailsMapper.selectOne(Wrappers.<SysSocialDetails>lambdaQuery()
.eq(SysSocialDetails::getType, LoginTypeEnum.dingtalk.getType()));
DingTalkClient client = new DefaultDingTalkClient(SecurityConstants.DING_OLD_GET_TOKEN);
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(dingTalk.getAppId());
request.setAppsecret(dingTalk.getAppSecret());
request.setHttpMethod(HttpMethod.GET.name());
try {
OapiGettokenResponse response = client.execute(request);
return response.getAccessToken();
}
catch (Exception e) {
log.error("调用钉钉异常", e);
}
return null;
}
private WxCpDefaultConfigImpl getCpConfig() {
WxCpDefaultConfigImpl config = new WxCpDefaultConfigImpl();
config.setCorpId("wwdfd8cc3eb1127464"); // 设置微信企业号的appid
config.setCorpSecret("mrJAJwC0msVJ0-F30Iwop6B-w8eledxD66l3flrjX5w"); // 设置微信企业号的app
// corpSecret
config.setAgentId(1000003); // 设置微信企业号应用ID
config.setToken("lengleng"); // 设置微信企业号应用的token
config.setAesKey("pc49WfQMwDg2tDwHHP8gfLN6fRjkgDzS4WkYCumZCF1"); // 设置微信企业号应用的EncodingAESKey
return config;
}
/**
* 查询当前部门下的所有部门
*/
@@ -196,82 +320,4 @@ public class ConnectServiceImpl implements ConnectService {
return sysDepts;
}
/**
* 同步部门下的钉钉用户
*
* @see <a href=
* "https://open.dingtalk.com/document/isvapp-server/query-the-list-of-department-userids"/>
* @see <a href=
* "https://open.dingtalk.com/document/isvapp-server/query-user-details"/>
*/
@SneakyThrows
@Override
public Boolean syncDingUser(Long deptId) {
// 数据库中现有用户
List<SysUser> users = sysUserService.list(Wrappers.emptyWrapper());
String token = getDingAccessToken();
// 查询部门下的用户id列表
DingTalkClient client = new DefaultDingTalkClient(SecurityConstants.DING_DEPT_USERIDS_URL);
OapiUserListidRequest req = new OapiUserListidRequest();
req.setDeptId(deptId);
OapiUserListidResponse rsp = client.execute(req, token);
JSONObject jsonObject = JSONUtil.parseObj(rsp.getBody());
JSONObject result = jsonObject.getJSONObject("result");
if (result == null) {
return false;
}
List<String> useridList = result.get("userid_list", List.class);
// 查询用户详情
for (String userid : useridList) {
DingTalkClient userClient = new DefaultDingTalkClient(SecurityConstants.DING_USER_INFO_URL);
OapiV2UserGetRequest userGetRequest = new OapiV2UserGetRequest();
userGetRequest.setUserid(userid);
OapiV2UserGetResponse userGetResponse = userClient.execute(userGetRequest, token);
JSONObject userResult = JSONUtil.parseObj(userGetResponse.getBody());
JSONObject userObj = JSONUtil.parseObj(userResult.get("result"));
boolean exist = users.stream().anyMatch(user -> user.getPhone().equals(userObj.getStr("mobile")));
if (exist) {
log.info("用户已存在 {}", userid);
continue;
}
// 用户部门信息
JSONArray deptOrders = userObj.getJSONArray("dept_order_list");
JSONObject deptInfo = (JSONObject) deptOrders.get(0);
// 用户信息
SysUser sysUser = new SysUser();
sysUser.setDeptId(Convert.toLong(deptInfo.get("dept_id")));
sysUser.setAvatar(userObj.getStr("avatar"));
sysUser.setUsername(userObj.getStr("mobile"));
sysUser.setPhone(userObj.getStr("mobile"));
sysUser.setNickname(userObj.getStr("nickname"));
sysUser.setName(userObj.getStr("name"));
sysUser.setEmail(userObj.getStr("email"));
sysUserService.save(sysUser);
// 用户角色信息
JSONArray roleList = userObj.getJSONArray("role_list");
if (roleList == null) {
continue;
}
JSONObject roleInfo = (JSONObject) roleList.get(0);
Long userRoleId = Convert.toLong(roleInfo.get("id"));
SysUserRole sysUserRole = new SysUserRole();
sysUserRole.setUserId(sysUser.getUserId());
sysUserRole.setRoleId(userRoleId);
sysUserRoleService.save(sysUserRole);
}
return Boolean.TRUE;
}
}
@@ -99,6 +99,17 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return userPost;
}).forEach(sysUserPostMapper::insert);
});
// 如果角色为空,赋默认角色
if (CollUtil.isEmpty(userDto.getRole())) {
// 获取默认角色编码
String defaultRole = ParamResolver.getStr("USER_DEFAULT_ROLE");
// 默认角色
SysRole sysRole = sysRoleService
.getOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleCode, defaultRole));
userDto.setRole(Collections.singletonList(sysRole.getRoleId()));
}
List<SysUserRole> userRoleList = userDto.getRole().stream().map(roleId -> {
SysUserRole userRole = new SysUserRole();
userRole.setUserId(sysUser.getUserId());
@@ -356,17 +367,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
String message = MsgUtils.getMessage(ErrorCodes.SYS_USER_USERNAME_EXISTING, userDto.getUsername());
return R.failed(message);
}
// 获取默认角色编码
String defaultRole = ParamResolver.getStr("USER_DEFAULT_ROLE");
// 默认角色
SysRole sysRole = sysRoleService.getOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleCode, defaultRole));
if (sysRole == null) {
return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_PARAM_CONFIG_ERROR, "USER_DEFAULT_ROLE"));
}
userDto.setRole(Collections.singletonList(sysRole.getRoleId()));
return R.ok(saveUser(userDto));
}
-1
View File
@@ -45,7 +45,6 @@
<spring-boot-admin.version>2.6.6</spring-boot-admin.version>
<captcha.version>1.2.7</captcha.version>
<cas.sdk.version>3.6.4</cas.sdk.version>
<dingtalk.version>1.3.40</dingtalk.version>
<dingtalk.old.version>2.0.0</dingtalk.old.version>
<swagger.fox.version>3.0.0</swagger.fox.version>
<knife4j.version>2.0.9</knife4j.version>