自动监听删除失效订单(quartz)

转载:https://blog.csdn.net/menghuanzhiming/article/details/77744267
任务需求:
  关闭超时未支付的订单,将订单信息置为失效状态
相关技术:
  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.nice.util.quartz;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import com.nice.dao.ValarmDataInfoMapper;
import com.nice.model.ValarmDataInfo;
import com.nice.service.AlarmDataService;
import org.apache.log4j.Logger;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import javax.annotation.Resource;

/**
 * quartz任务的job,用于检测数据库失效订单并将其关闭
 * @DisallowConcurrentExecution 这个注解标明上个任务没有执行完毕不会执行下个任务
 */

@DisallowConcurrentExecution
@Component
public class CancelOrderJob implements Job {
    @Autowired
    private AlarmDataService service;
    //订单有效时间3分钟
    public static final long EFFTIVE_TIME = 3 * 60 * 1000;
    private Logger logger = Logger.getLogger(CancelOrderJob.class);

    @Override
            public void execute(JobExecutionContext arg0) throws JobExecutionException {
            
                //下面这行代码必须加上,不然无法注入Bean,会报空指针错误
                SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
                System.out.println("失效订单检测任务开始执行!");
                Queue queue = new LinkedList<>();

                // 在每次启动Job时去数据库查找失效订单,并加入到队列中(从数据库中查询,此处使用假数据)
                List list = service.queryAll();
                System.out.println("list大小:"+list.size());
                if (!list.isEmpty()) {
                    for (ValarmDataInfo o : list) {
                        queue.offer(o);
                    }
                }
                // 获取队列的头元素,开始检测头订单是否失效
                ValarmDataInfo element = queue.peek();
                System.out.println("element="+element);
                while (element != null) {
            //时间差值
            Long diff = this.checkOrder(element);
            if (diff != null && diff >= EFFTIVE_TIME) {
                System.out.println("开始关闭订单" + element.getDevicename() + "下单时间" + element.getAlarmstarttime());
                // 弹出队列
                queue.poll();
                // 取下一个元素
                element = queue.peek();
            } else if (diff < EFFTIVE_TIME) {
                try {
                    System.out.println("等待检测订单" + element.getDevicename() + "下单时间" + element.getAlarmstarttime() + "已下单"
                            + 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(ValarmDataInfo order) {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Long diff = null;
        if (order != null) {
            Date createTime = order.getAlarmstarttime();
            try {
                diff = sdf.parse(sdf.format(date)).getTime() - sdf.parse(sdf.format(createTime)).getTime();
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        // 返回值为毫秒
        return diff;
    }
   

}

监听器类

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文件中添加监听器,启动程序时执行执行任务


    
        com.taotao.order.listener.CancelOrderListener
    

你可能感兴趣的:(spring)