Преглед на файлове

perf: 在线人员列表查询缓存

zqqqqqq преди 1 месец
родител
ревизия
48feb14384

+ 2 - 0
fs-common/src/main/java/com/fs/common/constant/LiveKeysConstant.java

@@ -12,4 +12,6 @@ public class LiveKeysConstant {
 
     public static final String LIVE_HOME_PAGE_LIST = "live:homePage:list"; //直播列表数据
     public static final Integer LIVE_HOME_PAGE_LIST_EXPIRE = 300; //首页缓存过期时间
+    public static final String LIVE_WATCH_USERS = "live:watch:users:%s"; //在线人数
+
 }

+ 8 - 0
fs-common/src/main/java/com/fs/common/core/redis/RedisUtil.java

@@ -190,6 +190,14 @@ public class RedisUtil {
         redisTemplate.opsForHash().put(key, hashKey, value);
     }
 
+    /**
+     * 向哈希表中添加键值对批量
+     *
+     * @param key 哈希表键
+     */
+    public void hashPut(String key, Map<String, String> var2) {
+        redisTemplate.opsForHash().putAll(key, var2);
+    }
     /**
      * 获取哈希表中的值
      *

+ 1 - 1
fs-service-system/src/main/java/com/fs/live/domain/LiveWatchUser.java

@@ -37,7 +37,7 @@ public class LiveWatchUser extends BaseEntity {
 
     /** 在线状态;0在线1离线 */
     @Excel(name = "在线状态;0在线1离线")
-    private Integer online;
+    private Integer online = 0;
 
     /** 用户名字 */
 

+ 2 - 0
fs-service-system/src/main/java/com/fs/live/service/ILiveWatchUserService.java

@@ -108,4 +108,6 @@ public interface ILiveWatchUserService {
 
 
     List<LiveWatchUser> selectLiveWatchAndRegisterUser(Long liveId, Long lotteryId,Integer totalLots);
+
+    List<LiveWatchUserVO> asyncToCache(Long liveId);
 }

+ 0 - 1
fs-service-system/src/main/java/com/fs/live/service/impl/LiveDataServiceImpl.java

@@ -364,7 +364,6 @@ public class LiveDataServiceImpl implements ILiveDataService {
     @Override
     @Transactional
     public R updateLikeByLiveId(Long liveId, Long userId) {
-        //一个用户一天只能点赞十次
         String key = "live:like:" + liveId + ":user:" + userId+":date:"+ DateUtils.getDate();
         LiveUserLike liveUserLike;
         boolean firstLike = redisCache.setIfAbsent(key, 1, 1, TimeUnit.DAYS);

+ 38 - 1
fs-service-system/src/main/java/com/fs/live/service/impl/LiveWatchUserServiceImpl.java

@@ -1,8 +1,15 @@
 package com.fs.live.service.impl;
 
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import com.alibaba.fastjson.JSON;
+import com.fs.common.constant.LiveKeysConstant;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.core.redis.RedisUtil;
 import com.fs.common.utils.DateUtils;
+import com.fs.live.domain.Live;
 import com.fs.live.domain.LiveWatchUser;
 import com.fs.live.mapper.LiveWatchUserMapper;
 import com.fs.live.service.ILiveWatchUserService;
@@ -10,10 +17,14 @@ import com.fs.live.vo.LiveWatchUserVO;
 import com.fs.store.domain.FsUser;
 import com.fs.store.service.IFsUserService;
 import com.fs.store.vo.FsUserVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * 直播间观看用户Service业务层处理
@@ -22,6 +33,7 @@ import java.util.*;
  * @date 2025-01-18
  */
 @Service
+@Slf4j
 public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
 
     @Autowired
@@ -31,7 +43,8 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
     @Autowired
     private LiveWatchUserMapper baseMapper;
 
-
+    @Autowired
+    private RedisUtil redisUtil;
     /**
      * 查询直播间观看用户
      *
@@ -215,4 +228,28 @@ public class LiveWatchUserServiceImpl implements ILiveWatchUserService {
         return baseMapper.selectLiveWatchAndRegisterUser(liveId, lotteryId,totalLots);
     }
 
+    @Override
+    public List<LiveWatchUserVO> asyncToCache(Long liveId) {
+        LiveWatchUser liveWatchUser = new LiveWatchUser();
+        liveWatchUser.setLiveId(liveId);
+        List<LiveWatchUserVO> liveWatchUserVOS = selectOnlineUserList(liveWatchUser);
+
+        log.info("开始同步直播在线人数到缓存,共{}条数据", liveWatchUserVOS.size());
+        if (CollUtil.isNotEmpty(liveWatchUserVOS)){
+            ThreadUtil.execute(()->{
+                String hashKey  = String.format(LiveKeysConstant.LIVE_WATCH_USERS, liveId);
+                // 清空数据
+                redisUtil.delete(hashKey);
+                Map<String, String> collect = liveWatchUserVOS.stream()
+                        .collect(Collectors.toMap(
+                                watchUserVO -> String.valueOf(watchUserVO.getUserId()),
+                                JSON::toJSONString
+                        ));
+                redisUtil.hashPut(hashKey,collect);
+                log.info("同步直播在线人数到缓存完成");
+            });
+        }
+        return liveWatchUserVOS;
+    }
+
 }

+ 2 - 0
fs-user-app/src/main/java/com/fs/app/controller/LiveDataController.java

@@ -8,6 +8,7 @@ import com.fs.live.service.ILiveWatchUserService;
 import com.fs.live.vo.LiveWatchUserVO;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
 
 import java.util.HashMap;
 import java.util.List;
@@ -45,6 +46,7 @@ public class LiveDataController extends AppBaseController{
      * */
     @Login
     @GetMapping("/like/{liveId}")
+    @ApiIgnore("直播端点赞接口")
     public R like(@PathVariable("liveId") Long liveId) {
         return liveDataService.updateLikeByLiveId(liveId,  Long.parseLong(getUserId()));
     }

+ 7 - 3
fs-user-app/src/main/java/com/fs/app/controller/LiveWatchUserController.java

@@ -1,10 +1,12 @@
 package com.fs.app.controller;
 
+import com.fs.app.facade.LiveFacadeService;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.DateUtils;
 import com.fs.live.domain.LiveWatchUser;
 import com.fs.live.service.ILiveWatchUserService;
 import com.fs.live.vo.LiveWatchUserVO;
@@ -26,14 +28,16 @@ public class LiveWatchUserController extends BaseController
     @Autowired
     private ILiveWatchUserService liveWatchUserService;
 
-
+    @Autowired
+    private LiveFacadeService liveFacadeService;
 
 
     @GetMapping("/watchUserList")
     public TableDataInfo watchUserList(LiveWatchUser param) {
-        param.setOnline(0);
+/*        param.setOnline(0);
         List<LiveWatchUserVO> onLineUserList = liveWatchUserService.selectOnlineUserList(param);
-        return getDataTable(onLineUserList);
+        return getDataTable(onLineUserList);*/
+        return liveFacadeService.watchUserList(param);
     }
 
 

+ 4 - 0
fs-user-app/src/main/java/com/fs/app/facade/LiveFacadeService.java

@@ -2,7 +2,11 @@ package com.fs.app.facade;
 
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.PageRequest;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.live.domain.LiveWatchUser;
 
 public interface LiveFacadeService {
     R liveList(PageRequest pageRequest);
+
+    TableDataInfo watchUserList(LiveWatchUser param);
 }

+ 39 - 1
fs-user-app/src/main/java/com/fs/app/facade/impl/LiveFacadeServiceImpl.java

@@ -1,24 +1,36 @@
 package com.fs.app.facade.impl;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fs.app.facade.LiveFacadeService;
 import com.fs.common.constant.LiveKeysConstant;
+import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.PageRequest;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.core.redis.RedisUtil;
 import com.fs.live.domain.Live;
+import com.fs.live.domain.LiveWatchUser;
 import com.fs.live.service.ILiveService;
+import com.fs.live.service.ILiveWatchUserService;
+import com.fs.live.vo.LiveWatchUserVO;
 import com.github.pagehelper.PageInfo;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 @Service
-public class LiveFacadeServiceImpl implements LiveFacadeService {
+@Slf4j
+public class LiveFacadeServiceImpl extends BaseController implements LiveFacadeService {
 
     @Autowired
     private RedisUtil redisUtil;
@@ -26,6 +38,9 @@ public class LiveFacadeServiceImpl implements LiveFacadeService {
     @Autowired
     private ILiveService liveService;
 
+    @Autowired
+    private ILiveWatchUserService liveWatchUserService;
+
     @Override
     public R liveList(PageRequest pageRequest) {
         int start = (pageRequest.getCurrentPage() - 1) * pageRequest.getPageSize();
@@ -60,4 +75,27 @@ public class LiveFacadeServiceImpl implements LiveFacadeService {
             return R.ok().put("data", result);
         }
     }
+
+    @Override
+    public TableDataInfo watchUserList(LiveWatchUser param) {
+        List<LiveWatchUserVO> liveWatchUserVOS ;
+        String setKey  = String.format(LiveKeysConstant.LIVE_WATCH_USERS, param.getLiveId());
+        Map<Object, Object> hashEntries = redisUtil.hashEntries(setKey);
+        if (CollUtil.isEmpty(hashEntries)){
+            liveWatchUserVOS = liveWatchUserService.asyncToCache(param.getLiveId());
+        }else {
+            liveWatchUserVOS = hashEntries.values().stream()
+                    .map(value -> {
+                        try {
+                            return JSONUtil.toBean(JSONUtil.parseObj(value), LiveWatchUserVO.class);
+                        } catch (Exception e) {
+                            log.error("反序列化LiveWatchUserVO失败: {}", value, e);
+                            return null;
+                        }
+                    })
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toList());
+        }
+        return getDataTable(liveWatchUserVOS);
+    }
 }

+ 91 - 0
fs-user-app/src/main/java/com/fs/core/aspectj/LiveWatchUserAspect.java

@@ -0,0 +1,91 @@
+package com.fs.core.aspectj;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.fs.common.core.redis.RedisUtil;
+import com.fs.live.domain.LiveWatchUser;
+import com.fs.live.service.ILiveWatchUserService;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@Aspect
+@Component
+@Slf4j
+public class LiveWatchUserAspect {
+
+    @Autowired
+    private RedisUtil redisUtil;
+
+    @Autowired
+    private ILiveWatchUserService liveWatchUserService;
+
+    @AfterReturning(pointcut = "execution(* com.fs.live.service.impl.LiveWatchUserServiceImpl.insertLiveWatchUser(..)) || " +
+            "execution(* com.fs.live.service.impl.LiveWatchUserServiceImpl.updateLiveWatchUser(..)) || " +
+            "execution(* com.fs.live.service.impl.LiveWatchUserServiceImpl.deleteLiveWatchUserById(..)) || " +
+            "execution(* com.fs.live.service.impl.LiveWatchUserServiceImpl.deleteLiveWatchUserByIds(..))",
+            returning = "result")
+    public void afterLiveWatchUserOperation(JoinPoint joinPoint, Object result) {
+        try {
+            String methodName = joinPoint.getSignature().getName();
+            Object[] args = joinPoint.getArgs();
+            log.info("直播观看用户数据发生变化,方法: {}, 参数: {}", methodName, Arrays.toString(args));
+            // 提取liveId并处理缓存更新
+            Set<Long> liveIds = extractLiveIds(methodName, args);
+            for (Long liveId : liveIds) {
+                liveWatchUserService.asyncToCache(liveId);
+            }
+        } catch (Exception e) {
+            log.error("执行直播观看用户变更后逻辑失败", e);
+        }
+    }
+
+    private Set<Long> extractLiveIds(String methodName, Object[] args) {
+        Set<Long> liveIds = new HashSet<>();
+        if (args == null || args.length == 0) {
+            return liveIds;
+        }
+        switch (methodName) {
+            case "insertLiveWatchUser":
+            case "updateLiveWatchUser":
+                // 参数是LiveWatchUser对象
+                if (args[0] instanceof LiveWatchUser) {
+                    LiveWatchUser liveWatchUser = (LiveWatchUser) args[0];
+                    if (liveWatchUser.getLiveId() != null) {
+                        liveIds.add(liveWatchUser.getLiveId());
+                    }
+                }
+                break;
+            case "deleteLiveWatchUserById":
+                // 参数是Long类型的id,需要先查询获取liveId
+                if (args[0] instanceof Long) {
+                    LiveWatchUser liveWatchUser = liveWatchUserService.selectLiveWatchUserById((Long) args[0]);
+                    if (ObjectUtil.isNotEmpty(liveWatchUser)) {
+                        liveIds.add(liveWatchUser.getLiveId());
+                    }
+                }
+                break;
+            case "deleteLiveWatchUserByIds":
+                // 参数是Long[]数组
+                if (args[0] instanceof Long[]) {
+                    Long[] ids = (Long[]) args[0];
+                    LiveWatchUser liveWatchUser = liveWatchUserService.selectLiveWatchUserById(ids[0]);
+                    if (ObjectUtil.isNotEmpty(liveWatchUser)) {
+                        liveIds.add(liveWatchUser.getLiveId());
+                    }
+                }
+                break;
+            default:
+                log.warn("未处理的方法: {}", methodName);
+        }
+        return liveIds;
+    }
+
+
+}