20 changed files with 639 additions and 39 deletions
@ -0,0 +1,273 @@ |
|||
package cc.hiver.mall.utils; |
|||
|
|||
import cc.hiver.core.common.redis.RedisTemplateHelper; |
|||
import cc.hiver.mall.pojo.vo.MallOrderVO; |
|||
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.ArrayList; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* 用户待完成订单缓存工具类 |
|||
* <p> |
|||
* 底层使用 Redis Hash 结构,保证按 userId + orderId 维度的 O(1) 读写效率。 |
|||
* <pre> |
|||
* Key = USER_PENDING_ORDERS:{userId} |
|||
* Field = orderId |
|||
* Value = MallOrderVO 的 JSON 序列化 |
|||
* </pre> |
|||
* <p> |
|||
* 使用场景:订单状态发生变化时(创建、更新、取消、完成等), |
|||
* 由业务方主动调用本工具类的方法维护缓存,以减少 getOrdersByUserId 接口对数据库的查询压力。 |
|||
* |
|||
* @author system |
|||
*/ |
|||
@Slf4j |
|||
@Component |
|||
public class UserPendingOrderCacheUtil { |
|||
|
|||
/** Redis Key 前缀 */ |
|||
private static final String KEY_PREFIX = "USER_PENDING_ORDERS:"; |
|||
|
|||
/** 订单完成/取消/退款等不再属于"待完成"的状态集合 */ |
|||
private static final int STATUS_DONE = 5; |
|||
private static final int STATUS_CANCELLED = 6; |
|||
private static final int STATUS_REFUNDED = 8; |
|||
private static final int STATUS_RETURNED = 12; |
|||
|
|||
@Autowired |
|||
private RedisTemplateHelper redisTemplateHelper; |
|||
|
|||
// ================================================================
|
|||
// Key 构建
|
|||
// ================================================================
|
|||
|
|||
private String buildKey(String userId) { |
|||
return KEY_PREFIX + userId; |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 存放(put)
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 存放单个订单到缓存 |
|||
* |
|||
* @param userId 用户ID |
|||
* @param orderVO 订单VO(必须包含有效的 id) |
|||
*/ |
|||
public void put(String userId, MallOrderVO orderVO) { |
|||
if (StringUtils.isBlank(userId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) { |
|||
log.warn("UserPendingOrderCacheUtil.put 参数无效, userId={}, orderVO={}", userId, orderVO); |
|||
return; |
|||
} |
|||
try { |
|||
String key = buildKey(userId); |
|||
String json = JSONUtil.toJsonStr(orderVO); |
|||
redisTemplateHelper.hPut(key, orderVO.getId(), json); |
|||
log.debug("缓存用户待完成订单: userId={}, orderId={}", userId, orderVO.getId()); |
|||
} catch (Exception e) { |
|||
log.error("缓存用户待完成订单失败: userId={}, orderId={}", userId, orderVO.getId(), e); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 批量存放订单到缓存(通常用于缓存预热 / 首次加载) |
|||
* |
|||
* @param userId 用户ID |
|||
* @param orders 订单列表 |
|||
*/ |
|||
public void putAll(String userId, List<MallOrderVO> orders) { |
|||
if (StringUtils.isBlank(userId) || orders == null || orders.isEmpty()) { |
|||
return; |
|||
} |
|||
try { |
|||
String key = buildKey(userId); |
|||
java.util.Map<String, String> map = new java.util.LinkedHashMap<>(orders.size()); |
|||
for (MallOrderVO order : orders) { |
|||
if (order != null && StringUtils.isNotBlank(order.getId())) { |
|||
map.put(order.getId(), JSONUtil.toJsonStr(order)); |
|||
} |
|||
} |
|||
if (!map.isEmpty()) { |
|||
redisTemplateHelper.hPutAll(key, map); |
|||
log.debug("批量缓存用户待完成订单: userId={}, count={}", userId, map.size()); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("批量缓存用户待完成订单失败: userId={}", userId, e); |
|||
} |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 删除(remove)
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 根据 userId 和 orderId 从缓存中删除指定订单 |
|||
* <p> |
|||
* 典型场景:订单完成、取消、退款成功后调用。 |
|||
* |
|||
* @param userId 用户ID |
|||
* @param orderId 订单ID |
|||
*/ |
|||
public void remove(String userId, String orderId) { |
|||
if (StringUtils.isBlank(userId) || StringUtils.isBlank(orderId)) { |
|||
log.warn("UserPendingOrderCacheUtil.remove 参数无效, userId={}, orderId={}", userId, orderId); |
|||
return; |
|||
} |
|||
try { |
|||
String key = buildKey(userId); |
|||
redisTemplateHelper.hDelete(key, orderId); |
|||
log.debug("删除用户待完成订单缓存: userId={}, orderId={}", userId, orderId); |
|||
} catch (Exception e) { |
|||
log.error("删除用户待完成订单缓存失败: userId={}, orderId={}", userId, orderId, e); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 清除指定用户的所有待完成订单缓存 |
|||
* <p> |
|||
* 典型场景:需要强制刷新该用户缓存时调用。 |
|||
* |
|||
* @param userId 用户ID |
|||
*/ |
|||
public void removeAll(String userId) { |
|||
if (StringUtils.isBlank(userId)) { |
|||
return; |
|||
} |
|||
try { |
|||
redisTemplateHelper.delete(buildKey(userId)); |
|||
log.debug("清除用户全部待完成订单缓存: userId={}", userId); |
|||
} catch (Exception e) { |
|||
log.error("清除用户全部待完成订单缓存失败: userId={}", userId, e); |
|||
} |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 更新(update)
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 根据 userId 和 orderId 更新缓存中的订单信息 |
|||
* <p> |
|||
* 如果更新后的订单状态已经不属于"待完成"(status ∈ {5,6,8,12}), |
|||
* 则自动从缓存中移除该订单,无需调用方额外判断。 |
|||
* |
|||
* @param userId 用户ID |
|||
* @param orderVO 更新后的订单VO |
|||
*/ |
|||
public void update(String userId, MallOrderVO orderVO) { |
|||
if (StringUtils.isBlank(userId) || orderVO == null || StringUtils.isBlank(orderVO.getId())) { |
|||
log.warn("UserPendingOrderCacheUtil.update 参数无效, userId={}, orderVO={}", userId, orderVO); |
|||
return; |
|||
} |
|||
try { |
|||
// 如果订单状态已不属于待完成,直接删除
|
|||
if (isTerminalStatus(orderVO.getStatus())) { |
|||
remove(userId, orderVO.getId()); |
|||
log.debug("订单已终态,从缓存移除: userId={}, orderId={}, status={}", |
|||
userId, orderVO.getId(), orderVO.getStatus()); |
|||
return; |
|||
} |
|||
// 否则覆盖更新
|
|||
put(userId, orderVO); |
|||
log.debug("更新用户待完成订单缓存: userId={}, orderId={}, status={}", |
|||
userId, orderVO.getId(), orderVO.getStatus()); |
|||
} catch (Exception e) { |
|||
log.error("更新用户待完成订单缓存失败: userId={}, orderId={}", userId, orderVO.getId(), e); |
|||
} |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 查询(get)
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 获取用户全部待完成订单缓存 |
|||
* |
|||
* @param userId 用户ID |
|||
* @return 缓存的订单列表,缓存不存在时返回 null(调用方可据此判断是否需要回源查库) |
|||
*/ |
|||
public List<MallOrderVO> getAll(String userId) { |
|||
if (StringUtils.isBlank(userId)) { |
|||
return null; |
|||
} |
|||
try { |
|||
String key = buildKey(userId); |
|||
Map<Object, Object> entries = redisTemplateHelper.hGetAll(key); |
|||
if (entries == null || entries.isEmpty()) { |
|||
return null; |
|||
} |
|||
List<MallOrderVO> result = new ArrayList<>(entries.size()); |
|||
for (Object value : entries.values()) { |
|||
if (value != null) { |
|||
result.add(JSONUtil.toBean(value.toString(), MallOrderVO.class)); |
|||
} |
|||
} |
|||
return result; |
|||
} catch (Exception e) { |
|||
log.error("获取用户待完成订单缓存失败: userId={}", userId, e); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取用户缓存中的单个订单 |
|||
* |
|||
* @param userId 用户ID |
|||
* @param orderId 订单ID |
|||
* @return 缓存的订单VO,不存在时返回 null |
|||
*/ |
|||
public MallOrderVO get(String userId, String orderId) { |
|||
if (StringUtils.isBlank(userId) || StringUtils.isBlank(orderId)) { |
|||
return null; |
|||
} |
|||
try { |
|||
String key = buildKey(userId); |
|||
Object value = redisTemplateHelper.hGet(key, orderId); |
|||
if (value == null) { |
|||
return null; |
|||
} |
|||
return JSONUtil.toBean(value.toString(), MallOrderVO.class); |
|||
} catch (Exception e) { |
|||
log.error("获取用户单个待完成订单缓存失败: userId={}, orderId={}", userId, orderId, e); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 判断该用户的缓存是否已存在 |
|||
* |
|||
* @param userId 用户ID |
|||
* @return true 表示缓存存在 |
|||
*/ |
|||
public boolean exists(String userId) { |
|||
if (StringUtils.isBlank(userId)) { |
|||
return false; |
|||
} |
|||
Boolean hasKey = redisTemplateHelper.hasKey(buildKey(userId)); |
|||
return hasKey != null && hasKey; |
|||
} |
|||
|
|||
// ================================================================
|
|||
// 内部工具
|
|||
// ================================================================
|
|||
|
|||
/** |
|||
* 判断订单状态是否为终态(不再属于"待完成") |
|||
*/ |
|||
private boolean isTerminalStatus(Integer status) { |
|||
if (status == null) { |
|||
return false; |
|||
} |
|||
return status == STATUS_DONE |
|||
|| status == STATUS_CANCELLED |
|||
|| status == STATUS_REFUNDED |
|||
|| status == STATUS_RETURNED; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue