运维开发网

SpringBoot入门十七,添加Quartz定时任务支持

运维开发网 https://www.qedev.com 2020-03-19 18:15 出处:51CTO 作者:pannijingling
SpringBoot添加Quartz定时任务支持

一、环境配置

  项目基本配置参考SpringBoot入门一,使用myEclipse新建一个SpringBoot项目,使用myEclipse新建一个SpringBoot项目即可。下面开始Quartz整合

二、pom.xml主要配置信息

    <!-- 设置父类,整合第三方常用框架依赖信息(各种依赖信息) -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.7.RELEASE</version>
        <relativePath />
    </parent>

    <!-- 设置公共参数 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!-- Maven install 时,测试环境@Test中如果有中文输出是乱码,加上这句话试试 -->
        <argLine>-Dfile.encoding=UTF-8</argLine>
    </properties>

    <dependencies>
        <!-- 1.开启springboot核心包,整合SpringMVC Web组件 -->
        <!-- 实现原理:Maven依赖继承关系,相当于把第三方常用Maven依赖信息,在parent项目中已经封装好了 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- 2.开启默认连接池,SpringBoot2.x采用hikari连接池 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- 3.开启thymeleaf模板引擎支持 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- 4.开启外部tomcat支持,打war包时加入此项, 告诉spring-boot tomcat相关jar包用外部的,不要打进去 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

        <!-- 5.引入MySQL连接支持 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- 6.开启mybatis支持,一定要使用starter,不然无法自动配置和注入 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!-- 7.开启分页插件pagehelper依赖包 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.2.7</version>
        </dependency>

        <!-- 8.引入fastjson支持 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.49</version>
        </dependency>

        <!--9.开启quartz依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
    </dependencies>

三、配置文件中添加以下配置信息

# mybatis配置
## 配置文件的路径
## mybatis.config-location=mybatis-config.xml
## mybatis映射文件位置
mybatis.mapper-locations=classpath:mybatis/mapping/*/*.xml
## mybatis自动映射实体类别名,多个包以","分割即可
mybatis.type-aliases-package=com.qfx.system.entity,com.qfx.system.vo

# quartz任务配置
spring.quartz.job-store-type=jdbc
spring.quartz.properties.org.quartz.scheduler.instanceName=clusteredScheduler
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=2000
spring.quartz.properties.org.quartz.jobStore.useProperties=false
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.threadCount=10
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true

四、编写QrtzJobDetailsMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qfx.system.dao.QrtzJobDetailsDao">
    <select id="selectAll" resultType="QuartzEntity">
        select
            job.job_name as jobName,job.job_group as jobGroup,job.description as description,
            job.job_class_name as jobClassName,cron.cron_expression as cronExpression,
            tri.trigger_name as triggerName,tri.trigger_state as triggerState,
            job.job_name as oldJobName,job.job_group as oldJobGroup
        from
            qrtz_job_details as job
        left join
            qrtz_triggers as tri on job.job_group = tri.job_group and job.job_name = tri.job_name
        left join
            qrtz_cron_triggers as cron on job.job_group = cron.trigger_group and cron.trigger_name = tri.trigger_name
        where
            tri.trigger_type = 'cron'
            <if test="jobName != null and jobName != ''">
                and job.job_name = #{jobName,jdbcType=VARCHAR}
            </if>
    </select>
</mapper>

五、编写QuartzService.java,Controller接受参数信息直接调用对应的方法即可

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.qfx.common.bean.MessageBean;
import com.qfx.common.service.BaseService;
import com.qfx.common.utils.Page;
import com.qfx.system.dao.QrtzJobDetailsDao;
import com.qfx.system.vo.QuartzEntity;

/**
 * <h5>描述:Quartz业务操作类</h5>
 * 
 * @author qfx  2019年8月16日 
 */
@Service
public class QuartzService extends BaseService {

    @Autowired
    QrtzJobDetailsDao qrtzJobDetailsDao;
    @Autowired
    private Scheduler scheduler;

    /**
     * <h5>功能:获取定时任务列表</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @return 
     */
    public Map<String, Object> list() {
        // 获取从request中传递过来的参数信息
        Map<String, Object> paramMap = getMaps();
        // 获取分页信息
        Page page = getPage(paramMap);
        PageHelper.startPage(page.getCurrentPage(), page.getPageSize());
        List<QuartzEntity> list = qrtzJobDetailsDao.selectAll(paramMap);

        PageInfo<QuartzEntity> pageInfo = new PageInfo<QuartzEntity>(list);
        //获得总条数
        long total = pageInfo.getTotal();

        Map<String, Object> dataMap = new HashMap<String, Object>();
        dataMap.put("code", 0);
        dataMap.put("count", total);
        dataMap.put("data", pageInfo.getList());

        return dataMap;
    }

    /**
     * <h5>功能:验证任务名称是否已经存在</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @return 
     */
    public MessageBean validateJobName() {
        MessageBean messageBean = new MessageBean();
        int count = Integer.parseInt(list().get("count").toString());
        if (count > 0) {
            messageBean.setResult(false);
            messageBean.setMessage("当前任务名称已存在");
        }
        return messageBean;
    }

    // ==================== 往下为Quartz业务方法 ====================

    /**
     * <h5>功能:重新编辑定时任务</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @param quartz
     * @return 
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public MessageBean edit(QuartzEntity quartz) {
        MessageBean messageBean = new MessageBean();
        String processingType ="新增";
        try {
            JobDataMap jobDataMap = null;
            // 1.验证是否是修改操作,如果是,则删除旧的任务
            if(quartz.getOldJobGroup()!= null && quartz.getOldJobGroup()!= ""){
                processingType = "修改";
                JobKey key =JobKey.jobKey(quartz.getOldJobName(),quartz.getOldJobGroup());
                JobDetail jobDetail = scheduler.getJobDetail(key);
                jobDataMap = jobDetail.getJobDataMap();
                for (String key1 : jobDataMap.keySet()) {
                    System.out.println(key1 + ":" + jobDataMap.get(key1));
                }
                key = new JobKey(quartz.getOldJobName(),quartz.getOldJobGroup());
                scheduler.deleteJob(key);
            }
            // 2.开始构建新的定时任务
            Class cls = Class.forName(quartz.getJobClassName()) ;
            cls.newInstance();
            // 2.1 构建新的job信息
            JobDetail job = JobBuilder.newJob(cls)
                    .withIdentity(quartz.getJobName(), quartz.getJobGroup())    //job名称和分组名称
                    .withDescription(quartz.getDescription())   //描述信息
                    .build();
            // 2.2 添加JobDataMap数据,如果没有则不需要配置
//          JobDataMap jobDataMap = new JobDataMap();
//          jobDataMap.put("userName", "zhangsan");
//          jobDataMap.put("age", 18);
//          job.getJobDataMap().putAll(jobDataMap);
            if (jobDataMap != null) {
                job.getJobDataMap().putAll(jobDataMap);
            }

            // 2.3 设置触发时间点
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder
                    .cronSchedule(quartz.getCronExpression())
                    // 表示等待下次Cron触发频率到达时刻开始按照Cron频率依次执行(即暂停期间的不再执行,去掉则表示补充执行)
                    .withMisfireHandlingInstructionDoNothing();
            // 2.4 设置触发器
            Trigger trigger = TriggerBuilder
                    .newTrigger()
                    .withIdentity("trigger" + quartz.getJobName(),quartz.getJobGroup()) //job名称和分组名称
//                  // 使用 Cron 表达式时,StartNow 方法不会起任何效果,Cron 有其自己的执行时间。目前看来 StartNow 应该只适用于 SimpleTrigger 触发器
//                  .startNow() // 一旦加入scheduler,立即生效()
                    .withSchedule(cronScheduleBuilder) //执行时间
                    .build();
            // 2.5 交由Scheduler安排触发
            scheduler.scheduleJob(job, trigger);
            messageBean.setMessage("定时任务[" + quartz.getJobName() + "]" + processingType +"成功~!");
        } catch (ClassNotFoundException e) {
            messageBean.setResult(false);
            messageBean.setMessage("要" + processingType +"的任务类[" + quartz.getJobClassName() + "]不存在,定时任务" + processingType +"失败~!");
            e.printStackTrace();
        } catch(ObjectAlreadyExistsException e){
            messageBean.setResult(false);
            messageBean.setMessage("当前分组定时任务[" + quartz.getJobName() + "]已存在,操作失败~!");
            e.printStackTrace();
        } catch (Exception e) {
            messageBean.setResult(false);
            messageBean.setMessage(processingType +"定时任务[" + quartz.getJobName() + "]发生异常,操作失败~!");
            e.printStackTrace();
        }
        return messageBean;
    }

    /**
     * <h5>功能:删除一个定时任务</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @param quartz
     * @return 
     */
    public MessageBean del(QuartzEntity quartz) {
        MessageBean messageBean = new MessageBean();
        try {  
            TriggerKey triggerKey = TriggerKey.triggerKey(quartz.getJobName(), quartz.getJobGroup());  
            // 停止触发器  
            scheduler.pauseTrigger(triggerKey);  
            // 移除触发器  
            scheduler.unscheduleJob(triggerKey);  
            // 删除任务  
            scheduler.deleteJob(JobKey.jobKey(quartz.getJobName(), quartz.getJobGroup()));  
            System.out.println("removeJob:"+JobKey.jobKey(quartz.getJobName()));
            messageBean.setMessage("定时任务[" + quartz.getJobName() + "]删除成功~!");
        } catch (Exception e) {
            messageBean.setResult(false);
            messageBean.setMessage("删除定时任务[" + quartz.getJobName() + "]发生异常,操作失败~!");
            e.printStackTrace();
        }  
        return messageBean;
    }

    /**
     * <h5>功能:暂停一个定时任务</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @param quartz
     * @return 
     */
    public MessageBean pause(QuartzEntity quartz) {
        MessageBean messageBean = new MessageBean();
        try {
            JobKey key = new JobKey(quartz.getJobName(), quartz.getJobGroup());
            scheduler.pauseJob(key);
            messageBean.setMessage("定时任务[" + quartz.getJobName() + "]停止成功~!");
        } catch (SchedulerException e) {
            messageBean.setResult(false);
            messageBean.setMessage("停止定时任务[" + quartz.getJobName() + "]发生异常,操作失败~!");
            e.printStackTrace();
        }
        return messageBean;
    }

    /**
     * <h5>功能:重新开始一个定时任务</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @param quartz
     * @return 
     */
    public MessageBean resume(QuartzEntity quartz) {
        MessageBean messageBean = new MessageBean();
        try {
             JobKey key = new JobKey(quartz.getJobName(),quartz.getJobGroup());
             scheduler.resumeJob(key);
             messageBean.setMessage("定时任务[" + quartz.getJobName() + "]恢复成功~!");
        } catch (SchedulerException e) {
            messageBean.setResult(false);
            messageBean.setMessage("恢复定时任务[" + quartz.getJobName() + "]发生异常,操作失败~!");
            e.printStackTrace();
        }
        return messageBean;
    }

    /**
     * <h5>功能:暂停所有定时任务</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @return 
     */
    public MessageBean pauseAll() {
        MessageBean messageBean = new MessageBean();
        try {
            if (!scheduler.isShutdown()) {  
                scheduler.pauseAll(); 
            }
            messageBean.setMessage("定时任务全部暂停执行成功~!");
        } catch (SchedulerException e) {
            messageBean.setResult(false);
            messageBean.setMessage("定时任务全部暂停执行发生异常,操作失败~!");
            e.printStackTrace();
        }  
        return messageBean;
    }

    /**
     * <h5>功能:重新开启所有定时任务</h5>
     * 
     * @author qfx  @date 2019年8月16日
     * @return 
     */
    public MessageBean resumeAll() {
        MessageBean messageBean = new MessageBean();
        try {
            scheduler.resumeAll();
            messageBean.setMessage("定时任务全部开启执行成功~!");
        } catch (SchedulerException e) {
            messageBean.setResult(false);
            messageBean.setMessage("定时任务全部开启执行发生异常,操作失败~!");
            e.printStackTrace();
        }  
        return messageBean;
    }
}

六、编写测试定时任务

// 测试任务一
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class TaskTest01 extends QuartzJobBean {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        log.info("[{}]执行了一条新的任务", this.getClass().getName());
    }
}

// 测试任务二
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class TaskTest02 extends QuartzJobBean {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        log.info("[{}]执行了一条新的任务", this.getClass().getName());
    }
}

// 测试任务三
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class TaskTest03 extends QuartzJobBean {
    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        log.info("[{}]执行了一条新的任务", this.getClass().getName());
    }
}

七、启动测试

从页面上进行操作测试

SpringBoot入门十七,添加Quartz定时任务支持

后台显示信息,可以看到三个定时任务都已经在正常运行了

SpringBoot入门十七,添加Quartz定时任务支持

8、源码

移步码云下载

扫码领视频副本.gif

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号