From f8f94bcc9705bcc22991c0f984ba104f452b2f7a Mon Sep 17 00:00:00 2001 From: JiyangTang <18010816106@163.com> Date: Tue, 27 Jun 2023 12:53:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=8E=A8=E9=80=81=E6=94=B9?= =?UTF-8?q?=E4=B8=BADINGDING?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- baogutang-admin/pom.xml | 12 +- .../admin/schedule/EdgeXNoticeSchedule.java | 33 ++++- .../admin/utils/DingTalkMsgPushUtils.java | 122 ++++++++++++++++++ baogutang-common/pom.xml | 5 + .../common/constants/CacheConstant.java | 5 + .../common/constants/DingTalkMsgTypeEnum.java | 62 +++++++++ .../constants/DingTalkServerConstants.java | 53 ++++++++ .../properties/BaoGuTangConfigStrategy.java | 54 ++++++++ .../common/properties/DingTalkAppConfig.java | 36 ++++++ .../properties/DingTalkConfigFactory.java | 46 +++++++ .../properties/DingTalkConfigStrategy.java | 21 +++ 11 files changed, 441 insertions(+), 8 deletions(-) create mode 100644 baogutang-admin/src/main/java/top/baogutang/admin/utils/DingTalkMsgPushUtils.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkMsgTypeEnum.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkServerConstants.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/properties/BaoGuTangConfigStrategy.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkAppConfig.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigFactory.java create mode 100644 baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigStrategy.java diff --git a/baogutang-admin/pom.xml b/baogutang-admin/pom.xml index 04d7452..04d8186 100644 --- a/baogutang-admin/pom.xml +++ b/baogutang-admin/pom.xml @@ -79,11 +79,7 @@ junit-jupiter-api test - - com.aliyun - dingtalk - 2.0.20 - + cn.dev33 @@ -103,7 +99,11 @@ forest-spring-boot-starter 1.5.26 - + + com.aliyun + alibaba-dingtalk-service-sdk + 2.0.0 + diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java b/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java index 1ee174c..56e1fb4 100644 --- a/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java +++ b/baogutang-admin/src/main/java/top/baogutang/admin/schedule/EdgeXNoticeSchedule.java @@ -2,15 +2,18 @@ package top.baogutang.admin.schedule; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; -import com.zjiecode.wxpusher.client.bean.Message; +import com.dingtalk.api.request.OapiMessageCorpconversationAsyncsendV2Request; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import top.baogutang.admin.domain.EdgeXAnnouncementsDto; import top.baogutang.admin.services.IWxMsgPushService; +import top.baogutang.admin.utils.DingTalkMsgPushUtils; +import top.baogutang.common.constants.DingTalkMsgTypeEnum; import top.baogutang.common.domain.Page; import top.baogutang.common.domain.Results; import top.baogutang.common.properties.WxMsgPushProperties; @@ -41,6 +44,12 @@ public class EdgeXNoticeSchedule { @Resource private RedisTemplate redisTemplate; + @Resource + private DingTalkMsgPushUtils dingTalkMsgPushUtils; + + @Value("${dingtalk.baogutang.agentId}") + private String agentId; + private static final String REQUEST_URL = "https://art-api.edge-x.cn/api/v1/art/announcements?pageNum=1&pageSize=1"; /** @@ -65,7 +74,27 @@ public class EdgeXNoticeSchedule { Boolean result = redisTemplate.opsForValue().setIfAbsent(cacheKey, 1, 5, TimeUnit.DAYS); if (Boolean.TRUE.equals(result)) { - wxMsgPushService.msgPush(Message.CONTENT_TYPE_HTML, announcementsDto.getTitle(), announcementsDto.getContent(), wxMsgPushProperties.getTopicIds()); + dingTalkMsgPushUtils.dingTalkMsgPush(agentId, Boolean.TRUE, null, null, this.geneMsg(announcementsDto)); +// wxMsgPushService.msgPush(Message.CONTENT_TYPE_HTML, announcementsDto.getTitle(), announcementsDto.getContent(), wxMsgPushProperties.getTopicIds()); } } + + private OapiMessageCorpconversationAsyncsendV2Request.Msg geneMsg(EdgeXAnnouncementsDto announcementsDto) { + // 读取消息文件 + OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); + msg.setMsgtype(DingTalkMsgTypeEnum.ACTION_CARD.getType()); + OapiMessageCorpconversationAsyncsendV2Request.ActionCard actionCard = new OapiMessageCorpconversationAsyncsendV2Request.ActionCard(); + // 透出到会话列表和通知的文案 + actionCard.setTitle(announcementsDto.getTitle()); + // 支持markdown格式的正文内容 + String title = "# " + announcementsDto.getTitle() + "+\n\n"; + String image = "![](" + announcementsDto.getCover() + ")"; + actionCard.setMarkdown(title + image); + // 跳转按钮展示 + actionCard.setSingleTitle("查看详情"); + // 跳转URL + actionCard.setSingleUrl("https://app.edge-x.cn/#/noticeDetail?noticeId=" + announcementsDto.getId()); + msg.setActionCard(actionCard); + return msg; + } } diff --git a/baogutang-admin/src/main/java/top/baogutang/admin/utils/DingTalkMsgPushUtils.java b/baogutang-admin/src/main/java/top/baogutang/admin/utils/DingTalkMsgPushUtils.java new file mode 100644 index 0000000..c63a415 --- /dev/null +++ b/baogutang-admin/src/main/java/top/baogutang/admin/utils/DingTalkMsgPushUtils.java @@ -0,0 +1,122 @@ +package top.baogutang.admin.utils; + +import com.alibaba.fastjson.JSON; +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.response.OapiGettokenResponse; +import com.dingtalk.api.response.OapiMessageCorpconversationAsyncsendV2Response; +import com.taobao.api.ApiException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.StringUtils; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; +import top.baogutang.common.exceptions.BusinessException; +import top.baogutang.common.properties.DingTalkConfigFactory; +import top.baogutang.common.properties.DingTalkConfigStrategy; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static top.baogutang.common.constants.CacheConstant.PREFIX_DING_TALK_ACCESS_TOKEN; +import static top.baogutang.common.constants.DingTalkServerConstants.ACC_TOKEN; +import static top.baogutang.common.constants.DingTalkServerConstants.CORP_CONVERSATION_ASYNC_SEND_V2; + + +/** + * @description: 钉钉消息推送工具类 + * @author: nikooh + * @date: 2023/04/03 : 16:29 + */ +@Slf4j +@Component +public class DingTalkMsgPushUtils { + + @Resource + private DingTalkConfigFactory dingTalkConfigFactory; + + @Resource + private RedisTemplate redisTemplate; + + /** + * 钉钉消息推送 {https://open.dingtalk.com/document/orgapp/work-notice-option} + * + * @param agentId 应用ID + * @param deptIdList 消息接收部门ID集合 + * @param userIdList 消息接收用户ID集合 + * @param message 具体消息内容 + * @return 消息ID + */ + public Long dingTalkMsgPush(String agentId, Boolean toAllUser, List deptIdList, List userIdList, OapiMessageCorpconversationAsyncsendV2Request.Msg message) { + + // 1.获取消息所属应用及应用token + String accessToken = this.getAccessToken(agentId); + if (StringUtils.isBlank(accessToken)) { + throw new BusinessException("消息发送失败->未能成功生成应用token"); + } + + // 2.组装dingTalk请求参数 + OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); + request.setAgentId(Long.parseLong(agentId)); + request.setToAllUser(toAllUser); + if (CollectionUtils.isNotEmpty(deptIdList)) { + request.setDeptIdList(StringUtils.join(deptIdList.toArray(), ",")); + } + if (CollectionUtils.isNotEmpty(userIdList)) { + request.setUseridList(StringUtils.join(userIdList.toArray(), ",")); + } + request.setMsg(message); + + // 3.请求钉钉发送消息 + DingTalkClient client = new DefaultDingTalkClient(CORP_CONVERSATION_ASYNC_SEND_V2); + OapiMessageCorpconversationAsyncsendV2Response response = null; + try { + response = client.execute(request, accessToken); + log.info(">>>>>>>>>>request dingTalk send msg res:{}<<<<<<<<<<", JSON.toJSONString(response)); + return response.getTaskId(); + } catch (Exception e) { + log.error(">>>>>>>>>>request dingTalk send msg error:{}<<<<<<<<<<", e.getMessage(), e); + return null; + } + } + + /** + * 获取钉钉应用accessToken + * + * @param agentId 应用ID + * @return token + */ + public String getAccessToken(String agentId) { + DingTalkConfigStrategy config = dingTalkConfigFactory.getConfigByAgentId(agentId); + String appKey = config.getAppKey(); + String appSecret = config.getAppSecret(); + String cacheKey = PREFIX_DING_TALK_ACCESS_TOKEN + appKey; + Object accessTokenObj = redisTemplate.opsForValue().get(cacheKey); + if (Objects.nonNull(accessTokenObj)) { + return (String) accessTokenObj; + } + // 缓存不存在,生成token + DingTalkClient client = new DefaultDingTalkClient(ACC_TOKEN); + OapiGettokenRequest request = new OapiGettokenRequest(); + request.setAppkey(appKey); + request.setAppsecret(appSecret); + request.setHttpMethod("GET"); + OapiGettokenResponse response; + try { + response = client.execute(request); + log.info(">>>>>>>>>>request dingTalk gene accessToken,request:[{}] response:[{}]<<<<<<<<<<", JSON.toJSONString(request), JSON.toJSONString(response)); + if (Objects.nonNull(response) && Objects.nonNull(response.getAccessToken())) { + redisTemplate.opsForValue().set(cacheKey, response.getAccessToken(), 7000L, TimeUnit.SECONDS); + return response.getAccessToken(); + } + } catch (Exception e) { + log.error(">>>>>>>>>>request dingTalk gene accessToken error! request:{},errorMsg:{}<<<<<<<<<<", JSON.toJSONString(request), e.getMessage(), e); + } + return null; + } + +} diff --git a/baogutang-common/pom.xml b/baogutang-common/pom.xml index ea7ae0b..49cb02d 100644 --- a/baogutang-common/pom.xml +++ b/baogutang-common/pom.xml @@ -144,6 +144,11 @@ hutool-all 5.7.4 + + com.aliyun + dingtalk + 2.0.14 + \ No newline at end of file diff --git a/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java b/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java index 65bb54a..9b20152 100644 --- a/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java +++ b/baogutang-common/src/main/java/top/baogutang/common/constants/CacheConstant.java @@ -34,4 +34,9 @@ public class CacheConstant { public static final Integer ENABLE = 0; + + /** + * 钉钉应用access_token缓存KEY前缀 + */ + public static final String PREFIX_DING_TALK_ACCESS_TOKEN = "top:baogutang:dingtalk:access_token:"; } diff --git a/baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkMsgTypeEnum.java b/baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkMsgTypeEnum.java new file mode 100644 index 0000000..8f151eb --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkMsgTypeEnum.java @@ -0,0 +1,62 @@ +package top.baogutang.common.constants; + +/** + * @description: 钉钉消息类型枚举 + * @author: nikooh + * @date: 2023/04/07 : 13:41 + */ +public enum DingTalkMsgTypeEnum { + + /** + * 文本消息 + */ + TEXT("text"), + + /** + * 图片消息 + */ + IMAGE("image"), + + /** + * 语音消息 + */ + VOICE("voice"), + + /** + * 文件消息 + */ + FILE("file"), + + /** + * 链接消息 + */ + LINK("link"), + + /** + * OA消息 + */ + OA("oa"), + + /** + * markdown消息 + */ + MARKDOWN("markdown"), + + /** + * 卡片消息 + */ + ACTION_CARD("action_card"), + + ; + + private final String type; + + DingTalkMsgTypeEnum(String type) { + this.type = type; + } + + + public String getType() { + return type; + } +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkServerConstants.java b/baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkServerConstants.java new file mode 100644 index 0000000..25c2bfd --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/constants/DingTalkServerConstants.java @@ -0,0 +1,53 @@ +package top.baogutang.common.constants; + +/** + * @description: 钉钉服务相关常量 + * @author: nikooh + * @date: 2023/06/21 : 16:53 + */ +public class DingTalkServerConstants { + + private DingTalkServerConstants() { + // private constructor + } + + /** + * token + */ + public static final String ACC_TOKEN = "https://oapi.dingtalk.com/gettoken"; + + /** + * 群组创建 + */ + public static final String CHAT_CREATE = "https://oapi.dingtalk.com/chat/create"; + + /** + * 群组修改 + */ + public static final String CHAT_UPDATE = "https://oapi.dingtalk.com/chat/update"; + + /** + * 工作通知 + */ + public static final String CORP_CONVERSATION_ASYNC_SEND_V2 = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"; + + /** + * 部门下员工 + */ + public static final String USER_LIST = "https://oapi.dingtalk.com/topapi/v2/user/list"; + + /** + * 部门列表 + */ + public static final String DEPARTMENT_LIST = "https://oapi.dingtalk.com/department/list"; + + /** + * 用户详情 + */ + public static final String USER_INFO = "https://oapi.dingtalk.com/user/getuserinfo"; + + /** + * 手机号搜索userId + */ + public static final String USER_ID_BY_MOBILE = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile"; +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/properties/BaoGuTangConfigStrategy.java b/baogutang-common/src/main/java/top/baogutang/common/properties/BaoGuTangConfigStrategy.java new file mode 100644 index 0000000..1292f3d --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/properties/BaoGuTangConfigStrategy.java @@ -0,0 +1,54 @@ +package top.baogutang.common.properties; + +import org.springframework.stereotype.Component; + +/** + * @author niko + * @version 0.1.0 + * @create 2023/3/31 19:25 + * @since 0.1.0 + **/ +@Component +public class BaoGuTangConfigStrategy implements DingTalkConfigStrategy { + private String agentId; + private String appKey; + private String appSecret; + private String appCorpId; + private String appSource; + + public BaoGuTangConfigStrategy() { + } + + public BaoGuTangConfigStrategy(String agentId, String appKey, String appSecret, String appCorpId, String appSource) { + this.agentId = agentId; + this.appKey = appKey; + this.appSecret = appSecret; + this.appCorpId = appCorpId; + this.appSource = appSource; + } + + @Override + public String getAgentId() { + return agentId; + } + + @Override + public String getAppKey() { + return appKey; + } + + @Override + public String getAppSecret() { + return appSecret; + } + + @Override + public String getAppCorpId() { + return appCorpId; + } + + @Override + public String getAppSource() { + return appSource; + } +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkAppConfig.java b/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkAppConfig.java new file mode 100644 index 0000000..0d160c7 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkAppConfig.java @@ -0,0 +1,36 @@ +package top.baogutang.common.properties; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author niko + * @version 0.1.0 + * @create 2023/3/31 17:15 + * @since 0.1.0 + **/ +@Component +@ConfigurationProperties(prefix = "dingtalk") +@Getter +@Setter +public class DingTalkAppConfig { + + private BaoGuTangProperties baoGuTang = new BaoGuTangProperties(); + + @NoArgsConstructor + @AllArgsConstructor + @Getter + @Setter + public static class BaoGuTangProperties { + private String agentId; + private String appKey; + private String appSecret; + private String appCorpId; + } + +} + diff --git a/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigFactory.java b/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigFactory.java new file mode 100644 index 0000000..faa4e50 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigFactory.java @@ -0,0 +1,46 @@ +package top.baogutang.common.properties; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * @author niko + * @version 0.1.0 + * @create 2023/3/31 19:25 + * @since 0.1.0 + **/ +@Component +public class DingTalkConfigFactory { + + public static final String BAO_GU_TANG = "BAO_GU_TANG"; + + private Map configMap; + + @Qualifier + public DingTalkAppConfig dingTalkAppConfig; + + @Autowired + public DingTalkConfigFactory(DingTalkAppConfig dingTalkAppConfig) { + this.dingTalkAppConfig = dingTalkAppConfig; + this.configMap = new HashMap<>(); + this.configMap.put(BAO_GU_TANG, new BaoGuTangConfigStrategy(dingTalkAppConfig.getBaoGuTang().getAgentId(), + dingTalkAppConfig.getBaoGuTang().getAppKey(), dingTalkAppConfig.getBaoGuTang().getAppSecret(), + dingTalkAppConfig.getBaoGuTang().getAppCorpId(), BAO_GU_TANG)); + } + + public DingTalkConfigStrategy getConfig(String appType) { + return configMap.get(appType); + } + + public DingTalkConfigStrategy getConfigByAgentId(String agentId) { + if (Objects.equals(agentId, dingTalkAppConfig.getBaoGuTang().getAgentId())) { + return getConfig(BAO_GU_TANG); + } + return null; + } +} diff --git a/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigStrategy.java b/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigStrategy.java new file mode 100644 index 0000000..77d5345 --- /dev/null +++ b/baogutang-common/src/main/java/top/baogutang/common/properties/DingTalkConfigStrategy.java @@ -0,0 +1,21 @@ +package top.baogutang.common.properties; + +/** + * @author niko + * @version 0.1.0 + * @create 2023/3/31 19:23 + * @since 0.1.0 + **/ +public interface DingTalkConfigStrategy { + + String getAgentId(); + + String getAppKey(); + + String getAppSecret(); + + String getAppCorpId(); + + String getAppSource(); + +} \ No newline at end of file