diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/NotifyMessageController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/NotifyMessageController.java index aec4236d9..3a6fcb0a2 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/NotifyMessageController.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/NotifyMessageController.java @@ -19,6 +19,10 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import static com.cf.imes.framework.common.pojo.CommonResult.success; import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @@ -56,9 +60,18 @@ public class NotifyMessageController { @GetMapping("/my-page") @Operation(summary = "获得我的站内信分页") public CommonResult> getMyMyNotifyMessagePage(@Valid NotifyMessageMyPageReqVO pageVO) { + Long loginUserId = getLoginUserId(); + if(!Objects.isNull(pageVO.getReadStatus())) { + return success(notifyMessageService.getPageResultByRead(pageVO)); + } PageResult pageResult = notifyMessageService.getMyMyNotifyMessagePage(pageVO, - getLoginUserId(), UserTypeEnum.ADMIN.getValue()); - return success(BeanUtils.toBean(pageResult, NotifyMessageRespVO.class)); + loginUserId, UserTypeEnum.ADMIN.getValue()); + PageResult respVOPageResult = BeanUtils.toBean(pageResult, NotifyMessageRespVO.class); + Set messageRead = notifyMessageService.getMessageRead(pageResult.getList().stream().map(e -> String.valueOf(e.getId())).collect(Collectors.toSet()), loginUserId); + respVOPageResult.getList().forEach(e->{ + e.setReadStatus(messageRead.contains(e.getId().toString())); + }); + return success(respVOPageResult); } @PutMapping("/update-read") diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java index 33ed0e533..3098145a2 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/message/NotifyMessageRespVO.java @@ -38,7 +38,7 @@ public class NotifyMessageRespVO { private Map templateParams; @Schema(description = "是否已读", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") - private Boolean readStatus; + private boolean readStatus; @Schema(description = "阅读时间") private LocalDateTime readTime; diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java index b4bd628c9..c0289f3be 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/notify/vo/template/NotifyTemplateSendReqVO.java @@ -12,12 +12,12 @@ import java.util.Map; public class NotifyTemplateSendReqVO { @Schema(description = "用户id", requiredMode = Schema.RequiredMode.REQUIRED, example = "01") - @NotNull(message = "用户id不能为空") - private Long userId; + //@NotNull(message = "用户id不能为空") + private Long userId = 0L; @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - @NotNull(message = "用户类型不能为空") - private Integer userType; + //@NotNull(message = "用户类型不能为空") + private Integer userType = 2; @Schema(description = "模板编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "01") @NotEmpty(message = "模板编码不能为空") diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notify/NotifyMessageDO.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notify/NotifyMessageDO.java index dc892b69c..7476e0ba5 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notify/NotifyMessageDO.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/dataobject/notify/NotifyMessageDO.java @@ -88,9 +88,9 @@ public class NotifyMessageDO extends BaseDO { // ========= 读取相关字段 ========= /** - * 是否已读 + * 是否已读 现在这个状态存在redis中,所以先注释此字段 */ - private Boolean readStatus; + /*private Boolean readStatus;*/ /** * 阅读时间 */ diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notify/NotifyMessageMapper.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notify/NotifyMessageMapper.java index 64b67c473..7a894c32f 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notify/NotifyMessageMapper.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/mysql/notify/NotifyMessageMapper.java @@ -10,6 +10,7 @@ import com.cf.imes.module.system.dal.dataobject.notify.NotifyMessageDO; import org.apache.ibatis.annotations.Mapper; import java.time.LocalDateTime; +import java.util.Arrays; import java.util.Collection; import java.util.List; @@ -28,33 +29,33 @@ public interface NotifyMessageMapper extends BaseMapperX { default PageResult selectPage(NotifyMessageMyPageReqVO reqVO, Long userId, Integer userType) { return selectPage(reqVO, new LambdaQueryWrapperX() - .eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus()) + //.eqIfPresent(NotifyMessageDO::getReadStatus, reqVO.getReadStatus()) .betweenIfPresent(NotifyMessageDO::getCreateTime, reqVO.getCreateTime()) - .eq(NotifyMessageDO::getUserId, userId) + .in(NotifyMessageDO::getUserId, Arrays.asList(userId, 0L)) .eq(NotifyMessageDO::getUserType, userType) .orderByDesc(NotifyMessageDO::getId)); } default int updateListRead(Collection ids, Long userId, Integer userType) { - return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()), + return update(new NotifyMessageDO().setReadTime(LocalDateTime.now()), new LambdaQueryWrapperX() .in(NotifyMessageDO::getId, ids) .eq(NotifyMessageDO::getUserId, userId) - .eq(NotifyMessageDO::getUserType, userType) - .eq(NotifyMessageDO::getReadStatus, false)); + .eq(NotifyMessageDO::getUserType, userType)); + //.eq(NotifyMessageDO::getReadStatus, false)); } default int updateListRead(Long userId, Integer userType) { - return update(new NotifyMessageDO().setReadStatus(true).setReadTime(LocalDateTime.now()), + return update(new NotifyMessageDO().setReadTime(LocalDateTime.now()), new LambdaQueryWrapperX() .eq(NotifyMessageDO::getUserId, userId) - .eq(NotifyMessageDO::getUserType, userType) - .eq(NotifyMessageDO::getReadStatus, false)); + .eq(NotifyMessageDO::getUserType, userType)); + //.eq(NotifyMessageDO::getReadStatus, false)); } default List selectUnreadListByUserIdAndUserType(Long userId, Integer userType, Integer size) { return selectList(new QueryWrapperX() // 由于要使用 limitN 语句,所以只能用 QueryWrapperX - .eq("user_id", userId) + .in("user_id", Arrays.asList(userId, 0L)) .eq("user_type", userType) .eq("read_status", false) .orderByDesc("id").limitN(size)); @@ -62,8 +63,8 @@ public interface NotifyMessageMapper extends BaseMapperX { default Long selectUnreadCountByUserIdAndUserType(Long userId, Integer userType) { return selectCount(new LambdaQueryWrapperX() - .eq(NotifyMessageDO::getReadStatus, false) - .eq(NotifyMessageDO::getUserId, userId) + //.eq(NotifyMessageDO::getReadStatus, false) + .in(NotifyMessageDO::getUserId, Arrays.asList(userId, 0L)) .eq(NotifyMessageDO::getUserType, userType)); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageService.java index 9db7c6cc8..1dfe7a98a 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageService.java @@ -3,12 +3,14 @@ package com.cf.imes.module.system.service.notify; import com.cf.imes.framework.common.pojo.PageResult; import com.cf.imes.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; import com.cf.imes.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import com.cf.imes.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO; import com.cf.imes.module.system.dal.dataobject.notify.NotifyMessageDO; import com.cf.imes.module.system.dal.dataobject.notify.NotifyTemplateDO; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; /** * 站内信 Service 接口 @@ -17,6 +19,8 @@ import java.util.Map; */ public interface NotifyMessageService { + String NOTIFY_MESSAGE_KEY = "notify-message:"; + /** * 创建站内信 * @@ -94,4 +98,18 @@ public interface NotifyMessageService { */ int updateAllNotifyMessageRead(Long userId, Integer userType); + /** + * 获取用户的站内信以读 + * @param messageIds + * @param userId + * @return + */ + Set getMessageRead(Collection messageIds, Long userId); + + /** + * 查询已读或未读站内信分页 + * @param pageVO + * @return + */ + PageResult getPageResultByRead(NotifyMessageMyPageReqVO pageVO); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageServiceImpl.java index 16a3b341a..ab444cda8 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifyMessageServiceImpl.java @@ -1,18 +1,27 @@ package com.cf.imes.module.system.service.notify; +import cn.hutool.core.collection.CollUtil; import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.common.util.object.BeanUtils; +import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; import com.cf.imes.module.system.controller.admin.notify.vo.message.NotifyMessageMyPageReqVO; import com.cf.imes.module.system.controller.admin.notify.vo.message.NotifyMessagePageReqVO; +import com.cf.imes.module.system.controller.admin.notify.vo.message.NotifyMessageRespVO; import com.cf.imes.module.system.dal.dataobject.notify.NotifyMessageDO; import com.cf.imes.module.system.dal.dataobject.notify.NotifyTemplateDO; import com.cf.imes.module.system.dal.mysql.notify.NotifyMessageMapper; +import org.springframework.data.redis.core.RedisCallback; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; + +import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; /** * 站内信 Service 实现类 @@ -26,13 +35,16 @@ public class NotifyMessageServiceImpl implements NotifyMessageService { @Resource private NotifyMessageMapper notifyMessageMapper; + @Resource + private StringRedisTemplate stringRedisTemplate; + @Override public Long createNotifyMessage(Long userId, Integer userType, NotifyTemplateDO template, String templateContent, Map templateParams) { NotifyMessageDO message = new NotifyMessageDO().setUserId(userId).setUserType(userType) .setTemplateId(template.getId()).setTemplateCode(template.getCode()) .setTemplateType(template.getType()).setTemplateNickname(template.getNickname()) - .setTemplateContent(templateContent).setTemplateParams(templateParams).setReadStatus(false); + .setTemplateContent(templateContent).setTemplateParams(templateParams); notifyMessageMapper.insert(message); return message.getId(); } @@ -59,17 +71,98 @@ public class NotifyMessageServiceImpl implements NotifyMessageService { @Override public Long getUnreadNotifyMessageCount(Long userId, Integer userType) { - return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType); + List notifyMessageDOS = notifyMessageMapper.selectList(new LambdaQueryWrapperX() + .eq(NotifyMessageDO::getUserType, userType) + .in(NotifyMessageDO::getUserId, Arrays.asList(userId, 0L)) + .select(NotifyMessageDO::getId) + ); + if(CollUtil.isEmpty(notifyMessageDOS)) { + return 0L; + } + Set messageIds = notifyMessageDOS.stream().map(e->e.getId().toString()).collect(Collectors.toSet()); + Set set = bitGet(messageIds, userId); + messageIds.removeAll(set); + return (long) messageIds.size(); + //return notifyMessageMapper.selectUnreadCountByUserIdAndUserType(userId, userType); } @Override public int updateNotifyMessageRead(Collection ids, Long userId, Integer userType) { - return notifyMessageMapper.updateListRead(ids, userId, userType); + bitset(ids.stream().map(Object::toString).collect(Collectors.toSet()), userId); + return 1; + //return notifyMessageMapper.updateListRead(ids, userId, userType); } @Override public int updateAllNotifyMessageRead(Long userId, Integer userType) { - return notifyMessageMapper.updateListRead(userId, userType); + List notifyMessageDOS = notifyMessageMapper.selectList(new LambdaQueryWrapperX() + .in(NotifyMessageDO::getUserId, Arrays.asList(userId, 0)) + .eq(NotifyMessageDO::getUserType, 2) + .select(NotifyMessageDO::getId) + ); + if (CollUtil.isNotEmpty(notifyMessageDOS)) { + Set messageIds = notifyMessageDOS.stream().map(e -> String.valueOf(e.getId())).collect(Collectors.toSet()); + bitset(messageIds, userId); + } + return 1; + //return notifyMessageMapper.updateListRead(userId, userType); } + @Override + public Set getMessageRead(Collection messageIds, Long userId) { + return bitGet(messageIds,userId); + } + + @Override + public PageResult getPageResultByRead(NotifyMessageMyPageReqVO pageVO) { + Boolean readStatus = pageVO.getReadStatus(); + Long userId = getLoginUserId(); + List notifyMessageDOS = notifyMessageMapper.selectList(new LambdaQueryWrapperX() + .eq(NotifyMessageDO::getUserType, 2) + .in(NotifyMessageDO::getUserId, Arrays.asList(userId, 0L)) + .betweenIfPresent(NotifyMessageDO::getCreateTime, pageVO.getCreateTime()) + ); + Set messageIds = notifyMessageDOS.stream().map(e -> e.getId().toString()).collect(Collectors.toSet()); + Set set = bitGet(messageIds, userId); + List respVOS = notifyMessageDOS.stream() + .filter(f -> readStatus ? set.contains(f.getId().toString()): !set.contains(f.getId().toString())) + .skip((long) (pageVO.getPageNo() - 1) * pageVO.getPageSize()) + .limit(pageVO.getPageSize()) + .map(e -> { + NotifyMessageRespVO respVO = BeanUtils.toBean(e, NotifyMessageRespVO.class); + respVO.setReadStatus(readStatus); + return respVO; + }) + .toList(); + + return new PageResult<>(respVOS, (long)respVOS.size()); + } + + private Boolean bitset(Collection keys, Long userId) { + return stringRedisTemplate.execute((RedisCallback) connection -> { + AtomicReference flag = new AtomicReference<>(false); + keys.forEach(key -> flag.set(connection.setBit(joinKey(key).getBytes(StandardCharsets.UTF_8), userId, true))); + return flag.get(); + } + ); + } + + private Set bitGet(Collection keys, Long userId) { + return stringRedisTemplate.execute((RedisCallback>)connection -> { + Set set = new HashSet<>(); + keys.forEach(key->{ + Boolean bit = connection.getBit(joinKey(key).getBytes(StandardCharsets.UTF_8), userId); + if(bit) { + set.add(key); + } + }); + return set; + }); + } + + private String joinKey(String key) { + return NOTIFY_MESSAGE_KEY + key; + } + + } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifySendServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifySendServiceImpl.java index 3dd94c886..50849acc1 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifySendServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/notify/NotifySendServiceImpl.java @@ -34,7 +34,22 @@ public class NotifySendServiceImpl implements NotifySendService { @Override public Long sendSingleNotifyToAdmin(Long userId, String templateCode, Map templateParams) { - return sendSingleNotify(userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + return sendSingleNotifyToAdmin(userId, UserTypeEnum.ADMIN.getValue(), templateCode, templateParams); + } + + private Long sendSingleNotifyToAdmin(Long userId, Integer userType, String templateCode, Map templateParams) { + // 校验模版 + NotifyTemplateDO template = validateNotifyTemplate(templateCode); + if (Objects.equals(template.getStatus(), CommonStatusEnum.DISABLE.getStatus())) { + log.info("[sendSingleNotify][模版({})已经关闭,无法给用户({}/{})发送]", templateCode, userId, userType); + return null; + } + // 校验参数 + validateTemplateParams(template, templateParams); + + // 发送站内信 + String content = notifyTemplateService.formatNotifyTemplateContent(template.getContent(), templateParams); + return notifyMessageService.createNotifyMessage(userId, userType, template, content, templateParams); } @Override diff --git a/cf-module-system/cf-module-system-biz/src/main/resources/application.yaml b/cf-module-system/cf-module-system-biz/src/main/resources/application.yaml index 471ccf244..17848700a 100644 --- a/cf-module-system/cf-module-system-biz/src/main/resources/application.yaml +++ b/cf-module-system/cf-module-system-biz/src/main/resources/application.yaml @@ -182,6 +182,7 @@ chenfeng: - system_label_template - system_label_element_template - system_data_source + - system_notify_message use-data-code: imes_prod #动态数据源标识,后期添加的数据源需要修改此值 sms-code: # 短信验证码相关的配置项