From 7a3bb207e0644f7a136857d09fac500a32045d76 Mon Sep 17 00:00:00 2001 From: lilong Date: Thu, 29 Aug 2024 17:57:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:(REQ-2699)=20=E4=B8=B4=E6=97=B6=E6=94=AF?= =?UTF-8?q?=E6=8C=81app=E7=AB=AF=E8=AF=AD=E9=9F=B3=E5=8A=A9=E6=89=8B?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E8=8F=9C=E5=8D=95=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E6=97=B6=E5=8F=91=E9=80=81=E9=92=89=E9=92=89?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tyr-server/pom.xml | 6 ++ .../tyr/server/common/util/DingTalkUtil.java | 68 +++++++++++++++++++ .../server/controller/PrivateController.java | 13 ++++ .../event/inner/SendDingTalkHandler.java | 63 +++++++++++++++++ .../SaasFeatureResourceUpsertPayload.java | 8 +++ .../entity/SaasFeatureResource.java | 10 +++ .../impl/FeatureResourceSyncServiceImpl.java | 21 ++++++ .../impl/SaasFeatureResourceServiceImpl.java | 25 ++++++- 8 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java create mode 100644 tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java diff --git a/tyr-server/pom.xml b/tyr-server/pom.xml index ac8c62dd..7b7f6217 100644 --- a/tyr-server/pom.xml +++ b/tyr-server/pom.xml @@ -138,6 +138,12 @@ apisix-plat-api 2.0.0-SNAPSHOT + + + com.aliyun + alibaba-dingtalk-service-sdk + 2.0.0 + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java b/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java new file mode 100644 index 00000000..1839c2c3 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/common/util/DingTalkUtil.java @@ -0,0 +1,68 @@ +package cn.axzo.tyr.server.common.util; + + +import cn.hutool.core.util.StrUtil; +import com.dingtalk.api.DefaultDingTalkClient; +import com.dingtalk.api.DingTalkClient; +import com.dingtalk.api.request.OapiRobotSendRequest; +import com.dingtalk.api.response.OapiRobotSendResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * @author wangsiqian + * @since 2024/07/30 + */ +@Slf4j +public class DingTalkUtil { + + /** + * 发送消息 + * + * @author wangsiqian + * @date 2024-07-30 + */ + public static void sendMessage(String content, String accessToken, String secret) { + Long timestamp = System.currentTimeMillis(); + String sign = getSign(timestamp, secret); + if (StrUtil.isBlank(sign)) { + return; + } + + String url = StrUtil.format("https://oapi.dingtalk.com/robot/send?access_token={}&sign={}×tamp={}", + accessToken, sign, String.valueOf(timestamp)); + DingTalkClient client = new DefaultDingTalkClient(url); + + OapiRobotSendRequest req = new OapiRobotSendRequest(); + OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text(); + text.setContent(content); + OapiRobotSendRequest.At at = new OapiRobotSendRequest.At(); + at.setIsAtAll(false); + req.setMsgtype("text"); + req.setText(text); + req.setAt(at); + try { + OapiRobotSendResponse response = client.execute(req); + log.info("发送钉钉消息结果:{}", response); + } catch (Exception error) { + log.info("发送钉钉消息失败:{}", error.getMessage()); + } + } + + private static String getSign(Long timestamp, String secret) { + try { + String stringToSign = timestamp + "\n" + secret; + Mac mac = Mac.getInstance("HmacSHA256"); + mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); + byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8)); + return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8"); + } catch (Exception ignored) { + return ""; + } + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java index f2a6055d..fc1845b8 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/PrivateController.java @@ -25,7 +25,9 @@ import cn.axzo.tyr.client.model.res.SaasRoleRes; import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam; import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO; import cn.axzo.tyr.client.model.vo.SaveOrUpdateRoleVO; +import cn.axzo.tyr.server.event.inner.SendDingTalkHandler; import cn.axzo.tyr.server.event.outer.CacheWorkspaceProductHandler; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.ServicePkgProductCreatedPayload; import cn.axzo.tyr.server.job.CacheProductFeatureResourceJob; import cn.axzo.tyr.server.job.CacheProductPermissionJob; @@ -176,6 +178,8 @@ public class PrivateController { private CacheWorkspaceProductJob cacheWorkspaceProductJob; @Autowired private RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService; + @Autowired + private SendDingTalkHandler sendDingTalkHandler; /** * 统一层级的roleGroup按照id升序,sort从1递增 @@ -1360,6 +1364,15 @@ public class PrivateController { .collect(Collectors.toList()); } + @PostMapping("/api/private/dingtalk/send") + public Object sendUpsertDingTalk(@RequestBody SaasFeatureResourceUpsertPayload request) { + Event event = Event.builder() + .data(request) + .build(); + sendDingTalkHandler.onFeatureResourceUpsert(event, null); + return "ok"; + } + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java new file mode 100644 index 00000000..f6cb2007 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/inner/SendDingTalkHandler.java @@ -0,0 +1,63 @@ +package cn.axzo.tyr.server.event.inner; + +import cn.axzo.framework.rocketmq.Event; +import cn.axzo.framework.rocketmq.EventConsumer; +import cn.axzo.tyr.server.common.util.DingTalkUtil; +import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Objects; + +@Slf4j +@Component +public class SendDingTalkHandler implements InitializingBean { + + @Autowired + private EventConsumer eventConsumer; + @Value("${spring.profiles.active}") + private String env; + + // 语音助手菜单变更通知,@沈尚只是临时的方案,所以没改成配置 + private static final String ACCESS_TOKEN = "11cdf26d77211ee887184844910bf249b94aa2675c7ce36d75a7aa87d619490f"; + private static final String SECRET = "SEC3c1be9e4fe4cc09f16eb4b2eebf91659f21d5bdfb1d764b52f3e47825e6bed3f"; + + + public void onFeatureResourceUpsert(Event event, EventConsumer.Context context) { + log.info("begin send dingTalk rocketmq event: {}", event); + SaasFeatureResourceUpsertPayload payload = event.normalizedData(SaasFeatureResourceUpsertPayload.class); + + if (Objects.isNull(payload.getAction())) { + return; + } + + if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.UPDATE) && + Objects.equals(payload.getNewValue().getUniCode(), payload.getOldValue().getUniCode())) { + return; + } + + StringBuilder sb = new StringBuilder(); + sb.append("环境:" + env + "\n"); + sb.append("操作:" + payload.getAction() + "\n"); + if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.CREATE)) { + sb.append("新code:" + payload.getNewValue().getUniCode()); + } else if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.UPDATE)) { + sb.append("新code:" + payload.getNewValue().getUniCode() + "\n"); + sb.append("旧code:" + payload.getOldValue().getUniCode()); + } else if (Objects.equals(payload.getAction(), SaasFeatureResource.Action.DELETE)) { + sb.append("旧code:" + payload.getOldValue().getUniCode()); + } + + DingTalkUtil.sendMessage(sb.toString(), ACCESS_TOKEN, SECRET); + log.info("end send dingTalk rocketmq event: {}", event); + } + + @Override + public void afterPropertiesSet() throws Exception { + eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onFeatureResourceUpsert); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java index 1cdcbafb..1cae0180 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/event/payload/SaasFeatureResourceUpsertPayload.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.server.event.payload; +import cn.axzo.tyr.server.repository.entity.SaasFeatureResource; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -14,5 +15,12 @@ import java.util.Set; @AllArgsConstructor public class SaasFeatureResourceUpsertPayload implements Serializable { + // 只有tyr消费,触发更新缓存,同步等很多批量操作要全部重构收口代码后,才能好修改这个payload private Set terminals; + + private SaasFeatureResource oldValue; + + private SaasFeatureResource newValue; + + private SaasFeatureResource.Action action; } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java index 448a4146..a3420f41 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java @@ -198,4 +198,14 @@ public class SaasFeatureResource extends BaseEntity { return Objects.equals(ALL_ROLE.getValue(), authType); } } + + @Getter + @AllArgsConstructor + public enum Action { + DELETE( "删除操作"), + CREATE( "创建操作"), + UPDATE( "更新操作"); + + private String desc; + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java index edca5332..a333ab88 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/FeatureResourceSyncServiceImpl.java @@ -241,6 +241,16 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic baseResource.setCreateBy(operatorId); baseResource.setUpdateBy(operatorId); newResource(baseResource, parent); + + Event event = Event.builder() + .targetType(SAAS_FEATURE_RESOURCE_TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .newValue(featureResourceDao.getById(baseResource.getId())) + .action(SaasFeatureResource.Action.CREATE) + .build()) + .build(); + mqProducer.send(event); } else { //更新 - 恢复不能变更的数据 baseResource.setId(resource.getId()); @@ -251,6 +261,17 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic baseResource.setUpdateBy(operatorId); baseResource.setAppItemId(resource.getAppItemId()); featureResourceDao.updateById(baseResource); + + Event event = Event.builder() + .targetType(SAAS_FEATURE_RESOURCE_TARGET_TYPE) + .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) + .data(SaasFeatureResourceUpsertPayload.builder() + .newValue(featureResourceDao.getById(baseResource.getId())) + .oldValue(resource) + .action(SaasFeatureResource.Action.UPDATE) + .build()) + .build(); + mqProducer.send(event); } // 处理资源关联的权限 diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index e58be619..68a95276 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -32,7 +32,6 @@ import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.server.common.util.Throws; import cn.axzo.tyr.server.config.MqProducer; -import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.ResourcePermission; import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO; @@ -89,7 +88,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND; -import static cn.axzo.tyr.server.event.inner.EventTypeEnum.ROLE_PERMISSION_CREATED; import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; @@ -272,12 +270,33 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl