Quartz定时任务(二)

Quartz定时任务-动态增删改

前言

ps:虽然说是动态实现,但是实际的任务逻辑还是需要手写Job类来实现,然后再去调度器中调度
入参中的*jobClass与jobDetailName*都是你所创建的Job类所在地即: 包路径 + 类名
其他参数都是动态可配,亦可修改的

创建Controller

ps:控制层个人习惯吧业务逻辑统一存放在业务层处理,控制层一般只存在简单的入参判断等. 具体的业务代码统一交给业务层使用

/**
 * @author xiao-_-wu
 * @date 2021/3/22 10:46
 */
@Slf4j
@RestController
@RequestMapping("/test/task")
public class TestTaskController {

    @Resource
    private TestTaskService testTaskService;

    @GetMapping("/stop/{jobDetailName}")
    public String stopTask(@PathVariable String jobDetailName){
        log.info("Controller-----停止定时任务");
        return testTaskService.stopTask(jobDetailName);
    }

    @GetMapping("/restore/{jobDetailName}")
    public String restoreTask(@PathVariable String jobDetailName){
        log.info("Controller-----恢复定时任务");
        return testTaskService.restoreTask(jobDetailName);
    }

    @PostMapping("/add")
    public String addTask(JobDetailsDTO dto){
        log.info("Controller-----新增定时任务");
        return testTaskService.addTask(dto);
    }

    @DeleteMapping("/remove/{jobDetailName}")
    public String removeTask(@PathVariable String jobDetailName){
        log.info("Controller-----删除定时任务");
        return testTaskService.removeTask(jobDetailName);
    }

    @PutMapping("/modify")
    public String modifyTask(JobDetailsDTO dto){
        log.info("Controller-----修改定时任务");
        return testTaskService.modifyTask(dto);
    }

    @GetMapping("/list")
    public JobAndTriggerDTO listTask(){
        log.info("Controller-----获取任务列表");
        return testTaskService.listTask();
    }
}

业务层接口

/**
 * @author xiao-_-wu
 */
public interface TestTaskService {

    /**
     * 暂停定时任务
     * @param jobDetailName 名称
     * @return ret
     */
    String stopTask(String jobDetailName);

    /**
     * 恢复定时任务
     * @param jobDetailName 名称
     * @return ret
     */
    String restoreTask(String jobDetailName);

    /**
     * 新增定时任务
     * @return ret
     * @param dto
     */
    String addTask(JobDetailsDTO dto);

    /**
     * 删除定时任务
     * @return ret
     * @param jobClassName
     */
    String removeTask(String jobClassName);

    /**
     * 修改定时任务
     * @return ret
     * @param dto
     */
    String modifyTask(JobDetailsDTO dto);

    /**
     * 查看当前任务信息
     * @return ret
     */
    JobAndTriggerDTO listTask();

}

业务实现类

/**
 * @author xiao-_-wu
 * @date 2021/3/22 11:34
 */
@Slf4j
@Service
public class TestTaskServiceImpl implements TestTaskService {

    @Resource
    private Scheduler scheduler;

    @Override
    public String stopTask(String jobDetailName) {
        JobKey jobKey = JobKey.jobKey(jobDetailName);
        try {
            if (!isJobDetail(jobKey)){
                return "定时任务不存在或已删除";
            }
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "暂停成功";
    }

    @Override
    public String restoreTask(String jobDetailName) {
        JobKey jobKey = JobKey.jobKey(jobDetailName);
        try {
            if (!isJobDetail(jobKey)){
                return "定时任务不存在或已删除";
            }
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "恢复成功";
    }

    @Override
    public String addTask(JobDetailsDTO dto) {
        try {
            // 启动调度器
            scheduler.start();

            // 获取创建的job任务
            Job job = JobUtil.getJobClass(dto.getJobClass());
            // 创建JobDetail
            JobDetail jobDetail = JobBuilder
                    .newJob(job.getClass())
                    // 给Job任务取名,分组
                    .withIdentity(dto.getJobClass(), dto.getJobGroup())
                    .build();
            jobDetail.requestsRecovery();
            jobDetail.getJobDataMap().put("jobKey", dto.getMassage());

            // 创建Trigger
            Trigger trigger = TriggerBuilder
                    .newTrigger()
                    // 给触发器设置名称和分组
                    .withIdentity(dto.getJobClass(), dto.getTriggerGroup())
                    // 设置定时策略 这里使用createSimple()方式, 也可以使用cron定时策略 createCron()
                    .withSchedule(createSimple(dto.getTime()))
                    .build();

            scheduler.scheduleJob(jobDetail, trigger);
            System.out.println("-----定时任务启动-----");

            /* 创建调度器,进行任务调度, 这里调度器交给了Spring容器进行管理 所以没有用这里的方法
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.scheduleJob(jobDetail, trigger);
            // 这是暂停定时任务的方法
//            scheduler.shutdown();
            */
        } catch (IllegalAccessException e) {
            System.out.println(e.getMessage());
            return "异常: 非法访问异常";
        } catch (InstantiationException e) {
            System.out.println(e.getMessage());
            return "异常: 实例化异常";
        } catch (ClassNotFoundException e) {
            System.out.println(e.getMessage());
            return "异常: 类找不到异常";
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "定时任务创建成功";
    }


    @Override
    public String removeTask(String jobClassName) {
        schedulerDelete(jobClassName);
        return "删除成功";
    }

    @Override
    public String modifyTask(JobDetailsDTO dto) {
        // 先删除任务
        schedulerDelete(dto.getJobClass());
        // 创建定时任务
        addTask(dto);
        return "修改成功";
    }


    @Override
    public JobAndTriggerDTO listTask() {
        List<Trigger> triggers = new ArrayList<>();
        List<JobDetail> jobDetails = new ArrayList<>();
        try {
            // 获取trigger集合
            listTrigger(triggers);
            // 获取JobDetail集合
            listJobDetail(jobDetails);
        } catch (Exception e) {
            log.error("获取定时任务信息出错", e);
            throw new RuntimeException("获取定时任务信息异常");
        }
        JobAndTriggerDTO dto = new JobAndTriggerDTO();
        List<JobInfoDTO> jobInfos = new ArrayList<>();
        for (JobDetail jobDetail : jobDetails) {
            // 存入jobKey信息
            KeyDTO keyDTO = KeyDTO.builder()
                    .key(jobDetail.getKey().getName())
                    .group(jobDetail.getKey().getGroup())
                    .build();
            // 存入JobDetail信息
            jobInfos.add(JobInfoDTO.builder()
                    .jobDataMap(jobDetail.getJobDataMap())
                    .jobKey(keyDTO)
                    .className(jobDetail.getJobClass().getName())
                    .build());
        }
        // 存入返回值
        dto.setJobInfos(jobInfos);
        return dto;
    }

    /**
     * 简单模式的Trigger
     * @return ret
     * @param time 间隔时间/秒
     */
    private SimpleScheduleBuilder createSimple(Integer time){
        return SimpleScheduleBuilder
                // 定时策略类型 普通
                .simpleSchedule()
                // 给定间隔时间 单位/秒
                .withIntervalInSeconds(time)
                .repeatForever();
    }

    /**
     * Cron 模式下的Trigger
     * ps:这里也可以使用Cron模式,使用这种模式需要了解 cron 语法
     * @return ret
     */
    private CronScheduleBuilder createCron(){
        return CronScheduleBuilder
                .cronSchedule("0 0/5 * * *?");
    }

    /**
     * 判断当前Job是否存在
     * @param jobKey jobKey
     * @return ret
     * @throws SchedulerException
     */
    private boolean isJobDetail(JobKey jobKey) throws SchedulerException {
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        return jobDetail != null;
    }

    /**
     * 删除定时任务
     *
     * @param jobClassName job名称
     */
    private void schedulerDelete(String jobClassName) {
        try {
            // 暂停Trigger
            scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName));
            // 从调度器中删除置顶Trigger
            scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName));
            // 删除Job任务
            scheduler.deleteJob(JobKey.jobKey(jobClassName));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("删除定时任务失败");
        }
    }

    /**
     * 获取触发器列表
     * @param triggers 触发器
     * @return ret
     * @throws SchedulerException 调度器程序异常
     */
    private List<Trigger> listTrigger(List<Trigger> triggers) throws SchedulerException {
        // 获取Scheduler下的所有group
        List<String> triggerGroupNames = scheduler.getTriggerGroupNames();
        // 获取所有Trigger名称
        for (String str : triggerGroupNames) {
            GroupMatcher<TriggerKey> groupMatcher = GroupMatcher.triggerGroupEquals(str);
            Set<TriggerKey> set = scheduler.getTriggerKeys(groupMatcher);
            for (TriggerKey key : set){
                triggers.add(scheduler.getTrigger(key));
            }
        }
        return triggers;
    }

    /**
     * 获取定时任务列表
     * @param jobDetails job详情
     * @return ret
     * @throws SchedulerException 调度器程序异常
     */
    private List<JobDetail> listJobDetail(List<JobDetail> jobDetails) throws SchedulerException {
        List<String> jobGroupNames = scheduler.getJobGroupNames();
        for (String str : jobGroupNames) {
            GroupMatcher<JobKey> groupMatcher = GroupMatcher.jobGroupEquals(str);
            Set<JobKey> set = scheduler.getJobKeys(groupMatcher);
            for (JobKey key : set){
                jobDetails.add(scheduler.getJobDetail(key));
            }

        }
        return jobDetails;
    }

}

其他类(entity、dto等)

列表参数类

/**
 * 列表参数类
 * @author xiao-_-wu
 * @date 2021/3/25 16:55
 */
@Data
public class JobAndTriggerDTO implements Serializable {
    private static final long serialVersionUID = -686788394437570442L;

    /**
     * jobDetail集合
     */
    List<JobInfoDTO> jobInfos;

}

通用key类

/**
 * 用来获取key 和 group
 * @author xiao-_-wu
 * @date 2021/3/26 10:38
 */
@Data
@Builder
public class KeyDTO {

    /**
     * key值
     */
    private String key;
    /**
     * 分组
     */
    private String group;
}

job任务信息类

/**
 * job信息类
 * @author xiao-_-wu
 * @date 2021/3/26 10:39
 */
@Data
@Builder
public class JobInfoDTO {

    /**
     * job
     */
    private KeyDTO jobKey;
    /**
     * 包路径
     */
    private String className;
    /**
     * map(用于传值)
     */
    private JobDataMap jobDataMap;
}

创建定时任务入参类

/**
 * job入参
 *
 * @author xiao-_-wu
 * @date 2021/3/25 10:10
 */
@Data
public class JobDetailsDTO {

    /**
     * job类包名
     */
    private String jobClass;

    /**
     * job定时工作类型,非必传
     */
    private Integer jobType;
    /**
     * 工作分组,非必传
     */
    private String jobGroup;
    /**
     * 触发器分组,非必传
     */
    private String triggerGroup;
    /**
     * 其他信息,非必传
     */
    private String massage;
    /**
     * 间隔时间/ 秒
     */
    private Integer time;
}

工具类

/**
 * job工具类
 * @author xiao-_-wu
 * @date 2021/3/25 10:20
 */
public class JobUtil {

    /**
     * 根据类包名获取类
     * @param jobClass 包名
     * @return ret'
     * @throws IllegalAccessException 非法访问异常
     * @throws InstantiationException 实例化异常
     * @throws ClassNotFoundException 类找不到异常
     */
    public static Job getJobClass(String jobClass) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        Class<?> job = Class.forName(jobClass);
        return (Job)job.newInstance();
    }

}

博客地址:Quartz定时任务(二)-CSDN博客

1 Like