Quartz 实现数据库配置定时任务

1 SQL(定时任务表)

创建定时任务表sql:

create table t_job(
	job_id varchar(36) primary key COMMENT '定时任务ID',
	job_name varchar(200) DEFAULT NULL COMMENT '定时任务名称',
	status varchar(1) DEFAULT null comment '有效状态',
	enable_flag varchar(1) DEFAULT null comment '可见状态',
	cron_expression varchar(200) DEFAULT null comment 'cron表达式',
	execute_target varchar(500) DEFAULT null comment '调用目标字符串'
) comment '定时任务表';

添加定时任务数据sql:

insert into t_job(job_id,job_name,status,enable_flag,cron_expression,execute_target) values('6ca3e86712a645aea01ebbebbb2277d5','测试定时任务','1','1','0/30 * * * * ?','testTask.test(\'6ca3e86712a645aea01ebbebbb2277d5\')');
insert into t_job(job_id,job_name,status,enable_flag,cron_expression,execute_target) values('6ca3e86712a645aea01ebbebbb2277d6','测试定时任务2','1','1','0/10 * * * * ?','testTask.test(\'6ca3e86712a645aea01ebbebbb2277d6\')');

2 Maven依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!--quartz定时任务-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

        <!--hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.5.1</version>
        </dependency>

3 applicattion.properties

server.port=8081
 
#数据库连接池设置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
 
#mybatis的相关配置
mybatis.mapper-locations=classpath:mapper/*.xml

4 实体类(定时任务)

TJob.java:

package com.entity;

import lombok.Data;

@Data
public class TJob {
    /**
     * 定时任务ID
     */
    private String jobId;
    /**
     * 定时任务名称
     */
    private String jobName;
    /**
     * 有效状态
     */
    private String status;
    /**
     * 可见状态
     */
    private String enableFlag;
    /**
     * cron表达式
     */
    private String cronExpression;
    /**
     * 调用目标字符串
     */
    private String executeTarget;
}

5 Mapper

TJobMapper.java:

package com.mapper;

import com.entity.TJob;

import java.util.List;

public interface TJobMapper {
    /**
     * 获取所有定时任务信息
     * @return
     */
    List<TJob> getAllJobList();
}

TJobMapper.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.mapper.TJobMapper">
    <select id="getAllJobList" resultType="com.entity.TJob">
        select job_id jobId,job_name jobName,status,enable_flag enableFlag,cron_expression cronExpression
         ,execute_target executeTarget 
         from t_job
    </select>
</mapper>

6 Service

TJobService.java:

package com.service;

public interface TJobService {
}

TJobServiceImpl.java:

package com.service.impl;

import cn.hutool.core.util.StrUtil;
import com.entity.TJob;
import com.mapper.TJobMapper;
import com.quartz.QuartJob;
import com.service.TJobService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class TJobServiceImpl implements TJobService {

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;
    @Autowired
    private TJobMapper jobMapper;

    /**
     * 初始化定时任务
     */
    @PostConstruct
    public void init() {
        //获取调度器
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        //获取所有定时任务
        List<TJob> jobList = jobMapper.getAllJobList();
        //定时任务不存在
        if (jobList == null || jobList.size() <= 0) {
            return;
        }
        //获取有效的定时任务
        jobList = jobList.stream().filter(x -> StrUtil.equals(x.getStatus(), "1")).collect(Collectors.toList());
        //没有需要创建的定时任务
        if (jobList == null || jobList.size() <= 0) {
            return;
        }

        try {
            //清空调动任务
            scheduler.clear();
            for (TJob job : jobList) {
                createJob(job,scheduler);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建定时任务
     *
     * @param job       定时任务
     * @param scheduler 调度器
     */
    public void createJob(TJob job, Scheduler scheduler) throws Exception {
        if (job == null) {
            return;
        }
        //触发器主键
        TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), null);
        // 表达式调度构建器
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
        //定时任务主键
        JobKey jobKey = JobKey.jobKey(job.getJobId(), null);
        // 构建job信息
        JobDetail jobDetail = JobBuilder.newJob(QuartJob.class).withIdentity(jobKey).build();
        //触发器
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
        // 放入参数,运行时的方法可以获取
        jobDetail.getJobDataMap().put("job", job);
        // 判断定时任务存在
        if (scheduler.checkExists(jobKey)) {
            // 定时任务已存在则重新设置触发器
            scheduler.rescheduleJob(triggerKey, cronTrigger);
        } else {
            // 定时任务不存在则创建定时任务
            scheduler.scheduleJob(jobDetail, cronTrigger);
        }
    }
}

 7 Job(定时任务)实现类

QuartJob.java:

package com.quartz;
 
import cn.hutool.core.date.DateUtil;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
 
import java.util.Date;
 
public class QuartJob implements Job {
 
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            before(context);
            doExecute(context);
            after(context, null);
        } catch (Exception e) {
            System.out.println("定时任务执行失败:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
            after(context, e);
        }
    }
 
    /**
     * 执行前
     *
     * @param context 工作执行上下文对象
     */
    protected void before(JobExecutionContext context) {
        System.out.println("------------");
        System.out.println("开始执行定时任务:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
    }
 
    /**
     * 执行后
     *
     * @param context 工作执行上下文对象
     */
    protected void after(JobExecutionContext context, Exception e) {
        System.out.println("定时任务执行结束:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
    }
 
    /**
     * 执行方法
     *
     * @param context 工作执行上下文对象
     * @throws Exception 执行过程中的异常
     */
    protected void doExecute(JobExecutionContext context) throws Exception {
        //获取JobDetail中关联的数据
        TJob job = (TJob) context.getJobDetail().getJobDataMap().get("job");
        System.out.println("定时任务正在执行中");
        System.out.println("当前时间 :" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "\n任务名(" + job.getJobName()+")");
    }
}

8 InvokeUtil(任务执行工具类)

InvokeUtil.java:

package com.util;

import cn.hutool.core.util.StrUtil;
import com.entity.TJob;

import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;

public class InvokeUtil {

    /**
     * 执行方法
     *
     * @param job 系统任务
     */
    public static void invokeMethod(TJob job) throws Exception {
        String executeTarget = job.getExecuteTarget();
        if (StrUtil.isBlank(executeTarget)) {
            return;
        }
        String beanName = executeTarget.substring(0, executeTarget.indexOf("."));
        if (StrUtil.isBlank(beanName)) {
            return;
        }
        String methodName = executeTarget.substring(executeTarget.indexOf(".") + 1, executeTarget.indexOf("("));
        if (StrUtil.isBlank(methodName)) {
            return;
        }
        List<Object[]> methodParams = getMethodParams(executeTarget);
        //创建调用目标实例
        Object bean = null;
        if (beanName.indexOf(".") < 0) {
            //bean名为自定义的实例名
            bean = SpringUtil.getBean(beanName);
        } else {
            //bean名带包名路径
            bean = Class.forName(beanName).newInstance();
        }

        if (methodParams != null && methodParams.size() > 0) {
            Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams));
            method.invoke(bean, getMethodParamsValue(methodParams));
        } else {
            Method method = bean.getClass().getDeclaredMethod(methodName);
            method.invoke(bean);
        }
    }

    /**
     * 获取参数类型
     *
     * @param methodParams 参数相关列表
     * @return 参数类型列表
     */
    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
        Class<?>[] classs = new Class<?>[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            classs[index] = (Class<?>) os[1];
            index++;
        }
        return classs;
    }

    /**
     * 获取参数值
     *
     * @param methodParams 参数相关列表
     * @return 参数值列表
     */
    public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
        Object[] classs = new Object[methodParams.size()];
        int index = 0;
        for (Object[] os : methodParams) {
            classs[index] = (Object) os[0];
            index++;
        }
        return classs;
    }

    /**
     * 获取method方法参数相关列表
     *
     * @param invokeTarget 目标字符串
     * @return method方法相关参数列表
     */
    public static List<Object[]> getMethodParams(String invokeTarget) {
        String methodStr = invokeTarget.substring(invokeTarget.indexOf("(") + 1, invokeTarget.indexOf(")"));
        if (StrUtil.isBlank(methodStr)) {
            return null;
        }
        String[] methodParams = methodStr.split(",");
        List<Object[]> classs = new LinkedList<>();
        for (int i = 0; i < methodParams.length; i++) {
            String str = StrUtil.isBlank(methodParams[i]) ? "" : methodParams[i].trim();
            ;
            // String字符串类型,包含'
            if (str.contains("'")) {
                classs.add(new Object[]{str.replace("'", ""), String.class});
            }
            // boolean布尔类型,等于true或者false
            else if (StrUtil.equals(str.toLowerCase(), "true") || StrUtil.equals(str.toLowerCase(), "false")) {
                classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});
            }
            // long长整形,包含L
            else if (str.toUpperCase().contains("L")) {
                classs.add(new Object[]{Long.valueOf(str.toUpperCase().replace("L", "")), Long.class});
            }
            // double浮点类型,包含D
            else if (str.toUpperCase().contains("D")) {
                classs.add(new Object[]{Double.valueOf(str.toUpperCase().replace("D", "")), Double.class});
            }
            // 其他类型归类为整形
            else {
                classs.add(new Object[]{Integer.valueOf(str), Integer.class});
            }
        }
        return classs;
    }
}

9 SpringUtil(Spring工具类)

SpringUtil.java:

package com.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class SpringUtil implements BeanFactoryPostProcessor {

    /**
     * Spring应用上下文环境
     */
    private static ConfigurableListableBeanFactory beanFactory;
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        SpringUtil.beanFactory=configurableListableBeanFactory;
    }
    /**
     * 获取对象
     *
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws org.springframework.beans.BeansException
     *
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException
    {
        return (T) beanFactory.getBean(name);
    }
}

10 Task(定时任务调用方法)

TestTask.java:

package com.task;

import org.springframework.stereotype.Component;

@Component("testTask")
public class TestTask {
    /**
     * 定时任务调用方法
     *
     * @param jobId 定时任务ID
     */
    public void test(String jobId) {
        System.out.println("当前执行的定时任务ID:" + jobId);
    }
}

11 Application(启动类)

QuartzApplication.java:

package com;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@MapperScan("com.mapper")
@SpringBootApplication
public class QuartzApplication {

    public static void main(String[] args) {
        SpringApplication.run(QuartzApplication.class, args);
    }

}

12 调试结果

猜你喜欢

转载自blog.csdn.net/qq_38974638/article/details/114962987