阅读数统计逻辑

This commit is contained in:
easonzhu 2025-02-14 15:09:49 +08:00
parent 2a518ff533
commit e4dbf59dd1
21 changed files with 192 additions and 36 deletions

View File

@ -37,12 +37,6 @@ public class AuthFilter implements Filter {
@Value("${jwt.secret}") @Value("${jwt.secret}")
private String jwtSecret; private String jwtSecret;
@Value("${aes.key}")
private String key;
@Value("${aes.iv}")
private String iv;
@Resource @Resource
private HazelcastInstance hazelcastInstance; private HazelcastInstance hazelcastInstance;
@ -52,9 +46,6 @@ public class AuthFilter implements Filter {
// jwt有效期(毫秒) // jwt有效期(毫秒)
public static final long jwtExpire = 60 * 60 * 1000 * 24; public static final long jwtExpire = 60 * 60 * 1000 * 24;
@Resource
private AuthService authService;
@Override @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
RequestIdUtil.setValue(); RequestIdUtil.setValue();

View File

@ -4,7 +4,7 @@ import com.upchina.common.query.OnlyIdQuery;
import com.upchina.common.result.AppPager; import com.upchina.common.result.AppPager;
import com.upchina.common.result.CommonResult; import com.upchina.common.result.CommonResult;
import com.upchina.common.vo.FrontUserVO; import com.upchina.common.vo.FrontUserVO;
import com.upchina.group.query.ListGroupAppQuery; import com.upchina.group.query.info.ListGroupAppQuery;
import com.upchina.group.service.GroupInfoService; import com.upchina.group.service.GroupInfoService;
import com.upchina.group.vo.GroupVO; import com.upchina.group.vo.GroupVO;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;

View File

@ -6,6 +6,7 @@ import com.upchina.common.result.CommonResult;
import com.upchina.common.result.ResponseStatus; import com.upchina.common.result.ResponseStatus;
import com.upchina.common.vo.FrontUserVO; import com.upchina.common.vo.FrontUserVO;
import com.upchina.group.query.message.ListGroupMessageAppQuery; import com.upchina.group.query.message.ListGroupMessageAppQuery;
import com.upchina.group.query.message.QueryUnreadCountAppQuery;
import com.upchina.group.query.message.ReadGroupMessageAppQuery; import com.upchina.group.query.message.ReadGroupMessageAppQuery;
import com.upchina.group.query.message.SendGroupMessageAppQuery; import com.upchina.group.query.message.SendGroupMessageAppQuery;
import com.upchina.group.service.app.AppGroupMessageService; import com.upchina.group.service.app.AppGroupMessageService;
@ -58,4 +59,13 @@ public class AppGroupMessageController {
return CommonResult.success(); return CommonResult.success();
} }
@ApiOperation("APP查询未读数量")
@PostMapping("/app/group/message/unreadCount")
public CommonResult<Integer> unreadCount(
@Validated @RequestBody @ApiParam(required = true) QueryUnreadCountAppQuery query,
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUser) {
Integer count = appGroupMessageService.queryUnreadCount(query, frontUser);
return CommonResult.success(count);
}
} }

View File

@ -178,6 +178,18 @@ public class GroupMessage implements Serializable {
@TableField("is_recommend") @TableField("is_recommend")
private Integer isRecommend; private Integer isRecommend;
/**
* 阅读数
*/
@TableField("read_count")
private Integer readCount;
/**
* 用户数
*/
@TableField("total_count")
private Integer totalCount;
public Integer getId() { public Integer getId() {
return id; return id;
} }
@ -394,6 +406,22 @@ public class GroupMessage implements Serializable {
this.isRecommend = isRecommend; this.isRecommend = isRecommend;
} }
public Integer getReadCount() {
return readCount;
}
public void setReadCount(Integer readCount) {
this.readCount = readCount;
}
public Integer getTotalCount() {
return totalCount;
}
public void setTotalCount(Integer totalCount) {
this.totalCount = totalCount;
}
@Override @Override
public String toString() { public String toString() {
return "GroupMessage{" + return "GroupMessage{" +
@ -424,6 +452,8 @@ public class GroupMessage implements Serializable {
", auditTime=" + auditTime + ", auditTime=" + auditTime +
", advisorId=" + advisorId + ", advisorId=" + advisorId +
", isRecommend=" + isRecommend + ", isRecommend=" + isRecommend +
", readCount=" + readCount +
", totalCount=" + totalCount +
'}'; '}';
} }
} }

View File

@ -29,15 +29,6 @@ public interface GroupMessageMapper extends BaseMapper<GroupMessage> {
"WHERE rn = 1") "WHERE rn = 1")
List<GroupMessage> selectPrivateChatList(@Param("groupId") Integer groupId); List<GroupMessage> selectPrivateChatList(@Param("groupId") Integer groupId);
@Update("<script>" +
"INSERT INTO group_message_read (message_id, user_id, group_id) VALUES " +
"<foreach collection='list' item='item' separator=','>" +
"(#{item.messageId}, #{item.userId}, #{item.groupId})" +
"</foreach>" +
" ON DUPLICATE KEY UPDATE message_id = message_id" +
"</script>")
void replaceBatch(List<GroupMessageRead> list);
@Select("SELECT group_id, interactive_type, user_type, COUNT(0) AS id \n" + @Select("SELECT group_id, interactive_type, user_type, COUNT(0) AS id \n" +
"FROM group_message \n" + "FROM group_message \n" +
"WHERE create_time >= #{startTime} AND create_time < #{endTime} \n" + "WHERE create_time >= #{startTime} AND create_time < #{endTime} \n" +

View File

@ -2,6 +2,9 @@ package com.upchina.group.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.upchina.group.entity.GroupMessageRead; import com.upchina.group.entity.GroupMessageRead;
import org.apache.ibatis.annotations.Update;
import java.util.List;
/** /**
* <p> * <p>
@ -13,4 +16,13 @@ import com.upchina.group.entity.GroupMessageRead;
*/ */
public interface GroupMessageReadMapper extends BaseMapper<GroupMessageRead> { public interface GroupMessageReadMapper extends BaseMapper<GroupMessageRead> {
@Update("<script>" +
"INSERT INTO group_message_read (message_id, user_id, group_id) VALUES " +
"<foreach collection='list' item='item' separator=','>" +
"(#{item.messageId}, #{item.userId}, #{item.groupId})" +
"</foreach>" +
" ON DUPLICATE KEY UPDATE message_id = message_id" +
"</script>")
void replaceBatch(List<GroupMessageRead> list);
} }

View File

@ -1,4 +1,4 @@
package com.upchina.group.query; package com.upchina.group.query.info;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package com.upchina.group.query; package com.upchina.group.query.info;
import com.upchina.common.query.PageQuery; import com.upchina.common.query.PageQuery;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;

View File

@ -1,4 +1,4 @@
package com.upchina.group.query; package com.upchina.group.query.info;
import com.upchina.common.vo.BackendUserVO; import com.upchina.common.vo.BackendUserVO;
import com.upchina.group.constant.GroupInfoStatus; import com.upchina.group.constant.GroupInfoStatus;

View File

@ -1,4 +1,4 @@
package com.upchina.group.query; package com.upchina.group.query.info;
import java.time.LocalDateTime; import java.time.LocalDateTime;

View File

@ -1,4 +1,4 @@
package com.upchina.group.query; package com.upchina.group.query.info;
import com.upchina.common.vo.BackendUserVO; import com.upchina.common.vo.BackendUserVO;
import com.upchina.group.entity.GroupInfo; import com.upchina.group.entity.GroupInfo;

View File

@ -1,4 +1,4 @@
package com.upchina.group.query; package com.upchina.group.query.info;
import com.upchina.common.vo.BackendUserVO; import com.upchina.common.vo.BackendUserVO;
import com.upchina.group.constant.GroupInfoStatus; import com.upchina.group.constant.GroupInfoStatus;

View File

@ -0,0 +1,47 @@
package com.upchina.group.query.message;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
public class QueryUnreadCountAppQuery {
@ApiModelProperty("交易圈ID")
@NotNull
private Integer groupId;
@ApiModelProperty("查询类型:1全部;2投顾;3用户;4精选;5私聊")
@NotNull
@Min(1)
@Max(5)
private Integer type;
@ApiModelProperty("已读最后ID")
private Integer lastId;
public Integer getGroupId() {
return groupId;
}
public void setGroupId(Integer groupId) {
this.groupId = groupId;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getLastId() {
return lastId;
}
public void setLastId(Integer lastId) {
this.lastId = lastId;
}
}

View File

@ -19,7 +19,7 @@ public class GroupTask {
private GroupCommonService groupCommonService; private GroupCommonService groupCommonService;
/** /**
* 拉取云端视频转码状态 * 保存消息已读
*/ */
@Scheduled(cron = "${cron.saveGroupMessageRead}") @Scheduled(cron = "${cron.saveGroupMessageRead}")
public void saveGroupMessageRead() { public void saveGroupMessageRead() {

View File

@ -30,6 +30,7 @@ import com.upchina.group.mapper.GroupCollectMapper;
import com.upchina.group.mapper.GroupInfoMapper; import com.upchina.group.mapper.GroupInfoMapper;
import com.upchina.group.query.*; import com.upchina.group.query.*;
import com.upchina.group.vo.GroupCollectVO; import com.upchina.group.vo.GroupCollectVO;
import com.upchina.group.query.info.*;
import com.upchina.group.vo.GroupVO; import com.upchina.group.vo.GroupVO;
import com.upchina.rbac.entity.UserDept; import com.upchina.rbac.entity.UserDept;
import com.upchina.rbac.service.AuthService; import com.upchina.rbac.service.AuthService;
@ -314,4 +315,5 @@ public class GroupInfoService {
public void clearCache(Integer id) { public void clearCache(Integer id) {
groupCache.delete(CacheKey.GroupKey.GROUP_INFO + id); groupCache.delete(CacheKey.GroupKey.GROUP_INFO + id);
} }
} }

View File

@ -101,9 +101,11 @@ public class AdminGroupMessageService {
groupMessageMapper.updateById(groupMessage); groupMessageMapper.updateById(groupMessage);
if (GroupMessageStatus.DELETED.equals(targetStatus)) { if (GroupMessageStatus.DELETED.equals(targetStatus)) {
groupMessageInDB.setStatus(GroupMessageStatus.DELETED.value);
groupCacheService.removeMessage(groupMessageInDB); groupCacheService.removeMessage(groupMessageInDB);
} else if (GroupMessageStatus.AUDITED.equals(targetStatus)) { } else if (GroupMessageStatus.AUDITED.equals(targetStatus)) {
if (IsOrNot.IS.value.equals(group.getFirstAudit())) { if (IsOrNot.IS.value.equals(group.getFirstAudit())) {
groupMessageInDB.setStatus(GroupMessageStatus.AUDITED.value);
groupMessageService.publishMessage(groupMessageInDB); groupMessageService.publishMessage(groupMessageInDB);
} }
} }
@ -147,6 +149,10 @@ public class AdminGroupMessageService {
if (GroupMessageUserType.CUSTOMER.value.equals(vo.getUserType())) { if (GroupMessageUserType.CUSTOMER.value.equals(vo.getUserType())) {
boolean isBlack = commentBlackService.checkIsBlack(vo.getUserId(), vo.getGroupId(), ProductType.GROUP.value); boolean isBlack = commentBlackService.checkIsBlack(vo.getUserId(), vo.getGroupId(), ProductType.GROUP.value);
vo.setIsForbidden(isBlack ? IsOrNot.IS.value : IsOrNot.NOT.value); vo.setIsForbidden(isBlack ? IsOrNot.IS.value : IsOrNot.NOT.value);
} else if (GroupMessageUserType.ADVISOR.value.equals(vo.getUserType()) || GroupMessageUserType.ASSISTANT.value.equals(vo.getUserType())) {
if (GroupInteractiveType.GROUP.value.equals(vo.getInteractiveType())) {
groupCacheService.queryMessageReadCount(vo);
}
} }
return vo; return vo;
}).collect(Collectors.toList()); }).collect(Collectors.toList());

View File

@ -18,6 +18,7 @@ import com.upchina.group.constant.QueryGroupMessageType;
import com.upchina.group.entity.GroupMessage; import com.upchina.group.entity.GroupMessage;
import com.upchina.group.mapper.GroupMessageMapper; import com.upchina.group.mapper.GroupMessageMapper;
import com.upchina.group.query.message.ListGroupMessageAppQuery; import com.upchina.group.query.message.ListGroupMessageAppQuery;
import com.upchina.group.query.message.QueryUnreadCountAppQuery;
import com.upchina.group.query.message.ReadGroupMessageAppQuery; import com.upchina.group.query.message.ReadGroupMessageAppQuery;
import com.upchina.group.query.message.SendGroupMessageAppQuery; import com.upchina.group.query.message.SendGroupMessageAppQuery;
import com.upchina.group.service.GroupInfoService; import com.upchina.group.service.GroupInfoService;
@ -133,4 +134,17 @@ public class AppGroupMessageService {
GroupMessageReadVO vo = new GroupMessageReadVO(frontUser.getUserId(), query.getMessageIds()); GroupMessageReadVO vo = new GroupMessageReadVO(frontUser.getUserId(), query.getMessageIds());
groupCacheService.readMessage(vo); groupCacheService.readMessage(vo);
} }
public Integer queryUnreadCount(QueryUnreadCountAppQuery query, FrontUserVO frontUser) {
Integer groupId = query.getGroupId();
Integer lastId = query.getLastId();
Integer type = query.getType();
String userId = frontUser.getUserId();
QueryGroupMessageType msgType = QueryGroupMessageType.fromValue(type);
NavigableSet<Integer> sortedSet = groupCacheService.getMessageIdSet(groupId, userId, msgType);
if (lastId != null) {
sortedSet = sortedSet.tailSet(lastId, false);
}
return sortedSet.size();
}
} }

View File

@ -13,15 +13,18 @@ import com.upchina.group.constant.GroupInteractiveType;
import com.upchina.group.constant.GroupMessageUserType; import com.upchina.group.constant.GroupMessageUserType;
import com.upchina.group.constant.QueryGroupMessageType; import com.upchina.group.constant.QueryGroupMessageType;
import com.upchina.group.entity.GroupMessage; import com.upchina.group.entity.GroupMessage;
import com.upchina.group.entity.GroupMessageRead;
import com.upchina.group.entity.GroupUserFlow; import com.upchina.group.entity.GroupUserFlow;
import com.upchina.group.mapper.GroupInfoMapper; import com.upchina.group.mapper.GroupInfoMapper;
import com.upchina.group.mapper.GroupMessageMapper; import com.upchina.group.mapper.GroupMessageMapper;
import com.upchina.group.mapper.GroupMessageReadMapper;
import com.upchina.group.mapper.GroupUserFlowMapper; import com.upchina.group.mapper.GroupUserFlowMapper;
import com.upchina.group.vo.message.GroupMessageReadVO; import com.upchina.group.vo.message.GroupMessageReadVO;
import com.upchina.group.vo.message.GroupMessageVO; import com.upchina.group.vo.message.GroupMessageVO;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -36,7 +39,7 @@ public class GroupCacheService {
private CacheService cacheService; private CacheService cacheService;
@Resource @Resource
private GroupInfoMapper groupInfoMapper; private GroupMessageReadMapper groupMessageReadMapper;
@Resource @Resource
private GroupMessageMapper groupMessageMapper; private GroupMessageMapper groupMessageMapper;
@ -164,4 +167,13 @@ public class GroupCacheService {
hazelcastInstance.getList(CacheKey.GroupKey.TEMP_READ_LIST).add(vo); hazelcastInstance.getList(CacheKey.GroupKey.TEMP_READ_LIST).add(vo);
} }
public void queryMessageReadCount(GroupMessageVO vo) {
// 当日消息查询明细表
if (vo.getCreateTime().isAfter(LocalDate.now().atStartOfDay())) {
LambdaQueryWrapper<GroupMessageRead> wrapper = Wrappers.<GroupMessageRead>lambdaQuery()
.eq(GroupMessageRead::getGroupId, vo.getGroupId())
.eq(GroupMessageRead::getMessageId, vo.getId());
vo.setReadCount(groupMessageReadMapper.selectCount(wrapper).intValue());
}
}
} }

View File

@ -14,10 +14,7 @@ import com.upchina.common.vo.IdCountVO;
import com.upchina.group.constant.GroupInteractiveType; import com.upchina.group.constant.GroupInteractiveType;
import com.upchina.group.constant.GroupMessageUserType; import com.upchina.group.constant.GroupMessageUserType;
import com.upchina.group.entity.*; import com.upchina.group.entity.*;
import com.upchina.group.mapper.GroupCollectMapper; import com.upchina.group.mapper.*;
import com.upchina.group.mapper.GroupInfoMapper;
import com.upchina.group.mapper.GroupMessageMapper;
import com.upchina.group.mapper.GroupUserFlowMapper;
import com.upchina.group.vo.GroupVO; import com.upchina.group.vo.GroupVO;
import com.upchina.group.vo.message.GroupMessageReadVO; import com.upchina.group.vo.message.GroupMessageReadVO;
import com.upchina.group.vo.message.GroupMessageVO; import com.upchina.group.vo.message.GroupMessageVO;
@ -51,7 +48,9 @@ public class GroupCommonService {
@Resource @Resource
private GroupCollectMapper groupCollectMapper; private GroupCollectMapper groupCollectMapper;
private CollectTask collectTask;
@Resource
private GroupMessageReadMapper groupMessageReadMapper;
public boolean validateUserPermission(String userId, GroupVO groupVO) { public boolean validateUserPermission(String userId, GroupVO groupVO) {
return true; return true;
@ -87,8 +86,14 @@ public class GroupCommonService {
}).collect(Collectors.toList()); }).collect(Collectors.toList());
}).filter(Objects::nonNull).flatMap(List::stream).collect(Collectors.toList()); }).filter(Objects::nonNull).flatMap(List::stream).collect(Collectors.toList());
if (CollUtil.isNotEmpty(list)) { if (CollUtil.isNotEmpty(list)) {
groupMessageMapper.replaceBatch(list); groupMessageReadMapper.replaceBatch(list);
} }
// 更新消息里的已读统计
if (CollUtil.isNotEmpty(map)) {
saveGroupMessageCollect(map.keySet());
}
cacheList.clear(); cacheList.clear();
} }
@ -152,7 +157,6 @@ public class GroupCommonService {
if (yesterdayLatest != null && yesterdayLatest.getCreateTime().isBefore(today.atStartOfDay())) { if (yesterdayLatest != null && yesterdayLatest.getCreateTime().isBefore(today.atStartOfDay())) {
collectGroupData(groupIds, yesterday); collectGroupData(groupIds, yesterday);
} }
collectGroupData(groupIds, today); collectGroupData(groupIds, today);
} }
@ -216,7 +220,6 @@ public class GroupCommonService {
} }
} }
return collect; return collect;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
if (CollUtil.isNotEmpty(collectList)) { if (CollUtil.isNotEmpty(collectList)) {
groupCollectMapper.delete(Wrappers.<GroupCollect>lambdaQuery().eq(GroupCollect::getDate, date)); groupCollectMapper.delete(Wrappers.<GroupCollect>lambdaQuery().eq(GroupCollect::getDate, date));
@ -224,6 +227,20 @@ public class GroupCommonService {
} }
} }
private void saveGroupMessageCollect(Set<Integer> messageIds) {
QueryWrapper<GroupMessageRead> wrapper = Wrappers.<GroupMessageRead>query()
.select("message_id", "count(0) as group_id")
.in("message_id", messageIds)
.groupBy("message_id");
List<GroupMessageRead> list = groupMessageReadMapper.selectList(wrapper);
for (GroupMessageRead read : list) {
GroupMessage message = new GroupMessage();
message.setId(read.getMessageId());
message.setReadCount(read.getGroupId());
groupMessageMapper.updateById(message);
}
}
private Integer getTotalMembers(Integer groupId) { private Integer getTotalMembers(Integer groupId) {
// TODO // TODO
return 0; return 0;

View File

@ -78,6 +78,12 @@ public class GroupMessageVO implements Serializable {
@ApiModelProperty("是否被禁言 1是 2否") @ApiModelProperty("是否被禁言 1是 2否")
private Integer isForbidden; private Integer isForbidden;
@ApiModelProperty("已读数量")
private Integer readCount;
@ApiModelProperty("总数量")
private Integer totalCount;
public GroupMessageVO() { public GroupMessageVO() {
} }
@ -102,6 +108,8 @@ public class GroupMessageVO implements Serializable {
this.advisorId = message.getAdvisorId(); this.advisorId = message.getAdvisorId();
this.isRecommend = message.getIsRecommend(); this.isRecommend = message.getIsRecommend();
this.advisor = advisor; this.advisor = advisor;
this.readCount = message.getReadCount();
this.totalCount = message.getTotalCount();
} }
public Integer getId() { public Integer getId() {
@ -287,4 +295,20 @@ public class GroupMessageVO implements Serializable {
public void setIsForbidden(Integer isForbidden) { public void setIsForbidden(Integer isForbidden) {
this.isForbidden = isForbidden; this.isForbidden = isForbidden;
} }
public Integer getReadCount() {
return readCount;
}
public void setReadCount(Integer readCount) {
this.readCount = readCount;
}
public Integer getTotalCount() {
return totalCount;
}
public void setTotalCount(Integer totalCount) {
this.totalCount = totalCount;
}
} }

View File

@ -16,7 +16,7 @@ hazelcast:
scheduledEnable: true scheduledEnable: true
cron: cron:
collectLivingVideo: "30 0/5 * * * ?" #每分钟统计已开始但未结束的视频直播数据 collectLivingVideo: "30 0/5 * * * ?" #每分钟统计已开始但未结束的视频直播数据
saveVideoCount: "30 1/2 * * * ?" #从cache刷新视频播放量到DB 每分钟的第10s执行 saveVideoCount: "30 1/5 * * * ?" #从cache刷新视频播放量到DB 每分钟的第10s执行
saveVideoUserDataToDB: "30 2/5 * * * ?" saveVideoUserDataToDB: "30 2/5 * * * ?"
saveCustomerDataToDB: "30 3/5 * * * ?" #收集用户信息 saveCustomerDataToDB: "30 3/5 * * * ?" #收集用户信息
refreshTranscodeStatus: "30 4/5 * * * ?" #从腾讯云拉取录播上传视频信息更新到DB refreshTranscodeStatus: "30 4/5 * * * ?" #从腾讯云拉取录播上传视频信息更新到DB