package com.doumee.core.track; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.concurrent.TimeUnit; /** * 电车「车辆 → 活跃骑行订单」Redis 缓存,收口读写删,供开锁 / 还车 / 位置上报三处统一调用。 *

用途:位置上报(JT/T 808,秒级高频)时,用 bikeCode O(1) 取活跃订单, * 替代每次查 member_rides,避免高频 DB 查询。 *

生命周期: *

*

TTL 仅为兜底:正常还车会主动删;防还车异常分支漏删导致映射泄漏 → 已还车的车继续被当活跃写脏轨迹。 *

降级:本类方法不吞异常,由调用方 try-catch 降级(缓存是优化、非业务正确性来源,失败不得阻断主流程)。 *

value 以 JSON 字符串存取(与抖音 token 缓存一致,避开 RedisTemplate 序列化器对 POJO 的依赖)。 * * @author rk * @date 2026/06/25 */ @Slf4j @Component public class RideActiveCache { /** Redis key 前缀:车辆维度活跃订单映射 */ private static final String KEY_PREFIX = "ride:active:"; /** 缓存 TTL(秒):24 小时,覆盖最长骑行;兜底防还车漏删导致映射泄漏 */ private static final long TTL_SECONDS = 24L * 60L * 60L; @Autowired private RedisTemplate redisTemplate; /** 拼 Redis key:ride:active:{bikeCode} */ private static String key(String bikeCode) { return KEY_PREFIX + bikeCode; } /** * 开锁成功时写入活跃订单映射(带 24h TTL)。 * * @param bikeCode 车辆编码(缓存维度) * @param ridesId 骑行订单主键 member_rides.id * @param orderId 支付订单主键 member_rides.ordre_id → goodsorder.id(可 null) */ public void set(String bikeCode, String ridesId, String orderId) { if (StringUtils.isBlank(bikeCode)) { return; } RideActiveInfo info = new RideActiveInfo(); info.setRidesId(ridesId); info.setOrderId(orderId); redisTemplate.opsForValue().set(key(bikeCode), JSON.toJSONString(info), TTL_SECONDS, TimeUnit.SECONDS); } /** * 位置上报时读取活跃订单映射。 * * @param bikeCode 车辆编码 * @return 活跃订单载荷;无映射 / 非 String 值返回 null(调用方据此跳过轨迹写入) */ public RideActiveInfo get(String bikeCode) { if (StringUtils.isBlank(bikeCode)) { return null; } Object cached = redisTemplate.opsForValue().get(key(bikeCode)); if (cached instanceof String) { return JSON.parseObject((String) cached, RideActiveInfo.class); } return null; } /** * 还车成功时删除活跃订单映射。 * * @param bikeCode 车辆编码 */ public void remove(String bikeCode) { if (StringUtils.isBlank(bikeCode)) { return; } redisTemplate.delete(key(bikeCode)); } }