自动取消失效订单(监听器 + quartz)

xiaoxiao2021-02-28  63

转载:http://www.cnblogs.com/qingxinshujuan/p/5403878.html CronTrigger最详细的Cron表达式范例参考:http://blog.csdn.net/zixiao217/article/details/53075009 任务需求:

  关闭超时未支付的订单,将订单信息置为失效状态

相关技术:

  quartz框架定时调度

实现思路:

1.在服务启动时,查询数据库中的已下单未支付的订单数据,按下单时间先后存入队列中,先下单的存到头不,后下单存入队列尾部,取队列的头元素 2.检测与现在的时间,如果超过40分钟,则执行数据操作,即关闭订单,但是只关闭未支付的订单,之后在将头元素从队列移出,并取出下一个元素进行检测,以此类推 3.如果检测出时间未到40分钟,则线程等待相应的时间差,之后在执行订单操作 相关问题:

1.在执行时要防止轮询任务追尾,即在上一个job未执行完毕时就开始下一次轮询,解决方法是在job上加@DisallowConcurrentExecution注解,该注解的作用是让下一次job要等待当前job执行完毕 2.设置的轮询间隔是35分钟一次,订单超时是40分钟,中间有5分钟的时间差,为了防止订单被多次加入队列中,在加入订单队列时要注意去重 相关代码

方式1:监听器 + quartz实现;

package com.taotao.order.scheduler; import org.apache.log4j.Logger; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import com.taotao.order.controller.OrderController; /** * * @ClassName: CancelOrderTask * @Description: TODO(取消订单执行类) * @author * @date 2017年9月1日 上午10:58:26 * */ public class CancelOrderTask { static Logger logger = Logger.getLogger(OrderController.class); /* * 1个job配置两个触发器 */ public void cancelOrderTask() throws SchedulerException { // 获得一个scheduler SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); // 创建一个job 任务名,任务组,任务执行类 JobDetail jobDetail = JobBuilder.newJob(CancelOrderJob.class) .withIdentity("cancelOrderJob", "orderJob") //设定job的name和group .storeDurably() //当job没有绑定触发器时放入scheduler不会抛出异常 .build(); scheduler.addJob(jobDetail, false); //创建一个简单触发器,当启动项目时立即执行,CronTrigger的startNow()方法在设定定时任务后不起作用 Trigger simpleTrigger = TriggerBuilder.newTrigger() .withIdentity("firstCancelOrderTrigger", "firstOrderTrigger") //设定触发器name和group .startNow() //设定立即执行 .forJob("cancelOrderJob", "orderJob") //触发器绑定job .build(); //触发器加入到scheduler scheduler.scheduleJob(simpleTrigger); /* * 创建一个CronTrigger触发器,设定触发时间 * CronTrigger触发器startNow没有任何作用,因为有自己的触发时间 */ CronTrigger cronTrigger = TriggerBuilder.newTrigger() .withIdentity("cancelOrderTrigger", "orderTrigger") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 * * * ?")) //触发时间(轮询时间) .forJob("cancelOrderJob", "orderJob").build(); //触发器绑定job // 将job和触发器绑定 scheduler.scheduleJob(cronTrigger); String logInfo = jobDetail.getKey() + "取消订单任务定时器启动"; logger.info(logInfo); System.out.println(logInfo); scheduler.start(); } public static void main(String[] args) { CancelOrderTask cancelOrderTask = new CancelOrderTask(); try { cancelOrderTask.cancelOrderTask(); } catch (SchedulerException e) { e.printStackTrace(); } } }

quartz任务的job,用于检测数据库失效订单并将其关闭,代码如下:

package com.taotao.order.scheduler; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Queue; import org.apache.log4j.Logger; import org.quartz.DisallowConcurrentExecution; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import com.taotao.order.pojo.Order; /** * quartz任务的job,用于检测数据库失效订单并将其关闭 * @DisallowConcurrentExecution 这个注解标明上个任务没有执行完毕不会执行下个任务 */ @DisallowConcurrentExecution public class CancelOrderJob implements Job { //订单有效时间40分钟 public static final long EFFTIVE_TIME = 40 * 60 * 1000; private Logger logger = Logger.getLogger(CancelOrderJob.class); @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { System.out.println("失效订单检测任务开始执行!"); Queue<Order> queue = new LinkedList<>(); // 在每次启动Job时去数据库查找失效订单,并加入到队列中(从数据库中查询,此处使用假数据) List<Order> list = getInvalidOrder(); if (!list.isEmpty()) { for (Order o : list) { queue.offer(o); } } // 获取队列的头元素,开始检测头订单是否失效 Order element = queue.peek(); while (element != null) { //时间差值 Long diff = this.checkOrder(element); if (diff != null && diff >= EFFTIVE_TIME) { System.out.println("开始关闭订单" + element.getOrderId() + "下单时间" + element.getCreateTime()); // 弹出队列 queue.poll(); // 取下一个元素 element = queue.peek(); } else if (diff < EFFTIVE_TIME) { try { System.out.println("等待检测订单" + element.getOrderId() + "下单时间" + element.getCreateTime() + "已下单" + diff / 1000 + "秒"); //线程等待 Thread.sleep(EFFTIVE_TIME - diff); } catch (InterruptedException e) { e.printStackTrace(); logger.info("CancelOrderJob.checkOrder定时任务出现问题"); } } } } /** * 获取订单的下单时间和现在的时间差 * * @author wangpeiqing 2016年4月16日 * @param order * @return * */ public Long checkOrder(Order order) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Long diff = null; if (order != null) { Date createTime = order.getCreateTime(); try { diff = sdf.parse(sdf.format(date)).getTime() - sdf.parse(sdf.format(createTime)).getTime(); } catch (ParseException e) { e.printStackTrace(); } } // 返回值为毫秒 return diff; } /** * * @Title: getInvalidOrder * @Description: TODO(生产订单假数据用于测试) * @return List<Order> 返回类型 * @return */ private List<Order> getInvalidOrder() { List<Order> invalidOrders = new ArrayList<>(); for (int i = 0; i < 50; i++) { Order order = new Order(); order.setOrderId(String.valueOf(i)); order.setCreateTime(new Date()); invalidOrders.add(order); } return invalidOrders; } }

监听器类

package com.taotao.order.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.quartz.SchedulerException; import com.taotao.order.scheduler.CancelOrderTask; public class CancelOrderListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent sce) { CancelOrderTask task = new CancelOrderTask(); try { task.cancelOrderTask(); } catch (SchedulerException e) { e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent sce) { } }

配置监听器:web.xml文件中添加监听器,启动程序时执行执行任务

<!--取消订单监听器,启动程序时执行执行任务 --> <listener> <listener-class>com.taotao.order.listener.CancelOrderListener</listener-class> </listener>

订单实体类:

package com.taotao.pojo; import java.util.Date; public class TbOrder { private String orderId; private String payment; private Integer paymentType; private String postFee; private Integer status; private Date createTime; private Date updateTime; private Date paymentTime; private Date consignTime; private Date endTime; private Date closeTime; private String shippingName; private String shippingCode; private Long userId; private String buyerMessage; private String buyerNick; private Integer buyerRate; public String getOrderId() { return orderId; } public void setOrderId(String orderId) { this.orderId = orderId == null ? null : orderId.trim(); } public String getPayment() { return payment; } public void setPayment(String payment) { this.payment = payment == null ? null : payment.trim(); } public Integer getPaymentType() { return paymentType; } public void setPaymentType(Integer paymentType) { this.paymentType = paymentType; } public String getPostFee() { return postFee; } public void setPostFee(String postFee) { this.postFee = postFee == null ? null : postFee.trim(); } public Integer getStatus() { return status; } public void setStatus(Integer status) { this.status = status; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } public Date getPaymentTime() { return paymentTime; } public void setPaymentTime(Date paymentTime) { this.paymentTime = paymentTime; } public Date getConsignTime() { return consignTime; } public void setConsignTime(Date consignTime) { this.consignTime = consignTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } public Date getCloseTime() { return closeTime; } public void setCloseTime(Date closeTime) { this.closeTime = closeTime; } public String getShippingName() { return shippingName; } public void setShippingName(String shippingName) { this.shippingName = shippingName == null ? null : shippingName.trim(); } public String getShippingCode() { return shippingCode; } public void setShippingCode(String shippingCode) { this.shippingCode = shippingCode == null ? null : shippingCode.trim(); } public Long getUserId() { return userId; } public void setUserId(Long userId) { this.userId = userId; } public String getBuyerMessage() { return buyerMessage; } public void setBuyerMessage(String buyerMessage) { this.buyerMessage = buyerMessage == null ? null : buyerMessage.trim(); } public String getBuyerNick() { return buyerNick; } public void setBuyerNick(String buyerNick) { this.buyerNick = buyerNick == null ? null : buyerNick.trim(); } public Integer getBuyerRate() { return buyerRate; } public void setBuyerRate(Integer buyerRate) { this.buyerRate = buyerRate; } } package com.taotao.order.pojo; import java.util.List; import com.taotao.pojo.TbOrder; import com.taotao.pojo.TbOrderItem; import com.taotao.pojo.TbOrderShipping; public class Order extends TbOrder{ private List<TbOrderItem> orderItems; private TbOrderShipping orderShipping; public List<TbOrderItem> getOrderItems() { return orderItems; } public void setOrderItems(List<TbOrderItem> orderItems) { this.orderItems = orderItems; } public TbOrderShipping getOrderShipping() { return orderShipping; } public void setOrderShipping(TbOrderShipping orderShipping) { this.orderShipping = orderShipping; } }
转载请注明原文地址: https://www.6miu.com/read-27611.html

最新回复(0)