7 changed files with 202 additions and 13 deletions
@ -0,0 +1,148 @@ |
|||
package cc.hiver.mall.utils; |
|||
|
|||
import cc.hiver.core.common.redis.RedisTemplateHelper; |
|||
import cn.hutool.json.JSONUtil; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 店铺主页数缓存工具类 |
|||
* <p> |
|||
* 底层使用 Redis Hash 结构,保证按 shopId + countType 维度的 O(1) 读写效率。 |
|||
* <pre> |
|||
* Key = SHOP_INDEX_COUNT:{shopId} |
|||
* Field = countType |
|||
* Value = Map<String,Integer> 的 JSON 序列化 |
|||
* </pre> |
|||
* <p> |
|||
* |
|||
* @author system |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
public class ShopIndexCountCacheUtil { |
|||
|
|||
/** Redis Key 前缀 */ |
|||
private static final String KEY_PREFIX = "SHOP:STATS:COUNT:"; |
|||
|
|||
@Autowired |
|||
private RedisTemplateHelper redisTemplateHelper; |
|||
|
|||
// ================================================================
|
|||
// Key 构建
|
|||
// ================================================================
|
|||
private String buildKey(String shopId) { |
|||
return KEY_PREFIX + shopId; |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 核心:更新操作 (增/改)
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 更新单个字段的数值(支持原子增减) |
|||
* 场景:订单状态变更时,只修改特定计数(如:待出餐 +1) |
|||
* |
|||
* @param shopId 店铺ID |
|||
* @param field 字段名(如 "pendingCooking") |
|||
* @param delta 变化量(正数表示增加,负数表示减少) |
|||
*/ |
|||
public void incrementField(String shopId, String field, long delta) { |
|||
if (StringUtils.isBlank(shopId) || StringUtils.isBlank(field)) { |
|||
return; |
|||
} |
|||
try { |
|||
String key = buildKey(shopId); |
|||
// Redis hIncrBy 自动处理不存在的情况(默认为0)
|
|||
redisTemplateHelper.hIncrBy(key, field, delta); |
|||
log.debug("更新计数缓存: shopId={}, field={}, delta={}", shopId, field, delta); |
|||
} catch (Exception e) { |
|||
log.error("更新计数缓存失败: shopId={}, field={}", shopId, field, e); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 覆盖式更新(全量替换) |
|||
* 场景:后台管理手动修正数据,或初始化数据 |
|||
*/ |
|||
public void put(String shopId, ShopStatsCountDTO statsDTO) { |
|||
if (StringUtils.isBlank(shopId) || statsDTO == null) { |
|||
return; |
|||
} |
|||
try { |
|||
String key = buildKey(shopId); |
|||
String json = JSONUtil.toJsonStr(statsDTO); |
|||
redisTemplateHelper.hPut(key, statsDTO.getShopId(), json); |
|||
log.info("全量覆盖计数缓存: shopId={}", shopId); |
|||
} catch (Exception e) { |
|||
log.error("全量覆盖计数缓存失败: shopId={}", shopId, e); |
|||
} |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 查询操作 (查)
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 获取所有统计数据 |
|||
*/ |
|||
public ShopStatsCountDTO getAll(String shopId) { |
|||
if (StringUtils.isBlank(shopId)) { |
|||
return null; |
|||
} |
|||
try { |
|||
String key = buildKey(shopId); |
|||
Map<Object, Object> entries = redisTemplateHelper.hGetAll(key); |
|||
if (entries == null || entries.isEmpty()) { |
|||
return null; |
|||
} |
|||
// 将 Map 转回 DTO 对象
|
|||
String json = JSONUtil.toJsonStr(entries); |
|||
return JSONUtil.toBean(json, ShopStatsCountDTO.class); |
|||
} catch (Exception e) { |
|||
log.error("获取计数缓存失败: shopId={}", shopId, e); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取单个字段的数值 |
|||
* 场景:首页只展示“待出餐”数量,无需查出整个对象 |
|||
*/ |
|||
public Integer getCount(String shopId, String field) { |
|||
if (StringUtils.isBlank(shopId) || StringUtils.isBlank(field)) { |
|||
return 0; |
|||
} |
|||
try { |
|||
Object val = redisTemplateHelper.hGet(buildKey(shopId), field); |
|||
return val == null ? 0 : Integer.parseInt(val.toString()); |
|||
} catch (Exception e) { |
|||
log.error("获取单个计数失败: shopId={}, field={}", shopId, field, e); |
|||
return 0; |
|||
} |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 删除操作 (删)
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 删除指定店铺的所有统计数据缓存 |
|||
*/ |
|||
public void remove(String shopId) { |
|||
if (StringUtils.isBlank(shopId)) { |
|||
return; |
|||
} |
|||
try { |
|||
redisTemplateHelper.delete(buildKey(shopId)); |
|||
log.info("清除店铺计数缓存: shopId={}", shopId); |
|||
} catch (Exception e) { |
|||
log.error("清除店铺计数缓存失败: shopId={}", shopId, e); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package cc.hiver.mall.utils; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@Data |
|||
public class ShopStatsCountDTO implements Serializable { |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
private String shopId; // 冗余存储,方便排查
|
|||
private Integer pendingConsumption = 0; // 待消费
|
|||
private Integer pendingCooking = 0; // 待出餐
|
|||
private Integer pendingPickup = 0; // 待取货
|
|||
private Integer pendingDelivery = 0; // 待送达
|
|||
|
|||
public ShopStatsCountDTO() {} |
|||
|
|||
public ShopStatsCountDTO(String shopId) { |
|||
this.shopId = shopId; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue