feat(REQ-3114) - 完善钉钉消息的处理,增加关键词以及转发 MQ 的实现
This commit is contained in:
parent
f956028378
commit
a17a046e83
@ -18,5 +18,9 @@
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-consumer-spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.rocketmq</groupId>
|
||||
<artifactId>axzo-common-rocketmq</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -20,5 +20,7 @@ public enum DingTalkMsgTypeEnum {
|
||||
sampleAudio,
|
||||
sampleFile,
|
||||
sampleVideo,
|
||||
// 非钉钉官方
|
||||
messageQueue,
|
||||
;
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
package cn.axzo.riven.client.common.enums;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
|
||||
/**
|
||||
* 流程实例相关的 MQ 事件枚举定义
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2023/9/25 11:47
|
||||
*/
|
||||
public enum DingtalkEventEnum {
|
||||
|
||||
receive("riven-dingtalk", "riven-dingtalk-receive", "钉钉消息"),
|
||||
;
|
||||
private final String module;
|
||||
private final String tag;
|
||||
private final String desc;
|
||||
private Event.EventCode eventCode;
|
||||
|
||||
DingtalkEventEnum(String module, String tag, String desc) {
|
||||
this.eventCode = Event.EventCode.builder()
|
||||
.module(module)
|
||||
.name(tag)
|
||||
.build();
|
||||
this.module = module;
|
||||
this.tag = tag;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getModule() {
|
||||
return module;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public Event.EventCode getEventCode() {
|
||||
return eventCode;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.axzo.riven.client.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 监听由 riven 转发的钉钉群消息模型
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 18:17
|
||||
*/
|
||||
@Data
|
||||
public class DingtalkReceiveMqModel implements Serializable {
|
||||
private final static long serialVersionUID = 1L;
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package cn.axzo.riven.client.model;
|
||||
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.riven.client.common.enums.DingTalkMsgTypeEnum;
|
||||
|
||||
/**
|
||||
* 回复消息 POJO
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 13:43
|
||||
*/
|
||||
public interface ReplyMessage<T> {
|
||||
|
||||
DingTalkMsgTypeEnum msgType();
|
||||
|
||||
T messageBody();
|
||||
|
||||
default String toJson() {
|
||||
return JSON.toJSONString(messageBody());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.riven.client.model;
|
||||
|
||||
import cn.axzo.riven.client.common.enums.DingTalkMsgTypeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 简单的 MD 内容
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 14:01
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SampleMarkdown implements ReplyMessage<SampleMarkdown> {
|
||||
private final String title;
|
||||
private final String text;
|
||||
|
||||
@Override
|
||||
public DingTalkMsgTypeEnum msgType() {
|
||||
return DingTalkMsgTypeEnum.sampleMarkdown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleMarkdown messageBody() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public static SampleMarkdown from(String title, String text) {
|
||||
return new SampleMarkdown(title, text);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package cn.axzo.riven.client.model;
|
||||
|
||||
import cn.axzo.riven.client.common.enums.DingTalkMsgTypeEnum;
|
||||
import com.google.common.base.Strings;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static cn.azxo.framework.common.constatns.Constants.CTX_LOG_ID_MDC;
|
||||
import static com.google.common.net.HttpHeaders.X_REQUEST_ID;
|
||||
|
||||
/**
|
||||
* 转发消息内容到后端服务
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 17:14
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SampleMessageQueue implements ReplyMessage<SampleMessageQueue> {
|
||||
private String applicationName;
|
||||
private String traceId;
|
||||
private String messageContent;
|
||||
|
||||
@Override
|
||||
public DingTalkMsgTypeEnum msgType() {
|
||||
return DingTalkMsgTypeEnum.messageQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleMessageQueue messageBody() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public static SampleMessageQueue from(String applicationName, String messageContent) {
|
||||
String traceId = MDC.get(X_REQUEST_ID);
|
||||
if (Strings.isNullOrEmpty(traceId)) {
|
||||
MDC.put(CTX_LOG_ID_MDC, traceId());
|
||||
}
|
||||
return new SampleMessageQueue(applicationName, traceId, messageContent);
|
||||
}
|
||||
|
||||
private static String traceId() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.riven.client.model;
|
||||
|
||||
import cn.axzo.riven.client.common.enums.DingTalkMsgTypeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 简单文本
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 13:45
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SampleText implements ReplyMessage<SampleText> {
|
||||
private final String content;
|
||||
|
||||
@Override
|
||||
public DingTalkMsgTypeEnum msgType() {
|
||||
return DingTalkMsgTypeEnum.sampleText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleText messageBody() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public static SampleText from(String content) {
|
||||
return new SampleText(content);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package cn.axzo.riven.client.req;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 钉钉会话的通用查询入参
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 17:47
|
||||
*/
|
||||
@Data
|
||||
public class ThirdDingtalkConversationReq {
|
||||
|
||||
private String conversationId;
|
||||
|
||||
private String conversationTitle;
|
||||
|
||||
private String conversationType;
|
||||
|
||||
private String chatbotCorpId;
|
||||
|
||||
private String chatbotUserId;
|
||||
|
||||
private String applicationName;
|
||||
}
|
||||
@ -19,9 +19,17 @@
|
||||
<groupId>com.dingtalk.open</groupId>
|
||||
<artifactId>app-stream-client</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.data</groupId>
|
||||
<artifactId>axzo-data-mybatis-plus</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.rocketmq</groupId>
|
||||
<artifactId>axzo-common-rocketmq</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
package cn.axzo.riven.dingtalk.callback.keyword;
|
||||
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.client.model.SampleText;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
|
||||
/**
|
||||
* 兜底的关键词,不用注册为 Spring 的 Bean
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 17:01
|
||||
*/
|
||||
public class DefaultKeywordProcessor implements KeywordProcessor {
|
||||
@Override
|
||||
public String[] getKeywords() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplyMessage process(ChatbotMessage chatbotMessage) {
|
||||
return SampleText.from("不能理解你说的话!");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.axzo.riven.dingtalk.callback.keyword;
|
||||
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
|
||||
/**
|
||||
* 机器人支持的关键词
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 16:29
|
||||
*/
|
||||
public interface KeywordProcessor {
|
||||
String[] getKeywords();
|
||||
|
||||
ReplyMessage process(ChatbotMessage chatbotMessage);
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package cn.axzo.riven.dingtalk.callback.keyword;
|
||||
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.client.model.SampleText;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 主菜单
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 16:28
|
||||
*/
|
||||
@Component
|
||||
public class MenuKeywordProcessor implements KeywordProcessor {
|
||||
public final static String[] KEYWORD = {"menu", "菜单"};
|
||||
|
||||
@Override
|
||||
public String[] getKeywords() {
|
||||
return KEYWORD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplyMessage process(ChatbotMessage chatbotMessage) {
|
||||
return SampleText.from("这里是菜单");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package cn.axzo.riven.dingtalk.callback.keyword;
|
||||
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.client.model.SampleText;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkConversation;
|
||||
import cn.axzo.riven.dingtalk.service.ThirdDingtalkConversationService;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static cn.axzo.riven.dingtalk.constant.DingTalkConstant.REGISTER;
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 16:31
|
||||
*/
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class RegisterKeywordProcessor implements KeywordProcessor {
|
||||
public final static String[] KEYWORD = {"register", "注册"};
|
||||
private final ThirdDingtalkConversationService thirdDingtalkConversationService;
|
||||
|
||||
@Override
|
||||
public String[] getKeywords() {
|
||||
return KEYWORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要功能如下:
|
||||
* 1. 单纯注册会话
|
||||
* 2. 注册会话并绑定后端服务
|
||||
* 3. 会话重绑定后端服务
|
||||
*
|
||||
* @param chatbotMessage
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ReplyMessage process(ChatbotMessage chatbotMessage) {
|
||||
ThirdDingtalkConversation conversation = new ThirdDingtalkConversation();
|
||||
BeanUtil.copyProperties(chatbotMessage, conversation);
|
||||
|
||||
String replyText = String.format("注册成功,但未关联服务。\r\n如需请@机器发送“注册 [服务名]”即可(示例:注册 pudge)。\r\n当前的会话 ID:%s", conversation.getConversationId());
|
||||
String content = chatbotMessage.getText().getContent();
|
||||
String applicationName;
|
||||
if (StringUtils.hasText(applicationName = content.replaceAll(REGISTER, "").trim())) {
|
||||
replyText = String.format("本群于" + applicationName + "服务关联成功。 \r\n本群的会话 ID:%s", conversation.getConversationId());
|
||||
conversation.setApplicationName(applicationName);
|
||||
}
|
||||
|
||||
// 进行机器人和会话的绑定注册
|
||||
thirdDingtalkConversationService.upsert(conversation);
|
||||
return SampleText.from(replyText);
|
||||
}
|
||||
}
|
||||
@ -1,8 +1,11 @@
|
||||
package cn.axzo.riven.dingtalk.callback.robot;
|
||||
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.dingtalk.callback.robot.strategy.RobotHandleStrategy;
|
||||
import cn.axzo.riven.dingtalk.reply.RobotReply;
|
||||
import cn.axzo.riven.dingtalk.robot.connection.model.ReplyContext;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.dingtalk.open.app.api.callback.OpenDingTalkCallbackListener;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -21,7 +24,9 @@ import java.util.List;
|
||||
@Component
|
||||
public class RobotMsgCallbackConsumer implements OpenDingTalkCallbackListener<ChatbotMessage, Void> {
|
||||
@Resource
|
||||
private List<RobotHandleStrategy> robotHandleStrategies;
|
||||
private List<RobotHandleStrategy<? extends ReplyMessage>> robotHandleStrategies;
|
||||
@Resource
|
||||
private RobotReply robotReply;
|
||||
|
||||
/**
|
||||
* 执行回调
|
||||
@ -34,15 +39,20 @@ public class RobotMsgCallbackConsumer implements OpenDingTalkCallbackListener<Ch
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("receive message : {}", JSON.toJSONString(message));
|
||||
}
|
||||
// 用户输入的信息
|
||||
String keyword = message.getText().getContent().trim();
|
||||
|
||||
robotHandleStrategies.stream()
|
||||
.filter(s -> s.support(keyword))
|
||||
.findFirst()
|
||||
.ifPresent(handle -> {
|
||||
Object result = handle.handle(message);
|
||||
if(result instanceof ReplyContext) {
|
||||
ReplyContext replyContext = (ReplyContext) result;
|
||||
}
|
||||
ReplyContext context = ReplyContext.builder()
|
||||
.conversationId(message.getConversationId())
|
||||
.sessionWebhook(message.getSessionWebhook())
|
||||
.sessionWebhookExpiredDate(DateUtil.date(message.getSessionWebhookExpiredTime()))
|
||||
.replyMessage(handle.handle(message))
|
||||
.build();
|
||||
robotReply.reply(context);
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,10 +1,75 @@
|
||||
package cn.axzo.riven.dingtalk.callback.robot.strategy;
|
||||
|
||||
import cn.axzo.framework.domain.ServiceException;
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkMessageRecord;
|
||||
import cn.axzo.riven.dingtalk.service.ThirdDingtalkMessageRecordService;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 抽象的机器人监听消息的处理策略
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-23 17:35
|
||||
*/
|
||||
public abstract class AbstractRobotHandleStrategy<T> implements RobotHandleStrategy<T> {
|
||||
public abstract class AbstractRobotHandleStrategy implements RobotHandleStrategy<ReplyMessage> {
|
||||
@Resource
|
||||
private ThirdDingtalkMessageRecordService thirdDingtalkMessageRecordService;
|
||||
|
||||
protected final String getContent(ChatbotMessage chatbotMessage) {
|
||||
if (Objects.nonNull(chatbotMessage)) {
|
||||
return chatbotMessage.getText().getContent();
|
||||
}
|
||||
throw new ServiceException("获取用户发送的消息内容失败");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplyMessage handle(ChatbotMessage chatbotMessage) {
|
||||
// 记录日志
|
||||
ThirdDingtalkMessageRecord record = insertLog(chatbotMessage);
|
||||
|
||||
// 后续处理
|
||||
ReplyMessage replyMessage = doHandle(chatbotMessage);
|
||||
|
||||
// 更新日志
|
||||
updateLog(record, replyMessage);
|
||||
return replyMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新日志的响应信息
|
||||
*
|
||||
* @param record
|
||||
* @param replyMessage
|
||||
*/
|
||||
private void updateLog(ThirdDingtalkMessageRecord record, ReplyMessage replyMessage) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志
|
||||
*
|
||||
* @param chatbotMessage
|
||||
* @return
|
||||
*/
|
||||
private ThirdDingtalkMessageRecord insertLog(ChatbotMessage chatbotMessage) {
|
||||
ThirdDingtalkMessageRecord record = new ThirdDingtalkMessageRecord();
|
||||
record.setConversationId(chatbotMessage.getConversationId());
|
||||
record.setConversationTitle(chatbotMessage.getConversationTitle());
|
||||
record.setConversationType(chatbotMessage.getConversationType());
|
||||
record.setMsgId(chatbotMessage.getMsgId());
|
||||
record.setSenderNick(chatbotMessage.getSenderNick());
|
||||
record.setSessionWebhook(chatbotMessage.getSessionWebhook());
|
||||
record.setSessionWebhookExpiredTime(DateUtil.date(chatbotMessage.getSessionWebhookExpiredTime()));
|
||||
record.setHandleType(this.getClass().getSimpleName());
|
||||
record.setRequestContent(JSON.toJSONString(chatbotMessage));
|
||||
return thirdDingtalkMessageRecordService.insert(record);
|
||||
}
|
||||
|
||||
protected abstract ReplyMessage doHandle(ChatbotMessage chatbotMessage);
|
||||
}
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
package cn.axzo.riven.dingtalk.callback.robot.strategy.impl;
|
||||
|
||||
import cn.axzo.riven.dingtalk.callback.robot.strategy.AbstractRobotHandleStrategy;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 默认的将群消息通过 MQ 广播也所有业务方
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-23 18:13
|
||||
*/
|
||||
@Component
|
||||
public class DefaultTransferToMQStrategy extends AbstractRobotHandleStrategy<String> {
|
||||
@Override
|
||||
public boolean support(String keyword) {
|
||||
return StringUtils.hasText(keyword);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(ChatbotMessage chatbotMessage) {
|
||||
// TODO 转发给 MQ 中去
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
package cn.axzo.riven.dingtalk.callback.robot.strategy.impl;
|
||||
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.dingtalk.callback.keyword.DefaultKeywordProcessor;
|
||||
import cn.axzo.riven.dingtalk.callback.keyword.KeywordProcessor;
|
||||
import cn.axzo.riven.dingtalk.callback.robot.strategy.AbstractRobotHandleStrategy;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 注册会话
|
||||
* <p>
|
||||
* 新创建的群,添加机器人后,在群内@机器人并发送【注册】两个字,即可完成注册。
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-23 17:30
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class KeywordProcessorStrategy extends AbstractRobotHandleStrategy {
|
||||
|
||||
// 容器中所有实现了的关键词 Spring's Bean
|
||||
private final List<KeywordProcessor> keywordProcessorHandles;
|
||||
|
||||
// 关键词对应的处理 Bean Map
|
||||
private Map<String, KeywordProcessor> keywordMap;
|
||||
// 具体的关键词
|
||||
private List<String> words;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
keywordProcessorHandles.forEach(bean -> {
|
||||
for (String keyword : bean.getKeywords()) {
|
||||
words.addAll(Lists.newArrayList(bean.getKeywords()));
|
||||
keywordMap.put(keyword, bean);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean support(String keyword) {
|
||||
if (!StringUtils.hasText(keyword)) {
|
||||
return false;
|
||||
}
|
||||
for (String word : words) {
|
||||
if (keyword.trim().startsWith(word)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplyMessage doHandle(ChatbotMessage chatbotMessage) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(" KeywordProcessorStrategy Entrance ");
|
||||
}
|
||||
|
||||
KeywordProcessor keywordProcessor = getKeywordHandle(chatbotMessage);
|
||||
|
||||
return keywordProcessor.process(chatbotMessage);
|
||||
}
|
||||
|
||||
private KeywordProcessor getKeywordHandle(ChatbotMessage chatbotMessage) {
|
||||
String command = chatbotMessage.getText().getContent().trim();
|
||||
for (String word : words) {
|
||||
if (command.startsWith(word)) {
|
||||
return keywordMap.get(word);
|
||||
}
|
||||
}
|
||||
return new DefaultKeywordProcessor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE + 2;
|
||||
}
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
package cn.axzo.riven.dingtalk.callback.robot.strategy.impl;
|
||||
|
||||
import cn.axzo.riven.dingtalk.callback.robot.strategy.AbstractRobotHandleStrategy;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkConversation;
|
||||
import cn.axzo.riven.dingtalk.robot.connection.model.ReplyContext;
|
||||
import cn.axzo.riven.dingtalk.service.ThirdDingtalkConversationService;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.riven.dingtalk.constant.DingTalkConstant.REGISTER;
|
||||
|
||||
/**
|
||||
* 注册会话
|
||||
* <p>
|
||||
* 新创建的群,添加机器人后,在群内@机器人并发送【注册】两个字,即可完成注册。
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-23 17:30
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@AllArgsConstructor
|
||||
public class RegisterConversationStrategy extends AbstractRobotHandleStrategy<ReplyContext> {
|
||||
|
||||
private final ThirdDingtalkConversationService thirdDingtalkConversationService;
|
||||
|
||||
@Override
|
||||
public boolean support(String keyword) {
|
||||
return Objects.equals(keyword, REGISTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplyContext handle(ChatbotMessage chatbotMessage) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(" RegisterConversationStrategy Entrance ");
|
||||
}
|
||||
|
||||
ThirdDingtalkConversation conversation = new ThirdDingtalkConversation();
|
||||
BeanUtils.copyProperties(chatbotMessage, conversation);
|
||||
|
||||
// 进行机器人和会话的绑定注册
|
||||
thirdDingtalkConversationService.upsert(conversation);
|
||||
return ReplyContext.from(chatbotMessage.getSessionWebhook(), String.format("注册成功,当前的会话 ID:%s", conversation.getConversationId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE + 2;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package cn.axzo.riven.dingtalk.callback.robot.strategy.impl;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.RocketMQEventProducer;
|
||||
import cn.axzo.riven.client.common.enums.DingtalkEventEnum;
|
||||
import cn.axzo.riven.client.model.DingtalkReceiveMqModel;
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.client.model.SampleMessageQueue;
|
||||
import cn.axzo.riven.client.model.SampleText;
|
||||
import cn.axzo.riven.client.req.ThirdDingtalkConversationReq;
|
||||
import cn.axzo.riven.dingtalk.callback.robot.strategy.AbstractRobotHandleStrategy;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkConversation;
|
||||
import cn.axzo.riven.dingtalk.service.ThirdDingtalkConversationService;
|
||||
import com.dingtalk.open.app.api.models.bot.ChatbotMessage;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 默认的将群消息通过 MQ 广播也所有业务方
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-23 18:13
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class TransferToMQStrategy extends AbstractRobotHandleStrategy {
|
||||
@Resource
|
||||
private RocketMQEventProducer producer;
|
||||
@Resource
|
||||
private ThirdDingtalkConversationService thirdDingtalkConversationService;
|
||||
private final Map</*会话 ID*/String, ThirdDingtalkConversation> conversationMap = new HashMap<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
conversationMap.putAll(thirdDingtalkConversationService.genericQuery(new ThirdDingtalkConversationReq())
|
||||
.stream()
|
||||
.collect(Collectors.toMap(ThirdDingtalkConversation::getConversationId, Function.identity(), (s, t) -> s)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean support(String keyword) {
|
||||
return StringUtils.hasText(keyword);
|
||||
}
|
||||
|
||||
public ReplyMessage doHandle(ChatbotMessage chatbotMessage) {
|
||||
// TODO 转发给 MQ 中去
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(" DefaultTransferToMQStrategy Entrance ");
|
||||
}
|
||||
|
||||
ThirdDingtalkConversation conversation = checkConversationExists(chatbotMessage);
|
||||
if (Objects.isNull(conversation)) {
|
||||
return SampleText.from("这里应该提示用法");
|
||||
}
|
||||
|
||||
SampleMessageQueue messageQueue = SampleMessageQueue.from(conversation.getApplicationName(), getContent(chatbotMessage));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("发送 MQ 的消息数据:{}", messageQueue.toJson());
|
||||
}
|
||||
|
||||
DingtalkReceiveMqModel model = new DingtalkReceiveMqModel();
|
||||
|
||||
producer.send(Event.builder()
|
||||
.shardingKey(chatbotMessage.getConversationId())
|
||||
.eventCode(DingtalkEventEnum.receive.getEventCode())
|
||||
.targetId(messageQueue.getTraceId())// traceId
|
||||
.targetType(chatbotMessage.getConversationId())
|
||||
.data(model)
|
||||
.build());
|
||||
return messageQueue;
|
||||
}
|
||||
|
||||
private ThirdDingtalkConversation checkConversationExists(ChatbotMessage chatbotMessage) {
|
||||
return conversationMap.getOrDefault(chatbotMessage.getConversationId(), null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package cn.axzo.riven.dingtalk.reply;
|
||||
|
||||
import cn.axzo.framework.domain.ServiceException;
|
||||
import cn.axzo.framework.jackson.utility.JSON;
|
||||
import cn.axzo.riven.dingtalk.reply.strategy.RobotReplyStrategy;
|
||||
import cn.axzo.riven.dingtalk.robot.connection.model.ReplyContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static cn.axzo.riven.client.common.enums.DingTalkMsgTypeEnum.messageQueue;
|
||||
|
||||
/**
|
||||
* 机器人回复的入口
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 10:11
|
||||
*/
|
||||
@Component
|
||||
public class RobotReply {
|
||||
@Resource
|
||||
private List<RobotReplyStrategy> robotReplyStrategies;
|
||||
|
||||
/**
|
||||
* 回复消息
|
||||
*
|
||||
* @param replyContext
|
||||
*/
|
||||
public void reply(ReplyContext replyContext) {
|
||||
if (Objects.isNull(replyContext)) {
|
||||
return;
|
||||
}
|
||||
if (Objects.equals(messageQueue, replyContext.getReplyMessage().msgType())) {
|
||||
// 通过 MQ 转发给其他后端,这里统一不在回复
|
||||
return;
|
||||
}
|
||||
beforeCheck(replyContext);
|
||||
robotReplyStrategies.forEach(strategy -> strategy.reply(replyContext));
|
||||
}
|
||||
|
||||
private void beforeCheck(ReplyContext replyContext) {
|
||||
boolean useConversation = StringUtils.hasText(replyContext.getConversationId());
|
||||
boolean useWebhook = StringUtils.hasText(replyContext.getSessionWebhook()) && Objects.nonNull(replyContext.getSessionWebhookExpiredDate());
|
||||
if (!useConversation && !useWebhook) {
|
||||
throw new ServiceException(String.format("构建的回复上下文缺失参数:%s", JSON.toJSONString(replyContext)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package cn.axzo.riven.dingtalk.reply.strategy;
|
||||
|
||||
import cn.axzo.riven.dingtalk.robot.connection.model.ReplyContext;
|
||||
|
||||
/**
|
||||
* 抽象的机器人回复
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-24 10:21
|
||||
*/
|
||||
public abstract class AbstractRobotReply implements RobotReplyStrategy {
|
||||
|
||||
@Override
|
||||
public void reply(ReplyContext replyContext) {
|
||||
if(doFilter(replyContext)) {
|
||||
doReply(replyContext);
|
||||
}
|
||||
}
|
||||
|
||||
abstract void doReply(ReplyContext replyContext);
|
||||
|
||||
abstract boolean doFilter(ReplyContext replyContext);
|
||||
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
package cn.axzo.riven.dingtalk.reply.strategy;
|
||||
|
||||
import cn.axzo.riven.dingtalk.robot.connection.model.ReplyContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 基于 Http Api 的回复
|
||||
* https://github.com/open-dingtalk/dingtalk-stream-sdk-java-quick-start/blob/main/src/main/java/org/example/service/RobotGroupMessagesService.java
|
||||
@ -8,5 +11,20 @@ package cn.axzo.riven.dingtalk.reply.strategy;
|
||||
* @author wangli
|
||||
* @since 2024-10-23 17:28
|
||||
*/
|
||||
public class BasedHttpReply {
|
||||
@Component
|
||||
public class BasedHttpReply extends AbstractRobotReply {
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
void doReply(ReplyContext replyContext) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean doFilter(ReplyContext replyContext) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
package cn.axzo.riven.dingtalk.reply.strategy;
|
||||
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import cn.axzo.riven.client.model.SampleMarkdown;
|
||||
import cn.axzo.riven.client.model.SampleText;
|
||||
import cn.axzo.riven.dingtalk.robot.connection.model.ReplyContext;
|
||||
import com.dingtalk.open.app.api.chatbot.BotReplier;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 基于 Session Webhook 的回复
|
||||
@ -11,15 +20,49 @@ import java.io.IOException;
|
||||
* @author wangli
|
||||
* @since 2024-10-23 17:28
|
||||
*/
|
||||
public class BasedSessionWebhookReply {
|
||||
@Slf4j
|
||||
@Component
|
||||
public class BasedSessionWebhookReply extends AbstractRobotReply {
|
||||
@Resource
|
||||
private BasedHttpReply basedHttpReply;
|
||||
|
||||
public void reply(ReplyContext replyContext) {
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
void doReply(ReplyContext replyContext) {
|
||||
try {
|
||||
// just reply generic text
|
||||
BotReplier.fromWebhook(replyContext.getSessionWebhook()).replyText(replyContext.getMsgContent());
|
||||
BotReplier botReplier = BotReplier.fromWebhook(replyContext.getSessionWebhook());
|
||||
|
||||
ReplyMessage replyMessage = replyContext.getReplyMessage();
|
||||
switch (replyMessage.msgType()) {
|
||||
case sampleText:
|
||||
SampleText text = (SampleText) replyMessage.messageBody();
|
||||
botReplier.replyText(text.getContent(), replyContext.getAtUserId());
|
||||
break;
|
||||
case sampleMarkdown:
|
||||
SampleMarkdown markdown = (SampleMarkdown) replyMessage.messageBody();
|
||||
botReplier.replyMarkdown(markdown.getTitle(), markdown.getText(), replyContext.getAtUserId());
|
||||
break;
|
||||
default:
|
||||
// current reply just supported text and markdown
|
||||
botReplier.replyText(replyMessage.toJson(), replyContext.getAtUserId());
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
log.warn("通过 sessionWebhook 回复发生异常,将通过 HTTP API 回复");
|
||||
basedHttpReply.doReply(replyContext);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean doFilter(ReplyContext replyContext) {
|
||||
return Objects.nonNull(replyContext.getSessionWebhook()) && Objects.nonNull(replyContext.getSessionWebhookExpiredDate())
|
||||
&& StringUtils.hasText(replyContext.getSessionWebhook())
|
||||
&& new Date().before(replyContext.getSessionWebhookExpiredDate());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
package cn.axzo.riven.dingtalk.reply;
|
||||
package cn.axzo.riven.dingtalk.reply.strategy;
|
||||
|
||||
import cn.axzo.riven.dingtalk.robot.connection.model.ReplyContext;
|
||||
import org.springframework.core.Ordered;
|
||||
|
||||
/**
|
||||
* 回复机器人
|
||||
* 回复机器人的策略
|
||||
*
|
||||
* @author wangli
|
||||
* @since 2024-10-23 20:37
|
||||
*/
|
||||
public interface RobotReplyStrategy {
|
||||
public interface RobotReplyStrategy extends Ordered {
|
||||
|
||||
void reply(ReplyContext replyContext);
|
||||
}
|
||||
@ -31,7 +31,7 @@ public class ThirdDingtalkConversation extends BaseEntity<ThirdDingtalkConversat
|
||||
* 1:单聊
|
||||
* 2:群聊
|
||||
*/
|
||||
private Integer conversationType;
|
||||
private String conversationType;
|
||||
|
||||
/**
|
||||
* 机器人所属企业
|
||||
@ -42,4 +42,9 @@ public class ThirdDingtalkConversation extends BaseEntity<ThirdDingtalkConversat
|
||||
* 机器人用户 ID(加密数据)
|
||||
*/
|
||||
private String chatbotUserId;
|
||||
|
||||
/**
|
||||
* 会话关联的应用名称
|
||||
*/
|
||||
private String applicationName;
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public class ThirdDingtalkMessageRecord extends BaseEntity<ThirdDingtalkMessageR
|
||||
* 1:单聊
|
||||
* 2:群聊
|
||||
*/
|
||||
private Integer conversationType;
|
||||
private String conversationType;
|
||||
|
||||
/**
|
||||
* 会话级的 Webhook
|
||||
@ -56,15 +56,20 @@ public class ThirdDingtalkMessageRecord extends BaseEntity<ThirdDingtalkMessageR
|
||||
*/
|
||||
private Date sessionWebhookExpiredTime;
|
||||
|
||||
/**
|
||||
* 该消息是怎么处理的,处理策略的类型
|
||||
*/
|
||||
private String handleType;
|
||||
|
||||
/**
|
||||
* 请求的内容
|
||||
*/
|
||||
private String requestContext;
|
||||
private String requestContent;
|
||||
|
||||
/**
|
||||
* 响应的内容
|
||||
*/
|
||||
private String responseContext;
|
||||
private String responseContent;
|
||||
/**
|
||||
* 响应的消息类型
|
||||
*/
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package cn.axzo.riven.dingtalk.repository.mapper;
|
||||
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdApplication;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkConversation;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
package cn.axzo.riven.dingtalk.robot.connection.model;
|
||||
|
||||
import cn.axzo.riven.client.common.enums.DingTalkMsgTypeEnum;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import cn.axzo.riven.client.model.ReplyMessage;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 统一的回复上下文模型
|
||||
@ -11,50 +17,35 @@ import lombok.Data;
|
||||
* @since 2024-10-23 20:11
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
@Accessors(chain = true)
|
||||
public class ReplyContext {
|
||||
|
||||
/**
|
||||
* 会话级的 Webhook
|
||||
*/
|
||||
private String sessionWebhook;
|
||||
/**
|
||||
* 会话级的 Webhook 有效期
|
||||
*/
|
||||
private Date sessionWebhookExpiredDate;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
* 会话 ID
|
||||
*/
|
||||
private DingTalkMsgTypeEnum msgType = DingTalkMsgTypeEnum.sampleText;
|
||||
private String conversationId;
|
||||
|
||||
/**
|
||||
* 默认的消息类型下,可直接传入要发送的文本
|
||||
* 如果要使用其他 msgType,则用 data 属性进行传值
|
||||
* 回复的消息
|
||||
*/
|
||||
private String msgContent;
|
||||
private ReplyMessage replyMessage;
|
||||
|
||||
/**
|
||||
* 根据不同的 msgType 传入不同请求模型
|
||||
* 参考:{@see https://open.dingtalk.com/document/orgapp/types-of-messages-sent-by-robots}
|
||||
* 回复消息时需要被@的用户
|
||||
*/
|
||||
private JSONObject data;
|
||||
private List<String> atUserId;
|
||||
|
||||
private ReplyContext(String sessionWebhook, DingTalkMsgTypeEnum msgType, String msgContent, JSONObject data) {
|
||||
this.sessionWebhook = sessionWebhook;
|
||||
this.msgType = msgType;
|
||||
this.msgContent = msgContent;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static ReplyContext from(String msgContent) {
|
||||
return new ReplyContext(null, DingTalkMsgTypeEnum.sampleText, msgContent, null);
|
||||
}
|
||||
|
||||
public static ReplyContext from(String sessionWebhook, String msgContent) {
|
||||
return new ReplyContext(sessionWebhook, DingTalkMsgTypeEnum.sampleText, msgContent, null);
|
||||
}
|
||||
|
||||
public static ReplyContext from(DingTalkMsgTypeEnum msgType, JSONObject data) {
|
||||
return new ReplyContext(null, msgType, null, data);
|
||||
}
|
||||
|
||||
public static ReplyContext from(String sessionWebhook, DingTalkMsgTypeEnum msgType, JSONObject data) {
|
||||
return new ReplyContext(sessionWebhook, msgType, null, data);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package cn.axzo.riven.dingtalk.service;
|
||||
|
||||
import cn.axzo.riven.client.req.ThirdDingtalkConversationReq;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkConversation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 三方钉钉群会话信息
|
||||
*
|
||||
@ -15,4 +18,6 @@ public interface ThirdDingtalkConversationService {
|
||||
* @param conversation
|
||||
*/
|
||||
void upsert(ThirdDingtalkConversation conversation);
|
||||
|
||||
List<ThirdDingtalkConversation> genericQuery(ThirdDingtalkConversationReq req);
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package cn.axzo.riven.dingtalk.service;
|
||||
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkMessageRecord;
|
||||
|
||||
/**
|
||||
* 三方钉钉群消息记录
|
||||
*
|
||||
@ -7,4 +9,5 @@ package cn.axzo.riven.dingtalk.service;
|
||||
* @since 2024-10-23 19:48
|
||||
*/
|
||||
public interface ThirdDingtalkMessageRecordService {
|
||||
ThirdDingtalkMessageRecord insert(ThirdDingtalkMessageRecord record);
|
||||
}
|
||||
|
||||
@ -1,14 +1,21 @@
|
||||
package cn.axzo.riven.dingtalk.service.impl;
|
||||
|
||||
import cn.axzo.riven.client.common.enums.CommonStatusEnum;
|
||||
import cn.axzo.riven.client.common.enums.sync.Channel;
|
||||
import cn.axzo.riven.client.req.ThirdApplicationReq;
|
||||
import cn.axzo.riven.client.req.ThirdDingtalkConversationReq;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdApplication;
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkConversation;
|
||||
import cn.axzo.riven.dingtalk.repository.mapper.ThirdDingtalkConversationMapper;
|
||||
import cn.axzo.riven.dingtalk.repository.mapper.ThirdDingtalkMessageRecordMapper;
|
||||
import cn.axzo.riven.dingtalk.service.ThirdDingtalkConversationService;
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -24,14 +31,30 @@ public class ThirdDingtalkConversationServiceImpl implements ThirdDingtalkConver
|
||||
|
||||
@Override
|
||||
public void upsert(ThirdDingtalkConversation conversation) {
|
||||
if (Objects.nonNull(conversation.getConversationId())) {
|
||||
ThirdDingtalkConversation oldEntity = thirdDingtalkConversationMapper
|
||||
.selectOne(new LambdaQueryWrapper<ThirdDingtalkConversation>()
|
||||
.eq(ThirdDingtalkConversation::getConversationId, conversation.getConversationId()));
|
||||
BeanUtils.copyProperties(conversation, oldEntity);
|
||||
if (Objects.nonNull(oldEntity)) {
|
||||
BeanUtil.copyProperties(conversation, oldEntity, "id", "idDelete", "createAt", "updateAt");
|
||||
thirdDingtalkConversationMapper.updateById(oldEntity);
|
||||
} else {
|
||||
thirdDingtalkConversationMapper.insert(conversation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThirdDingtalkConversation> genericQuery(ThirdDingtalkConversationReq req) {
|
||||
return thirdDingtalkConversationMapper.selectList(buildQueryWrapper(req));
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ThirdDingtalkConversation> buildQueryWrapper(ThirdDingtalkConversationReq req) {
|
||||
return new LambdaQueryWrapper<ThirdDingtalkConversation>()
|
||||
.eq(StringUtils.hasText(req.getConversationId()), ThirdDingtalkConversation::getConversationId, req.getConversationId())
|
||||
.like(StringUtils.hasText(req.getConversationTitle()), ThirdDingtalkConversation::getConversationTitle, req.getConversationTitle())
|
||||
.eq(StringUtils.hasText(req.getConversationType()), ThirdDingtalkConversation::getConversationType, req.getConversationType())
|
||||
.eq(StringUtils.hasText(req.getChatbotCorpId()), ThirdDingtalkConversation::getChatbotCorpId, req.getChatbotCorpId())
|
||||
.eq(StringUtils.hasText(req.getChatbotUserId()), ThirdDingtalkConversation::getChatbotUserId, req.getChatbotUserId())
|
||||
.eq(StringUtils.hasText(req.getApplicationName()), ThirdDingtalkConversation::getApplicationName, req.getApplicationName())
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package cn.axzo.riven.dingtalk.service.impl;
|
||||
|
||||
import cn.axzo.riven.dingtalk.repository.entity.ThirdDingtalkMessageRecord;
|
||||
import cn.axzo.riven.dingtalk.repository.mapper.ThirdDingtalkMessageRecordMapper;
|
||||
import cn.axzo.riven.dingtalk.service.ThirdDingtalkMessageRecordService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
@ -13,4 +15,11 @@ import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class ThirdDingtalkMessageRecordServiceImpl implements ThirdDingtalkMessageRecordService {
|
||||
private final ThirdDingtalkMessageRecordMapper thirdDingtalkMessageRecordMapper;
|
||||
|
||||
@Override
|
||||
public ThirdDingtalkMessageRecord insert(ThirdDingtalkMessageRecord record) {
|
||||
thirdDingtalkMessageRecordMapper.insert(record);
|
||||
return record;
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,9 +26,10 @@ create table third_dingtalk_conversation
|
||||
primary key,
|
||||
conversation_id varchar(255) not null comment '会话ID',
|
||||
conversation_title varchar(255) not null comment '会话名称',
|
||||
conversation_type tinyint(1) not null comment '会话类型 1:单聊 2:群聊',
|
||||
conversation_type varchar(1) not null comment '会话类型 1:单聊 2:群聊',
|
||||
chatbot_corp_id varchar(255) not null comment '机器人所属企业',
|
||||
chatbot_user_id varchar(255) not null comment '机器人用户ID',
|
||||
application_name varchar(255) default '' not null comment '会话关联的应用名称',
|
||||
create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间',
|
||||
update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
|
||||
is_delete bigint default 0 not null comment '删除标志'
|
||||
@ -40,13 +41,16 @@ create table third_dingtalk_msg_record
|
||||
primary key,
|
||||
conversation_id varchar(255) not null comment '会话ID',
|
||||
conversation_title varchar(255) not null comment '会话名称',
|
||||
conversation_type tinyint(1) not null comment '会话类型 1:单聊 2:群聊',
|
||||
conversation_type varchar(1) not null comment '会话类型 1:单聊 2:群聊',
|
||||
msg_id varchar(255) not null comment '消息ID',
|
||||
sender_nick varchar(255) not null comment '发送人昵称',
|
||||
session_webhook varchar(255) not null comment '会话webhook url',
|
||||
session_webhook_expire_time datetime not null comment '会话webhook url过期时间',
|
||||
request_content varchar(255) not null comment '请求内容',
|
||||
sender_nick varchar(64) not null comment '发送人昵称',
|
||||
session_webhook varchar(512) not null comment '会话webhook url',
|
||||
session_webhook_expired_time datetime not null comment '会话webhook url过期时间',
|
||||
request_content varchar(4000) not null comment '请求内容',
|
||||
handle_type varchar(64) not null comment '处理类型',
|
||||
response_content varchar(4000) default '' not null comment '响应内容',
|
||||
response_msg_type varchar(255) default 'sampleText' not null comment '响应消息类型'
|
||||
response_msg_type varchar(32) default '' not null comment '响应消息类型',
|
||||
create_at datetime default CURRENT_TIMESTAMP not null comment '创建时间',
|
||||
update_at datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
|
||||
is_delete bigint default 0 not null comment '删除标志'
|
||||
) comment '钉钉群消息记录';
|
||||
Loading…
Reference in New Issue
Block a user