diff --git a/fw-hestia-common/src/main/java/cn/fw/hestia/common/constant/MessageStr.java b/fw-hestia-common/src/main/java/cn/fw/hestia/common/constant/MessageStr.java index 3e43254..8eb33b8 100644 --- a/fw-hestia-common/src/main/java/cn/fw/hestia/common/constant/MessageStr.java +++ b/fw-hestia-common/src/main/java/cn/fw/hestia/common/constant/MessageStr.java @@ -9,4 +9,6 @@ package cn.fw.hestia.common.constant; public interface MessageStr { String QUERY_FAILURE = "查询失败"; String SAVE_FAILURE = "操作失败"; + + String SUCCEED_STR = "succeed"; } diff --git a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/db/MessageHistory.java b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/db/MessageHistory.java index f059721..bd8e82f 100644 --- a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/db/MessageHistory.java +++ b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/db/MessageHistory.java @@ -1,6 +1,6 @@ package cn.fw.hestia.domain.db; -import cn.fw.hestia.domain.enums.SendStateEnum; +import cn.fw.hestia.domain.enums.MessageStateEnum; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.Data; @@ -65,7 +65,11 @@ public class MessageHistory extends Model { /** * 发送状态 */ - private SendStateEnum sendState; + private MessageStateEnum state; + /** + * 是否有效 + */ + private Boolean yn; /** * 创建时间 */ diff --git a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/enums/SendStateEnum.java b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/enums/MessageStateEnum.java index aebb318..d34b150 100644 --- a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/enums/SendStateEnum.java +++ b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/enums/MessageStateEnum.java @@ -11,15 +11,15 @@ import lombok.Getter; * @description : 发送状态 * @date: 2020-08-11 17:37 */ -public enum SendStateEnum implements IEnum { +public enum MessageStateEnum implements IEnum { /** - * 等待回调 + * 未处理 */ - OK(1, "发送成功"), + MADA(1, "未处理"), /** - * 完成回调 + * 已处理 */ - FAIL(2, "发送失败"), + SUMI(2, "已处理"), ; /** @@ -32,7 +32,7 @@ public enum SendStateEnum implements IEnum { @Getter private final String name; - SendStateEnum(final Integer value, final String name) { + MessageStateEnum(final Integer value, final String name) { this.value = value; this.name = name; } @@ -41,8 +41,8 @@ public enum SendStateEnum implements IEnum { * 根据枚举值获取枚举对象 */ @JsonCreator - public static SendStateEnum ofValue(final Integer value) { - for (final SendStateEnum stateEnum : SendStateEnum.values()) { + public static MessageStateEnum ofValue(final Integer value) { + for (final MessageStateEnum stateEnum : MessageStateEnum.values()) { if (stateEnum.value.equals(value)) { return stateEnum; } @@ -68,7 +68,7 @@ public enum SendStateEnum implements IEnum { */ @JsonCreator public static String getNameByVale(final Integer value) { - for (final SendStateEnum stateEnum : SendStateEnum.values()) { + for (final MessageStateEnum stateEnum : MessageStateEnum.values()) { if (stateEnum.value.equals(value)) { return stateEnum.getName(); } diff --git a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/Demo.java b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/Demo.java deleted file mode 100644 index e3b8f1b..0000000 --- a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/Demo.java +++ /dev/null @@ -1,10 +0,0 @@ -package cn.fw.hestia.domain.vo; - -/** - * @author : kurisu - * @className : Demo - * @description : - * @date: 2021-09-23 15:26 - */ -public class Demo { -} diff --git a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/HistoryQuery.java b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/HistoryQuery.java new file mode 100644 index 0000000..7572151 --- /dev/null +++ b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/HistoryQuery.java @@ -0,0 +1,22 @@ +package cn.fw.hestia.domain.vo; + +import cn.fw.common.page.BasePageQuery; +import cn.fw.common.web.annotation.LoginContextField; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * @author : kurisu + * @className : HistoryQuery + * @description : 查询条件 + * @date: 2021-09-25 10:45 + */ +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class HistoryQuery extends BasePageQuery { + + @LoginContextField(LoginContextField.Name.USER_ID) + private Long memberId; +} diff --git a/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/MessageHistoryVO.java b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/MessageHistoryVO.java new file mode 100644 index 0000000..f2db9f1 --- /dev/null +++ b/fw-hestia-domain/src/main/java/cn/fw/hestia/domain/vo/MessageHistoryVO.java @@ -0,0 +1,54 @@ +package cn.fw.hestia.domain.vo; + +import cn.fw.hestia.domain.db.MessageHistory; +import lombok.Data; +import lombok.ToString; + +import java.util.Date; +import java.util.Objects; + +/** + * @author : kurisu + * @className : Demo + * @description : + * @date: 2021-09-23 15:26 + */ +@Data +@ToString +public class MessageHistoryVO { + private Long messageId; + /** + * 会员id + */ + private Long memberId; + /** + * 消息内容 + */ + private String title; + /** + * 备注 + */ + private String remark; + /** + * 是否已读 + */ + private Boolean readz; + /** + * 发送时间 + */ + private Date messageTime; + + public static MessageHistoryVO with(MessageHistory history) { + if (Objects.isNull(history)) { + return null; + } + MessageHistoryVO vo = new MessageHistoryVO(); + vo.setMessageId(history.getId()); + vo.setMemberId(history.getMemberId()); + vo.setTitle(history.getTitle()); + vo.setReadz(history.getReadz()); + vo.setRemark(history.getRemark()); + vo.setMessageTime(history.getCreateTime()); + return vo; + } +} diff --git a/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/TemplateMessageService.java b/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/TemplateMessageService.java index 3f0bbdd..660db80 100644 --- a/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/TemplateMessageService.java +++ b/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/TemplateMessageService.java @@ -1,16 +1,16 @@ package cn.fw.hestia.rpc.passport; import cn.fw.data.base.domain.common.Message; +import cn.fw.hestia.common.constant.MessageStr; import cn.fw.hestia.common.utils.StringUtils; import cn.fw.hestia.rpc.passport.dto.TMParam; import cn.fw.passport.sdk.api.WxMpTemplateMessageApi; import cn.fw.passport.sdk.api.param.WxMpTempMessageData; import cn.fw.passport.sdk.api.param.WxMpTempMessageParam; -import lombok.Getter; +import com.alibaba.fastjson.JSONArray; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import java.util.Arrays; import java.util.List; /** @@ -31,12 +31,6 @@ public class TemplateMessageService { } /** - * 消息模板Code - */ - @Getter - private final String templateCode = "OPENTM412432053"; - - /** * 发送消息通知 * * @param messageParam @@ -46,34 +40,33 @@ public class TemplateMessageService { try { WxMpTempMessageParam param = new WxMpTempMessageParam(); param.setCusId(messageParam.getMemberId()); - param.setTempCode(getTemplateCode()); + param.setTempCode(messageParam.getTemplateCode()); WxMpTempMessageData remark = new WxMpTempMessageData(); remark.setValue(messageParam.getRemark()); - remark.setColor("#a61b29"); param.setRemark(remark); param.setTitle(new WxMpTempMessageData(messageParam.getTitle())); - List keywords = Arrays.asList( - new WxMpTempMessageData(messageParam.getChangeType()), - //门店 - new WxMpTempMessageData(messageParam.getChangeResult()) - //到期时间 - ); - param.setKeyWordList(keywords); - param.setPagePath(getPagePath(messageParam.getPath(), messageParam.getSceneToken())); + if (StringUtils.isValid(messageParam.getKeywords())) { + List keywords = JSONArray.parseArray(messageParam.getKeywords(), WxMpTempMessageData.class); + param.setKeyWordList(keywords); + } + String pagePath = getPagePath(messageParam.getPath(), messageParam.getSceneToken()); + if (StringUtils.isValid(pagePath)) { + param.setPagePath(pagePath); + } Message msg = wxMpTemplateMessageApi.send(param); if (!msg.isSuccess()) { log.error("【passport系统】发送模板消息失败:{}", msg.getResult()); return msg.getResult(); } - return ""; + return MessageStr.SUCCEED_STR; } catch (Exception e) { log.error("发送模板消息失败", e); - return "系统异常"; + return "系统调用异常"; } } - private String getPagePath(String path, String sceneToken) { + private String getPagePath(String path, Long sceneToken) { if (StringUtils.isEmpty(path)) { return null; } diff --git a/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/dto/TMParam.java b/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/dto/TMParam.java index 47f615e..a0b8937 100644 --- a/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/dto/TMParam.java +++ b/fw-hestia-rpc/src/main/java/cn/fw/hestia/rpc/passport/dto/TMParam.java @@ -28,26 +28,20 @@ public class TMParam { * 标题 */ private String title; + + private String keywords; /** * 备注 */ private String remark; - /** - * 变更类型 - */ - private String changeType; - /** - * 变更结果 - */ - private String changeResult; + /** * 如需跳转小程序,则是小程序页面路径 */ private String path; - /** - * 跳转小程序所携带的参数 - */ - private Map paramMap; - private String sceneToken; + + private Long sceneToken; + + private String templateCode; } diff --git a/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/api/IMessageCenterService.java b/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/api/IMessageCenterService.java index 47655af..6f4033a 100644 --- a/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/api/IMessageCenterService.java +++ b/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/api/IMessageCenterService.java @@ -3,10 +3,12 @@ package cn.fw.hestia.sdk.api; import cn.fw.data.base.domain.common.Message; import cn.fw.hestia.sdk.params.TemplateMessageParam; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import javax.validation.Valid; +import javax.validation.constraints.NotNull; /** * @author : kurisu @@ -16,19 +18,22 @@ import javax.validation.Valid; */ @FeignClient(value = "fw-hestia", path = "/api/hestia/mc") public interface IMessageCenterService { + /** - * 异步发送模板消息 + * 发送模板消息 + * * @param templateMessageParam * @return */ - @PostMapping("/asynSend") - Message asynSend(@Valid @RequestBody TemplateMessageParam templateMessageParam); + @PostMapping("/send") + Message send(@Valid @RequestBody TemplateMessageParam templateMessageParam); /** - * 同步 - * @param templateMessageParam + * 撤回消息 + * + * @param sceneToken * @return */ - @PostMapping("/send") - Message send(@Valid @RequestBody TemplateMessageParam templateMessageParam); + @DeleteMapping("/send") + Message revokeMessage(@NotNull(message = "Token不能为空") Long sceneToken); } diff --git a/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/params/TemplateMessageParam.java b/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/params/TemplateMessageParam.java index bbb332e..1320280 100644 --- a/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/params/TemplateMessageParam.java +++ b/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/params/TemplateMessageParam.java @@ -3,6 +3,8 @@ package cn.fw.hestia.sdk.params; import lombok.Data; import lombok.ToString; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; import java.util.Map; /** @@ -15,6 +17,12 @@ import java.util.Map; * 变更结果:{{keyword2.DATA}} * {{remark.DATA}} * + * 示例: + * 尊敬的客户,您的业务状态已经发生变更 变更详情如下: + * 变更类型:组局地点 + * 变更结果:由清水河改为滨江 + * 如有疑问,请拨打客服电话 + * * @author kurisu */ @Data @@ -23,10 +31,12 @@ public class TemplateMessageParam { /** * 会员id */ + @NotNull(message = "会员id不能为空") private Long memberId; /** - * 标题 对应「first」字段 + * 标题内容 对应「first」字段 */ + @NotBlank(message = "标题内容不能为空") private String title; /** * 备注 @@ -35,10 +45,12 @@ public class TemplateMessageParam { /** * 变更类型 */ + @NotBlank(message = "变更类型不能为空") private String changeType; /** * 变更结果 */ + @NotBlank(message = "变更结果不能为空") private String changeResult; /** * 如需跳转小程序,则是小程序页面路径 diff --git a/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/result/MessageSendMq.java b/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/result/MessageSendMq.java new file mode 100644 index 0000000..32cd6f2 --- /dev/null +++ b/fw-hestia-sdk/src/main/java/cn/fw/hestia/sdk/result/MessageSendMq.java @@ -0,0 +1,28 @@ +package cn.fw.hestia.sdk.result; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @author : kurisu + * @className : MessageSendMQ + * @description : 消息发送成功的通知 + * @date: 2021-09-25 09:27 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class MessageSendMq { + public final static String TOPIC = "message_send"; + /** + * 唯一标识 + */ + private Long sceneToken; + /** + * 发送时间 + */ + private Date sendTime; +} diff --git a/fw-hestia-server/src/main/java/cn/fw/hestia/server/controller/api/MessageCenterServiceImpl.java b/fw-hestia-server/src/main/java/cn/fw/hestia/server/controller/api/MessageCenterServiceImpl.java index 77f6f3a..a05855f 100644 --- a/fw-hestia-server/src/main/java/cn/fw/hestia/server/controller/api/MessageCenterServiceImpl.java +++ b/fw-hestia-server/src/main/java/cn/fw/hestia/server/controller/api/MessageCenterServiceImpl.java @@ -4,13 +4,15 @@ import cn.fw.common.web.annotation.ControllerMethod; import cn.fw.data.base.domain.common.Message; import cn.fw.hestia.sdk.api.IMessageCenterService; import cn.fw.hestia.sdk.params.TemplateMessageParam; +import cn.fw.hestia.service.buz.MessageCenterBizService; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import static cn.fw.common.web.util.ResultBuilder.success; /** * @author : kurisu @@ -22,18 +24,24 @@ import javax.validation.Valid; @RestController @RequestMapping("/api/hestia/mc") public class MessageCenterServiceImpl implements IMessageCenterService { + private final MessageCenterBizService messageCenterBizService; - @PostMapping("/asynSend") - @Override - @ControllerMethod("保存进站记录") - public Message asynSend(@Valid @RequestBody TemplateMessageParam templateMessageParam) { - return null; + @Autowired + public MessageCenterServiceImpl(final MessageCenterBizService messageCenterBizService) { + this.messageCenterBizService = messageCenterBizService; } @PostMapping("/send") @Override - @ControllerMethod("保存进站记录") + @ControllerMethod("发送模板消息") public Message send(@Valid @RequestBody TemplateMessageParam templateMessageParam) { - return null; + return success(messageCenterBizService.saveMessage(templateMessageParam)); + } + + @Override + @DeleteMapping("/revoke") + @ControllerMethod("撤回消息") + public Message revokeMessage(@NotNull(message = "Token不能为空") Long sceneToken) { + return success(messageCenterBizService.revokeMessage(sceneToken)); } } diff --git a/fw-hestia-server/src/main/java/cn/fw/hestia/server/controller/wx/MessageCenterController.java b/fw-hestia-server/src/main/java/cn/fw/hestia/server/controller/wx/MessageCenterController.java new file mode 100644 index 0000000..243fd79 --- /dev/null +++ b/fw-hestia-server/src/main/java/cn/fw/hestia/server/controller/wx/MessageCenterController.java @@ -0,0 +1,61 @@ +package cn.fw.hestia.server.controller.wx; + +import cn.fw.common.page.AppPage; +import cn.fw.common.web.annotation.ControllerMethod; +import cn.fw.common.web.auth.PassportAuthBean; +import cn.fw.common.web.auth.annotation.CurrentUser; +import cn.fw.data.base.domain.common.Message; +import cn.fw.hestia.domain.vo.HistoryQuery; +import cn.fw.hestia.domain.vo.MessageHistoryVO; +import cn.fw.hestia.service.buz.MessageCenterBizService; +import cn.fw.security.auth.client.annotation.Authorization; +import cn.fw.security.auth.client.enums.AuthType; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.constraints.NotNull; +import java.util.Map; + +import static cn.fw.common.web.util.ResultBuilder.success; + +/** + * @author : kurisu + * @className : MessageCenterController + * @description : + * @date: 2021-09-23 15:39 + */ +@Slf4j +@Validated +@RestController +@Authorization(AuthType.WECHAT) +@RequestMapping("/wx/message") +public class MessageCenterController { + private final MessageCenterBizService messageCenterBizService; + + @Autowired + public MessageCenterController(final MessageCenterBizService messageCenterBizService) { + this.messageCenterBizService = messageCenterBizService; + } + + @GetMapping("/unread") + @ControllerMethod("查询消息未读数") + public Message send(@CurrentUser PassportAuthBean user) { + return success(messageCenterBizService.unreadCount(user.getUserId())); + } + + @GetMapping("/query/pageParams") + @ControllerMethod("查询小程序页面的参数") + public Message> queryPageParams(@NotNull(message = "sceneToken不能为空") final Long sceneToken) { + return success(messageCenterBizService.queryPageParams(sceneToken)); + } + + @GetMapping("/query/history") + @ControllerMethod("查询消息历史记录") + public Message> queryHistory(HistoryQuery query) { + return success(messageCenterBizService.queryHistory(query)); + } +} diff --git a/fw-hestia-server/src/main/java/cn/fw/hestia/server/task/SendMessageTask.java b/fw-hestia-server/src/main/java/cn/fw/hestia/server/task/SendMessageTask.java new file mode 100644 index 0000000..c625ccb --- /dev/null +++ b/fw-hestia-server/src/main/java/cn/fw/hestia/server/task/SendMessageTask.java @@ -0,0 +1,58 @@ +package cn.fw.hestia.server.task; + +import cn.fw.hestia.domain.db.MessageHistory; +import cn.fw.hestia.domain.enums.MessageStateEnum; +import cn.fw.hestia.service.buz.MessageCenterBizService; +import cn.fw.hestia.service.data.MessageHistoryService; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.Date; +import java.util.List; + +/** + * @author : kurisu + * @className : FollowNoticeTask + * @description : 服务号消息定时任务 + * @date: 2020-08-25 16:57 + */ +@Component +@ConditionalOnProperty(prefix = "task", name = "switch", havingValue = "on") +public class SendMessageTask { + private final MessageCenterBizService messageCenterBizService; + private final MessageHistoryService messageHistoryService; + + private final static int MAX_FREQUENCY = 5; + + @Autowired + public SendMessageTask(final MessageCenterBizService messageCenterBizService, + final MessageHistoryService messageHistoryService) { + this.messageCenterBizService = messageCenterBizService; + this.messageHistoryService = messageHistoryService; + } + + /** + * 发送模板消息 + */ + @Scheduled(initialDelay = 1000 * 10, fixedRate = 1000 * 10) + @Transactional(rollbackFor = Exception.class) + public void sendNotice() { + List list = messageHistoryService.list(Wrappers.lambdaQuery() + .eq(MessageHistory::getState, MessageStateEnum.MADA) + .eq(MessageHistory::getYn, Boolean.TRUE) + .lt(MessageHistory::getFrequency, MAX_FREQUENCY) + .lt(MessageHistory::getSendTime, new Date()) + ); + if (CollectionUtils.isEmpty(list)) { + return; + } + for (MessageHistory history : list) { + messageCenterBizService.sendMessage(history); + } + } +} diff --git a/fw-hestia-server/src/main/resources/application.yml b/fw-hestia-server/src/main/resources/application.yml index 7b2426f..8ffddf7 100644 --- a/fw-hestia-server/src/main/resources/application.yml +++ b/fw-hestia-server/src/main/resources/application.yml @@ -37,7 +37,7 @@ spring: max-wait: 1S min-idle: 3 port: 6379 - database: 3 + database: 4 rest-result-processor: enabled: false servlet: @@ -91,7 +91,7 @@ jedis: test-while-idle: true host: 192.168.0.8 port: 6379 - db: 3 + db: 4 mybatis-plus: configuration: cache-enabled: false diff --git a/fw-hestia-service/src/main/java/cn/fw/hestia/component/SendMsgProducer.java b/fw-hestia-service/src/main/java/cn/fw/hestia/component/SendMsgProducer.java new file mode 100644 index 0000000..262b0e7 --- /dev/null +++ b/fw-hestia-service/src/main/java/cn/fw/hestia/component/SendMsgProducer.java @@ -0,0 +1,28 @@ +package cn.fw.hestia.component; + +import cn.fw.hestia.sdk.result.MessageSendMq; +import lombok.extern.slf4j.Slf4j; +import org.apache.rocketmq.spring.core.RocketMQTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * @author kurisu + */ +@Slf4j +@Component +public class SendMsgProducer { + @Autowired + private RocketMQTemplate rocketMQTemplate; + + @RequestMapping(value = "send") + public void send(MessageSendMq messageSendMq) { + try { + log.info("模板消息发送成功mq: body:[{}]", messageSendMq); + rocketMQTemplate.syncSend(MessageSendMq.TOPIC + ":*", messageSendMq); + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/fw-hestia-service/src/main/java/cn/fw/hestia/service/buz/MessageCenterBizService.java b/fw-hestia-service/src/main/java/cn/fw/hestia/service/buz/MessageCenterBizService.java new file mode 100644 index 0000000..6a02c95 --- /dev/null +++ b/fw-hestia-service/src/main/java/cn/fw/hestia/service/buz/MessageCenterBizService.java @@ -0,0 +1,211 @@ +package cn.fw.hestia.service.buz; + +import cn.fw.common.data.mybatis.pagination.PageData; +import cn.fw.common.page.AppPage; +import cn.fw.hestia.common.constant.MessageStr; +import cn.fw.hestia.common.utils.DateUtil; +import cn.fw.hestia.common.utils.StringUtils; +import cn.fw.hestia.component.SendMsgProducer; +import cn.fw.hestia.domain.db.MessageHistory; +import cn.fw.hestia.domain.db.SendLog; +import cn.fw.hestia.domain.enums.MessageStateEnum; +import cn.fw.hestia.domain.vo.HistoryQuery; +import cn.fw.hestia.domain.vo.MessageHistoryVO; +import cn.fw.hestia.rpc.passport.TemplateMessageService; +import cn.fw.hestia.rpc.passport.dto.TMParam; +import cn.fw.hestia.sdk.params.TemplateMessageParam; +import cn.fw.hestia.sdk.result.MessageSendMq; +import cn.fw.hestia.service.data.MessageHistoryService; +import cn.fw.hestia.service.data.SendLogService; +import cn.fw.passport.sdk.api.param.WxMpTempMessageData; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +import static cn.fw.common.businessvalidator.Validator.BV; + +/** + * @author : kurisu + * @className : MessageCenterBizService + * @description : 消息中心处理类 + * @date: 2021-09-24 17:10 + */ +@Service +@RequiredArgsConstructor +@Slf4j +public class MessageCenterBizService { + private final MessageHistoryService messageHistoryService; + private final SendLogService sendLogService; + private final TemplateMessageService templateMessageService; + private final SendMsgProducer sendMsgProducer; + + /** + * 消息模板Code + */ + @Getter + private final String templateCode = "OPENTM412432053"; + + /** + * 发送 + * + * @param templateMessageParam + * @return token + */ + @Transactional(rollbackFor = Exception.class) + public Long saveMessage(TemplateMessageParam templateMessageParam) { + MessageHistory messageHistory = createBean(templateMessageParam); + messageHistoryService.save(messageHistory); + return messageHistory.getId(); + } + + + /** + * 发送模板消息 + * + * @param history + */ + @Transactional(rollbackFor = Exception.class) + public void sendMessage(MessageHistory history) { + TMParam tmParam = createTmParam(history); + String result = templateMessageService.sendTemplateMessage(tmParam); + boolean succeed = MessageStr.SUCCEED_STR.equals(result); + final int frequency = history.getFrequency() + 1; + history.setFrequency(frequency); + if (succeed) { + history.setState(MessageStateEnum.SUMI); + //发送成功发送mq + sendMsgProducer.send(new MessageSendMq(history.getId(), new Date())); + } else { + history.setSendTime(DateUtil.getExpired(history.getSendTime(), 1 << frequency, Calendar.MINUTE)); + } + messageHistoryService.updateById(history); + SendLog sendLog = new SendLog(); + sendLog.setMessageId(history.getId()); + sendLog.setSendTime(new Date()); + sendLog.setSucceed(succeed); + sendLog.setResult(result); + sendLogService.save(sendLog); + } + + /** + * 撤回消息 + * + * @param sceneToken + * @return + */ + @Transactional(rollbackFor = Exception.class) + public Boolean revokeMessage(Long sceneToken) { + MessageHistory history = messageHistoryService.getById(sceneToken); + if (Objects.isNull(history)) { + return Boolean.TRUE; + } + history.setYn(Boolean.FALSE); + return messageHistoryService.updateById(history); + } + + /** + * 查询未读数 + * + * @param memberId + * @return + */ + public int unreadCount(Long memberId) { + return messageHistoryService.count(Wrappers.lambdaQuery() + .eq(MessageHistory::getMemberId, memberId) + .eq(MessageHistory::getReadz, Boolean.FALSE) + .eq(MessageHistory::getYn, Boolean.TRUE) + ); + } + + /** + * 查询页面所需参数 + * + * @param sceneToken + * @return + */ + public Map queryPageParams(Long sceneToken) { + MessageHistory history = messageHistoryService.getById(sceneToken); + BV.notNull(history, () -> "消息不存在或者已经被撤销"); + readMessage(history); + String pageParams = history.getPageParams(); + if (StringUtils.isEmpty(pageParams)) { + return new HashMap<>(0); + } + return JSON.>parseObject(pageParams, HashMap.class); + } + + /** + * 查询历史消息记录 + * @param query + * @return + */ + public AppPage queryHistory(HistoryQuery query) { + PageData pageData = messageHistoryService.page(new PageData<>(query), Wrappers.lambdaQuery() + .eq(MessageHistory::getMemberId, query.getMemberId()) + .eq(MessageHistory::getYn, Boolean.TRUE) + .orderByDesc(MessageHistory::getCreateTime) + ); + AppPage page = AppPage.empty(query); + page.setCurrent((int) pageData.getCurrent()); + page.setPageSize((int) pageData.getSize()); + page.setTotal(pageData.getTotal()); + page.setData(new ArrayList<>()); + if (!CollectionUtils.isEmpty(pageData.getRecords())) { + List voList = pageData.getRecords().stream().map(MessageHistoryVO::with).collect(Collectors.toList()); + page.setData(voList); + } + return page; + } + + @Transactional(rollbackFor = Exception.class) + protected void readMessage(MessageHistory history) { + if (Boolean.FALSE.equals(history.getReadz())) { + history.setReadz(Boolean.TRUE); + messageHistoryService.updateById(history); + } + } + + private MessageHistory createBean(TemplateMessageParam param) { + MessageHistory messageHistory = new MessageHistory(); + messageHistory.setMemberId(param.getMemberId()); + messageHistory.setTemplateCode(getTemplateCode()); + messageHistory.setTitle(param.getTitle()); + messageHistory.setRemark(param.getRemark()); + messageHistory.setPagePath(param.getPath()); + messageHistory.setReadz(Boolean.FALSE); + messageHistory.setFrequency(0); + messageHistory.setYn(Boolean.TRUE); + messageHistory.setSendTime(new Date()); + messageHistory.setState(MessageStateEnum.MADA); + List keywords = Arrays.asList( + new WxMpTempMessageData(param.getChangeType()), + new WxMpTempMessageData(param.getChangeResult()) + ); + messageHistory.setKeywords(JSONArray.toJSONString(keywords)); + if (!CollectionUtils.isEmpty(param.getParamMap())) { + messageHistory.setPageParams(JSON.toJSONString(param.getParamMap())); + } + return messageHistory; + } + + private TMParam createTmParam(MessageHistory history) { + TMParam tmParam = new TMParam(); + tmParam.setSceneToken(history.getId()); + tmParam.setTitle(history.getTitle()); + tmParam.setRemark(history.getRemark()); + tmParam.setPath(history.getPagePath()); + tmParam.setTemplateCode(history.getTemplateCode()); + tmParam.setMemberId(history.getMemberId()); + tmParam.setKeywords(history.getKeywords()); + return tmParam; + } +} diff --git a/fw-hestia-service/src/main/java/cn/fw/hestia/service/MessageHistoryService.java b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/MessageHistoryService.java index 6841d4e..f17796e 100644 --- a/fw-hestia-service/src/main/java/cn/fw/hestia/service/MessageHistoryService.java +++ b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/MessageHistoryService.java @@ -1,4 +1,4 @@ -package cn.fw.hestia.service; +package cn.fw.hestia.service.data; import cn.fw.hestia.domain.db.MessageHistory; import com.baomidou.mybatisplus.extension.service.IService; diff --git a/fw-hestia-service/src/main/java/cn/fw/hestia/service/SendLogService.java b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/SendLogService.java index dc64cfa..0efc66d 100644 --- a/fw-hestia-service/src/main/java/cn/fw/hestia/service/SendLogService.java +++ b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/SendLogService.java @@ -1,4 +1,4 @@ -package cn.fw.hestia.service; +package cn.fw.hestia.service.data; import cn.fw.hestia.domain.db.SendLog; import com.baomidou.mybatisplus.extension.service.IService; diff --git a/fw-hestia-service/src/main/java/cn/fw/hestia/service/impl/MessageHistoryServiceImpl.java b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/impl/MessageHistoryServiceImpl.java index d61641f..17240fa 100644 --- a/fw-hestia-service/src/main/java/cn/fw/hestia/service/impl/MessageHistoryServiceImpl.java +++ b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/impl/MessageHistoryServiceImpl.java @@ -1,8 +1,8 @@ -package cn.fw.hestia.service.impl; +package cn.fw.hestia.service.data.impl; import cn.fw.hestia.dao.MessageHistoryDao; import cn.fw.hestia.domain.db.MessageHistory; -import cn.fw.hestia.service.MessageHistoryService; +import cn.fw.hestia.service.data.MessageHistoryService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; diff --git a/fw-hestia-service/src/main/java/cn/fw/hestia/service/impl/SendLogServiceImpl.java b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/impl/SendLogServiceImpl.java index 2ee4c3d..e52d107 100644 --- a/fw-hestia-service/src/main/java/cn/fw/hestia/service/impl/SendLogServiceImpl.java +++ b/fw-hestia-service/src/main/java/cn/fw/hestia/service/data/impl/SendLogServiceImpl.java @@ -1,8 +1,8 @@ -package cn.fw.hestia.service.impl; +package cn.fw.hestia.service.data.impl; import cn.fw.hestia.dao.SendLogDao; import cn.fw.hestia.domain.db.SendLog; -import cn.fw.hestia.service.SendLogService; +import cn.fw.hestia.service.data.SendLogService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service;