已读和统计逻辑初始提交
This commit is contained in:
parent
53a6dbea2d
commit
fdc4a4aeb9
22
pom.xml
22
pom.xml
@ -180,31 +180,9 @@
|
||||
<version>1.7.36</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.8.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
<version>4.5.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
<configuration>
|
||||
<skipTests>true</skipTests>
|
||||
<testFailureIgnore>true</testFailureIgnore>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
|
||||
@ -20,12 +20,8 @@ public class CacheKey {
|
||||
public static final String DISTRIBUTED_LOCK = "distributed_lock";
|
||||
|
||||
public static class LockKey {
|
||||
// 从cache刷新观点互动数量到DB 分布式锁(字符串常量)
|
||||
public static final String SAVE_VIEW_COUNT_TO_DB_LOCK = "save_view_count_to_db_lock";
|
||||
// 清除多余定时器日志
|
||||
public static final String CLEAR_HISTORY_SCHEDULE_LOG = "clearHistoryScheduleLog";
|
||||
// 自动解除锁定用户
|
||||
public static final String UN_LOCK_USER = "un_lock_user";
|
||||
// 结束直播中/暂停中的直播 分布式锁(字符串常量)
|
||||
public static final String STOP_LIVING_VIDEO_LOCK = "stop_living_video_lock";
|
||||
// 刷新视频直播状态 分布式锁(字符串常量)
|
||||
@ -47,6 +43,9 @@ public class CacheKey {
|
||||
|
||||
public static final String SYNC_APP_ORDER = "sync_app_order";
|
||||
public static final String LOAD_USER_BLACK_LIST = "load_user_black_list";
|
||||
public static final String SAVE_MESSAGE_READ = "save_message_read";
|
||||
public static final String SAVE_GROUP_USER = "save_group_user";
|
||||
public static final String COLLECT_GROUP_DATA = "collect_group_data";
|
||||
}
|
||||
|
||||
// 消息主题
|
||||
@ -135,71 +134,6 @@ public class CacheKey {
|
||||
public static final String USER_ADVISOR_DEPT_MAP = "user_advisor_dept_map";
|
||||
}
|
||||
|
||||
// 观点栏目
|
||||
public static final String VIEW_COLUMN = "view_column";
|
||||
|
||||
public static final class ViewColumnKey {
|
||||
// columnId -> columnName
|
||||
public static final String VIEW_COLUMN_MAP = "column_map";
|
||||
// List<ViewColumnAppVO>
|
||||
public static final String APP_COLUMN_LIST = "app_column_list|";
|
||||
}
|
||||
|
||||
// 观点
|
||||
public static final String VIEW_INFO = "view_info";
|
||||
|
||||
public static class ViewInfoKey {
|
||||
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
|
||||
public static final String APP_PUBLISH_TIME_LIST = "app_publish_time_list";
|
||||
// SortedSet<ViewSortEntity, Integer> (readCount, viewId)
|
||||
public static final String APP_READ_COUNT_LIST = "app_read_count_list";
|
||||
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
|
||||
public static final String APP_KEYWORD_LIST = "app_keyword_all|";
|
||||
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
|
||||
public static final String APP_COLUMN_LIST = "app_column_list|";
|
||||
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
|
||||
public static final String APP_ADVISOR_LIST = "app_advisor_list|";
|
||||
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
|
||||
public static final String APP_PACKAGE_LIST = "app_package_list|";
|
||||
// ViewInfoAppVO
|
||||
public static final String APP_OBJ = "app_obj|";
|
||||
// ViewDetailAppVO
|
||||
public static final String APP_DETAIL_OBJ = "app_detail_obj|";
|
||||
// userId -> Set<ViewId>
|
||||
public static final String USER_FAVOR_VIEW_IDS = "user_favor_view_ids|";
|
||||
// viewId -> PN Counter<favorCount>
|
||||
public static final String APP_FAVOR_COUNT = "app_favor_count|";
|
||||
// viewId -> PN Counter<readCount>
|
||||
public static final String APP_READ_COUNT = "app_read_count|";
|
||||
// Set<ViewRead>
|
||||
public static final String TEMP_READ_COUNT_SET = "temp_read_count_set";
|
||||
}
|
||||
|
||||
// 观点包
|
||||
public static final String VIEW_PACKAGE = "view_package";
|
||||
|
||||
public static class ViewPackageKey {
|
||||
// id -> ViewPackageAppVO
|
||||
public static final String APP_OBJ = "app_obj|";
|
||||
// SortedSet<ViewSortEntity> (weight, subCount, packageId)
|
||||
public static final String APP_LIST = "app_list";
|
||||
// SortedSet<ViewSortEntity> (inPackageWeight, subCount, packageId)
|
||||
public static final String APP_KEYWORD_LIST = "app_keyword_list|";
|
||||
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
|
||||
public static final String APP_COLUMN_LIST = "app_column_list|";
|
||||
// SortedSet<ViewSortEntity, Integer> (publishTime, viewId)
|
||||
public static final String APP_ADVISOR_LIST = "app_advisor_list|";
|
||||
public static final String APP_ADVISOR_ORDER_BY_SUBCOUNT_LIST = "app_advisor_order_by_subcount_list|";
|
||||
}
|
||||
|
||||
//观点卡片
|
||||
public static final String VIEW_CARD = "view_card";
|
||||
|
||||
public static class ViewCardKey {
|
||||
//viewId --> List<ViewCard>
|
||||
public static final String VIEW_CARD_LIST = "view_card_list|";
|
||||
}
|
||||
|
||||
public static final String ADVERT = "advert";
|
||||
|
||||
public static class AdvertKey {
|
||||
@ -420,6 +354,7 @@ public class CacheKey {
|
||||
public static final String GROUP_MESSAGE_LIST = "group_message_list|";
|
||||
public static final String GROUP_MESSAGE_DETAIL = "group_message_detail|";
|
||||
public static final String USER_TOTAL_ONLINE = "user_total_online|";
|
||||
public static final String TEMP_READ_LIST = "temp_read_list";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -60,11 +60,7 @@ public class HazelcastConfiguration {
|
||||
|
||||
configMap.put(DEPT, new LocalMapConfig(10000, 3600));
|
||||
configMap.put(TAG, new LocalMapConfig(10000, 3600));
|
||||
configMap.put(VIEW_COLUMN, new LocalMapConfig(10000, 3600));
|
||||
configMap.put(ADVISOR_INFO, new LocalMapConfig(10000, 300));
|
||||
configMap.put(VIEW_INFO, new LocalMapConfig(10000, 300));
|
||||
configMap.put(VIEW_PACKAGE, new LocalMapConfig(10000, 300));
|
||||
configMap.put(VIEW_CARD, new LocalMapConfig(10000, 300));
|
||||
|
||||
configMap.put(RECOMMEND, new LocalMapConfig(10000, 300));
|
||||
configMap.put(USER, new LocalMapConfig(10000, 3600));
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.upchina.video.entity;
|
||||
package com.upchina.common.entity;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
@ -3,10 +3,10 @@ package com.upchina.common.interceptor;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.constant.ProductType;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.vo.FrontUserVO;
|
||||
import com.upchina.group.service.common.GroupCacheService;
|
||||
import com.upchina.group.service.common.GroupMessageService;
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import com.upchina.video.service.common.VideoCacheService;
|
||||
import com.upchina.video.service.common.VideoMessageService;
|
||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||
|
||||
@ -6,6 +6,7 @@ import com.upchina.common.result.CommonResult;
|
||||
import com.upchina.common.result.ResponseStatus;
|
||||
import com.upchina.common.vo.FrontUserVO;
|
||||
import com.upchina.group.query.message.ListGroupMessageAppQuery;
|
||||
import com.upchina.group.query.message.ReadGroupMessageAppQuery;
|
||||
import com.upchina.group.query.message.SendGroupMessageAppQuery;
|
||||
import com.upchina.group.service.app.AppGroupMessageService;
|
||||
import com.upchina.group.vo.message.GroupMessageVO;
|
||||
@ -48,4 +49,13 @@ public class AppGroupMessageController {
|
||||
return CommonResult.success(vo);
|
||||
}
|
||||
|
||||
@ApiOperation("APP保存消息已读")
|
||||
@PostMapping("/app/group/message/readMessage")
|
||||
public CommonResult<Void> readMessage(
|
||||
@Validated @RequestBody @ApiParam(required = true) ReadGroupMessageAppQuery query,
|
||||
@RequestAttribute(value = "frontUser", required = false) FrontUserVO frontUser) {
|
||||
appGroupMessageService.readMessage(query, frontUser);
|
||||
return CommonResult.success();
|
||||
}
|
||||
|
||||
}
|
||||
223
src/main/java/com/upchina/group/entity/GroupCollect.java
Normal file
223
src/main/java/com/upchina/group/entity/GroupCollect.java
Normal file
@ -0,0 +1,223 @@
|
||||
package com.upchina.group.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 交易圈统计信息
|
||||
* </p>
|
||||
*
|
||||
* @author easonzhu
|
||||
* @since 2025-02-13
|
||||
*/
|
||||
public class GroupCollect implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* ID
|
||||
*/
|
||||
@TableId(value = "group_id", type = IdType.AUTO)
|
||||
private Integer groupId;
|
||||
|
||||
/**
|
||||
* 日期
|
||||
*/
|
||||
private LocalDate date;
|
||||
|
||||
/**
|
||||
* 总成员数
|
||||
*/
|
||||
@TableField("total_members")
|
||||
private Integer totalMembers;
|
||||
|
||||
/**
|
||||
* 访问成员数
|
||||
*/
|
||||
@TableField("visited_members")
|
||||
private Integer visitedMembers;
|
||||
|
||||
/**
|
||||
* 新增成员数
|
||||
*/
|
||||
@TableField("new_members")
|
||||
private Integer newMembers;
|
||||
|
||||
/**
|
||||
* 发互动成员数
|
||||
*/
|
||||
@TableField("interaction_members")
|
||||
private Integer interactionMembers;
|
||||
|
||||
/**
|
||||
* 发私聊成员数
|
||||
*/
|
||||
@TableField("private_chat_members")
|
||||
private Integer privateChatMembers;
|
||||
|
||||
/**
|
||||
* 投顾发布互动数
|
||||
*/
|
||||
@TableField("advisor_group_content")
|
||||
private Integer advisorGroupContent;
|
||||
|
||||
/**
|
||||
* 助教发布互动数
|
||||
*/
|
||||
@TableField("assistant_group_content")
|
||||
private Integer assistantGroupContent;
|
||||
|
||||
/**
|
||||
* 用户发布互动数
|
||||
*/
|
||||
@TableField("customer_group_content")
|
||||
private Integer customerGroupContent;
|
||||
|
||||
/**
|
||||
* 投顾发布私聊数
|
||||
*/
|
||||
@TableField("advisor_private_content")
|
||||
private Integer advisorPrivateContent;
|
||||
|
||||
/**
|
||||
* 助教发布私聊数
|
||||
*/
|
||||
@TableField("assistant_private_content")
|
||||
private Integer assistantPrivateContent;
|
||||
|
||||
/**
|
||||
* 用户发布私聊数
|
||||
*/
|
||||
@TableField("customer_private_content")
|
||||
private Integer customerPrivateContent;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public Integer getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(Integer groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
public Integer getTotalMembers() {
|
||||
return totalMembers;
|
||||
}
|
||||
|
||||
public void setTotalMembers(Integer totalMembers) {
|
||||
this.totalMembers = totalMembers;
|
||||
}
|
||||
public Integer getVisitedMembers() {
|
||||
return visitedMembers;
|
||||
}
|
||||
|
||||
public void setVisitedMembers(Integer visitedMembers) {
|
||||
this.visitedMembers = visitedMembers;
|
||||
}
|
||||
public Integer getNewMembers() {
|
||||
return newMembers;
|
||||
}
|
||||
|
||||
public void setNewMembers(Integer newMembers) {
|
||||
this.newMembers = newMembers;
|
||||
}
|
||||
public Integer getInteractionMembers() {
|
||||
return interactionMembers;
|
||||
}
|
||||
|
||||
public void setInteractionMembers(Integer interactionMembers) {
|
||||
this.interactionMembers = interactionMembers;
|
||||
}
|
||||
public Integer getPrivateChatMembers() {
|
||||
return privateChatMembers;
|
||||
}
|
||||
|
||||
public void setPrivateChatMembers(Integer privateChatMembers) {
|
||||
this.privateChatMembers = privateChatMembers;
|
||||
}
|
||||
public Integer getAdvisorGroupContent() {
|
||||
return advisorGroupContent;
|
||||
}
|
||||
|
||||
public void setAdvisorGroupContent(Integer advisorGroupContent) {
|
||||
this.advisorGroupContent = advisorGroupContent;
|
||||
}
|
||||
public Integer getAssistantGroupContent() {
|
||||
return assistantGroupContent;
|
||||
}
|
||||
|
||||
public void setAssistantGroupContent(Integer assistantGroupContent) {
|
||||
this.assistantGroupContent = assistantGroupContent;
|
||||
}
|
||||
public Integer getCustomerGroupContent() {
|
||||
return customerGroupContent;
|
||||
}
|
||||
|
||||
public void setCustomerGroupContent(Integer customerGroupContent) {
|
||||
this.customerGroupContent = customerGroupContent;
|
||||
}
|
||||
public Integer getAdvisorPrivateContent() {
|
||||
return advisorPrivateContent;
|
||||
}
|
||||
|
||||
public void setAdvisorPrivateContent(Integer advisorPrivateContent) {
|
||||
this.advisorPrivateContent = advisorPrivateContent;
|
||||
}
|
||||
public Integer getAssistantPrivateContent() {
|
||||
return assistantPrivateContent;
|
||||
}
|
||||
|
||||
public void setAssistantPrivateContent(Integer assistantPrivateContent) {
|
||||
this.assistantPrivateContent = assistantPrivateContent;
|
||||
}
|
||||
public Integer getCustomerPrivateContent() {
|
||||
return customerPrivateContent;
|
||||
}
|
||||
|
||||
public void setCustomerPrivateContent(Integer customerPrivateContent) {
|
||||
this.customerPrivateContent = customerPrivateContent;
|
||||
}
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GroupCollect{" +
|
||||
"groupId=" + groupId +
|
||||
", date=" + date +
|
||||
", totalMembers=" + totalMembers +
|
||||
", visitedMembers=" + visitedMembers +
|
||||
", newMembers=" + newMembers +
|
||||
", interactionMembers=" + interactionMembers +
|
||||
", privateChatMembers=" + privateChatMembers +
|
||||
", advisorGroupContent=" + advisorGroupContent +
|
||||
", assistantGroupContent=" + assistantGroupContent +
|
||||
", customerGroupContent=" + customerGroupContent +
|
||||
", advisorPrivateContent=" + advisorPrivateContent +
|
||||
", assistantPrivateContent=" + assistantPrivateContent +
|
||||
", customerPrivateContent=" + customerPrivateContent +
|
||||
", createTime=" + createTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
81
src/main/java/com/upchina/group/entity/GroupMessageRead.java
Normal file
81
src/main/java/com/upchina/group/entity/GroupMessageRead.java
Normal file
@ -0,0 +1,81 @@
|
||||
package com.upchina.group.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 交易圈消息已读
|
||||
* </p>
|
||||
*
|
||||
* @author easonzhu
|
||||
* @since 2025-02-13
|
||||
*/
|
||||
public class GroupMessageRead implements Serializable {
|
||||
|
||||
|
||||
/**
|
||||
* 消息ID
|
||||
*/
|
||||
@TableField("message_id")
|
||||
private Integer messageId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@TableField("user_id")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 交易圈ID
|
||||
*/
|
||||
@TableField("group_id")
|
||||
private Integer groupId;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
public Integer getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
public void setMessageId(Integer messageId) {
|
||||
this.messageId = messageId;
|
||||
}
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
public Integer getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
public void setGroupId(Integer groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
public LocalDateTime getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(LocalDateTime createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GroupMessageRead{" +
|
||||
"messageId=" + messageId +
|
||||
", userId=" + userId +
|
||||
", groupId=" + groupId +
|
||||
", createTime=" + createTime +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package com.upchina.group.mapper;
|
||||
|
||||
import com.upchina.common.mapper.EasyBaseMapper;
|
||||
import com.upchina.group.entity.GroupCollect;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 交易圈统计信息 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author easonzhu
|
||||
* @since 2025-02-13
|
||||
*/
|
||||
public interface GroupCollectMapper extends EasyBaseMapper<GroupCollect> {
|
||||
|
||||
}
|
||||
@ -2,9 +2,12 @@ package com.upchina.group.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.upchina.group.entity.GroupMessage;
|
||||
import com.upchina.group.entity.GroupMessageRead;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -25,4 +28,25 @@ public interface GroupMessageMapper extends BaseMapper<GroupMessage> {
|
||||
") t\n" +
|
||||
"WHERE rn = 1")
|
||||
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" +
|
||||
"FROM group_message \n" +
|
||||
"WHERE create_time >= #{startTime} AND create_time < #{endTime} \n" +
|
||||
"GROUP BY group_id, interactive_type, user_type")
|
||||
List<GroupMessage> collectMessage(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
|
||||
|
||||
@Select("SELECT group_id, interactive_type, COUNT(DISTINCT user_id) AS id \n" +
|
||||
"FROM group_message \n" +
|
||||
"WHERE user_type = 2 AND create_time >= #{startTime} AND create_time < #{endTime} \n" +
|
||||
"GROUP BY group_id, interactive_type")
|
||||
List<GroupMessage> collectMessageMember(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
|
||||
}
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
package com.upchina.group.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.upchina.group.entity.GroupMessageRead;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 交易圈消息已读 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author easonzhu
|
||||
* @since 2025-02-13
|
||||
*/
|
||||
public interface GroupMessageReadMapper extends BaseMapper<GroupMessageRead> {
|
||||
|
||||
}
|
||||
@ -1,13 +1,15 @@
|
||||
package com.upchina.group.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.mapper.EasyBaseMapper;
|
||||
import com.upchina.common.vo.IdCountVO;
|
||||
import com.upchina.group.entity.GroupUserFlow;
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -18,10 +20,22 @@ import java.util.List;
|
||||
* @author easonzhu
|
||||
* @since 2025-02-04
|
||||
*/
|
||||
public interface GroupUserFlowMapper extends BaseMapper<GroupUserFlow> {
|
||||
public interface GroupUserFlowMapper extends EasyBaseMapper<GroupUserFlow> {
|
||||
|
||||
@Select("SELECT h.group_id, h.user_id, h.session_id, 2 as is_online " +
|
||||
"FROM group_user_flow h " +
|
||||
"${ew.customSqlSegment}")
|
||||
List<OnlineUser> loadHis(@Param(Constants.WRAPPER) LambdaQueryWrapper<GroupUserFlow> wrapper);
|
||||
|
||||
@Select("SELECT \n" +
|
||||
" group_id, \n" +
|
||||
" COUNT(DISTINCT user_id) AS user_count \n" +
|
||||
"FROM \n" +
|
||||
" group_user_flow \n" +
|
||||
"WHERE \n" +
|
||||
" time >= #{startTime} \n" +
|
||||
" AND time < #{endTime} \n" +
|
||||
"GROUP BY \n" +
|
||||
" group_id")
|
||||
List<IdCountVO> selectGroupUserCount(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime);
|
||||
}
|
||||
|
||||
@ -0,0 +1,22 @@
|
||||
package com.upchina.group.query.message;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
public class ReadGroupMessageAppQuery {
|
||||
|
||||
@ApiModelProperty("消息ID")
|
||||
@NotEmpty
|
||||
private List<Integer> messageIds;
|
||||
|
||||
public List<Integer> getMessageIds() {
|
||||
return messageIds;
|
||||
}
|
||||
|
||||
public void setMessageIds(List<Integer> messageIds) {
|
||||
this.messageIds = messageIds;
|
||||
}
|
||||
|
||||
}
|
||||
51
src/main/java/com/upchina/group/schedule/GroupTask.java
Normal file
51
src/main/java/com/upchina/group/schedule/GroupTask.java
Normal file
@ -0,0 +1,51 @@
|
||||
package com.upchina.group.schedule;
|
||||
|
||||
import com.upchina.common.config.cache.CacheKey;
|
||||
import com.upchina.common.service.CacheService;
|
||||
import com.upchina.group.service.common.GroupCommonService;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Component
|
||||
public class GroupTask {
|
||||
|
||||
@Resource
|
||||
private CacheService cacheService;
|
||||
|
||||
@Resource
|
||||
private GroupCommonService groupCommonService;
|
||||
|
||||
/**
|
||||
* 拉取云端视频转码状态
|
||||
*/
|
||||
@Scheduled(cron = "${cron.saveGroupMessageRead}")
|
||||
public void saveGroupMessageRead() {
|
||||
cacheService.lock(CacheKey.LockKey.SAVE_MESSAGE_READ,
|
||||
0, TimeUnit.SECONDS,
|
||||
4, TimeUnit.MINUTES,
|
||||
groupCommonService::saveGroupMessageRead
|
||||
);
|
||||
}
|
||||
|
||||
@Scheduled(cron = "${cron.saveGroupUser}")
|
||||
public void saveGroupUser() {
|
||||
cacheService.lock(CacheKey.LockKey.SAVE_GROUP_USER,
|
||||
0, TimeUnit.SECONDS,
|
||||
4, TimeUnit.MINUTES,
|
||||
groupCommonService::saveGroupUser
|
||||
);
|
||||
}
|
||||
|
||||
@Scheduled(cron = "${cron.collectGroupData}")
|
||||
public void collectGroupData() {
|
||||
cacheService.lock(CacheKey.LockKey.COLLECT_GROUP_DATA,
|
||||
0, TimeUnit.SECONDS,
|
||||
4, TimeUnit.MINUTES,
|
||||
groupCommonService::collectGroupData
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@ -18,12 +18,14 @@ import com.upchina.group.constant.QueryGroupMessageType;
|
||||
import com.upchina.group.entity.GroupMessage;
|
||||
import com.upchina.group.mapper.GroupMessageMapper;
|
||||
import com.upchina.group.query.message.ListGroupMessageAppQuery;
|
||||
import com.upchina.group.query.message.ReadGroupMessageAppQuery;
|
||||
import com.upchina.group.query.message.SendGroupMessageAppQuery;
|
||||
import com.upchina.group.service.GroupInfoService;
|
||||
import com.upchina.group.service.common.GroupCacheService;
|
||||
import com.upchina.group.service.common.GroupCommonService;
|
||||
import com.upchina.group.service.common.GroupMessageService;
|
||||
import com.upchina.group.vo.GroupVO;
|
||||
import com.upchina.group.vo.message.GroupMessageReadVO;
|
||||
import com.upchina.group.vo.message.GroupMessageVO;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -127,4 +129,8 @@ public class AppGroupMessageService {
|
||||
return vo;
|
||||
}
|
||||
|
||||
public void readMessage(ReadGroupMessageAppQuery query, FrontUserVO frontUser) {
|
||||
GroupMessageReadVO vo = new GroupMessageReadVO(frontUser.getUserId(), query.getMessageIds());
|
||||
groupCacheService.readMessage(vo);
|
||||
}
|
||||
}
|
||||
@ -2,22 +2,23 @@ package com.upchina.group.service.common;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.upchina.advisor.vo.AdvisorBasicVO;
|
||||
import com.upchina.common.config.cache.CacheKey;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.handler.BizException;
|
||||
import com.upchina.common.result.ResponseStatus;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.service.CacheService;
|
||||
import com.upchina.group.constant.GroupInteractiveType;
|
||||
import com.upchina.group.constant.GroupMessageUserType;
|
||||
import com.upchina.group.constant.QueryGroupMessageType;
|
||||
import com.upchina.group.entity.GroupMessage;
|
||||
import com.upchina.group.entity.GroupUserFlow;
|
||||
import com.upchina.group.mapper.GroupInfoMapper;
|
||||
import com.upchina.group.mapper.GroupMessageMapper;
|
||||
import com.upchina.group.mapper.GroupUserFlowMapper;
|
||||
import com.upchina.group.vo.message.GroupMessageReadVO;
|
||||
import com.upchina.group.vo.message.GroupMessageVO;
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@ -28,9 +29,15 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class GroupCacheService {
|
||||
|
||||
@Resource
|
||||
private HazelcastInstance hazelcastInstance;
|
||||
|
||||
@Resource
|
||||
private CacheService cacheService;
|
||||
|
||||
@Resource
|
||||
private GroupInfoMapper groupInfoMapper;
|
||||
|
||||
@Resource
|
||||
private GroupMessageMapper groupMessageMapper;
|
||||
|
||||
@ -40,15 +47,6 @@ public class GroupCacheService {
|
||||
@Resource
|
||||
private IMap<String, Object> groupCache;
|
||||
|
||||
// public void clearMessageCache(Integer msgId, Integer groupId) {
|
||||
// if (msgId != null) {
|
||||
// groupCache.remove(CacheKey.GroupKey.GROUP_MESSAGE_DETAIL + msgId);
|
||||
// }
|
||||
// if (groupId != null) {
|
||||
// groupCache.remove(CacheKey.GroupKey.GROUP_MESSAGE_LIST + groupId);
|
||||
// }
|
||||
// }
|
||||
|
||||
public NavigableSet<Integer> getMessageIdSet(Integer groupId, String userId, QueryGroupMessageType type) {
|
||||
String cacheKey = buildMessageIdSetKey(userId, type);
|
||||
return cacheService.get(groupCache, cacheKey, () -> {
|
||||
@ -136,7 +134,7 @@ public class GroupCacheService {
|
||||
}
|
||||
|
||||
public GroupMessageVO getMessage(GroupMessage message, Map<Integer, AdvisorBasicVO> advisorMap) {
|
||||
GroupMessageVO vo = new GroupMessageVO(message, advisorMap.get(message.getAdvisorId()));
|
||||
GroupMessageVO vo = new GroupMessageVO(message, advisorMap == null ? null : advisorMap.get(message.getAdvisorId()));
|
||||
vo.setReplyMessage(getMessage(message.getReplyId(), advisorMap));
|
||||
vo.setQuoteMessage(getMessage(message.getQuoteId(), advisorMap));
|
||||
return vo;
|
||||
@ -161,4 +159,9 @@ public class GroupCacheService {
|
||||
}
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
public void readMessage(GroupMessageReadVO vo) {
|
||||
hazelcastInstance.getList(CacheKey.GroupKey.TEMP_READ_LIST).add(vo);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,13 +1,236 @@
|
||||
package com.upchina.group.service.common;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.upchina.common.config.cache.CacheKey;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.vo.IdCountVO;
|
||||
import com.upchina.group.constant.GroupInteractiveType;
|
||||
import com.upchina.group.constant.GroupMessageUserType;
|
||||
import com.upchina.group.entity.*;
|
||||
import com.upchina.group.mapper.GroupCollectMapper;
|
||||
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.message.GroupMessageReadVO;
|
||||
import com.upchina.group.vo.message.GroupMessageVO;
|
||||
import com.upchina.video.schedule.CollectTask;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class GroupCommonService {
|
||||
|
||||
@Resource
|
||||
private HazelcastInstance hazelcastInstance;
|
||||
|
||||
@Resource
|
||||
private GroupCacheService groupCacheService;
|
||||
|
||||
@Resource
|
||||
private GroupMessageMapper groupMessageMapper;
|
||||
|
||||
@Resource
|
||||
private GroupInfoMapper groupInfoMapper;
|
||||
|
||||
@Resource
|
||||
private GroupUserFlowMapper groupUserFlowMapper;
|
||||
|
||||
@Resource
|
||||
private GroupCollectMapper groupCollectMapper;
|
||||
private CollectTask collectTask;
|
||||
|
||||
public boolean validateUserPermission(String userId, GroupVO groupVO) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveGroupMessageRead() {
|
||||
List<GroupMessageReadVO> cacheList = hazelcastInstance.getList(CacheKey.GroupKey.TEMP_READ_LIST);
|
||||
// 合并重复项
|
||||
Map<Integer, Set<String>> map = new HashMap<>(cacheList.size());
|
||||
for (GroupMessageReadVO read : cacheList) {
|
||||
if (read != null) {
|
||||
read.getMessageIds().stream().forEach(m ->
|
||||
map.computeIfAbsent(m, k -> new HashSet<>()).add(read.getUserId()));
|
||||
}
|
||||
}
|
||||
List<GroupMessageRead> list = map.entrySet().stream()
|
||||
.map(entry -> {
|
||||
Integer messageId = entry.getKey();
|
||||
GroupMessageVO message = groupCacheService.getMessage(messageId, null);
|
||||
if (message == null
|
||||
|| !GroupInteractiveType.GROUP.value.equals(message.getInteractiveType())
|
||||
|| (!GroupMessageUserType.ADVISOR.value.equals(message.getUserType()) &&
|
||||
!GroupMessageUserType.ASSISTANT.value.equals(message.getUserType()))) {
|
||||
return null;
|
||||
}
|
||||
return entry.getValue().stream().map(userId -> {
|
||||
GroupMessageRead read = new GroupMessageRead();
|
||||
read.setMessageId(messageId);
|
||||
read.setUserId(userId);
|
||||
read.setGroupId(message.getGroupId());
|
||||
return read;
|
||||
}).collect(Collectors.toList());
|
||||
}).filter(Objects::nonNull).flatMap(List::stream).collect(Collectors.toList());
|
||||
if (CollUtil.isNotEmpty(list)) {
|
||||
groupMessageMapper.replaceBatch(list);
|
||||
}
|
||||
cacheList.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入视频用户数据
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveGroupUser() {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LambdaQueryWrapper<GroupInfo> wrapper = Wrappers.<GroupInfo>lambdaQuery()
|
||||
.select(GroupInfo::getId, GroupInfo::getStatus);
|
||||
List<GroupInfo> groups = groupInfoMapper.selectList(wrapper);
|
||||
if (CollUtil.isEmpty(groups)) {
|
||||
return;
|
||||
}
|
||||
LocalDateTime time = now.withSecond(0).withNano(0);
|
||||
LocalDateTime startTime = now.plusMinutes(-1);
|
||||
|
||||
groups.forEach(g -> {
|
||||
Integer id = g.getId();
|
||||
IMap<String, OnlineUser> onlineMap = groupCacheService.getTotalOnlineMap(id);
|
||||
if (onlineMap == null || onlineMap.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 将实时在线人落库,并添加是否正在观看
|
||||
List<GroupUserFlow> onLineList = onlineMap.values().stream()
|
||||
.filter(u -> IsOrNot.IS.value.equals(u.getIsOnline()) || (u.getExitTime() != null && u.getExitTime().isAfter(startTime)))
|
||||
.map(o -> {
|
||||
GroupUserFlow groupUserFlow = new GroupUserFlow();
|
||||
groupUserFlow.setGroupId(id);
|
||||
groupUserFlow.setUserId(o.getUserId());
|
||||
groupUserFlow.setSessionId(o.getSessionId());
|
||||
groupUserFlow.setTime(time);
|
||||
groupUserFlow.setEnterTime(o.getCreateTime() != null ? o.getCreateTime().withSecond(0).withNano(0) : null);
|
||||
groupUserFlow.setExitTime(o.getExitTime() != null ? o.getExitTime().withSecond(0).withNano(0) : null);
|
||||
return groupUserFlow;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
if (CollUtil.isNotEmpty(onLineList)) {
|
||||
ListUtil.split(onLineList, 1000).stream().filter(CollUtil::isNotEmpty).forEach(groupUserFlowMapper::insertBatchSomeColumn);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void collectGroupData() {
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate yesterday = today.minusDays(1);
|
||||
LambdaQueryWrapper<GroupInfo> groupWrapper = Wrappers.<GroupInfo>lambdaQuery()
|
||||
.select(GroupInfo::getId);
|
||||
List<GroupInfo> groups = groupInfoMapper.selectList(groupWrapper);
|
||||
if (CollUtil.isEmpty(groups)) {
|
||||
return;
|
||||
}
|
||||
List<Integer> groupIds = groups.stream().map(GroupInfo::getId).collect(Collectors.toList());
|
||||
// 获取昨日数据
|
||||
// 如果昨天数据还是昨天统计的,那需要重新计算;否则不需计算
|
||||
QueryWrapper<GroupCollect> collectWrapper = Wrappers.<GroupCollect>query()
|
||||
.select("max(create_time) as create_time")
|
||||
.eq("date", yesterday);
|
||||
GroupCollect yesterdayLatest = groupCollectMapper.selectOne(collectWrapper);
|
||||
if (yesterdayLatest != null && yesterdayLatest.getCreateTime().isBefore(today.atStartOfDay())) {
|
||||
collectGroupData(groupIds, yesterday);
|
||||
}
|
||||
|
||||
collectGroupData(groupIds, today);
|
||||
}
|
||||
|
||||
public void collectGroupData(List<Integer> groupIds, LocalDate date) {
|
||||
LocalDateTime startTime = date.atStartOfDay();
|
||||
LocalDateTime endTime = date.plusDays(1).atStartOfDay();
|
||||
List<IdCountVO> visitMemberList = groupUserFlowMapper.selectGroupUserCount(startTime, endTime);
|
||||
Map<Integer, Integer> visitMemberMap = visitMemberList.stream().collect(Collectors.toMap(IdCountVO::getId, IdCountVO::getCount));
|
||||
|
||||
List<GroupMessage> messageMemberCollect = groupMessageMapper.collectMessageMember(startTime, endTime);
|
||||
Map<Integer, List<GroupMessage>> groupMessageMemberMap = messageMemberCollect.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId));
|
||||
|
||||
List<GroupMessage> messageCollect = groupMessageMapper.collectMessage(startTime, endTime);
|
||||
Map<Integer, List<GroupMessage>> groupMessageMap = messageCollect.stream().collect(Collectors.groupingBy(GroupMessage::getGroupId));
|
||||
|
||||
List<GroupCollect> collectList = groupIds.stream().map(groupId -> {
|
||||
GroupCollect collect = new GroupCollect();
|
||||
collect.setGroupId(groupId);
|
||||
collect.setDate(date);
|
||||
collect.setTotalMembers(getTotalMembers(groupId));
|
||||
collect.setVisitedMembers(visitMemberMap.getOrDefault(groupId, 0));
|
||||
collect.setNewMembers(getNewMembers(groupId));
|
||||
collect.setInteractionMembers(0);
|
||||
collect.setPrivateChatMembers(0);
|
||||
List<GroupMessage> messageMemberList = groupMessageMemberMap.get(groupId);
|
||||
if (CollUtil.isNotEmpty(messageMemberList)) {
|
||||
for (GroupMessage groupMessage : messageMemberList) {
|
||||
if (GroupInteractiveType.GROUP.value.equals(groupMessage.getInteractiveType())) {
|
||||
collect.setInteractionMembers(groupMessage.getId());
|
||||
} else if (GroupInteractiveType.PRIVATE.value.equals(groupMessage.getInteractiveType())) {
|
||||
collect.setPrivateChatMembers(groupMessage.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
collect.setAdvisorGroupContent(0);
|
||||
collect.setAssistantGroupContent(0);
|
||||
collect.setCustomerGroupContent(0);
|
||||
collect.setAdvisorPrivateContent(0);
|
||||
collect.setAssistantPrivateContent(0);
|
||||
collect.setCustomerPrivateContent(0);
|
||||
List<GroupMessage> messageList = groupMessageMap.get(groupId);
|
||||
if (CollUtil.isNotEmpty(messageList)) {
|
||||
for (GroupMessage groupMessage : messageList) {
|
||||
if (GroupInteractiveType.GROUP.value.equals(groupMessage.getInteractiveType())) {
|
||||
if (GroupMessageUserType.ADVISOR.value.equals(groupMessage.getUserType())) {
|
||||
collect.setAdvisorGroupContent(groupMessage.getId());
|
||||
} else if (GroupMessageUserType.ASSISTANT.value.equals(groupMessage.getUserType())) {
|
||||
collect.setAssistantGroupContent(groupMessage.getId());
|
||||
} else if (GroupMessageUserType.CUSTOMER.value.equals(groupMessage.getUserType())) {
|
||||
collect.setCustomerGroupContent(groupMessage.getId());
|
||||
}
|
||||
} else if (GroupInteractiveType.PRIVATE.value.equals(groupMessage.getInteractiveType())) {
|
||||
if (GroupMessageUserType.ADVISOR.value.equals(groupMessage.getUserType())) {
|
||||
collect.setAdvisorPrivateContent(groupMessage.getId());
|
||||
} else if (GroupMessageUserType.ASSISTANT.value.equals(groupMessage.getUserType())) {
|
||||
collect.setAssistantPrivateContent(groupMessage.getId());
|
||||
} else if (GroupMessageUserType.CUSTOMER.value.equals(groupMessage.getUserType())) {
|
||||
collect.setCustomerPrivateContent(groupMessage.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return collect;
|
||||
|
||||
}).collect(Collectors.toList());
|
||||
if (CollUtil.isNotEmpty(collectList)) {
|
||||
groupCollectMapper.delete(Wrappers.<GroupCollect>lambdaQuery().eq(GroupCollect::getDate, date));
|
||||
groupCollectMapper.insertBatchSomeColumn(collectList);
|
||||
}
|
||||
}
|
||||
|
||||
private Integer getTotalMembers(Integer groupId) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
private Integer getNewMembers(Integer groupId) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ import com.hazelcast.topic.ITopic;
|
||||
import com.upchina.advisor.service.AdvisorInfoService;
|
||||
import com.upchina.advisor.vo.AdvisorBasicVO;
|
||||
import com.upchina.common.config.cache.CacheKey;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.vo.FrontUserVO;
|
||||
import com.upchina.group.constant.GroupInteractiveType;
|
||||
import com.upchina.group.constant.GroupMessageChannel;
|
||||
@ -13,7 +14,6 @@ import com.upchina.group.constant.GroupMessageType;
|
||||
import com.upchina.group.entity.GroupMessage;
|
||||
import com.upchina.group.vo.message.GroupMessageVO;
|
||||
import com.upchina.group.vo.message.GroupWsMessageVO;
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package com.upchina.group.vo.message;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public class GroupMessageReadVO implements Serializable {
|
||||
|
||||
private String userId;
|
||||
|
||||
private List<Integer> messageIds;
|
||||
|
||||
public GroupMessageReadVO() {}
|
||||
|
||||
public GroupMessageReadVO(String userId, List<Integer> messageIds) {
|
||||
this.userId = userId;
|
||||
this.messageIds = messageIds;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public List<Integer> getMessageIds() {
|
||||
return messageIds;
|
||||
}
|
||||
|
||||
public void setMessageIds(List<Integer> messageIds) {
|
||||
this.messageIds = messageIds;
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,7 @@ import com.upchina.common.result.CommonResult;
|
||||
import com.upchina.common.vo.AuthVO;
|
||||
import com.upchina.common.vo.BackendUserVO;
|
||||
import com.upchina.rbac.query.ChangeMobileQuery;
|
||||
import com.upchina.rbac.query.ChangePasswordQuery;
|
||||
import com.upchina.rbac.query.LoginDeptQuery;
|
||||
import com.upchina.rbac.query.LoginQuery;
|
||||
import com.upchina.rbac.service.AuthService;
|
||||
@ -82,6 +83,15 @@ public class AuthController {
|
||||
return CommonResult.success(vo);
|
||||
}
|
||||
|
||||
@ApiOperation("修改用户密码")
|
||||
@PostMapping("/changePassword")
|
||||
@Auth(role = AccessRole.LOGIN)
|
||||
public CommonResult<Void> changePassword(@Validated @RequestBody @ApiParam(required = true) ChangePasswordQuery query,
|
||||
@RequestAttribute(value = "backendUser", required = false) BackendUserVO backendUserVO) {
|
||||
authService.changePassword(query, backendUserVO);
|
||||
return CommonResult.success(null);
|
||||
}
|
||||
|
||||
@ApiOperation("修改用户手机号")
|
||||
@PostMapping("/changeMobile")
|
||||
@Auth(role = AccessRole.LOGIN)
|
||||
|
||||
@ -25,10 +25,7 @@ import com.upchina.rbac.entity.UserDept;
|
||||
import com.upchina.rbac.entity.UserLogin;
|
||||
import com.upchina.rbac.mapper.UserDeptMapper;
|
||||
import com.upchina.rbac.mapper.UserLoginMapper;
|
||||
import com.upchina.rbac.query.ChangeMobileQuery;
|
||||
import com.upchina.rbac.query.ListRoleByUserIdQuery;
|
||||
import com.upchina.rbac.query.LoginDeptQuery;
|
||||
import com.upchina.rbac.query.LoginQuery;
|
||||
import com.upchina.rbac.query.*;
|
||||
import com.upchina.rbac.vo.*;
|
||||
import com.upchina.video.constant.VideoUserType;
|
||||
import com.wf.captcha.SpecCaptcha;
|
||||
@ -183,6 +180,25 @@ public class AuthService {
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void changePassword(ChangePasswordQuery query, BackendUserVO backendUserVO) {
|
||||
Integer loginId = backendUserVO.getLoginId();
|
||||
UserLogin userInDB = userLoginMapper.selectById(loginId);
|
||||
if (userInDB == null) {
|
||||
throw new BizException(ResponseStatus.USER_STATUS_ERROR);
|
||||
}
|
||||
String originalPassword = query.getOriginalPassword();
|
||||
if (!CodecUtil.md5(originalPassword).equals(userInDB.getPassword())) {
|
||||
throw new BizException(ResponseStatus.ORIGINAL_PASSWORD_ERROR);
|
||||
}
|
||||
String md5 = CodecUtil.md5(query.getPassword());
|
||||
UserLogin user = new UserLogin();
|
||||
user.setLoginId(loginId);
|
||||
user.setPassword(md5);
|
||||
userLoginMapper.updateById(user);
|
||||
userService.clearCache();
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void changeMobile(ChangeMobileQuery query, BackendUserVO backendUserVO) {
|
||||
Integer loginId = backendUserVO.getLoginId();
|
||||
|
||||
@ -2,8 +2,8 @@ package com.upchina.video.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.mapper.EasyBaseMapper;
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import com.upchina.video.entity.VideoLiveTrend;
|
||||
import com.upchina.video.entity.VideoUserFlow;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@ -14,6 +14,7 @@ import com.upchina.advisor.entity.AdvisorFollow;
|
||||
import com.upchina.advisor.mapper.AdvisorFollowMapper;
|
||||
import com.upchina.common.constant.IsFollow;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.video.constant.VideoLiveStatus;
|
||||
import com.upchina.video.constant.VideoMessageContentType;
|
||||
import com.upchina.video.constant.VideoMessageStatus;
|
||||
|
||||
@ -15,6 +15,7 @@ import com.upchina.common.config.cache.CacheKey;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.constant.ProductType;
|
||||
import com.upchina.common.constant.UserType;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.handler.BizException;
|
||||
import com.upchina.common.result.Pager;
|
||||
import com.upchina.common.result.ResponseStatus;
|
||||
|
||||
@ -15,6 +15,7 @@ import com.upchina.common.config.cache.CacheKey;
|
||||
import com.upchina.common.constant.IsActive;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.constant.ProductType;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.result.AppPager;
|
||||
import com.upchina.common.service.AdvertService;
|
||||
import com.upchina.common.service.CacheService;
|
||||
|
||||
@ -9,6 +9,7 @@ import com.google.common.collect.Table;
|
||||
import com.upchina.common.config.cache.CacheKey;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.constant.ProductType;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.handler.BizException;
|
||||
import com.upchina.common.result.ResponseStatus;
|
||||
import com.upchina.common.service.*;
|
||||
|
||||
@ -9,13 +9,13 @@ import com.hazelcast.map.IMap;
|
||||
import com.hazelcast.topic.ITopic;
|
||||
import com.upchina.advisor.service.AdvisorInfoService;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.common.handler.BizException;
|
||||
import com.upchina.common.result.ResponseStatus;
|
||||
import com.upchina.common.util.logger.LoggerUtil;
|
||||
import com.upchina.common.vo.FrontUserVO;
|
||||
import com.upchina.rbac.service.UserService;
|
||||
import com.upchina.video.constant.*;
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import com.upchina.video.entity.VideoLive;
|
||||
import com.upchina.video.entity.VideoLiveMessage;
|
||||
import com.upchina.video.helper.VideoHelper;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.upchina.video.vo.message;
|
||||
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.upchina.video.vo.message;
|
||||
|
||||
import com.upchina.video.entity.OnlineUser;
|
||||
import com.upchina.common.entity.OnlineUser;
|
||||
import com.upchina.video.entity.VideoCart;
|
||||
import com.upchina.video.vo.cart.CouponVO;
|
||||
import com.upchina.video.vo.question.NotifyQuestionVO;
|
||||
|
||||
@ -15,16 +15,19 @@ hazelcast:
|
||||
serverPort: 5709 #自己作为缓存服务器监听的端口号
|
||||
scheduledEnable: true
|
||||
cron:
|
||||
collectLivingVideo: "30 1/5 * * * ?" #每分钟统计已开始但未结束的视频直播数据
|
||||
saveVideoCount: "30 2/2 * * * ?" #从cache刷新视频播放量到DB 每分钟的第10s执行
|
||||
saveVideoUserDataToDB: "30 3/5 * * * ?"
|
||||
saveCustomerDataToDB: "30 4/5 * * * ?" #收集用户信息
|
||||
refreshTranscodeStatus: "30 0/5 * * * ?" #从腾讯云拉取录播上传视频信息更新到DB
|
||||
collectLivingVideo: "30 0/5 * * * ?" #每分钟统计已开始但未结束的视频直播数据
|
||||
saveVideoCount: "30 1/2 * * * ?" #从cache刷新视频播放量到DB 每分钟的第10s执行
|
||||
saveVideoUserDataToDB: "30 2/5 * * * ?"
|
||||
saveCustomerDataToDB: "30 3/5 * * * ?" #收集用户信息
|
||||
refreshTranscodeStatus: "30 4/5 * * * ?" #从腾讯云拉取录播上传视频信息更新到DB
|
||||
updateLiveStatus: "0 1 * * * ?" #更新视频录播状态
|
||||
stopLivingVideo: "0 1-5 0 * * ?" #结束前一天直播中/暂停中的视频直播
|
||||
saveWatchSeconds: "0 0/5 * * * ?" #保存短视频观看时长
|
||||
collectLastWeek: "0 30 3 * * ?" #统计一周内的数据
|
||||
collectRecentEndVideo: "0 2/5 * * * ?" #每5分钟统计已结束48小时以内的视频直播数据
|
||||
saveWatchSeconds: "0 0/5 * * * ?" #保存短视频观看时长
|
||||
collectRecentEndVideo: "0 1/5 * * * ?" #每5分钟统计已结束48小时以内的视频直播数据
|
||||
saveGroupMessageRead: "0 2/5 * * * ?" #每5分钟统计已结束48小时以内的视频直播数据
|
||||
saveGroupUser: "0 3/5 * * * ?"
|
||||
collectGroupData: "0 4/5 * * * ?"
|
||||
user:
|
||||
admin:
|
||||
roles: 1,3,4,5 #管理员角色id,用逗号隔开
|
||||
|
||||
@ -1,192 +0,0 @@
|
||||
package com.upchina.group.service;
|
||||
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.upchina.advisor.entity.AdvisorBasic;
|
||||
import com.upchina.advisor.service.AdvisorInfoService;
|
||||
import com.upchina.common.query.OnlyIdQuery;
|
||||
import com.upchina.common.service.AppUserService;
|
||||
import com.upchina.common.service.CacheService;
|
||||
import com.upchina.common.service.SensitiveWordService;
|
||||
import com.upchina.common.state.StateMachine;
|
||||
import com.upchina.common.vo.BackendUserVO;
|
||||
import com.upchina.common.vo.InsertIdVO;
|
||||
import com.upchina.course.service.PageService;
|
||||
import com.upchina.group.constant.GroupInfoStatus;
|
||||
import com.upchina.group.entity.GroupInfo;
|
||||
import com.upchina.group.mapper.GroupInfoMapper;
|
||||
import com.upchina.group.query.SaveGroupQuery;
|
||||
import com.upchina.group.query.UpdateGroupQuery;
|
||||
import com.upchina.group.query.UpdateGroupStatusQuery;
|
||||
import com.upchina.rbac.entity.UserDept;
|
||||
import com.upchina.rbac.service.AuthService;
|
||||
import com.upchina.rbac.service.UserService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class GroupInfoServiceTest {
|
||||
|
||||
@Mock
|
||||
private GroupInfoMapper groupInfoMapper;
|
||||
|
||||
@Mock
|
||||
private SensitiveWordService sensitiveWordService;
|
||||
|
||||
@Mock
|
||||
private StateMachine<GroupInfoStatus> groupSM;
|
||||
|
||||
@Mock
|
||||
private AdvisorInfoService advisorInfoService;
|
||||
|
||||
@Mock
|
||||
private UserService userService;
|
||||
|
||||
@Mock
|
||||
private AuthService authService;
|
||||
|
||||
@Mock
|
||||
private PageService pageService;
|
||||
|
||||
@Mock
|
||||
private CacheService cacheService;
|
||||
|
||||
@Mock
|
||||
private AppUserService appUserService;
|
||||
|
||||
@Mock
|
||||
private IMap<String, Object> groupCache;
|
||||
|
||||
@InjectMocks
|
||||
private GroupInfoService groupInfoService;
|
||||
|
||||
private BackendUserVO mockBackendUser;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mockBackendUser = new BackendUserVO();
|
||||
mockBackendUser.setUserId(1);
|
||||
mockBackendUser.setAdvisorId(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
void save_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
SaveGroupQuery query = new SaveGroupQuery();
|
||||
query.setName("测试群组");
|
||||
query.setRemark("测试备注");
|
||||
query.setDetail("测试详情");
|
||||
query.setAdvisorId(100);
|
||||
|
||||
// 设置模拟行为
|
||||
doNothing().when(sensitiveWordService).check(anyString(), anyString(), anyString());
|
||||
when(groupInfoMapper.insert(any(GroupInfo.class))).thenReturn(1);
|
||||
|
||||
// 执行测试
|
||||
InsertIdVO result = groupInfoService.save(query, mockBackendUser);
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(result);
|
||||
verify(groupInfoMapper).insert(any(GroupInfo.class));
|
||||
verify(sensitiveWordService).check(anyString(), anyString(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void update_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
UpdateGroupQuery query = new UpdateGroupQuery();
|
||||
query.setId(1);
|
||||
query.setName("更新的群组名");
|
||||
|
||||
GroupInfo existingGroup = new GroupInfo();
|
||||
existingGroup.setId(1);
|
||||
existingGroup.setStatus(GroupInfoStatus.TO_COMMIT.value);
|
||||
existingGroup.setAdvisorId(100);
|
||||
|
||||
// 设置模拟行为 - 修改这里的 mock 设置
|
||||
when(groupInfoMapper.selectById(1)).thenReturn(existingGroup);
|
||||
when(groupInfoMapper.updateById(any(GroupInfo.class))).thenReturn(1);
|
||||
|
||||
// 执行测试
|
||||
groupInfoService.update(query, mockBackendUser);
|
||||
|
||||
// 验证结果
|
||||
verify(groupInfoMapper).updateById(any(GroupInfo.class));
|
||||
verify(groupCache).delete(anyString());
|
||||
// 验证 sensitiveWordService.check 被调用,使用参数捕获器
|
||||
verify(sensitiveWordService).check(
|
||||
eq("更新的群组名"), // 名称
|
||||
isNull(), // 备注
|
||||
isNull() // 详情
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateStatus_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
UpdateGroupStatusQuery query = new UpdateGroupStatusQuery();
|
||||
query.setId(1);
|
||||
query.setEvent(GroupInfoStatus.EVENT_SUBMIT.value);
|
||||
|
||||
GroupInfo existingGroup = new GroupInfo();
|
||||
existingGroup.setId(1);
|
||||
existingGroup.setStatus(GroupInfoStatus.TO_AUDIT.value);
|
||||
existingGroup.setAdvisorId(100);
|
||||
|
||||
// 设置模拟行为
|
||||
when(groupInfoMapper.selectById(1)).thenReturn(existingGroup);
|
||||
when(groupInfoMapper.updateById(any(GroupInfo.class))).thenReturn(1);
|
||||
when(groupSM.send(any(), any())).thenReturn(GroupInfoStatus.TO_AUDIT);
|
||||
|
||||
// 执行测试
|
||||
groupInfoService.updateStatus(query, mockBackendUser);
|
||||
|
||||
// 验证结果
|
||||
verify(groupInfoMapper).updateById(any(GroupInfo.class));
|
||||
verify(groupCache).delete(anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void get_ShouldReturnGroupVO() {
|
||||
// 准备测试数据
|
||||
OnlyIdQuery query = new OnlyIdQuery(1);
|
||||
|
||||
GroupInfo groupInfo = new GroupInfo();
|
||||
groupInfo.setId(1);
|
||||
groupInfo.setAdvisorId(100);
|
||||
|
||||
Map<Integer, AdvisorBasic> advisorMap = new HashMap<>();
|
||||
AdvisorBasic advisor = new AdvisorBasic();
|
||||
advisor.setId(100);
|
||||
advisorMap.put(100, advisor);
|
||||
|
||||
Map<Integer, UserDept> userMap = new HashMap<>();
|
||||
UserDept userDept = new UserDept();
|
||||
userDept.setUserId(1);
|
||||
userDept.setName("测试用户");
|
||||
userMap.put(1, userDept);
|
||||
|
||||
// 设置模拟行为
|
||||
when(groupInfoMapper.selectById(1)).thenReturn(groupInfo);
|
||||
when(advisorInfoService.getAdvisorMap()).thenReturn(advisorMap);
|
||||
when(userService.getUserMap()).thenReturn(userMap);
|
||||
|
||||
// 执行测试
|
||||
var result = groupInfoService.get(query, mockBackendUser);
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(result);
|
||||
assertEquals(1, result.getId());
|
||||
}
|
||||
}
|
||||
@ -1,134 +0,0 @@
|
||||
package com.upchina.group.service.admin;
|
||||
|
||||
import com.upchina.common.state.StateMachine;
|
||||
import com.upchina.common.vo.BackendUserVO;
|
||||
import com.upchina.common.vo.OnlyIdVO;
|
||||
import com.upchina.group.constant.GroupMessageChannel;
|
||||
import com.upchina.group.constant.GroupMessageStatus;
|
||||
import com.upchina.group.constant.GroupMessageType;
|
||||
import com.upchina.group.entity.GroupInfo;
|
||||
import com.upchina.group.entity.GroupMessage;
|
||||
import com.upchina.group.mapper.GroupInfoMapper;
|
||||
import com.upchina.group.mapper.GroupMessageMapper;
|
||||
import com.upchina.group.query.message.GroupMessageProductQuery;
|
||||
import com.upchina.group.query.message.GroupMessageStatusQuery;
|
||||
import com.upchina.group.query.message.SendGroupMessageAdminQuery;
|
||||
import com.upchina.group.service.common.GroupCacheService;
|
||||
import com.upchina.group.service.common.GroupMessageService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AdminGroupMessageServiceTest {
|
||||
|
||||
@Mock
|
||||
private GroupMessageMapper groupMessageMapper;
|
||||
|
||||
@Mock
|
||||
private GroupInfoMapper groupInfoMapper;
|
||||
|
||||
@Mock
|
||||
private GroupMessageService groupMessageService;
|
||||
|
||||
@Mock
|
||||
private GroupCacheService groupCacheService;
|
||||
|
||||
@Mock
|
||||
private StateMachine<GroupMessageStatus> groupMessageSM;
|
||||
|
||||
@InjectMocks
|
||||
private AdminGroupMessageService adminGroupMessageService;
|
||||
|
||||
private BackendUserVO mockBackendUser;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mockBackendUser = new BackendUserVO();
|
||||
mockBackendUser.setUserId(1);
|
||||
mockBackendUser.setAdvisorId(100);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendAdvisorMessage_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
SendGroupMessageAdminQuery query = new SendGroupMessageAdminQuery();
|
||||
query.setGroupId(1);
|
||||
query.setContent("测试消息");
|
||||
|
||||
when(groupMessageMapper.insert(any(GroupMessage.class))).thenReturn(1);
|
||||
|
||||
// 执行测试
|
||||
OnlyIdVO result = adminGroupMessageService.sendAdvisorMessage(query, mockBackendUser);
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(result);
|
||||
verify(groupMessageMapper).insert(any(GroupMessage.class));
|
||||
verify(groupMessageService).publishGroupMessage(
|
||||
eq(GroupMessageChannel.ALL),
|
||||
eq(GroupMessageType.RECOMMEND_PRODUCT),
|
||||
eq(query.getGroupId()),
|
||||
any()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendInteractiveStatusMessage_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
GroupMessageStatusQuery query = new GroupMessageStatusQuery();
|
||||
query.setGroupId(1);
|
||||
query.setStatus(1);
|
||||
|
||||
GroupInfo mockGroupInfo = new GroupInfo();
|
||||
mockGroupInfo.setId(1);
|
||||
|
||||
when(groupInfoMapper.selectById(query.getGroupId())).thenReturn(mockGroupInfo);
|
||||
when(groupInfoMapper.updateById(any(GroupInfo.class))).thenReturn(1);
|
||||
|
||||
// 执行测试
|
||||
adminGroupMessageService.sendInteractiveStatusMessage(query, mockBackendUser);
|
||||
|
||||
// 验证结果
|
||||
verify(groupInfoMapper).selectById(query.getGroupId());
|
||||
verify(groupInfoMapper).updateById(any(GroupInfo.class));
|
||||
verify(groupMessageService).publishGroupMessage(
|
||||
eq(GroupMessageChannel.APP),
|
||||
eq(GroupMessageType.OPEN_INTERACTIVE),
|
||||
eq(query.getGroupId()),
|
||||
eq(query.getStatus())
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void saveProductMessage_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
GroupMessageProductQuery query = new GroupMessageProductQuery();
|
||||
query.setGroupId(1);
|
||||
query.setProductId(100);
|
||||
query.setProductName("测试产品");
|
||||
query.setProductDesc("产品描述");
|
||||
query.setProductUrl("http://example.com");
|
||||
|
||||
when(groupMessageMapper.insert(any(GroupMessage.class))).thenReturn(1);
|
||||
|
||||
// 执行测试
|
||||
OnlyIdVO result = adminGroupMessageService.saveProductMessage(query, mockBackendUser);
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(result);
|
||||
verify(groupMessageMapper).insert(any(GroupMessage.class));
|
||||
verify(groupMessageService).publishGroupMessage(
|
||||
eq(GroupMessageChannel.ALL),
|
||||
eq(GroupMessageType.RECOMMEND_PRODUCT),
|
||||
eq(query.getGroupId()),
|
||||
any()
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,208 +0,0 @@
|
||||
package com.upchina.group.service.app;
|
||||
|
||||
import com.hazelcast.map.IMap;
|
||||
import com.upchina.common.constant.IsOrNot;
|
||||
import com.upchina.common.handler.BizException;
|
||||
import com.upchina.common.query.OnlyIdQuery;
|
||||
import com.upchina.common.result.AppPager;
|
||||
import com.upchina.common.service.CacheService;
|
||||
import com.upchina.common.service.SensitiveWordService;
|
||||
import com.upchina.common.vo.FrontUserVO;
|
||||
import com.upchina.group.constant.GroupMessageChannel;
|
||||
import com.upchina.group.constant.GroupMessageType;
|
||||
import com.upchina.group.constant.QueryGroupMessageType;
|
||||
import com.upchina.group.entity.GroupMessage;
|
||||
import com.upchina.group.mapper.GroupMessageMapper;
|
||||
import com.upchina.group.query.message.ListGroupMessageAppQuery;
|
||||
import com.upchina.group.query.message.SendGroupMessageAppQuery;
|
||||
import com.upchina.group.service.GroupInfoService;
|
||||
import com.upchina.group.service.common.GroupCacheService;
|
||||
import com.upchina.group.service.common.GroupCommonService;
|
||||
import com.upchina.group.service.common.GroupMessageService;
|
||||
import com.upchina.group.vo.GroupVO;
|
||||
import com.upchina.group.vo.message.GroupMessageVO;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.NavigableSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class AppGroupMessageServiceTest {
|
||||
|
||||
@Mock
|
||||
private GroupMessageMapper groupMessageMapper;
|
||||
|
||||
@Mock
|
||||
private GroupMessageService groupMessageService;
|
||||
|
||||
@Mock
|
||||
private GroupInfoService groupInfoService;
|
||||
|
||||
@Mock
|
||||
private GroupCacheService groupCacheService;
|
||||
|
||||
@Mock
|
||||
private GroupCommonService groupCommonService;
|
||||
|
||||
@Mock
|
||||
private SensitiveWordService sensitiveWordService;
|
||||
|
||||
@Mock
|
||||
private CacheService cacheService;
|
||||
|
||||
@Mock
|
||||
private IMap<String, Object> groupCache;
|
||||
|
||||
@InjectMocks
|
||||
private AppGroupMessageService appGroupMessageService;
|
||||
|
||||
private FrontUserVO mockFrontUser;
|
||||
private GroupVO mockGroupVO;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
mockFrontUser = new FrontUserVO();
|
||||
mockFrontUser.setUserId("123");
|
||||
|
||||
mockGroupVO = new GroupVO();
|
||||
mockGroupVO.setId(1);
|
||||
mockGroupVO.setPrivateChatStatus(IsOrNot.IS.value);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMessageList_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
ListGroupMessageAppQuery query = new ListGroupMessageAppQuery();
|
||||
query.setGroupId(1);
|
||||
query.setType(QueryGroupMessageType.ADVISOR.value);
|
||||
query.setSize(10);
|
||||
|
||||
NavigableSet<Integer> mockSet = new TreeSet<>();
|
||||
mockSet.add(1);
|
||||
mockSet.add(2);
|
||||
|
||||
GroupMessageVO mockMessageVO = new GroupMessageVO();
|
||||
mockMessageVO.setId(1);
|
||||
|
||||
// 设置模拟行为
|
||||
when(groupInfoService.getForApp(any(OnlyIdQuery.class), any())).thenReturn(mockGroupVO);
|
||||
when(groupCommonService.validateUserPermission(anyString(), any(GroupVO.class))).thenReturn(true);
|
||||
when(cacheService.get(eq(groupCache), anyString(), any())).thenReturn(mockSet);
|
||||
|
||||
// 执行测试
|
||||
AppPager<GroupMessageVO> result = appGroupMessageService.getMessageList(query, mockFrontUser);
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(result);
|
||||
assertFalse(result.getList().isEmpty());
|
||||
assertEquals(1, result.getList().get(0).getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMessageList_WithPrivateType_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
ListGroupMessageAppQuery query = new ListGroupMessageAppQuery();
|
||||
query.setGroupId(1);
|
||||
query.setType(QueryGroupMessageType.PRIVATE.value);
|
||||
query.setSize(10);
|
||||
|
||||
NavigableSet<Integer> mockSet = new TreeSet<>();
|
||||
mockSet.add(1);
|
||||
|
||||
GroupMessageVO mockMessageVO = new GroupMessageVO();
|
||||
mockMessageVO.setId(1);
|
||||
|
||||
// 设置模拟行为
|
||||
when(groupInfoService.getForApp(any(OnlyIdQuery.class), any())).thenReturn(mockGroupVO);
|
||||
when(groupCommonService.validateUserPermission(anyString(), any(GroupVO.class))).thenReturn(true);
|
||||
when(cacheService.get(eq(groupCache), anyString(), any())).thenReturn(mockSet);
|
||||
|
||||
// 执行测试
|
||||
AppPager<GroupMessageVO> result = appGroupMessageService.getMessageList(query, mockFrontUser);
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(result);
|
||||
assertFalse(result.getList().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendMessage_ShouldSucceed() {
|
||||
// 准备测试数据
|
||||
SendGroupMessageAppQuery query = new SendGroupMessageAppQuery();
|
||||
query.setGroupId(1);
|
||||
query.setContent("测试消息");
|
||||
|
||||
// 设置模拟行为
|
||||
doNothing().when(sensitiveWordService).check(anyString());
|
||||
when(groupMessageMapper.insert(any(GroupMessage.class))).thenReturn(1);
|
||||
|
||||
// 执行测试
|
||||
GroupMessageVO result = appGroupMessageService.sendMessage(query, mockFrontUser);
|
||||
|
||||
// 验证结果
|
||||
assertNotNull(result);
|
||||
verify(groupMessageService).publishGroupMessage(
|
||||
eq(GroupMessageChannel.ALL),
|
||||
eq(GroupMessageType.NORMAL),
|
||||
eq(query.getGroupId()),
|
||||
any(GroupMessageVO.class)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendMessage_WhenGroupClosed_ShouldThrowException() {
|
||||
// 准备测试数据
|
||||
SendGroupMessageAppQuery query = new SendGroupMessageAppQuery();
|
||||
query.setGroupId(1);
|
||||
query.setContent("测试消息");
|
||||
|
||||
// 设置模拟行为
|
||||
doNothing().when(sensitiveWordService).check(anyString());
|
||||
|
||||
// 执行测试并验证异常
|
||||
assertThrows(BizException.class, () ->
|
||||
appGroupMessageService.sendMessage(query, mockFrontUser)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sendMessage_WhenUserForbidden_ShouldThrowException() {
|
||||
// 准备测试数据
|
||||
SendGroupMessageAppQuery query = new SendGroupMessageAppQuery();
|
||||
query.setGroupId(1);
|
||||
query.setContent("测试消息");
|
||||
|
||||
// 设置模拟行为
|
||||
doNothing().when(sensitiveWordService).check(anyString());
|
||||
|
||||
// 执行测试并验证异常
|
||||
assertThrows(BizException.class, () ->
|
||||
appGroupMessageService.sendMessage(query, mockFrontUser)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getMessageList_WithInvalidGroup_ShouldThrowException() {
|
||||
// 准备测试数据
|
||||
ListGroupMessageAppQuery query = new ListGroupMessageAppQuery();
|
||||
query.setGroupId(1);
|
||||
query.setType(QueryGroupMessageType.ADVISOR.value);
|
||||
|
||||
// 设置模拟行为
|
||||
when(groupInfoService.getForApp(any(OnlyIdQuery.class), any())).thenReturn(null);
|
||||
|
||||
// 执行测试并验证异常
|
||||
assertThrows(BizException.class, () ->
|
||||
appGroupMessageService.getMessageList(query, mockFrontUser)
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user