7天自动收货,30分钟不支付订单自动取消是如何实现的?

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 自动取消 delayQueue

转载。 https://blog.csdn.net/goldenfish1919/article/details/50923450

1.我们以支付以后7天自动收货为例来说明下:

(1)用户支付完成以后,把订单ID插入到内存的一个DelayQueue中,同时插入到Redis中。

(2)7天之内,用户点击了确认收货,则从DelayQueue中删除,从Redis中删除。

(3)超过7天,DelayQueue中的订单ID出队,查询数据库,改状态为自动收货,删除redis。

(4)如果7天之内,web服务器重启过,则web服务器启动以后,从redis中读取待收货的订单,插入到DelayQueue。

看下具体的代码:


@Controller
@RequestMapping(value = "")
public class OrderController {
@Autowired
DelayService delayService;
@Autowired
RedisService redisServie;
@Autowired
ConfigService configService;
//模拟数据库
private List<Long> ordeIds = new ArrayList<Long>();
private static final Logger log = Logger.getLogger(OrderController.class);
@RequestMapping(value = "/order", method = RequestMethod.GET)
public String order(final HttpServletRequest request, final Model model) {
return "order";
}
@RequestMapping(value = "/pay", method = RequestMethod.GET)
@ResponseBody
public Response<Void> pay(final HttpServletRequest request, final Model model) {
final long orderId = Long.parseLong(request.getParameter("orderId"));
ordeIds.add(orderId);
log.error("订单已支付:"+orderId);
//把订单插入到待收货的队列和redis
ThreadPoolUtil.execute(new Runnable(){
@Override
public void run() {
//1 插入到待收货队列
DSHOrder dshOrder = new DSHOrder(orderId, configService.getDshTimeOut());
delayService.add(dshOrder);
log.error("订单入队:"+orderId);
//2插入到redis
redisServie.set(Constants.RedisKey.DSH_PREFIX+orderId, dshOrder, RedisService.DB.DSH);
log.error("订单入redis:"+orderId);
}
});
return new Response<Void>(0,"成功");
}
@RequestMapping(value = "/confirm_delivery", method = RequestMethod.GET)
@ResponseBody
public Response<Void> confirm_delivery(final HttpServletRequest request, final Model model) {
final long orderId = Long.parseLong(request.getParameter("orderId"));
ordeIds.remove(orderId);
log.error("订单已确认收货:"+orderId);
//从delay队列删除,从redis删除
ThreadPoolUtil.execute(new Runnable(){
public void run(){
//从delay队列删除
delayService.remove(orderId);
log.error("订单手动出队:"+orderId);
//从redis删除
redisServie.delete(Constants.RedisKey.DSH_PREFIX+orderId, RedisService.DB.DSH);
log.error("订单手动出redis:"+orderId);
}
});
return new Response<Void>(0,"成功");
}
}


@Service
public class DelayService {
private static final Logger log = Logger.getLogger(DelayService.class);
@Autowired
ConfigService configService;
private boolean start ;
private OnDelayedListener listener;
private DelayQueue<DSHOrder> delayQueue = new DelayQueue<DSHOrder>();
public static interface OnDelayedListener{
public void onDelayedArrived(DSHOrder order);
}
public void start(OnDelayedListener listener){
if(start){
return;
}
log.error("DelayService 启动");
start = true;
this.listener = listener;
new Thread(new Runnable(){
public void run(){
try{
while(true){
DSHOrder order = delayQueue.take();
if(DelayService.this.listener != null){
DelayService.this.listener.onDelayedArrived(order);
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}).start();;
}
public void add(DSHOrder order){
delayQueue.put(order);
}
public boolean remove(DSHOrder order){
return delayQueue.remove(order);
}
public void add(long orderId){
delayQueue.put(new DSHOrder(orderId, configService.getDshTimeOut()));
}
public void remove(long orderId){
DSHOrder[] array = delayQueue.toArray(new DSHOrder[]{});
if(array == null || array.length <= 0){
return;
}
DSHOrder target = null;
for(DSHOrder order : array){
if(order.getOrderId() == orderId){
target = order;
break;
}
}
if(target != null){
delayQueue.remove(target);
}
}
}


public class DSHOrder implements Delayed {
private long orderId;
private long startTime;
public DSHOrder(){
}
/**
* orderId:订单id
* timeout:自动收货的超时时间,秒
* */
public DSHOrder(long orderId, int timeout){
this.orderId = orderId;
this.startTime = System.currentTimeMillis() + timeout*1000L;
}
@Override
public int compareTo(Delayed other) {
if (other == this){
return 0;
}
if(other instanceof DSHOrder){
DSHOrder otherRequest = (DSHOrder)other;
long otherStartTime = otherRequest.getStartTime();
return (int)(this.startTime - otherStartTime);
}
return 0;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(startTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (orderId ^ (orderId >>> 32));
result = prime * result + (int) (startTime ^ (startTime >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DSHOrder other = (DSHOrder) obj;
if (orderId != other.orderId)
return false;
if (startTime != other.startTime)
return false;
return true;
}
public long getStartTime() {
return startTime;
}
public long getOrderId() {
return orderId;
}
public void setOrderId(long orderId) {
this.orderId = orderId;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
@Override
public String toString() {
return "DSHOrder [orderId=" + orderId + ", startTime=" + startTime + "]";
}
}


@Service
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger log = Logger.getLogger(StartupListener.class);
@Autowired
DelayService delayService;
@Autowired
RedisService redisService;
@Override
public void onApplicationEvent(ContextRefreshedEvent evt) {
log.error(">>>>>>>>>>>>系统启动完成,onApplicationEvent()");
if (evt.getApplicationContext().getParent() == null) {
return;
}
//自动收货
delayService.start(new OnDelayedListener(){
@Override
public void onDelayedArrived(final DSHOrder order) {
//异步来做
ThreadPoolUtil.execute(new Runnable(){
public void run(){
long orderId = order.getOrderId();
//查库判断是否需要自动收货
log.error("自动确认收货,onDelayedArrived():"+orderId);
//从redis删除
redisService.delete(Constants.RedisKey.DSH_PREFIX+orderId, RedisService.DB.DSH);
log.error("自动确认收货,删除redis:"+orderId);
}
});
}
});
//查找需要入队的订单
ThreadPoolUtil.execute(new Runnable(){
@Override
public void run() {
log.error("查找需要入队的订单");
//扫描redis,找到所有可能的orderId
List<String> keys = redisService.scan(RedisService.DB.DSH);
if(keys == null || keys.size() <= 0){
return;
}
log.error("需要入队的订单keys:"+keys);
//写到DelayQueue
for(String key : keys){
DSHOrder order = redisService.get(key, DSHOrder.class, RedisService.DB.DSH);
log.error("读redis,key:"+key);
if(order != null){
delayService.add(order);
log.error("订单自动入队:"+order.getOrderId());
}
}
}
});
}
}

最新的代码: https://github.com/xjs1919/util/tree/master/src/main/java/com/github/xjs/util/delay
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
4月前
|
消息中间件 NoSQL Kafka
订单超时取消的11种方式(非常详细清楚)
订单超时取消的11种方式(非常详细清楚)
566 1
订单超时取消的11种方式(非常详细清楚)
|
7月前
|
消息中间件 NoSQL 数据库
订单超时未支付自动取消--实现简述
订单超时未支付自动取消--实现简述
141 0
|
8月前
|
前端开发 小程序 安全
从零玩转系列之微信支付实战PC端我的订单接入退款取消接口1
从零玩转系列之微信支付实战PC端我的订单接入退款取消接口
55 0
|
8月前
|
JSON 前端开发 Java
从零玩转系列之微信支付实战PC端我的订单接入退款取消接口2
从零玩转系列之微信支付实战PC端我的订单接入退款取消接口
68 0
|
11月前
筛选拆单后订单状态全部为已取消状态的订单有哪些
筛选拆单后订单状态全部为已取消状态的订单有哪些
49 0
|
消息中间件 Java 程序员
订单支付超时,自动关闭订单实现
今天跟大家一起探讨一个场景:用户对商品下单,约定30分钟没支付,超时订单将被系统自动关闭。
329 0
订单支付超时,自动关闭订单实现
|
弹性计算
阿里云存在未支付订单导致无法下单解决方法
解决阿里云存在未支付订单请支付或作废后再下单,阿里云服务器或其他云资源无法立即购买,提示“您选择的资源存在未支付订单,请支付或作废后再下单!”什么原因?这是由于你的阿里云账号之前已经创建了该订单,只是订单没有支付,所以无法再次创建订单。解决方法是,要么取消之前的订单,要么支付之前的订单。阿里云百科来详细说下阿里云账号下存在未支付订单的解决方法:
705 0
阿里云存在未支付订单导致无法下单解决方法
|
前端开发 应用服务中间件 API
订单异步通知修改订单状态
订单异步通知修改订单状态
订单异步通知修改订单状态
|
XML Linux PHP
shopnc自动结算的问题
shopnc自动结算的问题
88 0
shopnc自动结算的问题
|
消息中间件 数据库 RocketMQ
取消订单|学习笔记
快速学习取消订单
76 0