WangHan
2024-09-12 d5855a4926926698b740bc6c7ba489de47adb68b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package tech.powerjob.server.core.alarm.impl;
 
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.OapiGettokenRequest;
import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request;
import com.dingtalk.api.request.OapiUserGetByMobileRequest;
import com.dingtalk.api.response.OapiGettokenResponse;
import com.dingtalk.api.response.OapiUserGetByMobileResponse;
import tech.powerjob.common.exception.PowerJobException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
 
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
/**
 * 钉钉工具类
 * 工作通知消息:https://ding-doc.dingtalk.com/doc#/serverapi2/pgoxpy
 *
 * @author tjq
 * @since 2020/8/8
 */
@Slf4j
public class DingTalkUtils implements Closeable {
 
    private String accessToken;
 
    private final DingTalkClient sendMsgClient;
    private final DingTalkClient accessTokenClient;
    private final DingTalkClient userIdClient;
    private final ScheduledExecutorService scheduledPool;
 
    private static final long FLUSH_ACCESS_TOKEN_RATE = 6000;
    private static final String GET_TOKEN_URL = "https://oapi.dingtalk.com/gettoken";
    private static final String SEND_URL = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2";
    private static final String GET_USER_ID_URL = "https://oapi.dingtalk.com/user/get_by_mobile";
 
 
    public DingTalkUtils(String appKey, String appSecret) {
 
        this.sendMsgClient = new DefaultDingTalkClient(SEND_URL);
        this.accessTokenClient = new DefaultDingTalkClient(GET_TOKEN_URL);
        this.userIdClient = new DefaultDingTalkClient(GET_USER_ID_URL);
 
        refreshAccessToken(appKey, appSecret);
 
        if (StringUtils.isEmpty(accessToken)) {
            throw new PowerJobException("fetch AccessToken failed, please check your appKey & appSecret");
        }
 
        scheduledPool = Executors.newSingleThreadScheduledExecutor();
        scheduledPool.scheduleAtFixedRate(() -> refreshAccessToken(appKey, appSecret), FLUSH_ACCESS_TOKEN_RATE, FLUSH_ACCESS_TOKEN_RATE, TimeUnit.SECONDS);
    }
 
    /**
     * 获取 AccessToken,AccessToken 是调用其他接口的基础,有效期 7200 秒,需要不断刷新
     * @param appKey 应用 appKey
     * @param appSecret 应用 appSecret
     */
    private void refreshAccessToken(String appKey, String appSecret) {
        try {
            OapiGettokenRequest req = new OapiGettokenRequest();
            req.setAppkey(appKey);
            req.setAppsecret(appSecret);
            req.setHttpMethod(HttpMethod.GET.name());
            OapiGettokenResponse rsp = accessTokenClient.execute(req);
 
            if (rsp.isSuccess()) {
                accessToken = rsp.getAccessToken();
            }else {
                log.warn("[DingTalkUtils] flush accessToken failed with req({}),code={},msg={}.", req.getTextParams(), rsp.getErrcode(), rsp.getErrmsg());
            }
        } catch (Exception e) {
            log.warn("[DingTalkUtils] flush accessToken failed.", e);
        }
    }
 
    public String fetchUserIdByMobile(String mobile) throws Exception {
        OapiUserGetByMobileRequest request = new OapiUserGetByMobileRequest();
        request.setMobile(mobile);
 
        OapiUserGetByMobileResponse execute = userIdClient.execute(request, accessToken);
        if (execute.isSuccess()) {
            return execute.getUserid();
        }
        log.info("[DingTalkUtils] fetch userId by mobile({}) failed,reason is {}.", mobile, execute.getErrmsg());
        throw new PowerJobException("fetch userId by phone number failed, reason is " + execute.getErrmsg());
    }
 
    public void sendMarkdownAsync(String title, List<MarkdownEntity> entities, String userList, Long agentId) throws Exception {
        OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
        request.setUseridList(userList);
        request.setAgentId(agentId);
        request.setToAllUser(false);
 
        OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
 
        StringBuilder mdBuilder=new StringBuilder();
        mdBuilder.append("## ").append(title).append("\n");
        for (MarkdownEntity entity:entities){
            mdBuilder.append("#### ").append(entity.title).append("\n");
            mdBuilder.append("> ").append(entity.detail).append("\n\n");
        }
 
        msg.setMsgtype("markdown");
        msg.setMarkdown(new OapiMessageCorpconversationAsyncsendV2Request.Markdown());
        msg.getMarkdown().setTitle(title);
        msg.getMarkdown().setText(mdBuilder.toString());
        request.setMsg(msg);
 
        sendMsgClient.execute(request, accessToken);
    }
 
    @Override
    public void close() throws IOException {
        scheduledPool.shutdownNow();
    }
 
    @AllArgsConstructor
    public static final class MarkdownEntity {
        private final String title;
        private final String detail;
    }
}