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 缓存,收口读写删,供开锁 / 还车 / 位置上报三处统一调用。
|
* <p>用途:位置上报(JT/T 808,秒级高频)时,用 bikeCode O(1) 取活跃订单,
|
* 替代每次查 member_rides,避免高频 DB 查询。
|
* <p>生命周期:
|
* <ul>
|
* <li>电车开锁成功(→ 骑行中):{@link #set} 写入,带 24h TTL</li>
|
* <li>电车还车成功(→ 已还车):{@link #remove} 删除(覆盖 backBike / autoBackBike / forceBack 多入口)</li>
|
* <li>临停(→ 临停中):不删,期间照常写轨迹</li>
|
* </ul>
|
* <p>TTL 仅为兜底:正常还车会主动删;防还车异常分支漏删导致映射泄漏 → 已还车的车继续被当活跃写脏轨迹。
|
* <p>降级:本类方法不吞异常,由调用方 try-catch 降级(缓存是优化、非业务正确性来源,失败不得阻断主流程)。
|
* <p>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<String, Object> 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));
|
}
|
}
|