7天自動收貨,30分鐘不支付訂單自動取消是如何實現的?
阿新 • • 發佈:2019-02-02
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