Przeglądaj źródła

perf(消费服务): 卡片缓存处理优化

1.如果redis缓存没有则从数据库中取
2.缓存根据查询要求按卡流水号、物理卡号和用户Id分开存放
3.增加了根据物理卡号进行校验的逻辑
autumnal_wind 11 miesięcy temu
rodzic
commit
bb0307dae9

+ 9 - 0
ruoyi-server/ruoyi-server-common/src/main/java/org/dromara/server/common/constant/ConsumeConstants.java

@@ -19,4 +19,13 @@ public interface ConsumeConstants {
         put("3", "晚餐");
         put("4", "夜宵");
     }};
+
+    // 用户校验模式 0-userId 1- userNo 2-userNumb
+    Integer userIdMode = 0;
+    Integer userNoMode = 1;
+    Integer userNumbMode = 2;
+    // 卡片校验模式 0-userId 1- cardNo
+    int CARD_USER = 0;
+    int CARD_NO = 1;
+    int CARD_FACTORY = 2;
 }

+ 3 - 9
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/BaseBusiness.java

@@ -81,6 +81,7 @@ public class BaseBusiness {
     private final RemoteRegisterInfoService remoteRegisterInfoService;
     @DubboReference
     private final RemoteCardService remoteCardService;
+    private final InitBusiness initBusiness;
 
     //region 原始消费记录处理
 
@@ -192,16 +193,9 @@ public class BaseBusiness {
 
         userCardVo.setLastMeal(mealType);
         userCardVo.setLastPay(consumeDate);
-        log.info("待更新的卡片日消费数据,[{}]", JSONUtil.toJsonStr(userCardVo));
-        String cardNo = String.valueOf(userCardVo.getCardNo());
-        String userId = String.valueOf(userCardVo.getUserId());
-
-        RedisUtils.delCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo);
-        RedisUtils.delCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId);
 
-        String strCard = JsonUtils.toJsonString(userCardVo);
-        RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, strCard);
-        RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, strCard);
+        log.info("待更新的卡片日消费数据,[{}]", JSONUtil.toJsonStr(userCardVo));
+        initBusiness.resetUserCard(userCardVo);
 
         // 更新数据库
         remoteCardService.updateCardDayData(userCardVo);

+ 36 - 20
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/business/InitBusiness.java

@@ -11,6 +11,7 @@ import org.dromara.backstage.api.domain.vo.*;
 import org.dromara.common.core.constant.CacheNames;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.server.common.util.CardDateUtils;
 import org.dromara.server.consume.domain.PtBag;
 import org.dromara.server.consume.domain.bo.XfCardLimitedBo;
 import org.dromara.server.consume.domain.bo.XfUserTotalBo;
@@ -25,6 +26,9 @@ import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.time.Duration;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -194,16 +198,13 @@ public class InitBusiness {
         if (CollUtil.isNotEmpty(list)) {
             RedisUtils.deleteKeys(CacheNames.PT_USER_CARD_NO);
             RedisUtils.deleteKeys(CacheNames.PT_USER_CARD_USER_ID);
-            list.forEach(v -> {
-                String cardNo = String.valueOf(v.getCardNo());
-                String userId = String.valueOf(v.getUserId());
-                String strCard = JsonUtils.toJsonString(v);
-                RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, strCard);
-                RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, strCard);
+            RedisUtils.deleteKeys(CacheNames.PT_USER_CARD_FACTORYID);
+
+            list.forEach(this::resetUserCard);
 
-            });
             RedisUtils.expire(CacheNames.PT_USER_CARD_NO, Duration.ofHours(5));
             RedisUtils.expire(CacheNames.PT_USER_CARD_USER_ID, Duration.ofHours(5));
+            RedisUtils.expire(CacheNames.PT_USER_CARD_FACTORYID, Duration.ofHours(5));
         }
         log.info("初始化人员卡片参数完成");
     }
@@ -215,19 +216,7 @@ public class InitBusiness {
      */
     public void initUserCardByUserId(Long id) {
         RemoteCardVo cardVo = remoteCardService.queryMainCardByUserId(id);
-        if (ObjectUtil.isNotEmpty(cardVo)) {
-            String cardNo = String.valueOf(cardVo.getCardNo());
-            String userId = String.valueOf(id);
-
-            RedisUtils.delCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo);
-            RedisUtils.delCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId);
-
-            String strCard = JsonUtils.toJsonString(cardVo);
-            RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, strCard);
-            RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, strCard);
-            // RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, cardVo);
-            // RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, cardVo);
-        }
+        resetUserCard(cardVo);
         log.info("初始指定人员卡片参数完成,人员Id:{}", id);
     }
 
@@ -314,4 +303,31 @@ public class InitBusiness {
 
         log.info("初始化消费餐类参数完成");
     }
+
+    /**
+     * 重置指定卡片的缓存数据
+     * @param cardVo 卡片信息
+     */
+    public void resetUserCard(RemoteCardVo cardVo){
+        if (ObjectUtil.isNotEmpty(cardVo)) {
+            String cardNo = String.valueOf(cardVo.getCardNo());
+            String userId = String.valueOf(cardVo.getUserId());
+            String factoryId = String.valueOf(cardVo.getFactoryId());
+
+            if (cardVo.getLastPay() == null) {
+                LocalDateTime beforeTime = LocalDateTime.now().plusDays(-1);
+                Date lastPay = CardDateUtils.toDate(beforeTime, ZoneId.of("Asia/Shanghai"));
+                cardVo.setLastPay(lastPay);
+            }
+            if (cardVo.getLastMeal() == null) {
+                cardVo.setLastMeal(0L);
+            }
+
+            String strCard = JsonUtils.toJsonString(cardVo);
+
+            RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_NO, cardNo, strCard);
+            RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, userId, strCard);
+            RedisUtils.setCacheMapValue(CacheNames.PT_USER_CARD_FACTORYID, factoryId, strCard);
+        }
+    }
 }

+ 56 - 0
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/cache/CardCacheManager.java

@@ -0,0 +1,56 @@
+package org.dromara.server.consume.cache;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.backstage.api.RemoteCardService;
+import org.dromara.backstage.api.domain.vo.RemoteCardVo;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.json.utils.JsonUtils;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+/**
+ * 卡片缓存处理
+ * <p>
+ * [功能说明]
+ * ${1:在此简要描述文件核心功能}
+ *
+ * @author luoyibo
+ * @version 2.2.0
+ * @date 2025-06-25
+ * @since JDK17
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class CardCacheManager {
+    @DubboReference
+    private final RemoteCardService remoteCardService;
+
+    @Cacheable(cacheNames = CacheNames.PT_USER_CARD_NO, key = "#cardNo", unless = "#result == null")
+    public String getByCardNo(Long cardNo) {
+        RemoteCardVo cardVo = remoteCardService.queryCardByCardNo(cardNo);
+        if (cardVo == null) {
+            return null;
+        }
+        return JsonUtils.toJsonString(cardVo);
+    }
+    @Cacheable(cacheNames = CacheNames.PT_USER_CARD_FACTORYID, key = "#factoryId", unless = "#result == null")
+    public String getByFactoryId(Long factoryId) {
+        RemoteCardVo cardVo = remoteCardService.queryCardByFactoryId(factoryId);
+        if (cardVo == null) {
+            return null;
+        }
+        return JsonUtils.toJsonString(cardVo);
+    }
+
+    @Cacheable(cacheNames = CacheNames.PT_USER_CARD_USER_ID, key = "#userId", unless = "#result == null")
+    public String getByUserId(Long userId) {
+        RemoteCardVo cardVo = remoteCardService.queryMainCardByUserId(userId);
+        if (cardVo == null) {
+            return null;
+        }
+        return JsonUtils.toJsonString(cardVo);
+    }
+}

+ 44 - 11
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/check/CommonCheck.java

@@ -20,10 +20,12 @@ import org.dromara.common.core.enums.TradeStatusEnum;
 import org.dromara.common.core.enums.UserAccountStatusEnum;
 import org.dromara.common.json.utils.JsonUtils;
 import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.server.common.constant.ConsumeConstants;
 import org.dromara.server.common.domain.consume.bo.ConsumptionBo;
 import org.dromara.server.common.util.CardDateUtils;
 import org.dromara.server.consume.business.BaseBusiness;
 import org.dromara.server.consume.business.InitBusiness;
+import org.dromara.server.consume.cache.CardCacheManager;
 import org.dromara.server.consume.domain.vo.XfCardLimitedVo;
 import org.dromara.server.consume.domain.vo.XfTermVo;
 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -59,12 +61,14 @@ public class CommonCheck {
     private static final Integer userNumbMode = 2;
     // 卡片校验模式 0-userId 1- cardNo
     private static final Integer cardIdMode = 0;
-    private static final Integer cardNoMode = 1;
+    private static final int cardNoMode = 1;
+    private static final Integer cardFactoryMode = 2;
     // 异步线程执行超时时间,以毫秒为单位
     private static final long VALIDATION_TIMEOUT = 500;
 
     private final BaseBusiness baseBusiness;
     private final InitBusiness initBusiness;
+    private final CardCacheManager cardCacheManager;
     private final ThreadPoolTaskExecutor taskExecutor;
 
     //region 账户、卡片与设备验证
@@ -314,12 +318,16 @@ public class CommonCheck {
     public R<ErrorInfo> checkUserAccount(AllowConsumeValidationContext ctx) {
         long cardNo = ObjectUtil.isEmpty(ctx.getCardNo()) ? 0 : ctx.getCardNo();
         long userNo = ObjectUtil.isEmpty(ctx.getUserNo()) ? 0 : ctx.getUserNo();
+        long factoryId = ObjectUtil.isEmpty(ctx.getFactoryId()) ? 0 : ctx.getFactoryId();
         String userNumb = ObjectUtil.isEmpty(ctx.getUserNumb()) ? null : ctx.getUserNumb();
 
         // 如果卡流水号>0验证卡信息
         if (cardNo > 0) {
             return checkCardNo(ctx);
         }
+        if (factoryId > 0) {
+            return checkFactoryId(ctx);
+        }
         if (userNo > 0) {
             return checkUserNo(ctx);
         }
@@ -364,6 +372,32 @@ public class CommonCheck {
         return R.ok();
     }
 
+    /**
+     * 根据物理卡号校验账户是否可以消费。
+     *
+     * @param ctx 消费有效性校验上下文,包含消费相关的基础信息(如用户流水号、消费金额等)
+     * @return 如果校验失败,则返回包含错误信息的 R 对象;如果校验成功,则返回表示成功的 R 对象
+     */
+    private R<ErrorInfo> checkFactoryId(AllowConsumeValidationContext ctx) {
+        // 检查卡片
+        long factoryId = ctx.getFactoryId();
+        R<ErrorInfo> result = checkCard(factoryId, cardFactoryMode, ctx);
+        if (R.isError(result)) {
+            return result;
+        }
+        // 获取消费账户信息
+        String strUserId = String.valueOf(ctx.getUserCardVo().getUserId());
+        result = checkUser(strUserId, userIdMode, ctx);
+        if (R.isError(result)) {
+            return result;
+        }
+        // 更新bo中部分值息
+        setCheckAfterAccountData(ctx);
+
+        return R.ok();
+    }
+
+
     /**
      * 根据用户流水号校验账户是否可以消费。
      *
@@ -491,7 +525,7 @@ public class CommonCheck {
             Date lastPay = CardDateUtils.toDate(beforeTime, ZoneId.of("Asia/Shanghai"));
             cardVo.setLastPay(lastPay);
         }
-        if(cardVo.getLastMeal() == null) {
+        if (cardVo.getLastMeal() == null) {
             cardVo.setLastMeal(0L);
         }
         ctx.setUserCardVo(cardVo);
@@ -531,19 +565,18 @@ public class CommonCheck {
     /**
      * 从缓存获取卡片信息
      *
-     * @param checkParam 用户标识
-     * @param checkMode  校验模
+     * @param checkParam 卡片标识
+     * @param checkMode  获取方
      * @return 账户信息对象
      */
     private RemoteCardVo getCardFromCache(Long checkParam, Integer checkMode) {
-        String cacheKey = checkParam.toString();
-        Object cacheCard = checkMode.equals(cardIdMode) ?
-            RedisUtils.getCacheMapValue(CacheNames.PT_USER_CARD_USER_ID, cacheKey) :
-            RedisUtils.getCacheMapValue(CacheNames.PT_USER_CARD_NO, cacheKey);
-        if (cacheCard == null) {
-            return null;
+        Object cacheCard = null;
+        switch (checkMode) {
+            case ConsumeConstants.CARD_NO -> cacheCard = cardCacheManager.getByCardNo(checkParam);
+            case ConsumeConstants.CARD_USER -> cacheCard = cardCacheManager.getByUserId(checkParam);
+            case ConsumeConstants.CARD_FACTORY -> cacheCard = cardCacheManager.getByFactoryId(checkParam);
         }
-        return JsonUtils.parseObject(cacheCard.toString(), RemoteCardVo.class);
+        return cacheCard == null ? null : JsonUtils.parseObject(cacheCard.toString(), RemoteCardVo.class);
     }
     // endregion
 

+ 8 - 8
ruoyi-server/ruoyi-server-consume/src/main/java/org/dromara/server/consume/task/InitTasks.java

@@ -32,14 +32,14 @@ public class InitTasks implements ApplicationRunner {
     public void run(ApplicationArguments args) throws Exception {
         log.info("初始化消费验证基础数据");
         long startTime = System.currentTimeMillis();
-        initBusiness.initGlobalData();
-        initBusiness.initTermInfo();
-        initBusiness.initMealTypeInfo();
-        initBusiness.initDiscountAndOther();
-        initBusiness.initUserCard();
-        initBusiness.initUserAccount();
-        initBusiness.initXfCardLimited();
-        initBusiness.initUserBalance();
+        // initBusiness.initGlobalData();
+        // initBusiness.initTermInfo();
+        // initBusiness.initMealTypeInfo();
+        // initBusiness.initDiscountAndOther();
+        // initBusiness.initUserCard();
+        // initBusiness.initUserAccount();
+        // initBusiness.initXfCardLimited();
+        // initBusiness.initUserBalance();
         validationParam.refresh();
 
         log.info("初始化消费验证基础数据完成。耗时:{} ms", System.currentTimeMillis() - startTime);