diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java index f068177..decba58 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/feign/MessageApi.java @@ -6,9 +6,11 @@ import cn.axzo.im.center.api.vo.req.CustomMessageInfo; import cn.axzo.im.center.api.vo.req.MessageInfo; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam; +import cn.axzo.im.center.api.vo.req.UpdateMessageRequest; import cn.axzo.im.center.api.vo.resp.MessageCustomResp; import cn.axzo.im.center.api.vo.resp.MessageDispatchResp; import cn.axzo.im.center.api.vo.resp.MessageTaskResp; +import cn.axzo.im.center.api.vo.resp.MessageUpdateResp; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -54,6 +56,12 @@ public interface MessageApi { @PostMapping("/api/im/template-message/async/send") ApiResult sendTemplateMessageAsync(@RequestBody @Validated SendTemplateMessageParam sendMessageParam); + /** + * 更新消息 + */ + @PostMapping("/api/im/template-message/updateMessage") + ApiResult updateMessage(@RequestBody @Validated UpdateMessageRequest request); + /** * * 接口已经作废,可以使用sendTemplateMessage来替换 diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java new file mode 100644 index 0000000..6c284b6 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/PersonAccountAttribute.java @@ -0,0 +1,46 @@ +package cn.axzo.im.center.api.vo; + +import cn.axzo.im.center.common.enums.AppTypeEnum; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * @author yanglin + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +// IMPORTANT: 不要删除这个注解, 避免@Data被@Setter, @Getter取代 +@EqualsAndHashCode +public class PersonAccountAttribute { + + /** + * 接收消息的personId + */ + @NotBlank(message = "personId不能为空") + private String personId; + + /** + * appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号, + * 所以需要根据organizationalUnitId获取账号 + */ + private Long ouId; + + /** + * 发送消息到App端 + * 工人端、企业端、服务器 + * CM、CMP、SYSTEM + * + * @See cn.axzo.im.center.common.enums.AppTypeEnum + */ + @NotNull(message = "appType不能为空") + private AppTypeEnum appType; + +} diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java index bd7bfe1..3188414 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/SendTemplateMessageParam.java @@ -1,18 +1,19 @@ package cn.axzo.im.center.api.vo.req; -import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.TemplatedMsgType; import com.alibaba.fastjson.JSONObject; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import lombok.NonNull; import javax.validation.Valid; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; +import java.util.HashSet; import java.util.List; +import java.util.Set; @Data @Builder @@ -25,7 +26,7 @@ public class SendTemplateMessageParam { */ @NotEmpty(message = "消息接收用户信息不能为空") @Valid - private List receivePersons; + private List receivePersons; /** * 消息标题 @@ -63,32 +64,16 @@ public class SendTemplateMessageParam { private Integer sendPriority; - @Data - @Builder - @AllArgsConstructor - @NoArgsConstructor - public static class ReceivePerson { + private TemplatedMsgType templatedMsgType = TemplatedMsgType.TEMPLATE; - /** - * 接收消息的personId - */ - @NotBlank(message = "personId不能为空") - private String personId; + private String updatableRefTemplateId; - /** - * appType = AppTypeEnum.CMP时,因为网易云信无法对同一个账号做企业隔离,只能一个企业一个账号, - * 所以需要根据organizationalUnitId获取账号 - */ - private Long ouId; - - /** - * 发送消息到App端 - * 工人端、企业端、服务器 - * CM、CMP、SYSTEM - * - * @See cn.axzo.im.center.common.enums.AppTypeEnum - */ - @NotNull(message = "appType不能为空") - private AppTypeEnum appType; + public boolean isUpdatable() { + return templatedMsgType.isUpdatable(); } + + public Set uniqueReceivePersons() { + return new HashSet<>(receivePersons); + } + } diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/UpdateMessageRequest.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/UpdateMessageRequest.java new file mode 100644 index 0000000..fcbe90d --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/req/UpdateMessageRequest.java @@ -0,0 +1,12 @@ +package cn.axzo.im.center.api.vo.req; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class UpdateMessageRequest { +} \ No newline at end of file diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/MessageTaskResp.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/MessageTaskResp.java index c73fc87..80cd969 100644 --- a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/MessageTaskResp.java +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/MessageTaskResp.java @@ -8,6 +8,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; +import java.util.List; @Data @Builder @@ -53,4 +54,6 @@ public class MessageTaskResp { private Date createAt; private Date updateAt; + + private List updatableMessageSendResults; } diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/MessageUpdateResp.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/MessageUpdateResp.java new file mode 100644 index 0000000..a9600d5 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/MessageUpdateResp.java @@ -0,0 +1,12 @@ +package cn.axzo.im.center.api.vo.resp; + +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class MessageUpdateResp { +} diff --git a/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UpdatableMessageSendResult.java b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UpdatableMessageSendResult.java new file mode 100644 index 0000000..5ca6951 --- /dev/null +++ b/im-center-api/src/main/java/cn/axzo/im/center/api/vo/resp/UpdatableMessageSendResult.java @@ -0,0 +1,15 @@ +package cn.axzo.im.center.api.vo.resp; + +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import lombok.Getter; +import lombok.Setter; + +/** + * @author yanglin + */ +@Setter +@Getter +public class UpdatableMessageSendResult { + private String bizMessageId; + private PersonAccountAttribute account; +} \ No newline at end of file diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java index 2ca7e81..62cf580 100644 --- a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/AppTypeEnum.java @@ -1,5 +1,6 @@ package cn.axzo.im.center.common.enums; +import cn.axzo.basics.common.constant.enums.CodeDefinition; import lombok.Getter; import org.apache.commons.lang3.StringUtils; @@ -14,7 +15,7 @@ import java.util.List; * @date 2023/10/9 16:01 */ @Getter -public enum AppTypeEnum { +public enum AppTypeEnum implements CodeDefinition { /** * 工人端 diff --git a/im-center-common/src/main/java/cn/axzo/im/center/common/enums/TemplatedMsgType.java b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/TemplatedMsgType.java new file mode 100644 index 0000000..685eb30 --- /dev/null +++ b/im-center-common/src/main/java/cn/axzo/im/center/common/enums/TemplatedMsgType.java @@ -0,0 +1,22 @@ +package cn.axzo.im.center.common.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * @author yanglin + */ +@Getter +@RequiredArgsConstructor +public enum TemplatedMsgType { + + TEMPLATE("template", "模板消息", false), + CARD("card", "卡片消息", true), + + ; + + private final String code; + private final String message; + private final boolean isUpdatable; + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java index d5f6442..2516e3c 100644 --- a/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java +++ b/im-center-server/src/main/java/cn/axzo/im/controller/MessageController.java @@ -11,9 +11,12 @@ import cn.axzo.im.center.api.vo.req.CustomMessageInfo; import cn.axzo.im.center.api.vo.req.MessageInfo; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam; +import cn.axzo.im.center.api.vo.req.UpdateMessageRequest; import cn.axzo.im.center.api.vo.resp.MessageCustomResp; import cn.axzo.im.center.api.vo.resp.MessageDispatchResp; import cn.axzo.im.center.api.vo.resp.MessageTaskResp; +import cn.axzo.im.center.api.vo.resp.MessageUpdateResp; +import cn.axzo.im.center.api.vo.resp.UpdatableMessageSendResult; import cn.axzo.im.center.api.vo.resp.UserAccountResp; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.entity.MessageTask; @@ -25,6 +28,7 @@ import cn.axzo.im.service.CustomMessageService; import cn.axzo.im.service.MessageHistoryService; import cn.axzo.im.service.MessageTaskService; import cn.axzo.im.service.RobotMsgTemplateService; +import cn.axzo.im.updatable.UpdatableMessageManager; import cn.axzo.pokonyan.exception.Aassert; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -38,10 +42,12 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -75,6 +81,8 @@ public class MessageController implements MessageApi { private MessageHistoryService messageHistoryService; @Autowired private CustomMessageService customMessageService; + @Autowired + private UpdatableMessageManager updatableMessageManager; @Override @@ -149,18 +157,22 @@ public class MessageController implements MessageApi { } @Override + @Transactional public ApiResult sendTemplateMessageAsync(SendTemplateMessageParam sendMessageParam) { String sendImAccount = check(sendMessageParam); MessageTask.BizData bizData = MessageTask.BizData.builder() .msgTemplateContent(sendMessageParam.getMsgTemplateContent()) .msgTemplateId(sendMessageParam.getMsgTemplateId()) + .templatedMsgType(sendMessageParam.getTemplatedMsgType()) .build(); Date now = new Date(); + List receivePersons = JSONArray.parseArray( + JSONObject.toJSONString(sendMessageParam.uniqueReceivePersons()), MessageTask.ReceivePerson.class); MessageTask messageTask = messageTaskService.create(MessageTask.builder() .bizId(sendMessageParam.getBizId()) .sendImAccount(sendImAccount) - .receivePersons(JSONArray.parseArray(JSONObject.toJSONString(sendMessageParam.getReceivePersons()), MessageTask.ReceivePerson.class)) + .receivePersons(receivePersons) .status(MessageTaskStatus.PENDING) .title(sendMessageParam.getMsgHeader()) .content(sendMessageParam.getMsgContent()) @@ -172,7 +184,19 @@ public class MessageController implements MessageApi { .determinePriority(sendMessageParam.getSendPriority())) .apiChannel(ApiChannel.COMMON_MESSAGE) .build()); - return ApiResult.ok(toMessageTaskResp(messageTask)); + List updatableMessageSendResults = Collections.emptyList(); + if (sendMessageParam.isUpdatable()) { + updatableMessageSendResults = updatableMessageManager.createUpdatableMessage(messageTask, sendMessageParam, receivePersons); + } + MessageTaskResp messageTaskResp = toMessageTaskResp(messageTask); + messageTaskResp.setUpdatableMessageSendResults(updatableMessageSendResults); + return ApiResult.ok(messageTaskResp); + } + + @Override + public ApiResult updateMessage(UpdateMessageRequest request) { + MessageUpdateResp resp = updatableMessageManager.updateMessage(request); + return ApiResult.ok(resp); } private void check(SendMessageParam sendMessageParam) { diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/BizDataMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/BizDataMapper.java deleted file mode 100644 index ddded85..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/BizDataMapper.java +++ /dev/null @@ -1,11 +0,0 @@ -package cn.axzo.im.dao.mapper; - -import cn.axzo.im.entity.BizData; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import org.springframework.stereotype.Repository; - -/** - * @author yanglin - */ -public interface BizDataMapper extends BaseMapper { -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/BizLogMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/BizLogMapper.java deleted file mode 100644 index dff7def..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/BizLogMapper.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.axzo.im.dao.mapper; - -import cn.axzo.im.entity.BizLog; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - * @author yanglin - */ -public interface BizLogMapper extends BaseMapper { -} diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/UpdatableMessageLogMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/UpdatableMessageLogMapper.java new file mode 100644 index 0000000..9a988cb --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/UpdatableMessageLogMapper.java @@ -0,0 +1,10 @@ +package cn.axzo.im.dao.mapper; + +import cn.axzo.im.entity.UpdatableMessageLog; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author yanglin + */ +public interface UpdatableMessageLogMapper extends BaseMapper { +} diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/mapper/UpdatableMessageMapper.java b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/UpdatableMessageMapper.java new file mode 100644 index 0000000..42bfe2f --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/mapper/UpdatableMessageMapper.java @@ -0,0 +1,10 @@ +package cn.axzo.im.dao.mapper; + +import cn.axzo.im.entity.UpdatableMessage; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * @author yanglin + */ +public interface UpdatableMessageMapper extends BaseMapper { +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/BizDataDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/BizDataDao.java deleted file mode 100644 index 945c1ab..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/BizDataDao.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.im.dao.repository; - -import cn.axzo.im.dao.mapper.BizDataMapper; -import cn.axzo.im.entity.BizData; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.stereotype.Repository; - -/** - * @author yanglin - */ -@Repository("bizDataDao") -public class BizDataDao extends ServiceImpl { -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/BizLogDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/BizLogDao.java deleted file mode 100644 index 7e8bd4e..0000000 --- a/im-center-server/src/main/java/cn/axzo/im/dao/repository/BizLogDao.java +++ /dev/null @@ -1,13 +0,0 @@ -package cn.axzo.im.dao.repository; - -import cn.axzo.im.dao.mapper.BizLogMapper; -import cn.axzo.im.entity.BizLog; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.stereotype.Repository; - -/** - * @author yanglin - */ -@Repository("bizLogDao") -public class BizLogDao extends ServiceImpl { -} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/UpdatableMessageDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/UpdatableMessageDao.java new file mode 100644 index 0000000..918292f --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/UpdatableMessageDao.java @@ -0,0 +1,26 @@ +package cn.axzo.im.dao.repository; + +import cn.axzo.im.dao.mapper.UpdatableMessageMapper; +import cn.axzo.im.entity.UpdatableMessage; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Repository; + +import java.util.Collections; +import java.util.List; + +/** + * @author yanglin + */ +@Repository("updatableMessageDao") +public class UpdatableMessageDao extends ServiceImpl { + + public List getByTaskIds(List taskIds) { + if (CollectionUtils.isEmpty(taskIds)) + return Collections.emptyList(); + return lambdaQuery() + .in(UpdatableMessage::getTaskId, taskIds) + .list(); + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/dao/repository/UpdatableMessageLogDao.java b/im-center-server/src/main/java/cn/axzo/im/dao/repository/UpdatableMessageLogDao.java new file mode 100644 index 0000000..8cc332f --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/dao/repository/UpdatableMessageLogDao.java @@ -0,0 +1,13 @@ +package cn.axzo.im.dao.repository; + +import cn.axzo.im.dao.mapper.UpdatableMessageLogMapper; +import cn.axzo.im.entity.UpdatableMessageLog; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Repository; + +/** + * @author yanglin + */ +@Repository("updatableMessageLogDao") +public class UpdatableMessageLogDao extends ServiceImpl { +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java index b4e91a1..3218233 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/MessageTask.java @@ -1,10 +1,11 @@ package cn.axzo.im.entity; +import cn.axzo.im.center.api.vo.ApiChannel; import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.center.common.enums.BizTypeEnum; +import cn.axzo.im.center.common.enums.TemplatedMsgType; import cn.axzo.im.config.BaseListTypeHandler; -import cn.axzo.im.center.api.vo.ApiChannel; import cn.axzo.im.enums.MessageTaskStatus; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.annotation.IdType; @@ -17,6 +18,7 @@ import com.google.common.collect.Table; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; @@ -115,6 +117,9 @@ public class MessageTask { @NoArgsConstructor @AllArgsConstructor public static class BizData { + + private TemplatedMsgType templatedMsgType = TemplatedMsgType.TEMPLATE; + private String msgTemplateId; /** @@ -151,12 +156,17 @@ public class MessageTask { * @See cn.axzo.im.center.common.enums.AppTypeEnum */ private List appTypes; + + public TemplatedMsgType determineTemplatedMsgType() { + return templatedMsgType == null ? TemplatedMsgType.TEMPLATE : templatedMsgType; + } } @Data @Builder @AllArgsConstructor @NoArgsConstructor + @EqualsAndHashCode public static class ReceivePerson { /** diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/BizData.java b/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessage.java similarity index 58% rename from im-center-server/src/main/java/cn/axzo/im/entity/BizData.java rename to im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessage.java index 7558742..16dd709 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/BizData.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessage.java @@ -1,7 +1,8 @@ package cn.axzo.im.entity; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; import cn.axzo.im.center.common.enums.AppTypeEnum; -import cn.axzo.im.utils.YesNo; +import cn.axzo.im.enums.UpdatableMessageState; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Getter; @@ -14,16 +15,19 @@ import java.util.Date; */ @Setter @Getter -@TableName(value = "im_biz_data", autoResultMap = true) -public class BizData { +@TableName(value = "im_updatable_message", autoResultMap = true) +public class UpdatableMessage { private Long id; + private String batchNo; + private String templateId; + private String refTemplateId; private String bizId; private Long taskId; - private Long receiverPersonId; + private String receiverPersonId; private Long receiverOuId; private AppTypeEnum appType; - private YesNo valid; + private UpdatableMessageState state; private String bizMessageId; private Long initHistoryId; private Long updateHistoryId; @@ -39,6 +43,14 @@ public class BizData { private Date createAt; private Date updateAt; + public PersonAccountAttribute parsePersonAccount() { + PersonAccountAttribute person = new PersonAccountAttribute(); + person.setPersonId(receiverPersonId); + person.setOuId(receiverOuId); + person.setAppType(appType); + return person; + } + @Getter @Setter public static class RecordExt { diff --git a/im-center-server/src/main/java/cn/axzo/im/entity/BizLog.java b/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessageLog.java similarity index 65% rename from im-center-server/src/main/java/cn/axzo/im/entity/BizLog.java rename to im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessageLog.java index 9257147..7522cd6 100644 --- a/im-center-server/src/main/java/cn/axzo/im/entity/BizLog.java +++ b/im-center-server/src/main/java/cn/axzo/im/entity/UpdatableMessageLog.java @@ -1,5 +1,7 @@ package cn.axzo.im.entity; +import cn.axzo.im.enums.UpdatableMessageLogLogType; +import cn.axzo.im.enums.UpdatableMessageState; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Getter; @@ -12,11 +14,13 @@ import java.util.Date; */ @Setter @Getter -@TableName(value = "im_biz_log", autoResultMap = true) -public class BizLog { +@TableName(value = "im_updatable_message_log", autoResultMap = true) +public class UpdatableMessageLog { private Long id; + private UpdatableMessageLogLogType type; private String bizId; private String bizMessageId; + private UpdatableMessageState messageState; private Long initHistoryId; private Long updateHistoryId; private JSONObject messageBody; diff --git a/im-center-server/src/main/java/cn/axzo/im/enums/UpdatableMessageLogLogType.java b/im-center-server/src/main/java/cn/axzo/im/enums/UpdatableMessageLogLogType.java new file mode 100644 index 0000000..632838b --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/enums/UpdatableMessageLogLogType.java @@ -0,0 +1,11 @@ +package cn.axzo.im.enums; + +/** + * @author yanglin + */ +public enum UpdatableMessageLogLogType { + + CREATE, + UPDATE + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/enums/UpdatableMessageState.java b/im-center-server/src/main/java/cn/axzo/im/enums/UpdatableMessageState.java new file mode 100644 index 0000000..c1faef3 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/enums/UpdatableMessageState.java @@ -0,0 +1,10 @@ +package cn.axzo.im.enums; + +/** + * @author yanglin + */ +public enum UpdatableMessageState { + CREATED, + INVALID, + VALID +} diff --git a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java index 885755d..d17e963 100644 --- a/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java +++ b/im-center-server/src/main/java/cn/axzo/im/job/CreateMessageHistoryJob.java @@ -34,7 +34,8 @@ public class CreateMessageHistoryJob extends IJobHandler { @Autowired private MessageTaskService messageTaskService; - private static final Integer DEFAULT_PAGE_SIZE = 500; + // 有数据量放大的可能, 设置小一些 + private static final Integer DEFAULT_PAGE_SIZE = 100; @Override @XxlJob("createMessageHistoryJob") diff --git a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java index 2594e67..1cb7460 100644 --- a/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java +++ b/im-center-server/src/main/java/cn/axzo/im/service/impl/MessageTaskServiceImpl.java @@ -4,11 +4,9 @@ import cn.axzo.im.center.api.vo.req.SendMessageParam; import cn.axzo.im.center.common.enums.AccountTypeEnum; import cn.axzo.im.center.common.enums.AppTypeEnum; import cn.axzo.im.channel.IMChannelProvider; -import cn.axzo.im.channel.netease.NimMsgTypeEnum; import cn.axzo.im.channel.netease.dto.MessageBody; import cn.axzo.im.dao.mapper.MessageTaskMapper; import cn.axzo.im.entity.AccountRegister; -import cn.axzo.im.entity.HistoryRecordExt; import cn.axzo.im.entity.MessageHistory; import cn.axzo.im.entity.MessageTask; import cn.axzo.im.enums.MessageHistoryStatus; @@ -17,6 +15,7 @@ import cn.axzo.im.service.AccountRegisterService.AccountRegisterDTO; import cn.axzo.im.service.AccountService; import cn.axzo.im.service.MessageHistoryService; import cn.axzo.im.service.MessageTaskService; +import cn.axzo.im.updatable.UpdatableMessageManager; import cn.axzo.im.utils.UUIDUtil; import cn.axzo.maokai.api.client.OrganizationalTeamOuRelationApi; import cn.axzo.maokai.api.vo.request.OrganizationalTeamOuRelationReq; @@ -64,6 +63,8 @@ public class MessageTaskServiceImpl extends ServiceImpl resolveMessageHistory(batchNo, messageTask, receivePerson, imAccounts, accountRegisters, ouIdMap)) .collect(Collectors.toList()); messageHistoryService.createBatch(messageHistories); + updatableMessageManager.onHistoryCreated(messageHistories); } private MessageHistory resolveMessageHistory(String batchNo, @@ -325,14 +328,14 @@ public class MessageTaskServiceImpl extends ServiceImpl defaultExtMap = Maps.newHashMap(); - MessageTask.BizData bizData = messageTask.getBizData(); if (StringUtils.isNotBlank(bizData.getMsgTemplateContent())) { messageBody.setMsgBody(bizData.getMsgTemplateContent()); defaultExtMap.put("msgTemplateId", bizData.getMsgTemplateId()); diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/InitHistories.java b/im-center-server/src/main/java/cn/axzo/im/updatable/InitHistories.java new file mode 100644 index 0000000..2811e4a --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/InitHistories.java @@ -0,0 +1,60 @@ +package cn.axzo.im.updatable; + +import cn.axzo.basics.common.constant.enums.CodeDefinition; +import cn.axzo.im.center.api.vo.PersonAccountAttribute; +import cn.axzo.im.center.common.enums.AppTypeEnum; +import cn.axzo.im.entity.MessageHistory; +import cn.axzo.im.entity.UpdatableMessage; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; + +/** + * @author yanglin + */ +class InitHistories { + + private final Map account2histories; + + InitHistories(List histories) { + this.account2histories = histories.stream() + .filter(history -> { + AppTypeEnum appType = CodeDefinition.findByCode( + AppTypeEnum.class, history.getAppType()).orElse(null); + return appType != null; + }) + .collect(toMap(history -> { + PersonAccountAttribute person = new PersonAccountAttribute(); + person.setPersonId(history.getReceivePersonId()); + person.setOuId(history.getReceiveOuId()); + person.setAppType(CodeDefinition.findByCode( + AppTypeEnum.class, history.getAppType()).orElse(null)); + return new HistoryTaskAccount(history.getImMessageTaskId(), person); + }, identity(), (oldValue, newValue) -> oldValue)); + } + + public Optional findHistory(UpdatableMessage message) { + HistoryTaskAccount account = new HistoryTaskAccount( + message.getTaskId(), message.parsePersonAccount()); + return Optional.ofNullable(account2histories.get(account)); + } + + @Setter + @Getter + @EqualsAndHashCode + // IMPORTANT: 不要删除这个注解 + @RequiredArgsConstructor + private static class HistoryTaskAccount { + final Long taskId; + final PersonAccountAttribute person; + } + +} \ No newline at end of file diff --git a/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java new file mode 100644 index 0000000..5dd8d97 --- /dev/null +++ b/im-center-server/src/main/java/cn/axzo/im/updatable/UpdatableMessageManager.java @@ -0,0 +1,139 @@ +package cn.axzo.im.updatable; + +import cn.axzo.im.center.api.vo.req.SendTemplateMessageParam; +import cn.axzo.im.center.api.vo.req.UpdateMessageRequest; +import cn.axzo.im.center.api.vo.resp.MessageUpdateResp; +import cn.axzo.im.center.api.vo.resp.UpdatableMessageSendResult; +import cn.axzo.im.dao.repository.UpdatableMessageDao; +import cn.axzo.im.dao.repository.UpdatableMessageLogDao; +import cn.axzo.im.entity.MessageHistory; +import cn.axzo.im.entity.MessageTask; +import cn.axzo.im.entity.MessageTask.ReceivePerson; +import cn.axzo.im.entity.UpdatableMessage; +import cn.axzo.im.entity.UpdatableMessageLog; +import cn.axzo.im.enums.MessageHistoryStatus; +import cn.axzo.im.enums.UpdatableMessageLogLogType; +import cn.axzo.im.enums.UpdatableMessageState; +import cn.axzo.im.utils.UUIDUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static java.util.stream.Collectors.toList; + +/** + * @author yanglin + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UpdatableMessageManager { + + private static final int BATCH_UPDATE_SIZE = 1000; + + private final UpdatableMessageDao updatableMessageDao; + private final UpdatableMessageLogDao updatableMessageLogDao; + + @Transactional + public List createUpdatableMessage( + MessageTask task, SendTemplateMessageParam request, List receivePersons) { + if (CollectionUtils.isEmpty(receivePersons)) return Collections.emptyList(); + String batchNo = UUIDUtil.uuidString(); + ArrayList sendResults = new ArrayList<>(); + ArrayList messages = new ArrayList<>(); + for (ReceivePerson person : receivePersons) { + UpdatableMessage message = new UpdatableMessage(); + messages.add(message); + message.setBatchNo(batchNo); + message.setTemplateId(request.getMsgTemplateId()); + message.setRefTemplateId(request.getUpdatableRefTemplateId()); + message.setBizId(request.getBizId()); + message.setTaskId(task.getId()); + message.setReceiverPersonId(person.getPersonId()); + message.setReceiverOuId(person.getOuId()); + message.setAppType(person.getAppType()); + message.setState(UpdatableMessageState.CREATED); + message.setBizMessageId(message.getBizMessageId()); + message.setDataVersion(1L); + + UpdatableMessageSendResult sendResult = new UpdatableMessageSendResult(); + sendResults.add(sendResult); + sendResult.setBizMessageId(message.getBizMessageId()); + sendResult.setAccount(message.parsePersonAccount()); + } + for (List batch : Lists.partition(messages, BATCH_UPDATE_SIZE)) + updatableMessageDao.saveBatch(batch); + + ArrayList logs = new ArrayList<>(); + for (UpdatableMessage message : messages) { + UpdatableMessageLog log = new UpdatableMessageLog(); + logs.add(log); + log.setType(UpdatableMessageLogLogType.CREATE); + log.setMessageState(UpdatableMessageState.CREATED); + log.setBizId(message.getBizId()); + log.setBizMessageId(message.getBizMessageId()); + log.setDataVersion(message.getDataVersion()); + } + for (List batch : Lists.partition(logs, BATCH_UPDATE_SIZE)) + updatableMessageLogDao.saveBatch(batch); + return sendResults; + } + + @Transactional + public void onHistoryCreated(List histories) { + if (CollectionUtils.isEmpty(histories)) return; + List taskIds = histories.stream() + .map(MessageHistory::getImMessageTaskId) + .distinct() + .collect(toList()); + List messages = updatableMessageDao.getByTaskIds(taskIds); + log.info("onHistoryCreated, taskIdSize={}, messageSize={}", taskIds.size(), messages.size()); + InitHistories initHistories = new InitHistories(histories); + ArrayList messageUpdates = new ArrayList<>(); + ArrayList messageLogUpdates = new ArrayList<>(); + for (UpdatableMessage message : messages) { + MessageHistory history = initHistories.findHistory(message).orElse(null); + if (history == null) continue; + String msgBodyJson = message.getMessageBody().getString("msgBody"); + JSONObject bizBody = JSON.parseObject(msgBodyJson); + + UpdatableMessage messageUpdate = new UpdatableMessage(); + messageUpdates.add(messageUpdate); + messageUpdate.setId(message.getId()); + messageUpdate.setInitHistoryId(history.getImMessageTaskId()); + messageUpdate.setMessageBody(message.getMessageBody()); + messageUpdate.setBizBody(bizBody); + messageUpdate.setState(history.getStatus() == MessageHistoryStatus.FAILED + ? UpdatableMessageState.INVALID + : UpdatableMessageState.VALID); + + UpdatableMessageLog messageLogUpdate = new UpdatableMessageLog(); + messageLogUpdates.add(messageLogUpdate); + messageLogUpdate.setMessageBody(message.getMessageBody()); + messageLogUpdate.setBizBody(bizBody); + messageLogUpdate.setInitHistoryId(history.getImMessageTaskId()); + messageLogUpdate.setMessageState(messageUpdate.getState()); + } + if (CollectionUtils.isNotEmpty(messageUpdates)) { + for (List batch : Lists.partition(messageUpdates, BATCH_UPDATE_SIZE)) + updatableMessageDao.updateBatchById(batch); + } + if (CollectionUtils.isNotEmpty(messageLogUpdates)) { + for (List batch : Lists.partition(messageLogUpdates, BATCH_UPDATE_SIZE)) + updatableMessageLogDao.updateBatchById(batch); + } + } + + public MessageUpdateResp updateMessage(UpdateMessageRequest request) { + return null; + } +} \ No newline at end of file