自动取消失效订单(spring整合quartz)

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

任务需求:

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

相关技术:
spring框架
  quartz框架定时调度

实现思路:

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

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

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.JobExecutionException;

import com.taotao.order.pojo.Order;

/**
 * quartz任务的job,用于检测数据库失效订单并将其关闭
 * @DisallowConcurrentExecution 这个注解标明上个任务没有执行完毕不会执行下个任务
 */
@DisallowConcurrentExecution
public class CancelOrderJob1 {
    //订单有效时间40分钟40 * 60 *
    public static final long EFFTIVE_TIME = 1000;
    private Logger logger = Logger.getLogger(CancelOrderJob1.class);

    public void execute() 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;
    }

}

spring整合quartz配置方式
spring的配置文件如下:

<!-- 配置取消订单job类  -->
    <bean id="cancelOrderJob1" class="com.taotao.order.scheduler.CancelOrderJob1"/>
    <!-- 配置取消订单JobDetail 使用MethodInvokingJobDetailFactoryBean这种方式job类不需要实现Job接口-->
    <bean id="cancelOrderJobDetail1"
        class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject">
            <ref bean="cancelOrderJob1" />
        </property>
        <property name="targetMethod">  <!-- 要执行的方法名称 -->
            <value>execute</value>
        </property>
    </bean>
    <!-- 配置取消订单简单触发器trigger,启动项目立即执行 -->
    <bean id="simpleTrigger1" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <property name="jobDetail" ref="cancelOrderJobDetail1"></property>
        <property name="startDelay" value="500" />  
        <property name="repeatInterval" value="0" />  
        <property name="repeatCount" value="0" />
    </bean>
    <!-- 配置取消订单触发器trigger -->
    <bean id="cancelOrderTrigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean ">
        <property name="jobDetail" ref="cancelOrderJobDetail1"></property>
        <property name="cronExpression" value="0 0/2 * * * ?"></property>
    </bean>

    <!-- 配置调度工厂 -->
    <bean id="SpringJobSchedulerFactoryBean"
        class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <!-- 取消订单的两个触发器 -->
                <ref bean="simpleTrigger1" />
                <ref bean="cancelOrderTrigger1" />
            </list>
        </property>
    </bean>

订单实体类:

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;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值