quartz实现动态任务管理系统

我们在开发中经常要对任务进行系统性的管理,比如新加一个任务每天0点更新,修改任务,删除任务,暂停任务等,就需要写一个集中的任务管理器,这边实现一个简单的任务管理系统

没有简单了解请看 quartz入门详解

在数据库中创建任务表以及字段进行任务数据管理
实现任务实体类,调用quartz官方api,实现对任务管理的逻辑
书写对应的接口,主要为增加任务,删除任务,修改任务,任务详情,暂停任务
实现了简单的前端测试代码,可以对任务动态管理进行测试
在实际项目中一般使用数据库存储任务,使用quartz框架进行增删改查暂停开启,达到定时任务的管理

1.创建任务表,sql脚本为

CREATE TABLE scheduled_tasks (
    task_id INT AUTO_INCREMENT PRIMARY KEY, -- 任务ID,自增主键
    task_name VARCHAR(255) NOT NULL, -- 任务名称,不允许为空
    task_group VARCHAR(255), -- 任务分组
    cron_expression VARCHAR(255) NOT NULL, -- Cron表达式,不允许为空
    job_class_name VARCHAR(255) NOT NULL, -- 任务类名,不允许为空
    is_active BOOLEAN -- 是否启用任务
);

2.加上quartz依赖

<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.2</version>
</dependency>

3.编写yml配置

# 数据源配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/your_database  # 数据库连接URL
    username: your_username  # 数据库用户名
    password: your_password  # 数据库密码
    driver-class-name: com.mysql.cj.jdbc.Driver  # 数据库驱动类名

# Quartz调度器配置
quartz:
  job-store-type: jdbc  # Quartz作业存储类型为JDBC
  properties:
    org:
      quartz:
        scheduler:
          instanceName: your_instance_name  # Quartz调度器实例名称
          instanceId: your_instance_id  # Quartz调度器实例ID
        jobStore:
          class: org.quartz.impl.jdbcjobstore.JobStoreTX  # Quartz作业存储类型
          driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # Quartz数据库操作委托类
          dataSource: your_data_source_name  # 数据源名称,连接到Spring中的数据源
          tablePrefix: QRTZ_  # Quartz表格前缀
          isClustered: true  # 启用Quartz集群模式
          clusterCheckinInterval: 20000  # 集群检查间隔时间(毫秒)

4.编写实体任务类

创建一个Java实体类(ScheduledTask)来映射数据库表,并创建一个JPA Repository来执行CRUD操作
@Data
public class ScheduledTask {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long taskId;            // 主键自动生成的任务ID
    private String taskName;        // 任务名称
    private String taskGroup;       // 任务分组
    private String cronExpression;  // Cron表达式,用于调度任务执行时间
    private String jobClassName;    // 任务执行的类名
    private boolean isActive;       // 任务是否处于活动状态
}

5.实现一个ScheduledTaskRepository,对任务进行操作

public interface ScheduledTaskRepository extends JpaRepository<ScheduledTask, Long> {
    // 通过任务名称和分组查找任务
    Optional<ScheduledTask> findByTaskNameAndTaskGroup(String taskName, String taskGroup);

    // 查找所有处于指定活动状态的任务
    List<ScheduledTask> findAllByIsActive(boolean isActive);
}

6.实现任务服务逻辑

创建一个服务类,负责任务的增加、删除、修改、查询、暂停和开启等操作
@Service
public class ScheduledTaskService {

    @Autowired
    private ScheduledTaskRepository taskRepository; // 任务数据存储库

    @Autowired
    private Scheduler scheduler; // 调度器

    // 获取所有已计划任务
    public List<ScheduledTask> getAllTasks() {
        return taskRepository.findAll();
    }

    // 通过任务ID获取指定任务
    public Optional<ScheduledTask> getTaskById(Long taskId) {
        return taskRepository.findById(taskId);
    }

    // 添加新任务
    public void addTask(ScheduledTask task) {
        taskRepository.save(task); // 保存任务信息到数据库

        try {
            // 创建JobDetail,定义任务的执行类和唯一标识
            JobDetail jobDetail = JobBuilder.newJob()
                    .ofType((Class<? extends Job>) Class.forName(task.getJobClassName()))
                    .withIdentity(task.getTaskName(), task.getTaskGroup())
                    .build();

            // 创建CronTrigger,定义任务的调度策略
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(task.getTaskName(), task.getTaskGroup())
                    .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression()))
                    .build();

            // 将任务和触发器添加到调度器中
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException | ClassNotFoundException e) {
            // 处理异常
        }
    }

    // 更新任务信息
    public void updateTask(ScheduledTask task) {
        taskRepository.save(task); // 更新任务信息到数据库

        try {
            // 获取原始任务的触发器标识
            TriggerKey triggerKey = new TriggerKey(task.getTaskName(), task.getTaskGroup());

            // 创建新的CronTrigger,更新任务的调度策略
            CronTrigger newTrigger = TriggerBuilder.newTrigger()
                    .withIdentity(task.getTaskName(), task.getTaskGroup())
                    .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression()))
                    .build();

            // 重新调度任务
            scheduler.rescheduleJob(triggerKey, newTrigger);
        } catch (SchedulerException e) {
            // 处理异常
        }
    }
   // 通过任务ID删除任务
   public void deleteTask(Long taskId) {
    
    Optional<ScheduledTask> task = taskRepository.findById(taskId);
    if (task.isPresent()) {
        // 从存储库中删除任务
        taskRepository.deleteById(taskId);

        try {
            // 根据任务信息创建作业键和触发器键
            JobKey jobKey = new JobKey(task.get().getTaskName(), task.get().getTaskGroup());
            TriggerKey triggerKey = new TriggerKey(task.get().getTaskName(), task.get().getTaskGroup());

            // 从调度程序中删除计划作业并取消其触发器
            scheduler.deleteJob(jobKey);
            scheduler.unscheduleJob(triggerKey);
        } catch (SchedulerException e) {
            // 处理调度程序操作可能引发的异常
        }
    }
}
   // 暂停开始任务
   public void toggleTaskStatus(Long taskId) {
    
    Optional<ScheduledTask> task = taskRepository.findById(taskId);
    if (task.isPresent()) {
        // 切换任务的活动状态
        task.get().setActive(!task.get().isActive());
        // 将更新后的任务信息保存到存储库中
        taskRepository.save(task.get());

        try {
            // 根据任务信息创建作业键
            JobKey jobKey = new JobKey(task.get().getTaskName(), task.get().getTaskGroup());

            // 检查任务状态并相应地恢复或暂停作业
            if (task.get().isActive()) {
                scheduler.resumeJob(jobKey);
            } else {
                scheduler.pauseJob(jobKey);
            }
        } catch (SchedulerException e) {
            // 处理调度程序操作可能引发的异常
        }
    }
}

7.实现控制器

@RestController
@RequestMapping("/api/tasks")
public class ScheduledTaskController {

    @Autowired
    private ScheduledTaskService taskService;

    // 获取所有计划任务的端点
    @GetMapping
    public ResponseEntity<List<ScheduledTask>> getAllTasks() {
        List<ScheduledTask> tasks = taskService.getAllTasks();
        return ResponseEntity.ok(tasks);
    }

    // 通过任务ID获取单个计划任务的端点
    @GetMapping("/{taskId}")
    public ResponseEntity<ScheduledTask> getTaskById(@PathVariable Long taskId) {
        Optional<ScheduledTask> task = taskService.getTaskById(taskId);
        return task.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
    }

    // 添加计划任务的端点
    @PostMapping
    public ResponseEntity<Void> addTask(@RequestBody ScheduledTask task) {
        taskService.addTask(task);
        return ResponseEntity.created(null).build();
    }

    // 更新计划任务的端点
    @PutMapping("/{taskId}")
    public ResponseEntity<Void> updateTask(@PathVariable Long taskId, @RequestBody ScheduledTask task) {
        if (!taskService.getTaskById(taskId).isPresent()) {
            return ResponseEntity.notFound().build();
        }

        taskService.updateTask(task);
        return ResponseEntity.noContent().build();
    }

    // 删除计划任务的端点
    @DeleteMapping("/{taskId}")
    public ResponseEntity<Void> deleteTask(@PathVariable Long taskId) {
        if (!taskService.getTaskById(taskId).isPresent()) {
            return ResponseEntity.notFound().build();
        }

        taskService.deleteTask(taskId);
        return ResponseEntity.noContent().build();
    }

    // 切换计划任务状态的端点
    @PatchMapping("/{taskId}/toggle-status")
    public ResponseEntity<Void> toggleTaskStatus(@PathVariable Long taskId) {
        if (!taskService.getTaskById(taskId).isPresent()) {
            return ResponseEntity.notFound().build();
        }

        taskService.toggleTaskStatus(taskId);
        return ResponseEntity.noContent().build();
    }
}

前端简单的html如下

<!DOCTYPE html>
<html>
<head>
    <title>Scheduled Task Management</title>
</head>
<body>
    <h1>Scheduled Task Management</h1>

    <!-- 列出所有任务 -->
    <h2>List of Tasks</h2>
    <ul id="taskList">
    </ul>

    <!-- 添加任务表单 -->
    <h2>Add a Task</h2>
    <form id="addTaskForm">
        <label for="taskName">Task Name:</label>
        <input type="text" id="taskName" name="taskName" required>
        <button type="submit">Add Task</button>
    </form>

    <!-- 更新任务表单 -->
    <h2>Update a Task</h2>
    <form id="updateTaskForm">
        <label for="taskIdToUpdate">Task ID to Update:</label>
        <input type="text" id="taskIdToUpdate" name="taskIdToUpdate" required>
        <label for="updatedTaskName">Updated Task Name:</label>
        <input type="text" id="updatedTaskName" name="updatedTaskName" required>
        <button type="submit">Update Task</button>
    </form>

    <!-- 删除任务表单 -->
    <h2>Delete a Task</h2>
    <form id="deleteTaskForm">
        <label for="taskIdToDelete">Task ID to Delete:</label>
        <input type="text" id="taskIdToDelete" name="taskIdToDelete" required>
        <button type="submit">Delete Task</button>
    </form>

    <!-- 切换任务状态表单 -->
    <h2>Toggle Task Status</h2>
    <form id="toggleTaskStatusForm">
        <label for="taskIdToToggle">Task ID to Toggle Status:</label>
        <input type="text" id="taskIdToToggle" name="taskIdToToggle" required>
        <button type="submit">Toggle Status</button>
    </form>

    <script>
        // JavaScript代码,用于与Spring Boot服务进行交互

        // 列出所有任务
        function listTasks() {
            fetch('/api/tasks')
                .then(response => response.json())
                .then(data => {
                    const taskList = document.getElementById('taskList');
                    taskList.innerHTML = '';
                    data.forEach(task => {
                        const listItem = document.createElement('li');
                        listItem.textContent = `Task ID: ${task.id}, Task Name: ${task.name}, Status: ${task.status}`;
                        taskList.appendChild(listItem);
                    });
                });
        }

        // 添加任务
        document.getElementById('addTaskForm').addEventListener('submit', function (event) {
            event.preventDefault();
            const taskName = document.getElementById('taskName').value;
            fetch('/api/tasks', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ name: taskName })
            })
                .then(() => {
                    listTasks();
                });
        });

        // 更新任务
        document.getElementById('updateTaskForm').addEventListener('submit', function (event) {
            event.preventDefault();
            const taskId = document.getElementById('taskIdToUpdate').value;
            const updatedTaskName = document.getElementById('updatedTaskName').value;
            fetch(`/api/tasks/${taskId}`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ id: taskId, name: updatedTaskName })
            })
                .then(() => {
                    listTasks();
                });
        });

        // 删除任务
        document.getElementById('deleteTaskForm').addEventListener('submit', function (event) {
            event.preventDefault();
            const taskId = document.getElementById('taskIdToDelete').value;
            fetch(`/api/tasks/${taskId}`, {
                method: 'DELETE'
            })
                .then(() => {
                    listTasks();
                });
        });

        // 切换任务状态
        document.getElementById('toggleTaskStatusForm').addEventListener('submit', function (event) {
            event.preventDefault();
            const taskId = document.getElementById('taskIdToToggle').value;
            fetch(`/api/tasks/${taskId}/toggle-status`, {
                method: 'PATCH'
            })
                .then(() => {
                    listTasks();
                });
        });

        // 页面加载时列出所有任务
        listTasks();
    </script>
</body>
</html>

这样子的话就可以实现一个简单的动态定时任务管理系统

  • 31
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Quartz是一个强大的开源调度框架,可以用来实现各种类型的定时任务,包括动态定时任务。下面是一个基于Spring框架和Quartz动态定时任务的示例: 1. 引入相关依赖 在项目的pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> ``` 2. 配置QuartzSpring的配置文件中配置Quartz,包括调度器、触发器和任务等。以下是一个简单的配置示例: ```xml <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="simpleTrigger" /> </list> </property> </bean> <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="jobDetail" /> <property name="repeatInterval" value="5000" /> <property name="startDelay" value="1000" /> </bean> <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="myTask" /> <property name="targetMethod" value="run" /> </bean> <bean id="myTask" class="com.example.MyTask" /> ``` 上面的配置中,定义了一个触发器simpleTrigger,它关联了一个任务jobDetail,任务实现类是MyTask,它的run方法将会被调用。 3. 编写动态任务的代码 在需要动态创建任务的地方,可以使用以下代码: ```java @Autowired private SchedulerFactoryBean schedulerFactoryBean; public void scheduleJob(String jobName, String groupName, String cronExpression) throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(MyTask.class) .withIdentity(jobName, groupName) .build(); CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(jobName, groupName) .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); Scheduler scheduler = schedulerFactoryBean.getScheduler(); scheduler.scheduleJob(jobDetail, trigger); } ``` 上面的代码中,使用JobBuilder和TriggerBuilder创建任务和触发器,然后将它们通过Scheduler的scheduleJob方法添加到调度器中。 4. 动态修改任务的执行时间 如果需要动态修改任务的执行时间,可以使用以下代码: ```java public void rescheduleJob(String jobName, String groupName, String cronExpression) throws SchedulerException { TriggerKey triggerKey = new TriggerKey(jobName, groupName); CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); if (oldTrigger == null) { return; } CronTrigger newTrigger = TriggerBuilder.newTrigger() .withIdentity(jobName, groupName) .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression)) .build(); scheduler.rescheduleJob(triggerKey, newTrigger); } ``` 上面的代码中,使用TriggerKey获取到原有的触发器,然后使用TriggerBuilder创建新的触发器,最后通过Scheduler的rescheduleJob方法更新触发器。 ### 回答2: Quartz是一个开源的Java任务调度框架,它提供了强大的动态定时任务管理功能。使用Quartz,我们可以轻松地创建、调度和管理定时任务Quartz支持多种触发器类型,如简单触发器和Cron表达式触发器,这使得我们能够根据时间、日期、周几等条件来触发任务的执行。同时,Quartz还支持设置任务的优先级、重复执行次数和间隔时间等属性,以满足不同任务需求。 Quartz动态定时任务管理功能是指可以在运行时动态地添加、修改和删除定时任务。通过Quartz的API,我们可以方便地创建和配置任务,然后将其提交给Quartz进行管理。当任务需要被修改或删除时,我们只需要更新相应的配置信息即可,不需要重新启动应用程序。 动态定时任务的管理有助于实现任务动态调度和灵活性。我们可以根据业务需求,动态地添加新的定时任务。例如,我们可以实现一个任务调度系统,允许用户按照自定义的触发条件和执行逻辑来添加定时任务。这样一来,用户可以根据业务需要,随时添加或删除任务,而不需要修改程序代码。 总而言之,Quartz动态定时任务管理功能为我们提供了一种便捷的方式来创建、调度和管理任务。它的灵活性和易用性使得我们能够更好地满足业务需求,实现高效的任务调度。 ### 回答3: Quartz是一个功能强大的开源的Java调度框架,用于实现各种复杂的调度需求。它支持静态和动态的定时任务动态定时任务是指在应用程序运行过程中动态添加、修改和删除定时任务Quartz提供了灵活的API和丰富的功能,使得动态定时任务的管理变得简单。 首先,我们需要创建一个调度器(Scheduler)对象,它是Quartz框架的核心组件。调度器负责管理和执行所有的定时任务。然后,我们可以使用JobDetail对象定义要执行的任务,以及任务的相关属性。接着,我们可以创建一个触发器(Trigger)对象,用于指定任务的触发时间和频率。 当我们需要动态地添加或修改定时任务时,可以使用调度器的addJob()方法将任务添加到调度器中。这样,调度器会根据定义的触发器来执行任务。如果需要删除某个任务,可以使用调度器的deleteJob()方法。 动态定时任务在很多场景下都非常有用。例如,我们可以根据用户的需求,动态地调整定时任务的执行时间和频率。另外,如果某个任务在执行过程中出现了问题,我们可以通过动态修改任务的相关属性来进行修复,而不需要停止整个应用程序。 总之,Quartz动态定时任务的特点是灵活、可扩展和易于管理。它可以帮助我们实现各种复杂的调度需求,并且可以根据应用程序的运行情况动态地添加、修改和删除定时任务

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大白猫~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值