首页展示取餐码

首页取餐码

需求描述:

下单后首页展示取餐码:

1、显示逻辑:小程序下单支付后30分钟内的订单(制作中、已完成),如果30分钟内有多个订单,则显示多个取餐码。最多显示3个,超过3个取餐码显示"查看更多>",如果用户手动关闭后,冷启动的时候再显示30分钟内的订单取餐码;

2、消失逻辑:用户可手动关闭,超过30分钟的订单首页也不再显示取餐码。订单退款后也不再显示,30分钟:以支付完成时间开始计算;

3、点击浮窗可以去到订单列表;

需求分析:

1、走缓存:用户打开小程序就会进首页,动一动猪脑子都知道这个查询取餐码的接口不能直接去数据库查询,更不需要专门建一张取餐码表来满足业务需求,因为此表数据量会暴增,大材小用,得不偿失;

2、如何缓存:取餐码展示小程序下单支付后30分钟内的订单,顾名思义,缓存过期时间就是半个小时。订单退款后取餐码不再展示,所以取消订单的时候需要手动删除缓存;初步分析缓存的key一定是跟用户id有关,value一定跟取餐码有关;

需求难点:

实现需求的时候遇到一个困难,如果用户三十分钟内下了多单,每一单设置了缓存时间会被覆盖,很难实现"超过30分钟的订单首页也不再显示取餐码"的需求;

代码实现:

1、添加缓存:

使用Redis中Hash数据类型,Key为userId,Field为订单id + 当前时间戳,Value为取餐码,在下单需要生成取餐码的地方添加缓存即可;

java 复制代码
    /**
     * 添加取餐码缓存
     * @param code
     */
    @Override
    public void saveOrderPickupCode(String code,Long orderId,Integer userId) {
        log.info("设置取餐码缓存中code->{},orderId->{},userId->{}",code,orderId,userId);
        String key = String.format(RedisKeyConstant.HOME_PAGE_PICKUP_CODE, userId);
        long currentTimeMillis = System.currentTimeMillis() / 1000;
        String str = orderId + "-" + currentTimeMillis;
        cacheService.hset(key,str,code,(int) TimeUnit.MINUTES.toSeconds(30));
    }

2、查询取餐码:

通过Field中的时间戳来判断取餐码是否过期,加入try/catch,防止添加取餐码出错,影响下单黄金流程;

java 复制代码
/**
 * 查询用户的首页取餐码列表,仅包括最近30分钟内的取餐码。
 *
 * @return 包含最近30分钟内取餐码的列表
 */
@Override
public List<String> queryOrderCode() {
    // 初始化一个用于存储取餐码的列表
    List<String> orderCodeList = new ArrayList<>();
    try {
        // 获取用户ID
        Integer userId = MiniAppContext.getTokenBo().getUid();
        // 构建Redis中的键
        String key = String.format(RedisKeyConstant.HOME_PAGE_PICKUP_CODE, userId);
        // 从Redis中获取所有取餐码数据
        Map<String, String> cacheOrderCodeMap = cacheService.hgetAll(key);
        if (MapUtils.isNotEmpty(cacheOrderCodeMap)) {
            // 获取当前时间的时间戳(单位:秒)
            long currentTimeSeconds = System.currentTimeMillis() / 1000;
            // 计算30分钟前的时间戳
            long thirtyMinutesAgo = currentTimeSeconds - 30 * 60;
            // 遍历取餐码数据
            for (Map.Entry<String, String> entry : cacheOrderCodeMap.entrySet()) {
                if (orderCodeList.size() >= 4) {
                    break; // 如果已经有4个取餐码,跳出循环
                }
                String keyStr = entry.getKey();
                String[] keyParts = keyStr.split("-");
                long keyTimestamp = Long.parseLong(keyParts[1]);
                // 如果时间戳在最近30分钟内
                if (keyTimestamp >= thirtyMinutesAgo) {
                    // 将取餐码添加到列表中
                    // 去掉额外的引号,并将取餐码添加到列表中
                    String orderCode = entry.getValue().replaceAll("^"|"$", "");
                    orderCodeList.add(orderCode);
                }
            }
        }

        if (!CollectionUtils.isEmpty(orderCodeList)) {
            Collections.reverse(orderCodeList);
        }
        // 返回包含最近30分钟内取餐码的列表
        return orderCodeList;
    } catch (Exception e) {
        log.error("首页查询取餐码异常,", e);
    }
    return orderCodeList;
}`

3、取消取餐码缓存

通过Field中的订单编号来判断是否取消取餐码,在取消订单时调用此方法;

java 复制代码
    /**
     * 取消取餐码缓存
     * @param orderId
     */
    @Override
    public void cancelOrderPickupCode(Long orderId,Integer uid) {
        String key = String.format(RedisKeyConstant.HOME_PAGE_PICKUP_CODE, uid);
        Map<String, String> cacheOrderCodeMap = cacheService.hgetAll(key);
        if (MapUtils.isNotEmpty(cacheOrderCodeMap)){
            for (Map.Entry<String, String> entry : cacheOrderCodeMap.entrySet()) {
                String keyStr = entry.getKey();
                String[] keyParts = keyStr.split("-");
                if (keyParts.length > 0){
                    long keyPart = Long.parseLong(keyParts[0]);
                    if (Objects.equals(orderId,keyPart)){
                        cacheService.hdel(key,new String[]{entry.getKey()});
                        break;
                    }
                }
            }
        }
    }

总结:

通过Hash数据结构,借助用户id,订单id,当前时间戳,实现取消订单删除取餐码缓存(利用订单id),下单生成取餐码缓存,查询取餐码缓存(利用当前时间戳,用户id)

相关推荐
m0_7369270413 分钟前
2025高频Java后端场景题汇总(全年汇总版)
java·开发语言·经验分享·后端·面试·职场和发展·跳槽
掘金者阿豪14 分钟前
“多余的”回车:从IDE的自动换行窥见软件工程的规范与协作
后端
Felix_XXXXL42 分钟前
Plugin ‘mysql_native_password‘ is not loaded`
java·后端
韩立学长44 分钟前
【开题答辩实录分享】以《基于SpringBoot在线小说阅读平台》为例进行答辩实录分享
java·spring boot·后端
程序猿小蒜1 小时前
基于SpringBoot的企业资产管理系统开发与设计
java·前端·spring boot·后端·spring
jzhwolp1 小时前
从基本链表到侵入式链表,体会内核设计思路
c语言·后端·设计模式
suzumiyahr1 小时前
用awesome-digital-human-live2d创建属于自己的数字人
前端·人工智能·后端
计算机学姐1 小时前
基于SpringBoot的健身房管理系统【智能推荐算法+可视化统计】
java·vue.js·spring boot·后端·mysql·spring·推荐算法
海边捡石子1 小时前
java内存泄漏问题排查和JVM调优
java·后端
申阳2 小时前
Day 10:08. 基于Nuxt开发博客项目-关于我页面开发
前端·后端·程序员