24282 2 년 전
부모
커밋
8aee118d87

+ 17 - 0
code/src/test/java/DingDingDataSource.java

@@ -0,0 +1,17 @@
+import fly.generator.GeneratorApplication;
+
+public class DingDingDataSource {
+
+    public static void main(String[] args) {
+        GeneratorApplication.builder()
+                .url("jdbc:mysql://36.134.91.96:17330/bytesailing_dingding?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true")
+                .username("fjhx2012mysql")
+                .password("3PN-Mzn#vnP&q6d")
+                .port(9989)
+                .module("hx-dingding")
+                .parent("com.fjhx.dingding")
+                .superServiceClass("com.ruoyi.common.core.service.BaseService")
+                .build();
+    }
+
+}

+ 4 - 0
hx-admin/src/main/resources/application-dev.yml

@@ -65,6 +65,10 @@ spring:
                     url: jdbc:mysql://36.134.91.96:17330/bytesailing_kd100?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
                     username: fjhx2012mysql
                     password: 3PN-Mzn#vnP&q6d
+                dingding:
+                    url: jdbc:mysql://36.134.91.96:17330/bytesailing_dingding?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+                    username: fjhx2012mysql
+                    password: 3PN-Mzn#vnP&q6d
 
     # redis 配置
     redis:

+ 4 - 0
hx-admin/src/main/resources/application-prod.yml

@@ -65,6 +65,10 @@ spring:
                     url: jdbc:mysql://192.168.0.238:23063/bytesailing_kd100?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
                     username: hx_mysql_byteSailing_rds
                     password: da~h2swYUI#aj134&y8K
+                dingding:
+                    url: jdbc:mysql://192.168.0.238:23063/bytesailing_dingding?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+                    username: hx_mysql_byteSailing_rds
+                    password: da~h2swYUI#aj134&y8K
 
     # redis 配置
     redis:

+ 4 - 0
hx-admin/src/main/resources/application-test.yml

@@ -65,6 +65,10 @@ spring:
                     url: jdbc:mysql://127.0.0.1:17330/bytesailing_kd100?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
                     username: fjhx2012mysql
                     password: 3PN-Mzn#vnP&q6d
+                dingding:
+                    url: jdbc:mysql://127.0.0.1:17330/bytesailing_dingding?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai
+                    username: fjhx2012mysql
+                    password: 3PN-Mzn#vnP&q6d
 
     # redis 配置
     redis:

+ 2 - 0
hx-common/src/main/java/com/fjhx/common/constant/SourceConstant.java

@@ -37,4 +37,6 @@ public interface SourceConstant {
      */
     String EHSD = "ehsd";
 
+    String DINGDING = "dingding";
+
 }

+ 6 - 0
hx-dingding/pom.xml

@@ -42,6 +42,12 @@
             <version>1.0</version>
         </dependency>
 
+        <dependency>
+            <groupId>io.github.biezhi</groupId>
+            <artifactId>TinyPinyin</artifactId>
+            <version>2.0.3.RELEASE</version>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 3 - 1
hx-dingding/src/main/java/com/fjhx/constant/Constant.java → hx-dingding/src/main/java/com/fjhx/dingding/constant/Constant.java

@@ -1,4 +1,4 @@
-package com.fjhx.constant;
+package com.fjhx.dingding.constant;
 
 /**
  * https://open-dev.dingtalk.com/fe/app#/appMgr/provider/h5/131175/17
@@ -31,4 +31,6 @@ public class Constant {
      */
     public static final String ENCODING_AES_KEY = "FFTCrWbBbdDauMGImmno7g6RSFKDF6HllywGl932b8o";
 
+
+
 }

+ 18 - 46
hx-dingding/src/main/java/com/fjhx/controller/DingController.java → hx-dingding/src/main/java/com/fjhx/dingding/controller/DingController.java

@@ -1,15 +1,16 @@
-package com.fjhx.controller;
+package com.fjhx.dingding.controller;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.aliyun.dingtalkoauth2_1_0.models.GetCorpAccessTokenResponseBody;
 import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
 import com.dingtalk.oapi.lib.aes.DingTalkEncryptor;
-import com.fjhx.constant.Constant;
-import com.fjhx.entity.dto.GetUserTokenDto;
-import com.fjhx.utils.DingUtil;
+import com.fjhx.dingding.constant.Constant;
+import com.fjhx.dingding.entity.dto.GetUserTokenDto;
+import com.fjhx.dingding.service.DingService;
+import com.fjhx.dingding.utils.DingUtil;
 import com.ruoyi.common.annotation.NonInterception;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.LinkedHashMap;
@@ -19,6 +20,10 @@ import java.util.LinkedHashMap;
 @RequestMapping("/open")
 public class DingController {
 
+
+    @Autowired
+    private DingService dingService;
+
     /**
      * 创建应用,验证回调URL创建有效事件(第一次保存回调URL之前)
      */
@@ -30,25 +35,9 @@ public class DingController {
     private static final String EVENT_CHECK_UPDATE_SUITE_URL = "check_update_suite_url";
 
     /**
-     * suite_ticket推送事件
-     */
-    private static final String EVENT_SUITE_TICKET = "suite_ticket";
-
-    /**
-     * 企业授权开通应用事件
-     */
-    private static final String EVENT_TMP_AUTH_CODE = "tmp_auth_code";
-
-    /**
-     * 高优先级数据,激活应用等
-     */
-    private static final String EVENT_SYNC_HTTP_PUSH_HIGH = "SYNC_HTTP_PUSH_HIGH";
-
-    /**
-     * 普通优先级数据,例如通讯录变更
+     * https://open.dingtalk.com/document/isvapp/configure-synchttp-push
+     * https://open.dingtalk.com/document/isvapp/authorization-event-1
      */
-    private static final String EVENT_SYNC_HTTP_PUSH_MEDIUM = "SYNC_HTTP_PUSH_MEDIUM";
-
     @NonInterception
     @PostMapping(value = "/dingCallback")
     public Object dingCallback(
@@ -71,6 +60,7 @@ public class DingController {
             // 根据回调事件类型做不同的业务处理
             String eventType = callBackContent.getString("EventType");
             switch (eventType) {
+
                 case EVENT_CHECK_CREATE_SUITE_URL:
                     log.info("验证新创建的回调URL有效性: " + plainText);
                     break;
@@ -79,30 +69,12 @@ public class DingController {
                     log.info("验证更新回调URL有效性: " + plainText);
                     break;
 
-                case EVENT_SUITE_TICKET:
-                    // suite_ticket用于用签名形式生成accessToken(访问钉钉服务端的凭证),需要保存到应用的db。
-                    // 钉钉会定期向本callback url推送suite_ticket新值用以提升安全性。
-                    // 应用在获取到新的时值时,保存db成功后,返回给钉钉success加密串(如本demo的return)
-                    log.info("应用suite_ticket数据推送: " + plainText);
-                    break;
-
-                case EVENT_TMP_AUTH_CODE:
-                    // 本事件应用应该异步进行授权开通企业的初始化,目的是尽最大努力快速返回给钉钉服务端。用以提升企业管理员开通应用体验
-                    // 即使本接口没有收到数据或者收到事件后处理初始化失败都可以后续再用户试用应用时从前端获取到corpId并拉取授权企业信息,进而初始化开通及企业。
-                    log.info("企业授权开通应用事件: " + plainText);
-                    break;
-
-                case EVENT_SYNC_HTTP_PUSH_HIGH:
-                    log.info("高优先级数据:" + plainText);
-                    break;
-
-                case EVENT_SYNC_HTTP_PUSH_MEDIUM:
-                    log.info("普通优先级数据:" + plainText);
-                    break;
-
                 default:
                     // 其他类型事件处理
                     log.info("其他类型事件: " + plainText);
+
+                    dingService.saveCallback(callBackContent);
+
             }
 
             // 返回success的加密信息表示回调处理成功
@@ -117,8 +89,8 @@ public class DingController {
 
     @PostMapping(value = "/dingApi/getUserToken")
     public LinkedHashMap<String, Object> getUserToken(@RequestBody GetUserTokenDto dto) {
-        GetCorpAccessTokenResponseBody corpAccessToken = DingUtil.getCorpAccessToken(dto.getCorpId());
-        OapiV2UserGetuserinfoResponse.UserGetByCodeResponse userInfo = DingUtil.getUserInfo(corpAccessToken.getAccessToken(), dto.getCode());
+        String corpAccessToken = DingUtil.getCorpAccessToken(dto.getCorpId());
+        OapiV2UserGetuserinfoResponse.UserGetByCodeResponse userInfo = DingUtil.getUserInfo(corpAccessToken, dto.getCode());
 
         LinkedHashMap<String, Object> map = new LinkedHashMap<>();
         map.put("tokenInfo", corpAccessToken);

+ 1 - 1
hx-dingding/src/main/java/com/fjhx/entity/dto/GetUserTokenDto.java → hx-dingding/src/main/java/com/fjhx/dingding/entity/dto/GetUserTokenDto.java

@@ -1,4 +1,4 @@
-package com.fjhx.entity.dto;
+package com.fjhx.dingding.entity.dto;
 
 import lombok.Getter;
 import lombok.Setter;

+ 41 - 0
hx-dingding/src/main/java/com/fjhx/dingding/entity/suite/po/SuiteTicketInfo.java

@@ -0,0 +1,41 @@
+package com.fjhx.dingding.entity.suite.po;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.BaseIdPo;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author
+ * @since 2023-05-05
+ */
+@Getter
+@Setter
+@TableName("suite_ticket_info")
+public class SuiteTicketInfo extends BaseIdPo {
+
+    private String suiteTicket;
+
+    private String corpId;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+}

+ 17 - 0
hx-dingding/src/main/java/com/fjhx/dingding/mapper/suite/SuiteTicketInfoMapper.java

@@ -0,0 +1,17 @@
+package com.fjhx.dingding.mapper.suite;
+
+import com.fjhx.dingding.entity.suite.po.SuiteTicketInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2023-05-05
+ */
+public interface SuiteTicketInfoMapper extends BaseMapper<SuiteTicketInfo> {
+
+}

+ 9 - 0
hx-dingding/src/main/java/com/fjhx/dingding/service/DingService.java

@@ -0,0 +1,9 @@
+package com.fjhx.dingding.service;
+
+import com.alibaba.fastjson.JSONObject;
+
+public interface DingService {
+
+    void saveCallback(JSONObject callBackContent);
+
+}

+ 173 - 0
hx-dingding/src/main/java/com/fjhx/dingding/service/impl/DingServiceImpl.java

@@ -0,0 +1,173 @@
+package com.fjhx.dingding.service.impl;
+
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.extra.pinyin.PinyinUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.fjhx.dingding.entity.suite.po.SuiteTicketInfo;
+import com.fjhx.dingding.service.DingService;
+import com.fjhx.dingding.service.suite.SuiteTicketInfoService;
+import com.fjhx.tenant.entity.tenant.po.TenantInfo;
+import com.fjhx.tenant.service.tenant.impl.TenantInfoServiceImpl;
+import com.ruoyi.common.constant.StatusConstant;
+import com.ruoyi.common.exception.ServiceException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.TransactionStatus;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class DingServiceImpl implements DingService {
+
+
+    @Autowired
+    private SuiteTicketInfoService suiteTicketInfoService;
+
+    @Autowired
+    private TenantInfoServiceImpl tenantInfoService;
+
+    @Autowired
+    private PlatformTransactionManager platformTransactionManager;
+
+    @Autowired
+    private TransactionDefinition transactionDefinition;
+
+    /**
+     * https://open.dingtalk.com/document/isvapp/data-formats
+     */
+    @Override
+    public void saveCallback(JSONObject callBackContent) {
+
+        JSONObject bizData = callBackContent.getJSONObject("bizData");
+
+        switch (bizData.getInteger("biz_type")) {
+
+            case 2:
+                saveSuiteTicketInfo(bizData);
+                break;
+
+            case 4:
+                corpAuthorization(bizData);
+                break;
+
+        }
+
+
+    }
+
+
+    /**
+     * 企业授权
+     * <p>
+     * https://open.dingtalk.com/document/isvapp/obtains-the-authorization-information-after-the-enterprise-activates-the-application
+     */
+    private void corpAuthorization(JSONObject bizData) {
+
+        String syncAction = bizData.getString("syncAction");
+
+        switch (syncAction) {
+
+            // 企业授权
+            case "org_suite_auth":
+
+                orgSuiteAuth(bizData);
+                break;
+
+            // 企业变更授权范围
+            case "org_suite_change":
+
+                break;
+
+            // 表示企业解除授权
+            case "org_suite_relieve":
+
+                break;
+        }
+
+    }
+
+    /**
+     * 保存 suite_ticket
+     */
+    private void saveSuiteTicketInfo(JSONObject bizData) {
+        String corpId = bizData.getString("corp_id");
+        String suiteTicket = bizData.getJSONObject("biz_data").getString("suiteTicket");
+        boolean update = suiteTicketInfoService.update(q -> q
+                .eq(SuiteTicketInfo::getCorpId, corpId)
+                .set(SuiteTicketInfo::getSuiteTicket, suiteTicket));
+
+        if (!update) {
+            SuiteTicketInfo suiteTicketInfo = new SuiteTicketInfo();
+            suiteTicketInfo.setCorpId(corpId);
+            suiteTicketInfo.setSuiteTicket(suiteTicket);
+            suiteTicketInfoService.save(suiteTicketInfo);
+        }
+
+    }
+
+    /**
+     * 企业授权
+     */
+    private void orgSuiteAuth(JSONObject bizData) {
+        JSONObject authCorpInfo = bizData.getJSONObject("auth_corp_info");
+
+        // 企业id
+        String corpid = authCorpInfo.getString("corpid");
+        // 企业名称
+        String corpName = authCorpInfo.getString("corp_name");
+
+        // 企业id存在则跳过
+        if (tenantInfoService.getOne(q -> q.eq(TenantInfo::getCorpid, corpid)) != null) {
+            return;
+        }
+
+        // 获取tenantId
+        String firstLetter = PinyinUtil.getFirstLetter(corpName, "");
+        String tenantId = "dd-" + firstLetter;
+
+        List<TenantInfo> list = tenantInfoService.list(q -> q
+                .likeRight(TenantInfo::getTenantId, "dd-" + firstLetter));
+
+        List<String> tenantIdList = list.stream().map(TenantInfo::getTenantId).collect(Collectors.toList());
+
+        if (list.size() > 0) {
+
+            String tempTenantId;
+            do {
+                tempTenantId = tenantId + "-" + RandomUtil.randomString(3);
+            } while (!tenantIdList.contains(tempTenantId));
+
+            tenantId = tempTenantId;
+
+        }
+
+        TenantInfo tenantInfo = new TenantInfo();
+        tenantInfo.setTenantId(tenantId);
+        tenantInfo.setEnterpriseName(corpName);
+        tenantInfo.setStatus(StatusConstant.ENABLE);
+        tenantInfo.setFlowStatus(2);
+        tenantInfo.setCorpid(corpid);
+
+        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
+
+
+
+
+        try {
+            // 保存租户
+            tenantInfoService.save(tenantInfo);
+
+            // 提交事务
+            platformTransactionManager.commit(transactionStatus);
+        } catch (Exception e) {
+            // 回滚事务
+            platformTransactionManager.rollback(transactionStatus);
+            throw new ServiceException("保存数据失败");
+        }
+
+    }
+
+}

+ 17 - 0
hx-dingding/src/main/java/com/fjhx/dingding/service/suite/SuiteTicketInfoService.java

@@ -0,0 +1,17 @@
+package com.fjhx.dingding.service.suite;
+
+import com.fjhx.dingding.entity.suite.po.SuiteTicketInfo;
+import com.ruoyi.common.core.service.BaseService;
+
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author 
+ * @since 2023-05-05
+ */
+public interface SuiteTicketInfoService extends BaseService<SuiteTicketInfo> {
+
+}

+ 21 - 0
hx-dingding/src/main/java/com/fjhx/dingding/service/suite/impl/SuiteTicketInfoServiceImpl.java

@@ -0,0 +1,21 @@
+package com.fjhx.dingding.service.suite.impl;
+
+import com.fjhx.dingding.entity.suite.po.SuiteTicketInfo;
+import com.fjhx.dingding.mapper.suite.SuiteTicketInfoMapper;
+import com.fjhx.dingding.service.suite.SuiteTicketInfoService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2023-05-05
+ */
+@Service
+public class SuiteTicketInfoServiceImpl extends ServiceImpl<SuiteTicketInfoMapper, SuiteTicketInfo> implements SuiteTicketInfoService {
+
+}

+ 54 - 9
hx-dingding/src/main/java/com/fjhx/utils/DingUtil.java → hx-dingding/src/main/java/com/fjhx/dingding/utils/DingUtil.java

@@ -1,6 +1,8 @@
-package com.fjhx.utils;
+package com.fjhx.dingding.utils;
 
+import cn.hutool.core.convert.Convert;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
 import com.aliyun.dingtalkoauth2_1_0.Client;
 import com.aliyun.dingtalkoauth2_1_0.models.GetCorpAccessTokenRequest;
 import com.aliyun.dingtalkoauth2_1_0.models.GetCorpAccessTokenResponseBody;
@@ -8,13 +10,20 @@ import com.aliyun.tea.TeaException;
 import com.aliyun.teaopenapi.models.Config;
 import com.dingtalk.api.DefaultDingTalkClient;
 import com.dingtalk.api.DingTalkClient;
+import com.dingtalk.api.request.OapiV2DepartmentListsubRequest;
 import com.dingtalk.api.request.OapiV2UserGetuserinfoRequest;
+import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
 import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
-import com.fjhx.constant.Constant;
+import com.fjhx.dingding.constant.Constant;
+import com.fjhx.dingding.entity.suite.po.SuiteTicketInfo;
+import com.fjhx.dingding.service.suite.SuiteTicketInfoService;
+import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.exception.ServiceException;
-import com.taobao.api.ApiException;
 import lombok.extern.slf4j.Slf4j;
 
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 
 /**
  * 钉钉第三方企业应用 - h5微应用
@@ -29,22 +38,39 @@ import lombok.extern.slf4j.Slf4j;
 @Slf4j
 public class DingUtil {
 
+    // private static final RedisCache redisCache = SpringUtil.getBean(RedisCache.class);
+    private static final RedisCache redisCache =null;
+
+    // private static final SuiteTicketInfoService suiteTicketInfoService = SpringUtil.getBean(SuiteTicketInfoService.class);
+    private static final SuiteTicketInfoService suiteTicketInfoService = null;
+
+    private static final String corpAccessTokenRedisKey = "corpAccessToken:";
+
     /**
      * 获取第三方应用授权企业的accessToken
      * https://open.dingtalk.com/document/isvapp/obtain-the-access_token-of-the-authorized-enterprise
      */
-    public static GetCorpAccessTokenResponseBody getCorpAccessToken(String corpId) {
+    public static String getCorpAccessToken(String corpId) {
+
+        String redisKey = corpAccessTokenRedisKey + corpId;
+        String corpAccessToken = redisCache.getCacheObject(redisKey);
+        if (StrUtil.isNotBlank(corpAccessToken)) {
+            return corpAccessToken;
+        }
+
+        SuiteTicketInfo suiteTicketInfo = suiteTicketInfoService.getOne(q -> q.eq(SuiteTicketInfo::getCorpId, corpId));
 
         GetCorpAccessTokenRequest getCorpAccessTokenRequest = new GetCorpAccessTokenRequest()
                 .setSuiteKey(Constant.SUITE_KEY)
                 .setSuiteSecret(Constant.SUITE_SECRET)
                 .setAuthCorpId(corpId)
-                .setSuiteTicket("Kn3hJvJR34e8rUEob0W7nqxK2YHqobAyPsuIQXYR35SsJMp6rE5XQBz9nwXTrJRZaVmXc4z9KjYkzXdkUdS8O3");
+                .setSuiteTicket(suiteTicketInfo.getSuiteTicket());
 
         try {
             Client client = getClient2();
-            GetCorpAccessTokenResponseBody corpAccessToken = client.getCorpAccessToken(getCorpAccessTokenRequest).getBody();
-            return corpAccessToken;
+            GetCorpAccessTokenResponseBody body = client.getCorpAccessToken(getCorpAccessTokenRequest).getBody();
+            redisCache.setCacheObject(redisKey, body.getAccessToken(), Convert.toInt(body.getExpireIn() - 60), TimeUnit.SECONDS);
+            return body.getAccessToken();
         } catch (Exception e) {
 
             TeaException teaException;
@@ -80,12 +106,31 @@ public class DingUtil {
             req.setCode(code);
             OapiV2UserGetuserinfoResponse rsp = client.execute(req, corpAccessToken);
             return rsp.getResult();
-        } catch (ApiException e) {
-            log.error("通过免登码获取用户信息失败");
+        } catch (Exception e) {
+            log.error("通过免登码获取用户信息失败", e);
             throw new ServiceException("通过免登码获取用户信息失败");
         }
     }
 
+    public static void main(String[] args) {
+        getDeptList("", 1L);
+    }
+
+    public static List<OapiV2DepartmentListsubResponse.DeptBaseResponse> getDeptList(String corpId, Long deptId) {
+        try {
+            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
+            OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
+            req.setDeptId(deptId);
+            req.setLanguage("zh_CN");
+            // OapiV2DepartmentListsubResponse rsp = client.execute(req, getCorpAccessToken(corpId));
+            OapiV2DepartmentListsubResponse rsp = client.execute(req, "53b78b270b28320e869bf98a9f8e8486");
+            return rsp.getResult();
+        } catch (Exception e) {
+            log.error("获取用户部门失败", e);
+            throw new ServiceException("获取用户部门失败");
+        }
+    }
+
 
     private static com.aliyun.dingtalkcontact_1_0.Client getClient1() throws Exception {
         Config config = new Config();

+ 4 - 0
hx-dingding/src/main/resources/mapper/suite/SuiteTicketInfoMapper.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fjhx.dingding.mapper.suite.SuiteTicketInfoMapper">
+</mapper>