商城系统中30分钟未付款自动取消订单怎么实现(简单几种方法)

这篇具有很好参考价值的文章主要介绍了商城系统中30分钟未付款自动取消订单怎么实现(简单几种方法)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

商城系统中30分钟未付款自动取消订单怎么实现(简单几种方法),java,spring boot,商城

实现以上功能

方法1:定时任务批量执行

写一个定时任务,每隔 30分钟执行一次,列出所有超出时间范围得订单id的列表

@Async
    @Scheduled(cron = "20 20 1 * * ?")
    public void cancelOrder(){
        log.info("【取消订单任务开始】");
        QueryWrapper<Order> qw = new QueryWrapper<>();
        qw.eq("status", Constants.OrderStatus.NOTPAID);
        qw.eq("aftersale_status", 1);
        List<Order> orderList = orderMapper.selectList(qw);
        List<Long> idList = orderList.stream()
                .filter(order -> LocalDateTimeUtil.between(order.getCreateTime(), LocalDateTime.now()).toMinutes() >= 15)
                .map(Order::getId)
                .collect(Collectors.toList());
        CancelOrderRequest request = new CancelOrderRequest();
        request.setIdList(idList);
        h5OrderService.orderBatchCancel(request, null);
        log.info("【取消订单任务结束】");
    }

批量执行取消订单操作

@Transactional
    public String orderBatchCancel(CancelOrderRequest request, Long userId) {
        LocalDateTime optDate = LocalDateTime.now();
        if (CollectionUtil.isEmpty(request.getIdList())) {
            throw new RuntimeException("未指定需要取消的订单号");
        }
        QueryWrapper<Order> orderQw = new QueryWrapper<>();
        orderQw.in("id", request.getIdList());
        List<Order> orderList = orderMapper.selectList(orderQw);
        if (orderList.size() < request.getIdList().size()) {
            throw new RuntimeException("未查询到订单信息");
        }
        Order order = orderList.get(0);

        //查orderItem
        QueryWrapper<OrderItem> qw = new QueryWrapper<>();
        qw.in("order_id", request.getIdList());
        List<OrderItem> orderItems = orderItemMapper.selectList(qw);
        if (CollectionUtil.isEmpty(orderItems)) {
            throw new RuntimeException("未查询到订单信息");
        }
        long count = orderList.stream().filter(it -> !Constants.H5OrderStatus.UN_PAY.equals(it.getStatus())).count();
        if (count > 0) {
            throw new RuntimeException("订单状态已更新,请刷新页面");
        }
        List<OrderOperateHistory> addHistoryList = new ArrayList<>();
        orderList.forEach(item -> {
            item.setStatus(Constants.H5OrderStatus.CLOSED);
            item.setUpdateTime(optDate);
            item.setUpdateBy(userId);
            OrderOperateHistory history = new OrderOperateHistory();
            history.setOrderId(item.getId());
            history.setOrderSn(item.getOrderSn());
            history.setOperateMan(userId == null ? "后台管理员" : "" + item.getMemberId());
            history.setOrderStatus(Constants.H5OrderStatus.CLOSED);
            history.setCreateTime(optDate);
            history.setCreateBy(userId);
            history.setUpdateBy(userId);
            history.setUpdateTime(optDate);
            addHistoryList.add(history);
        });
        //取消订单
        int rows = orderMapper.cancelBatch(orderList);
        if (rows < 1) {
            throw new RuntimeException("更改订单状态失败");
        }
        orderItems.stream().collect(Collectors.groupingBy(it -> it.getSkuId())).forEach((k, v) -> {
            AtomicReference<Integer> totalCount = new AtomicReference<>(0);
            v.forEach(it -> totalCount.updateAndGet(v1 -> v1 + it.getQuantity()));
            skuMapper.updateStockById(k, optDate, -1 * totalCount.get());
        });
        //创建订单操作记录
        boolean flag = orderOperateHistoryService.saveBatch(addHistoryList);
        if (!flag) {
            throw new RuntimeException("创建订单操作记录失败");
        }
        // 根据order 退还积分
        orderUsePointsService.refundOrderUsePoints(order.getId());
        return "取消订单成功";
    }

方法2:使用jdk自带的阻塞队列

实现一个简单的队列,每隔一定时间执行队列。

/**
     * (30分钟扫描三十分钟内需要发送的订单)
     */
    @Scheduled(cron = "0 0/30 * * * ?")
    public void checkOrderStatus() {
        DelayQueue<ItemVo<Order>> queue = new DelayQueue<ItemVo<Order>>();
        try {
            // 插入订单
            new Thread(new PutOrder(queue)).start();

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

这里使用队列的优势可以跟前端时间匹配上,前端读秒几秒这里就什么时候取消 



import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.toolkit.CollectionUtils;
import com.kxmall.market.biz.BeanContext;
import com.kxmall.market.data.dto.PrivatePlanAndDetailDO;
import com.kxmall.market.data.mapper.PrivatePlanMapper;
import com.kxmall.market.data.util.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.List;
import java.util.concurrent.DelayQueue;

/**
 * 模拟订单插入的功能
 */

public class PutOrder implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(PutOrder.class);

    //    public static PutOrder putOrder;
    @Autowired
    private PrivatePlanMapper privatePlanMapper;

    // 使用DelayQueue:一个使用优先级队列实现的无界阻塞队列。
    private DelayQueue<ItemVo<Order>> queue;

    public PutOrder(DelayQueue<ItemVo<Order>> queue) {
        super();
        this.queue = queue;
    }

    @Override
    public void run() {
        Date startTime = new Date();
        privatePlanMapper = BeanContext.getApplicationContext().getBean(PrivatePlanMapper.class);
        // 每隔半小时获取半小时内需要取消的
        List<PrivatePlanAndDetailDO> privatePlanDOS = privatePlanMapper.getPrivatePlanDetailList();
        logger.info("待取消清单->{}", JSON.toJSONString(privatePlanDOS));
        if (CollectionUtils.isNotEmpty(privatePlanDOS)) {
            privatePlanDOS.forEach(s -> {
                long count = DateUtil.calLastedTime(startTime,s.getTodoTime() )*1000;
                Order tbOrder = new Order(s.getId().toString(), 0.0);
                ItemVo<Order> itemVoTb = new ItemVo<Order>(count, tbOrder);
                queue.offer(itemVoTb);
                logger.info("订单{}将在->{}秒后取消", s.getId().toString(),count/1000);
            });
            // 取出过期订单的线程
            new Thread(new FetchOrder(queue)).start();
        }else {
            logger.info("没有待发送订单->");
        }
    }
}


import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
 * 存到队列里的元素
 * 支持延时获取的元素的阻塞队列,元素必须要实现Delayed接口。
 * 根据订单有效时间作为队列的优先级
 * @param <T>
 */
public class ItemVo<T> implements Delayed{
    // 到期时间 单位:ms
    private long activeTime;
    // 订单实体(使用泛型是因为后续扩展其他业务共用此业务类)
    private T data;

    public ItemVo(long activeTime, T data) {
        super();
        // 将传入的时间转换为超时的时刻
        this.activeTime = TimeUnit.NANOSECONDS.convert(activeTime, TimeUnit.MILLISECONDS)
                + System.nanoTime();
        this.data = data;
    }

    public long getActiveTime() {
        return activeTime;
    }
    public T getData() {
        return data;
    }

    // 按照剩余时间进行排序
    @Override
    public int compareTo(Delayed o) {
        // 订单剩余时间-当前传入的时间= 实际剩余时间(单位纳秒)
        long d = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
        // 根据剩余时间判断等于0 返回1 不等于0
        // 有可能大于0 有可能小于0  大于0返回1  小于返回-1
        return (d == 0) ? 0 : ((d > 0) ? 1 : -1);
    }

    // 获取剩余时间
    @Override
    public long getDelay(TimeUnit unit) {
        // 剩余时间= 到期时间-当前系统时间,系统一般是纳秒级的,所以这里做一次转换
        long d = unit.convert(activeTime-System.nanoTime(), TimeUnit.NANOSECONDS);
        return d;
    }

}

方法3:分布式场景(mq队列)

使用mq队列,消费消息。如果消息到达30分钟没有付款,那么就取消

方法4:分布式场景(redis)

使用redis商品下单,设置过期时间 30分钟,并且写一个redis监听器,监听过期需要操作的key,然后判单是否过期文章来源地址https://www.toymoban.com/news/detail-820794.html

到了这里,关于商城系统中30分钟未付款自动取消订单怎么实现(简单几种方法)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 超简单的RabbitMq实现订单超时自动取消

    很简单的实现方法,大家帮忙看看能不能继续完善。 步骤: 添加rabbitmq配置 添加rabbitmq配置类 添加订单生产者 添加订单消费者(修改状态) 1、添加rabbitmq配置 注意一定要开启手动应答,不然可能会报错 2、添加rabbitmq配置类 下面这段代码看着有点繁琐,我解释一下逻辑关系

    2024年02月11日
    浏览(26)
  • 订单超时自动取消的技术方案解析及代码实现

    订单超时自动取消是电商平台中常见的功能之一,例如在淘宝、京东、拼多多等商城下单后,如果在一定的时间内没有付款,那么订单会自动被取消,是怎么做到的呢?作为技术人员我们应该了解自动取消的原理和实现逻辑,本文将介绍几种常用的技术方案,帮助开发者实现

    2024年02月16日
    浏览(31)
  • SpringBoot+RabbitMQ实现超时未支付订单自动取消,localhost:15672没有登录页面。

    简介 安装RabbitMQ需要安装Erlang/OTP,并保持版本匹配。 RabbitMQ官网:RabbitMQ: One broker to queue them all | RabbitMQ RabbitMQ与Erlang/OTP版本对照表:Erlang Version Requirements | RabbitMQ Erlang官网下载:Downloads - Erlang/OTP 1.Windows上安装RabbitMQ前需要安装Erlang。(下载安装不做叙述,除了需要自定义安

    2024年04月15日
    浏览(46)
  • Django图书商城系统实战开发-实现订单管理

    在本教程中,我们将继续基于Django框架开发图书商城系统,这次的重点是实现订单管理功能。订单管理是一个电子商务系统中非常重要的部分,它涉及到用户下单、支付、发货以及订单状态的管理等方面。通过学习本教程,您将了解如何使用Django框架来构建强大的订单管理系

    2024年02月12日
    浏览(43)
  • App支付报错"商家订单参数异常,请重新发起付款"排查流程

      今天在对接支付宝 APP 支付的时候遇到了一个报错,记录下问题的排查过程~     APP 中弹窗提示的报错“商家订单参数异常,请重新发起付款”,检查了下参数感觉没啥问题,不知道是啥问题导致的。   去官网搜了下,折腾排查了一遍,发现是环境问题,沙箱环境没有切回

    2024年02月07日
    浏览(69)
  • 帝国CMS商城系统实现在线支付后发送订单邮件提醒功能

    本文实例讲述了帝国CMS商城系统实现在线支付后发送订单邮件提醒功能。分享给大家供大家参考,具体如下: 帝国CMS是个强大的内容管理系统,其商城的功能也很强大,当用户下单,支付后我们怎么知道有用户下单了呢?因为我们不能时时刻刻都在网站后台,不断的刷新页面去看

    2023年04月24日
    浏览(35)
  • Spring Boot + Vue + Element UI的网上商城后台管理之订单管理系统

    以下是订单管理系统的思维导图,展示了系统的主要功能和模块之间的关系。 根节点 订单列表 查看订单列表 搜索订单 排序订单 导出订单列表 订单详情 查看订单详情 修改订单信息 修改商品信息 修改价格 修改收货地址 取消订单 处理订单 处理订单操作 确认订单 拒绝订单

    2024年02月03日
    浏览(36)
  • 怎么取消手机APP自动续费?详细方法来了,轻松易懂

    在使用手机上网的时候,无论是游戏、外卖、看视频、听音乐等等,都拥有会员服务。每次开通会员的时候,平台会推出一种优惠政策,只需要同意自动续费的服务,就能够以极低的价格开通会员服务。可当自己不再需要会员的时候, 怎么取消手机APP自动续费呢? 其实很简

    2024年02月09日
    浏览(28)
  • 支付超时取消订单实现方案 - 定时任务、延迟队列、消息队列等

    在实际业务场景中,我们经常会碰到类似一下场景: 淘宝等购物平台在订单支付时,如果30分钟内未支付自动取消。 腾讯会议预约会议后,在会议开始前15分钟提醒。 未使用的优惠券有效期结束后,自动将优惠券状态更新为已过期。 等等。。。 像这种支付超时取消的场景需

    2024年04月22日
    浏览(29)
  • tp6的runtime/Logs目录下产生大量日记文件,怎么取消自动生成?

    一开始查了好多网上提供的,很幸运都是抄袭别人的,没一个成功,最后无奈只能自己解决方法 其实很简单,不用修改config/log.php文件,没用因为只要有登入错误,警告,消息或者sql错误都会写入 解决方法: 关闭调试模式 配置数据库文件  .env文件 true改为false即可  总结:

    2024年02月16日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包