SSM的quartz动态定时器


Controller层:

package com.smartteam.controller;

import com.smartteam.controller.BaseController;
import com.smartteam.service.SampleTryEntryService;

/**
 * 

* 前端控制器 *

* * @author XiaoDeng * @since 2019-08-06 */ @Api(tags = "动态定时器") @RestController @RequestMapping("/sampleTry") public class SampleTryController extends BaseController { @Autowired private SampleTryEntryService sampleTryEntryService; /** * 逻辑处理 */ public void sampleTryEntity(){ // 逻辑处理之后启动定时任务 sampleTryEntryService.scrhySendMessage(); } }

SampleTryEntryService层:

package com.smartteam.service;

import com.baomidou.mybatisplus.extension.service.IService;

/**
 * 

* 服务类 *

* * @author XiaoDeng * @since 2019-08-06 */ public interface SampleTryEntryService extends IService { /** * 逻辑处理之后启动定时任务 */ void scrhySendMessage(); }

SampleTryEntryServiceImpl层:

package com.smartteam.service.impl;

import com.smartteam.common.DateUtil;
import com.smartteam.common.quartz.CronUtils;
import com.smartteam.common.quartz.QuartzManager;
import com.smartteam.mapper.erp.SampleTryEntryMapper;
import com.smartteam.service.SampleTryEntryService;
import com.smartteam.vo.quartz.QuartzVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;

/**
 * 

* 服务实现类 *

* * @author XiaoDeng * @since 2019-08-06 */ @Service public class SampleTryEntryServiceImpl extends ServiceImpl implements SampleTryEntryService { /** * 判断定时任务是否开启 */ public boolean startQuartz = false; /** * new一个定时器 */ QuartzManager quartz = new QuartzManager(); /** * 保存定时任务要用到的信息 */ public static List> scymaps = new ArrayList<>(); /** * 逻辑处理之后启动定时任务 */ @Override public void scrhySendMessage() { // 把计划回收日期小于当前日期的数据的发送消息状态设置为1(防止服务断掉的时候,导致发送消息失败) QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("SENDOUT", 0); wrapper.lt("FSAMPLERECOVERYD", new Date()); List tryEntries = list(wrapper); for (SampleTryEntry entry : tryEntries) { entry.setSendout(1); updateEntry(entry); } // 获取定时任务要用到的信息 List> maps = this.baseMapper.trialWearerData(); scymaps = maps; // 移除定时任务 if(startQuartz == true){ try { quartz.removeJob("定时任务提醒", "System"); } catch (SchedulerException e) { e.printStackTrace(); } }else{ // 开启定时任务 quartz.start(); startQuartz = true; } if(maps.size() > 0){ // 时间都是一样的:比如有6行数据,每行数据FSAMPLERECOVERYD的值都一样 String fsamplerecoveryd = maps.get(0).getOrDefault("FSAMPLERECOVERYD", "").toString(); // 把日期转化为cron表达式 String crontime = CronUtils.getCron(DateUtil.parseTime(fsamplerecoveryd, "yyyy-MM-dd HH:mm:ss")); // 添加定时任务 QuartzVo vo = new QuartzVo(); vo.setClassName("com.smartteam.quartz.YygQuartzJob"); vo.setJobName("定时任务提醒"); vo.setJobGroup("System"); vo.setCronExpression(crontime); quartz.addJob(vo); } } }

CronUtils类:日期转换cron表达式

package com.smartteam.common.quartz;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;

/**
 * 日期转换cron表达式
 * @author Administrator
 *
 */
public class CronUtils {

    //"ss mm HH dd MM ? yyyy"
    private static final SimpleDateFormat sdf = new SimpleDateFormat("ss mm HH dd MM ?");

    /***
     *  功能描述:日期转换cron表达式
     * @param date
     * @return
     */
    public static String formatDateByPattern(Date date) {
        String formatTimeStr = null;
        if (Objects.nonNull(date)) {
            formatTimeStr = sdf.format(date);
        }
        return formatTimeStr;
    }

    /***
     * convert Date to cron, eg "0 07 10 15 1 ?"
     * @param date  : 时间点
     * @return
     */
    public static String getCron(Date date) {
        return formatDateByPattern(date);
    }
}

定时任务管理器QuartzManager:

package com.smartteam.common.quartz;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;

import com.smartteam.vo.quartz.QuartzVo;

/**
 * 定时任务管理器
 * @author Administrator
 *
 */
public class QuartzManager {

    private Logger log = LogManager.getLogger(QuartzManager.class);

    private Scheduler scheduler = null;

    /**
     * 初始化调度器 
     */
    public QuartzManager() {
        try {
            scheduler = new StdSchedulerFactory().getScheduler();
            log.info("初始化调度器 ");
        } catch (SchedulerException ex) {
            log.error("初始化调度器=> [失败]:" + ex.getLocalizedMessage());
        }
    }
    //初始化启动任务
    public void initJob(){
        this.start();
    }

     /**
      * 添加定时任务
* className:时间到了要执行的类名:com.information.quartz.YygQuartzJob
* jobName:自定义任务名:定时任务提醒
* jobGroup:自定义组名:System
* cronExpression:cron定时表达式:00 16 18 18 06 ?
* @param record */ public void addJob(QuartzVo vo){ String className = vo.getClassName(); String name = vo.getJobName(); String group = vo.getJobGroup(); String cronExpression = vo.getCronExpression(); this.addJob(name, group, className, cronExpression); } public void addJob(String name, String group, String className, String cronExpression) { Class<? extends Job> jobClazz = null; try { jobClazz = Class.forName(className).asSubclass(Job.class); } catch (Exception e) { log.error(className+"没有继承job,e=="+e); } JobDataMap map = new JobDataMap(); addJob(name,group,jobClazz,cronExpression,map); } public void addJob(String name, String group, Class<? extends Job> jobClazz, String cronExpression,JobDataMap map) { try { // 构造任务 JobDetail job = newJob(jobClazz).withIdentity(name, group).usingJobData(map).build(); // 构造任务触发器 Trigger trg = newTrigger().withIdentity(name, group).withSchedule(cronSchedule(cronExpression)).build(); // 将作业添加到调度器 scheduler.scheduleJob(job, trg); log.info("创建作业=> [作业名称:" + name + " 作业组:" + group + "] "); } catch (SchedulerException e) { e.printStackTrace(); log.error("创建作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]"); } } /** * 移除定时任务 * @param name * @param group * @throws SchedulerException */ public void removeJob(String name, String group) throws SchedulerException { TriggerKey tk = TriggerKey.triggerKey(name, group); scheduler.pauseTrigger(tk);// 停止触发器 scheduler.unscheduleJob(tk);// 移除触发器 JobKey jobKey = JobKey.jobKey(name, group); scheduler.deleteJob(jobKey);// 删除作业 log.info("删除作业=> [作业名称:" + name + " 作业组:" + group + "] "); } /** * 启动定时任务 */ public void start() { try { scheduler.start(); log.info("启动调度器 "); } catch (SchedulerException e) { e.printStackTrace(); log.error("启动调度器=> [失败]"); } } /** * 关闭定时任务 */ public void shutdown() { try { scheduler.shutdown(); log.info("停止调度器 "); } catch (SchedulerException e) { e.printStackTrace(); log.error("停止调度器=> [失败]"); } } }

定时任务管理器用到的自定义QuartzVo:

package com.smartteam.vo.quartz;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;


/**
 * @description:
 * @program: midplatform-privilege
 * @author: XiaoDeng
 * @created: 2019-08-06
 **/
@Data
@ApiModel
public class QuartzVo implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "时间到了要执行的类名:com.information.quartz.YygQuartzJob")
    private String className;

    @ApiModelProperty(value = "自定义任务名:定时任务提醒")
    private String jobName;

    @ApiModelProperty(value = "自定义组名:System")
    private String jobGroup;

    @ApiModelProperty(value = "cron定时表达式:00 16 18 18 06 ?")
    private String cronExpression;

}

时间到了,跳转的的YygQuartzJob类:

package com.smartteam.quartz;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import com.smartteam.common.quartz.QuartzServletContextListener;
import com.smartteam.service.SampleTryEntryService;
import com.smartteam.service.impl.SampleTryEntryServiceImpl;

/**
 * 动态定时器
 * @author Administrator
 *
 */
@Component
public class YygQuartzJob implements Job {
    
    
    @Override
    public void execute(JobExecutionContext jobContext) throws JobExecutionException {
        // 定时任务quartz的job中注入service为null解决方案
        ServletContext context = null;
        try {
            context = (ServletContext) jobContext.getScheduler().getContext()
                    .get(QuartzServletContextListener.MY_CONTEXT_NAME);
        } catch (SchedulerException e1) {
            e1.printStackTrace();
        }
        WebApplicationContext cxt = (WebApplicationContext) context.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
        SampleTryEntryService sampleTryEntryService = (SampleTryEntryService) cxt.getBean("sampleTryEntryServiceImpl");
        // 定时任务要用到的信息
        List> maps = SampleTryEntryServiceImpl.scymaps;
        ................逻辑处理................
        // 这里重新调用定时任务的方法,业务需求
        ampleTryEntryService.scrhySendMessage();
    }
    
}

QuartzServletContextListener类:定时任务quartz的job中注入service为null解决方案

package com.smartteam.common.quartz;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;

import org.quartz.SchedulerException;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.stereotype.Component;

/**
 * 定时任务quartz的job中注入service为null解决类QuartzServletContextListener
 * @author Administrator
 *
 */
@Component
public class QuartzServletContextListener extends QuartzInitializerListener {

    public static final String MY_CONTEXT_NAME = "servletContext";
     
    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // TODO Auto-generated method stub
        super.contextDestroyed(sce);
    }
 
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // TODO Auto-generated method stub
        super.contextInitialized(sce);
        ServletContext servletContext = sce.getServletContext();
        StdSchedulerFactory factory = (StdSchedulerFactory) servletContext
                .getAttribute(QuartzInitializerListener.QUARTZ_FACTORY_KEY);
        try {
            factory.getScheduler().getContext()
                    .put(QuartzServletContextListener.MY_CONTEXT_NAME, servletContext);
        } catch (SchedulerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

maven依赖:



    org.quartz-scheduler
    quartz
    2.3.0