feat:(REQ-2699) 临时支持app端语音助手功能,菜单更新编码时发送钉钉事件

This commit is contained in:
lilong 2024-08-29 17:57:21 +08:00
parent ec757f3ed1
commit 7a3bb207e0
8 changed files with 212 additions and 2 deletions

View File

@ -138,6 +138,12 @@
<artifactId>apisix-plat-api</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -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={}&timestamp={}",
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 "";
}
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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<String> terminals;
private SaasFeatureResource oldValue;
private SaasFeatureResource newValue;
private SaasFeatureResource.Action action;
}

View File

@ -198,4 +198,14 @@ public class SaasFeatureResource extends BaseEntity<SaasFeatureResource> {
return Objects.equals(ALL_ROLE.getValue(), authType);
}
}
@Getter
@AllArgsConstructor
public enum Action {
DELETE( "删除操作"),
CREATE( "创建操作"),
UPDATE( "更新操作");
private String desc;
}
}

View File

@ -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);
}
// 处理资源关联的权限

View File

@ -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<SaasFeatureResou
// 生成唯一编码用于pre菜单同步
baseResource.setFeatureCode(req.getUniCode());
newResource(baseResource, parent == null ? "" : parent.getPath());
Event event = Event.builder()
.targetType(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 {
//补充path
SaasFeatureResource newValue = featureResourceDao.getById(baseResource.getId());
SaasFeatureResource dbResource = featureResourceDao.getById(req.getId());
baseResource.setPath(dbResource.getPath());
baseResource.setFeatureCode(req.getUniCode());
featureResourceDao.updateById(baseResource);
Event event = Event.builder()
.targetType(TARGET_TYPE)
.eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode())
.data(SaasFeatureResourceUpsertPayload.builder()
.oldValue(featureResourceDao.getById(baseResource.getId()))
.newValue(newValue)
.build())
.build();
mqProducer.send(event);
}
// 保存组件与页面元素关系如果是页面改的是默认路由
ModifyPageElementRelationDTO modifyPageElementRelation = ModifyPageElementRelationDTO.builder()
@ -714,6 +733,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
.eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode())
.data(SaasFeatureResourceUpsertPayload.builder()
.terminals(Sets.newHashSet(featureResource.getTerminal()))
.oldValue(featureResource)
.action(SaasFeatureResource.Action.DELETE)
.build())
.build();
mqProducer.send(event);