serv-定时任务
This commit is contained in:
248
schoolNewsServ/crontab/README.md
Normal file
248
schoolNewsServ/crontab/README.md
Normal file
@@ -0,0 +1,248 @@
|
||||
# 定时任务模块 (Crontab Module)
|
||||
|
||||
## 模块简介
|
||||
|
||||
定时任务模块是基于Spring Boot和Quartz框架实现的动态定时任务管理系统,支持任务的动态创建、修改、启动、暂停和删除,并提供完整的任务执行日志记录功能。
|
||||
|
||||
## 主要功能
|
||||
|
||||
### 1. 任务管理
|
||||
- **创建任务**: 动态创建定时任务,支持Cron表达式
|
||||
- **更新任务**: 修改任务配置,自动重新调度
|
||||
- **删除任务**: 删除任务并停止调度
|
||||
- **启动/暂停**: 控制任务的运行状态
|
||||
- **立即执行**: 手动触发任务执行一次
|
||||
|
||||
### 2. 任务配置
|
||||
- **Bean名称和方法名**: 指定要执行的Spring Bean和方法
|
||||
- **Cron表达式**: 灵活的时间调度配置
|
||||
- **并发控制**: 支持控制任务是否允许并发执行
|
||||
- **错过执行策略**: 配置任务错过执行时间后的处理策略
|
||||
|
||||
### 3. 日志记录
|
||||
- **执行记录**: 记录每次任务执行的详细信息
|
||||
- **执行时长**: 统计任务执行耗时
|
||||
- **异常信息**: 详细记录执行失败的异常堆栈
|
||||
- **日志清理**: 支持定期清理过期日志
|
||||
|
||||
## 数据库表结构
|
||||
|
||||
### tb_crontab_task (定时任务配置表)
|
||||
```sql
|
||||
- id: 主键ID
|
||||
- task_id: 任务ID
|
||||
- task_name: 任务名称
|
||||
- task_group: 任务分组
|
||||
- bean_name: Bean名称
|
||||
- method_name: 方法名称
|
||||
- method_params: 方法参数
|
||||
- cron_expression: Cron表达式
|
||||
- status: 任务状态(0:暂停 1:运行中)
|
||||
- description: 任务描述
|
||||
- concurrent: 是否允许并发执行
|
||||
- misfire_policy: 错过执行策略
|
||||
- creator: 创建者
|
||||
- updater: 更新者
|
||||
- create_time: 创建时间
|
||||
- update_time: 更新时间
|
||||
- delete_time: 删除时间
|
||||
- deleted: 是否删除
|
||||
```
|
||||
|
||||
### tb_crontab_log (定时任务执行日志表)
|
||||
```sql
|
||||
- id: 主键ID
|
||||
- task_id: 任务ID
|
||||
- task_name: 任务名称
|
||||
- task_group: 任务分组
|
||||
- bean_name: Bean名称
|
||||
- method_name: 方法名称
|
||||
- method_params: 方法参数
|
||||
- execute_status: 执行状态(0:失败 1:成功)
|
||||
- execute_message: 执行结果信息
|
||||
- exception_info: 异常信息
|
||||
- start_time: 开始时间
|
||||
- end_time: 结束时间
|
||||
- execute_duration: 执行时长(毫秒)
|
||||
- create_time: 创建时间
|
||||
- update_time: 更新时间
|
||||
- delete_time: 删除时间
|
||||
- deleted: 是否删除
|
||||
```
|
||||
|
||||
## API接口
|
||||
|
||||
### 任务管理接口
|
||||
|
||||
#### 1. 创建定时任务
|
||||
```
|
||||
POST /crontab/task
|
||||
Body: TbCrontabTask对象
|
||||
```
|
||||
|
||||
#### 2. 更新定时任务
|
||||
```
|
||||
PUT /crontab/task
|
||||
Body: TbCrontabTask对象
|
||||
```
|
||||
|
||||
#### 3. 删除定时任务
|
||||
```
|
||||
DELETE /crontab/task
|
||||
Body: TbCrontabTask对象
|
||||
```
|
||||
|
||||
#### 4. 查询任务详情
|
||||
```
|
||||
GET /crontab/task/{taskId}
|
||||
```
|
||||
|
||||
#### 5. 查询任务列表
|
||||
```
|
||||
POST /crontab/task/list
|
||||
Body: 过滤条件
|
||||
```
|
||||
|
||||
#### 6. 分页查询任务
|
||||
```
|
||||
POST /crontab/task/page
|
||||
Body: PageRequest<TbCrontabTask>
|
||||
```
|
||||
|
||||
#### 7. 启动任务
|
||||
```
|
||||
POST /crontab/task/start/{taskId}
|
||||
```
|
||||
|
||||
#### 8. 暂停任务
|
||||
```
|
||||
POST /crontab/task/pause/{taskId}
|
||||
```
|
||||
|
||||
#### 9. 立即执行任务
|
||||
```
|
||||
POST /crontab/task/execute/{taskId}
|
||||
```
|
||||
|
||||
#### 10. 验证Cron表达式
|
||||
```
|
||||
GET /crontab/task/validate?cronExpression={expression}
|
||||
```
|
||||
|
||||
### 日志管理接口
|
||||
|
||||
#### 1. 根据任务ID查询日志
|
||||
```
|
||||
GET /crontab/log/task/{taskId}
|
||||
```
|
||||
|
||||
#### 2. 查询日志列表
|
||||
```
|
||||
POST /crontab/log/list
|
||||
Body: 过滤条件
|
||||
```
|
||||
|
||||
#### 3. 分页查询日志
|
||||
```
|
||||
POST /crontab/log/page
|
||||
Body: PageRequest<TbCrontabLog>
|
||||
```
|
||||
|
||||
#### 4. 查询日志详情
|
||||
```
|
||||
GET /crontab/log/{logId}
|
||||
```
|
||||
|
||||
#### 5. 清理过期日志
|
||||
```
|
||||
DELETE /crontab/log/clean/{days}
|
||||
```
|
||||
|
||||
#### 6. 删除日志
|
||||
```
|
||||
DELETE /crontab/log
|
||||
Body: TbCrontabLog对象
|
||||
```
|
||||
|
||||
## 示例任务
|
||||
|
||||
模块内置了三个示例任务:
|
||||
|
||||
### 1. SystemStatisticsTask (系统数据统计任务)
|
||||
- Bean名称: `systemStatisticsTask`
|
||||
- 方法名称: `execute`
|
||||
- 功能: 执行系统数据统计
|
||||
|
||||
### 2. LogCleanTask (清理过期日志任务)
|
||||
- Bean名称: `logCleanTask`
|
||||
- 方法名称: `execute`
|
||||
- 功能: 清理指定天数之前的日志
|
||||
- 参数: 天数(默认30天)
|
||||
|
||||
### 3. DataBackupTask (数据备份任务)
|
||||
- Bean名称: `dataBackupTask`
|
||||
- 方法名称: `execute`
|
||||
- 功能: 执行数据备份
|
||||
- 参数: 备份类型(full-全量,incremental-增量)
|
||||
|
||||
## 自定义任务
|
||||
|
||||
要创建自定义任务,按照以下步骤:
|
||||
|
||||
1. 创建一个Spring Bean类
|
||||
```java
|
||||
@Component("myCustomTask")
|
||||
public class MyCustomTask {
|
||||
|
||||
public void execute() {
|
||||
// 任务执行逻辑
|
||||
}
|
||||
|
||||
public void execute(String params) {
|
||||
// 带参数的任务执行逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. 在数据库中添加任务配置
|
||||
```sql
|
||||
INSERT INTO tb_crontab_task (id, task_id, task_name, bean_name, method_name, cron_expression, status)
|
||||
VALUES ('xxx', 'xxx', '我的自定义任务', 'myCustomTask', 'execute', '0 0 * * * ?', 1);
|
||||
```
|
||||
|
||||
3. 或通过API接口创建任务
|
||||
|
||||
## Cron表达式示例
|
||||
|
||||
```
|
||||
0 0 1 * * ? 每天凌晨1点执行
|
||||
0 */5 * * * ? 每5分钟执行一次
|
||||
0 0 0 1 * ? 每月1号凌晨执行
|
||||
0 0 9-18 * * ? 每天9点到18点,每小时执行
|
||||
0 0 * * * ? 每小时执行
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **Cron表达式格式**: 使用Spring的Cron表达式格式(6位或7位)
|
||||
2. **并发控制**: 设置`concurrent=0`可防止同一任务并发执行
|
||||
3. **异常处理**: 任务执行失败会记录详细的异常信息到日志表
|
||||
4. **任务初始化**: 系统启动时会自动加载所有状态为"运行中"的任务
|
||||
5. **线程池配置**: 默认线程池大小为10,可在`SchedulerConfig`中调整
|
||||
|
||||
## 技术栈
|
||||
|
||||
- Spring Boot 3.5.6
|
||||
- Spring Scheduling
|
||||
- MyBatis Plus 3.5.14
|
||||
- MySQL 9.4.0
|
||||
- Java 21
|
||||
|
||||
## 作者
|
||||
|
||||
yslg @ xyzh
|
||||
|
||||
## 更新日期
|
||||
|
||||
2025-10-25
|
||||
|
||||
90
schoolNewsServ/crontab/pom.xml
Normal file
90
schoolNewsServ/crontab/pom.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>school-news</artifactId>
|
||||
<version>${school-news.version}</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>crontab</artifactId>
|
||||
<version>${school-news.version}</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!-- API依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>api-crontab</artifactId>
|
||||
<version>${school-news.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Common模块依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.xyzh</groupId>
|
||||
<artifactId>common-all</artifactId>
|
||||
<version>${school-news.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot Web -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis Plus for Spring Boot 3 -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MySQL驱动 -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.zaxxer</groupId>
|
||||
<artifactId>HikariCP</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Log4j2 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Quartz定时任务 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<parameters>true</parameters>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.xyzh.crontab.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
/**
|
||||
* @description 定时任务配置
|
||||
* @filename SchedulerConfig.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
public class SchedulerConfig {
|
||||
|
||||
/**
|
||||
* @description 配置任务调度线程池
|
||||
* @return TaskScheduler
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Bean
|
||||
public TaskScheduler taskScheduler() {
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
// 设置线程池大小
|
||||
scheduler.setPoolSize(10);
|
||||
// 设置线程名称前缀
|
||||
scheduler.setThreadNamePrefix("crontab-task-");
|
||||
// 设置是否等待所有任务完成后再关闭
|
||||
scheduler.setWaitForTasksToCompleteOnShutdown(true);
|
||||
// 设置等待时间(秒)
|
||||
scheduler.setAwaitTerminationSeconds(60);
|
||||
// 设置拒绝策略
|
||||
scheduler.setRejectedExecutionHandler(new java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy());
|
||||
// 初始化
|
||||
scheduler.initialize();
|
||||
|
||||
return scheduler;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
package org.xyzh.crontab.controller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.xyzh.api.crontab.CrontabService;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.core.page.PageRequest;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabTask;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabLog;
|
||||
|
||||
/**
|
||||
* @description 定时任务控制器
|
||||
* @filename CrontabController.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/crontab")
|
||||
public class CrontabController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CrontabController.class);
|
||||
|
||||
@Autowired
|
||||
private CrontabService crontabService;
|
||||
|
||||
// ----------------定时任务管理--------------------------------
|
||||
|
||||
/**
|
||||
* @description 创建定时任务
|
||||
* @param task 任务对象
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task")
|
||||
public ResultDomain<TbCrontabTask> createTask(@RequestBody TbCrontabTask task) {
|
||||
return crontabService.createTask(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 更新定时任务
|
||||
* @param task 任务对象
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PutMapping("/task")
|
||||
public ResultDomain<TbCrontabTask> updateTask(@RequestBody TbCrontabTask task) {
|
||||
return crontabService.updateTask(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除定时任务
|
||||
* @param task 任务对象
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@DeleteMapping("/task")
|
||||
public ResultDomain<TbCrontabTask> deleteTask(@RequestBody TbCrontabTask task) {
|
||||
return crontabService.deleteTask(task.getID());
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据ID查询任务
|
||||
* @param taskId 任务ID
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@GetMapping("/task/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> getTaskById(@PathVariable String taskId) {
|
||||
return crontabService.getTaskById(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 查询任务列表
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/list")
|
||||
public ResultDomain<TbCrontabTask> getTaskList(@RequestBody TbCrontabTask filter) {
|
||||
return crontabService.getTaskList(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分页查询任务列表
|
||||
* @param pageRequest 分页请求对象
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/page")
|
||||
public ResultDomain<TbCrontabTask> getTaskPage(@RequestBody PageRequest<TbCrontabTask> pageRequest) {
|
||||
TbCrontabTask filter = pageRequest.getFilter();
|
||||
PageParam pageParam = pageRequest.getPageParam();
|
||||
return crontabService.getTaskPage(filter, pageParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 启动定时任务
|
||||
* @param taskId 任务ID
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/start/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> startTask(@PathVariable String taskId) {
|
||||
return crontabService.startTask(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 暂停定时任务
|
||||
* @param taskId 任务ID
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/pause/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> pauseTask(@PathVariable String taskId) {
|
||||
return crontabService.pauseTask(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 立即执行一次任务
|
||||
* @param taskId 任务ID
|
||||
* @return ResultDomain<TbCrontabTask>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/task/execute/{taskId}")
|
||||
public ResultDomain<TbCrontabTask> executeTaskOnce(@PathVariable String taskId) {
|
||||
return crontabService.executeTaskOnce(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 验证Cron表达式
|
||||
* @param cronExpression Cron表达式
|
||||
* @return ResultDomain<String>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@GetMapping("/task/validate")
|
||||
public ResultDomain<String> validateCronExpression(@RequestParam String cronExpression) {
|
||||
return crontabService.validateCronExpression(cronExpression);
|
||||
}
|
||||
|
||||
// ----------------定时任务日志--------------------------------
|
||||
|
||||
/**
|
||||
* @description 根据任务ID查询日志
|
||||
* @param taskId 任务ID
|
||||
* @return ResultDomain<TbCrontabLog>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@GetMapping("/log/task/{taskId}")
|
||||
public ResultDomain<TbCrontabLog> getLogsByTaskId(@PathVariable String taskId) {
|
||||
return crontabService.getLogsByTaskId(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 查询日志列表
|
||||
* @param filter 过滤条件
|
||||
* @return ResultDomain<TbCrontabLog>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/log/list")
|
||||
public ResultDomain<TbCrontabLog> getLogList(@RequestBody TbCrontabLog filter) {
|
||||
return crontabService.getLogList(filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 分页查询日志列表
|
||||
* @param pageRequest 分页请求对象
|
||||
* @return ResultDomain<TbCrontabLog>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@PostMapping("/log/page")
|
||||
public ResultDomain<TbCrontabLog> getLogPage(@RequestBody PageRequest<TbCrontabLog> pageRequest) {
|
||||
TbCrontabLog filter = pageRequest.getFilter();
|
||||
PageParam pageParam = pageRequest.getPageParam();
|
||||
return crontabService.getLogPage(filter, pageParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据ID查询日志详情
|
||||
* @param logId 日志ID
|
||||
* @return ResultDomain<TbCrontabLog>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@GetMapping("/log/{logId}")
|
||||
public ResultDomain<TbCrontabLog> getLogById(@PathVariable String logId) {
|
||||
return crontabService.getLogById(logId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 清理指定天数之前的日志
|
||||
* @param days 天数
|
||||
* @return ResultDomain<Integer>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@DeleteMapping("/log/clean/{days}")
|
||||
public ResultDomain<Integer> cleanLogs(@PathVariable Integer days) {
|
||||
return crontabService.cleanLogs(days);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 删除日志
|
||||
* @param log 日志对象
|
||||
* @return ResultDomain<TbCrontabLog>
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@DeleteMapping("/log")
|
||||
public ResultDomain<TbCrontabLog> deleteLog(@RequestBody TbCrontabLog log) {
|
||||
return crontabService.deleteLog(log.getID());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
package org.xyzh.crontab.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabLog;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 定时任务日志数据访问层
|
||||
* @filename CrontabLogMapper.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Mapper
|
||||
public interface CrontabLogMapper extends BaseMapper<TbCrontabLog> {
|
||||
|
||||
/**
|
||||
* @description 插入日志
|
||||
* @param log 日志信息
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int insertLog(@Param("log") TbCrontabLog log);
|
||||
|
||||
/**
|
||||
* @description 根据ID查询日志
|
||||
* @param logId 日志ID
|
||||
* @return TbCrontabLog 日志信息
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
TbCrontabLog selectLogById(@Param("logId") String logId);
|
||||
|
||||
/**
|
||||
* @description 根据任务ID查询日志列表
|
||||
* @param taskId 任务ID
|
||||
* @return List<TbCrontabLog> 日志列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabLog> selectLogsByTaskId(@Param("taskId") String taskId);
|
||||
|
||||
/**
|
||||
* @description 根据过滤条件查询日志列表
|
||||
* @param filter 过滤条件
|
||||
* @return List<TbCrontabLog> 日志列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabLog> selectLogList(@Param("filter") TbCrontabLog filter);
|
||||
|
||||
/**
|
||||
* @description 分页查询日志列表
|
||||
* @param filter 过滤条件
|
||||
* @param pageParam 分页参数
|
||||
* @return List<TbCrontabLog> 日志列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabLog> selectLogPage(@Param("filter") TbCrontabLog filter, @Param("pageParam") PageParam pageParam);
|
||||
|
||||
/**
|
||||
* @description 统计日志总数
|
||||
* @param filter 过滤条件
|
||||
* @return long 总数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
long countLogs(@Param("filter") TbCrontabLog filter);
|
||||
|
||||
/**
|
||||
* @description 删除日志(逻辑删除)
|
||||
* @param logId 日志ID
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int deleteLog(@Param("logId") String logId);
|
||||
|
||||
/**
|
||||
* @description 批量删除日志
|
||||
* @param ids 日志ID列表
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int batchDeleteLogs(@Param("ids") List<String> ids);
|
||||
|
||||
/**
|
||||
* @description 清理指定时间之前的日志
|
||||
* @param beforeDate 指定时间
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int cleanLogsByDate(@Param("beforeDate") Date beforeDate);
|
||||
|
||||
/**
|
||||
* @description 根据任务ID和执行状态查询日志
|
||||
* @param taskId 任务ID
|
||||
* @param executeStatus 执行状态
|
||||
* @return List<TbCrontabLog> 日志列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabLog> selectLogsByTaskIdAndStatus(@Param("taskId") String taskId, @Param("executeStatus") Integer executeStatus);
|
||||
|
||||
/**
|
||||
* @description 查询最近的执行日志
|
||||
* @param taskId 任务ID
|
||||
* @param limit 限制数量
|
||||
* @return List<TbCrontabLog> 日志列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabLog> selectRecentLogs(@Param("taskId") String taskId, @Param("limit") Integer limit);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package org.xyzh.crontab.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabTask;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 定时任务数据访问层
|
||||
* @filename CrontabTaskMapper.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Mapper
|
||||
public interface CrontabTaskMapper extends BaseMapper<TbCrontabTask> {
|
||||
|
||||
/**
|
||||
* @description 插入任务
|
||||
* @param task 任务信息
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int insertTask(@Param("task") TbCrontabTask task);
|
||||
|
||||
/**
|
||||
* @description 更新任务
|
||||
* @param task 任务信息
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int updateTask(@Param("task") TbCrontabTask task);
|
||||
|
||||
/**
|
||||
* @description 删除任务(逻辑删除)
|
||||
* @param taskId 任务ID
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int deleteTask(@Param("taskId") String taskId);
|
||||
|
||||
/**
|
||||
* @description 根据ID查询任务
|
||||
* @param taskId 任务ID
|
||||
* @return TbCrontabTask 任务信息
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
TbCrontabTask selectTaskById(@Param("taskId") String taskId);
|
||||
|
||||
/**
|
||||
* @description 根据过滤条件查询任务列表
|
||||
* @param filter 过滤条件
|
||||
* @return List<TbCrontabTask> 任务列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabTask> selectTaskList(@Param("filter") TbCrontabTask filter);
|
||||
|
||||
/**
|
||||
* @description 分页查询任务列表
|
||||
* @param filter 过滤条件
|
||||
* @param pageParam 分页参数
|
||||
* @return List<TbCrontabTask> 任务列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabTask> selectTaskPage(@Param("filter") TbCrontabTask filter, @Param("pageParam") PageParam pageParam);
|
||||
|
||||
/**
|
||||
* @description 查询所有运行中的任务
|
||||
* @return List<TbCrontabTask> 任务列表
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
List<TbCrontabTask> selectRunningTasks();
|
||||
|
||||
/**
|
||||
* @description 更新任务状态
|
||||
* @param taskId 任务ID
|
||||
* @param status 状态
|
||||
* @return int 影响行数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
int updateTaskStatus(@Param("taskId") String taskId, @Param("status") Integer status);
|
||||
|
||||
/**
|
||||
* @description 根据Bean名称和方法名称查询任务
|
||||
* @param beanName Bean名称
|
||||
* @param methodName 方法名称
|
||||
* @return TbCrontabTask 任务信息
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
TbCrontabTask selectTaskByBeanAndMethod(@Param("beanName") String beanName, @Param("methodName") String methodName);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.xyzh.crontab.scheduler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabTask;
|
||||
import org.xyzh.crontab.mapper.CrontabTaskMapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 定时任务初始化器,启动时加载所有运行中的任务
|
||||
* @filename SchedulerInitializer.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Component
|
||||
public class SchedulerInitializer implements CommandLineRunner {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SchedulerInitializer.class);
|
||||
|
||||
@Autowired
|
||||
private CrontabTaskMapper taskMapper;
|
||||
|
||||
@Autowired
|
||||
private SchedulerManager schedulerManager;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
try {
|
||||
logger.info("开始初始化定时任务...");
|
||||
|
||||
// 查询所有运行中的任务
|
||||
List<TbCrontabTask> runningTasks = taskMapper.selectRunningTasks();
|
||||
|
||||
if (runningTasks != null && !runningTasks.isEmpty()) {
|
||||
for (TbCrontabTask task : runningTasks) {
|
||||
try {
|
||||
schedulerManager.scheduleTask(task);
|
||||
logger.info("加载定时任务: {} [{}]", task.getTaskName(), task.getCronExpression());
|
||||
} catch (Exception e) {
|
||||
logger.error("加载定时任务失败: {}", task.getTaskName(), e);
|
||||
}
|
||||
}
|
||||
logger.info("定时任务初始化完成,共加载 {} 个任务", runningTasks.size());
|
||||
} else {
|
||||
logger.info("没有需要加载的定时任务");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("定时任务初始化异常: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
package org.xyzh.crontab.scheduler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.support.CronTrigger;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabTask;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
|
||||
/**
|
||||
* @description 定时任务调度管理器
|
||||
* @filename SchedulerManager.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Component
|
||||
public class SchedulerManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SchedulerManager.class);
|
||||
|
||||
@Autowired
|
||||
private TaskScheduler taskScheduler;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
/**
|
||||
* 存储已调度的任务
|
||||
* Key: 任务ID, Value: ScheduledFuture
|
||||
*/
|
||||
private final Map<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* @description 调度任务
|
||||
* @param task 任务对象
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void scheduleTask(TbCrontabTask task) {
|
||||
try {
|
||||
String taskId = task.getID();
|
||||
|
||||
// 如果任务已经在调度中,先取消
|
||||
if (scheduledTasks.containsKey(taskId)) {
|
||||
unscheduleTask(task);
|
||||
}
|
||||
|
||||
// 创建Cron触发器
|
||||
CronTrigger cronTrigger = new CronTrigger(task.getCronExpression());
|
||||
|
||||
// 调度任务
|
||||
ScheduledFuture<?> future = taskScheduler.schedule(
|
||||
() -> taskExecutor.executeTask(task),
|
||||
cronTrigger
|
||||
);
|
||||
|
||||
// 保存调度信息
|
||||
scheduledTasks.put(taskId, future);
|
||||
|
||||
logger.info("任务调度成功: {} [{}]", task.getTaskName(), task.getCronExpression());
|
||||
} catch (Exception e) {
|
||||
logger.error("任务调度失败: {}", task.getTaskName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 取消任务调度
|
||||
* @param task 任务对象
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void unscheduleTask(TbCrontabTask task) {
|
||||
try {
|
||||
String taskId = task.getID();
|
||||
ScheduledFuture<?> future = scheduledTasks.get(taskId);
|
||||
|
||||
if (future != null) {
|
||||
future.cancel(false);
|
||||
scheduledTasks.remove(taskId);
|
||||
logger.info("任务取消调度成功: {}", task.getTaskName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("任务取消调度失败: {}", task.getTaskName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 重新调度任务
|
||||
* @param task 任务对象
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void rescheduleTask(TbCrontabTask task) {
|
||||
unscheduleTask(task);
|
||||
scheduleTask(task);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 立即执行一次任务
|
||||
* @param task 任务对象
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void executeTaskOnce(TbCrontabTask task) {
|
||||
try {
|
||||
taskExecutor.executeTask(task);
|
||||
logger.info("立即执行任务: {}", task.getTaskName());
|
||||
} catch (Exception e) {
|
||||
logger.error("立即执行任务失败: {}", task.getTaskName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 检查任务是否在调度中
|
||||
* @param taskId 任务ID
|
||||
* @return boolean
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public boolean isTaskScheduled(String taskId) {
|
||||
return scheduledTasks.containsKey(taskId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取所有调度中的任务数量
|
||||
* @return int
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public int getScheduledTaskCount() {
|
||||
return scheduledTasks.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 清除所有任务调度
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void clearAllSchedules() {
|
||||
scheduledTasks.forEach((taskId, future) -> {
|
||||
future.cancel(false);
|
||||
});
|
||||
scheduledTasks.clear();
|
||||
logger.info("已清除所有任务调度");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
package org.xyzh.crontab.scheduler;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabLog;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabTask;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.crontab.mapper.CrontabLogMapper;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description 任务执行器
|
||||
* @filename TaskExecutor.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Component
|
||||
public class TaskExecutor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TaskExecutor.class);
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private CrontabLogMapper logMapper;
|
||||
|
||||
/**
|
||||
* @description 执行任务
|
||||
* @param task 任务对象
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void executeTask(TbCrontabTask task) {
|
||||
Date startTime = new Date();
|
||||
TbCrontabLog log = new TbCrontabLog();
|
||||
log.setID(IDUtils.generateID());
|
||||
log.setTaskId(task.getTaskId());
|
||||
log.setTaskName(task.getTaskName());
|
||||
log.setTaskGroup(task.getTaskGroup());
|
||||
log.setBeanName(task.getBeanName());
|
||||
log.setMethodName(task.getMethodName());
|
||||
log.setMethodParams(task.getMethodParams());
|
||||
log.setStartTime(startTime);
|
||||
log.setCreateTime(new Date());
|
||||
log.setDeleted(false);
|
||||
|
||||
try {
|
||||
// 检查是否允许并发执行
|
||||
if (task.getConcurrent() == 0) {
|
||||
// TODO: 可以添加分布式锁来防止并发执行
|
||||
}
|
||||
|
||||
// 获取Bean实例
|
||||
Object bean = applicationContext.getBean(task.getBeanName());
|
||||
|
||||
// 获取方法
|
||||
Method method;
|
||||
if (task.getMethodParams() != null && !task.getMethodParams().isEmpty()) {
|
||||
// 如果有参数,需要解析参数类型
|
||||
method = bean.getClass().getMethod(task.getMethodName(), String.class);
|
||||
method.invoke(bean, task.getMethodParams());
|
||||
} else {
|
||||
// 无参方法
|
||||
method = bean.getClass().getMethod(task.getMethodName());
|
||||
method.invoke(bean);
|
||||
}
|
||||
|
||||
// 执行成功
|
||||
Date endTime = new Date();
|
||||
log.setEndTime(endTime);
|
||||
log.setExecuteDuration((int) (endTime.getTime() - startTime.getTime()));
|
||||
log.setExecuteStatus(1);
|
||||
log.setExecuteMessage("执行成功");
|
||||
|
||||
logger.info("任务执行成功: {} [{}ms]", task.getTaskName(), log.getExecuteDuration());
|
||||
} catch (Exception e) {
|
||||
// 执行失败
|
||||
Date endTime = new Date();
|
||||
log.setEndTime(endTime);
|
||||
log.setExecuteDuration((int) (endTime.getTime() - startTime.getTime()));
|
||||
log.setExecuteStatus(0);
|
||||
log.setExecuteMessage("执行失败");
|
||||
log.setExceptionInfo(getExceptionStackTrace(e));
|
||||
|
||||
logger.error("任务执行失败: {}", task.getTaskName(), e);
|
||||
} finally {
|
||||
// 保存执行日志
|
||||
try {
|
||||
logMapper.insertLog(log);
|
||||
} catch (Exception e) {
|
||||
logger.error("保存任务执行日志失败: {}", task.getTaskName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取异常堆栈信息
|
||||
* @param e 异常
|
||||
* @return String
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
private String getExceptionStackTrace(Exception e) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(e.getClass().getName()).append(": ").append(e.getMessage()).append("\n");
|
||||
|
||||
StackTraceElement[] stackTrace = e.getStackTrace();
|
||||
int limit = Math.min(stackTrace.length, 10); // 只保留前10行
|
||||
|
||||
for (int i = 0; i < limit; i++) {
|
||||
sb.append("\tat ").append(stackTrace[i].toString()).append("\n");
|
||||
}
|
||||
|
||||
if (stackTrace.length > limit) {
|
||||
sb.append("\t... ").append(stackTrace.length - limit).append(" more\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,494 @@
|
||||
package org.xyzh.crontab.service.impl;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.support.CronExpression;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.xyzh.api.crontab.CrontabService;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.common.core.page.PageParam;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabTask;
|
||||
import org.xyzh.common.dto.crontab.TbCrontabLog;
|
||||
import org.xyzh.common.utils.IDUtils;
|
||||
import org.xyzh.crontab.mapper.CrontabTaskMapper;
|
||||
import org.xyzh.crontab.mapper.CrontabLogMapper;
|
||||
import org.xyzh.crontab.scheduler.SchedulerManager;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @description 定时任务服务实现类
|
||||
* @filename CrontabServiceImpl.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Service
|
||||
public class CrontabServiceImpl implements CrontabService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CrontabServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private CrontabTaskMapper taskMapper;
|
||||
|
||||
@Autowired
|
||||
private CrontabLogMapper logMapper;
|
||||
|
||||
@Autowired
|
||||
private SchedulerManager schedulerManager;
|
||||
|
||||
// ----------------定时任务管理--------------------------------
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultDomain<TbCrontabTask> createTask(TbCrontabTask task) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
// 验证Cron表达式
|
||||
if (!CronExpression.isValidExpression(task.getCronExpression())) {
|
||||
resultDomain.fail("Cron表达式格式不正确");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 生成ID
|
||||
task.setID(IDUtils.generateID());
|
||||
task.setTaskId(IDUtils.generateID());
|
||||
task.setCreateTime(new Date());
|
||||
task.setDeleted(false);
|
||||
|
||||
// 默认值
|
||||
if (task.getStatus() == null) {
|
||||
task.setStatus(0); // 默认暂停
|
||||
}
|
||||
if (task.getConcurrent() == null) {
|
||||
task.setConcurrent(0); // 默认不允许并发
|
||||
}
|
||||
if (task.getMisfirePolicy() == null) {
|
||||
task.setMisfirePolicy(1); // 默认立即执行
|
||||
}
|
||||
|
||||
int result = taskMapper.insertTask(task);
|
||||
if (result > 0) {
|
||||
logger.info("创建定时任务成功: {}", task.getTaskName());
|
||||
|
||||
// 如果任务状态为启动,则立即调度
|
||||
if (task.getStatus() == 1) {
|
||||
schedulerManager.scheduleTask(task);
|
||||
}
|
||||
|
||||
resultDomain.success("创建定时任务成功", task);
|
||||
} else {
|
||||
resultDomain.fail("创建定时任务失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("创建定时任务异常: ", e);
|
||||
resultDomain.fail("创建定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultDomain<TbCrontabTask> updateTask(TbCrontabTask task) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (task.getID() == null) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 验证Cron表达式
|
||||
if (task.getCronExpression() != null && !CronExpression.isValidExpression(task.getCronExpression())) {
|
||||
resultDomain.fail("Cron表达式格式不正确");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
task.setUpdateTime(new Date());
|
||||
int result = taskMapper.updateTask(task);
|
||||
|
||||
if (result > 0) {
|
||||
logger.info("更新定时任务成功: {}", task.getTaskName());
|
||||
|
||||
// 重新调度任务
|
||||
TbCrontabTask dbTask = taskMapper.selectTaskById(task.getID());
|
||||
if (dbTask != null && dbTask.getStatus() == 1) {
|
||||
schedulerManager.rescheduleTask(dbTask);
|
||||
}
|
||||
|
||||
resultDomain.success("更新定时任务成功", task);
|
||||
} else {
|
||||
resultDomain.fail("更新定时任务失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("更新定时任务异常: ", e);
|
||||
resultDomain.fail("更新定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultDomain<TbCrontabTask> deleteTask(String taskId) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (taskId == null || taskId.isEmpty()) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 先停止任务调度
|
||||
TbCrontabTask task = taskMapper.selectTaskById(taskId);
|
||||
if (task != null && task.getStatus() == 1) {
|
||||
schedulerManager.unscheduleTask(task);
|
||||
}
|
||||
|
||||
int result = taskMapper.deleteTask(taskId);
|
||||
if (result > 0) {
|
||||
logger.info("删除定时任务成功,任务ID: {}", taskId);
|
||||
resultDomain.success("删除定时任务成功", (TbCrontabTask) null);
|
||||
} else {
|
||||
resultDomain.fail("删除定时任务失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("删除定时任务异常: ", e);
|
||||
resultDomain.fail("删除定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabTask> getTaskById(String taskId) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (taskId == null || taskId.isEmpty()) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
TbCrontabTask task = taskMapper.selectTaskById(taskId);
|
||||
if (task != null) {
|
||||
resultDomain.success("查询成功", task);
|
||||
} else {
|
||||
resultDomain.fail("任务不存在");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("查询定时任务异常: ", e);
|
||||
resultDomain.fail("查询定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabTask> getTaskList(TbCrontabTask filter) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (filter == null) {
|
||||
filter = new TbCrontabTask();
|
||||
}
|
||||
filter.setDeleted(false);
|
||||
|
||||
List<TbCrontabTask> list = taskMapper.selectTaskList(filter);
|
||||
resultDomain.success("查询成功", list);
|
||||
} catch (Exception e) {
|
||||
logger.error("查询定时任务列表异常: ", e);
|
||||
resultDomain.fail("查询定时任务列表异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabTask> getTaskPage(TbCrontabTask filter, PageParam pageParam) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (filter == null) {
|
||||
filter = new TbCrontabTask();
|
||||
}
|
||||
filter.setDeleted(false);
|
||||
|
||||
if (pageParam == null) {
|
||||
pageParam = new PageParam();
|
||||
}
|
||||
|
||||
List<TbCrontabTask> list = taskMapper.selectTaskPage(filter, pageParam);
|
||||
resultDomain.success("查询成功", list);
|
||||
} catch (Exception e) {
|
||||
logger.error("分页查询定时任务异常: ", e);
|
||||
resultDomain.fail("分页查询定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultDomain<TbCrontabTask> startTask(String taskId) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (taskId == null || taskId.isEmpty()) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
TbCrontabTask task = taskMapper.selectTaskById(taskId);
|
||||
if (task == null) {
|
||||
resultDomain.fail("任务不存在");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (task.getStatus() == 1) {
|
||||
resultDomain.fail("任务已在运行中");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 更新状态为运行中
|
||||
int result = taskMapper.updateTaskStatus(taskId, 1);
|
||||
if (result > 0) {
|
||||
task.setStatus(1);
|
||||
// 调度任务
|
||||
schedulerManager.scheduleTask(task);
|
||||
|
||||
logger.info("启动定时任务成功: {}", task.getTaskName());
|
||||
resultDomain.success("启动定时任务成功", task);
|
||||
} else {
|
||||
resultDomain.fail("启动定时任务失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("启动定时任务异常: ", e);
|
||||
resultDomain.fail("启动定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultDomain<TbCrontabTask> pauseTask(String taskId) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (taskId == null || taskId.isEmpty()) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
TbCrontabTask task = taskMapper.selectTaskById(taskId);
|
||||
if (task == null) {
|
||||
resultDomain.fail("任务不存在");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (task.getStatus() == 0) {
|
||||
resultDomain.fail("任务已暂停");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 取消调度
|
||||
schedulerManager.unscheduleTask(task);
|
||||
|
||||
// 更新状态为暂停
|
||||
int result = taskMapper.updateTaskStatus(taskId, 0);
|
||||
if (result > 0) {
|
||||
task.setStatus(0);
|
||||
logger.info("暂停定时任务成功: {}", task.getTaskName());
|
||||
resultDomain.success("暂停定时任务成功", task);
|
||||
} else {
|
||||
resultDomain.fail("暂停定时任务失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("暂停定时任务异常: ", e);
|
||||
resultDomain.fail("暂停定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabTask> executeTaskOnce(String taskId) {
|
||||
ResultDomain<TbCrontabTask> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (taskId == null || taskId.isEmpty()) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
TbCrontabTask task = taskMapper.selectTaskById(taskId);
|
||||
if (task == null) {
|
||||
resultDomain.fail("任务不存在");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 立即执行一次
|
||||
schedulerManager.executeTaskOnce(task);
|
||||
|
||||
logger.info("立即执行定时任务: {}", task.getTaskName());
|
||||
resultDomain.success("立即执行定时任务成功", task);
|
||||
} catch (Exception e) {
|
||||
logger.error("立即执行定时任务异常: ", e);
|
||||
resultDomain.fail("立即执行定时任务异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<String> validateCronExpression(String cronExpression) {
|
||||
ResultDomain<String> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (cronExpression == null || cronExpression.isEmpty()) {
|
||||
resultDomain.fail("Cron表达式不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
if (!CronExpression.isValidExpression(cronExpression)) {
|
||||
resultDomain.fail("Cron表达式格式不正确");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// 计算下次执行时间
|
||||
CronExpression cron = CronExpression.parse(cronExpression);
|
||||
LocalDateTime nextExecution = cron.next(LocalDateTime.now());
|
||||
|
||||
if (nextExecution != null) {
|
||||
String message = "Cron表达式有效,下次执行时间: " + nextExecution;
|
||||
resultDomain.success("验证成功", message);
|
||||
} else {
|
||||
resultDomain.fail("无法计算下次执行时间");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("验证Cron表达式异常: ", e);
|
||||
resultDomain.fail("验证Cron表达式异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
// ----------------定时任务日志--------------------------------
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabLog> getLogsByTaskId(String taskId) {
|
||||
ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (taskId == null || taskId.isEmpty()) {
|
||||
resultDomain.fail("任务ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
List<TbCrontabLog> list = logMapper.selectLogsByTaskId(taskId);
|
||||
resultDomain.success("查询成功", list);
|
||||
} catch (Exception e) {
|
||||
logger.error("查询任务日志异常: ", e);
|
||||
resultDomain.fail("查询任务日志异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabLog> getLogList(TbCrontabLog filter) {
|
||||
ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (filter == null) {
|
||||
filter = new TbCrontabLog();
|
||||
}
|
||||
filter.setDeleted(false);
|
||||
|
||||
List<TbCrontabLog> list = logMapper.selectLogList(filter);
|
||||
resultDomain.success("查询成功", list);
|
||||
} catch (Exception e) {
|
||||
logger.error("查询日志列表异常: ", e);
|
||||
resultDomain.fail("查询日志列表异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabLog> getLogPage(TbCrontabLog filter, PageParam pageParam) {
|
||||
ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (filter == null) {
|
||||
filter = new TbCrontabLog();
|
||||
}
|
||||
filter.setDeleted(false);
|
||||
|
||||
if (pageParam == null) {
|
||||
pageParam = new PageParam();
|
||||
}
|
||||
|
||||
List<TbCrontabLog> list = logMapper.selectLogPage(filter, pageParam);
|
||||
resultDomain.success("查询成功", list);
|
||||
} catch (Exception e) {
|
||||
logger.error("分页查询日志异常: ", e);
|
||||
resultDomain.fail("分页查询日志异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbCrontabLog> getLogById(String logId) {
|
||||
ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (logId == null || logId.isEmpty()) {
|
||||
resultDomain.fail("日志ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
TbCrontabLog log = logMapper.selectLogById(logId);
|
||||
if (log != null) {
|
||||
resultDomain.success("查询成功", log);
|
||||
} else {
|
||||
resultDomain.fail("日志不存在");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("查询日志详情异常: ", e);
|
||||
resultDomain.fail("查询日志详情异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultDomain<Integer> cleanLogs(Integer days) {
|
||||
ResultDomain<Integer> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (days == null || days <= 0) {
|
||||
resultDomain.fail("天数参数无效");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -days);
|
||||
Date beforeDate = calendar.getTime();
|
||||
|
||||
int count = logMapper.cleanLogsByDate(beforeDate);
|
||||
logger.info("清理{}天前的日志,共{}条", days, count);
|
||||
|
||||
resultDomain.success("清理成功", count);
|
||||
} catch (Exception e) {
|
||||
logger.error("清理日志异常: ", e);
|
||||
resultDomain.fail("清理日志异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ResultDomain<TbCrontabLog> deleteLog(String logId) {
|
||||
ResultDomain<TbCrontabLog> resultDomain = new ResultDomain<>();
|
||||
try {
|
||||
if (logId == null || logId.isEmpty()) {
|
||||
resultDomain.fail("日志ID不能为空");
|
||||
return resultDomain;
|
||||
}
|
||||
|
||||
int result = logMapper.deleteLog(logId);
|
||||
if (result > 0) {
|
||||
logger.info("删除日志成功,日志ID: {}", logId);
|
||||
resultDomain.success("删除日志成功", (TbCrontabLog) null);
|
||||
} else {
|
||||
resultDomain.fail("删除日志失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("删除日志异常: ", e);
|
||||
resultDomain.fail("删除日志异常: " + e.getMessage());
|
||||
}
|
||||
return resultDomain;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package org.xyzh.crontab.task;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description 数据备份任务
|
||||
* @filename DataBackupTask.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Component("dataBackupTask")
|
||||
public class DataBackupTask {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DataBackupTask.class);
|
||||
|
||||
/**
|
||||
* @description 执行数据备份
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void execute() {
|
||||
logger.info("开始执行数据备份任务...");
|
||||
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||
String backupTime = sdf.format(new Date());
|
||||
|
||||
// TODO: 实现数据备份逻辑
|
||||
// 1. 备份数据库
|
||||
// 2. 备份文件
|
||||
// 3. 压缩备份文件
|
||||
// 4. 上传到备份服务器或云存储
|
||||
|
||||
Thread.sleep(2000); // 模拟执行
|
||||
|
||||
logger.info("数据备份任务执行完成,备份标识: {}", backupTime);
|
||||
} catch (Exception e) {
|
||||
logger.error("数据备份任务执行失败: ", e);
|
||||
throw new RuntimeException("数据备份任务执行失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 执行带参数的备份任务
|
||||
* @param params 参数(备份类型:full-全量,incremental-增量)
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void execute(String params) {
|
||||
logger.info("开始执行数据备份任务,备份类型: {}", params);
|
||||
execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.xyzh.crontab.task;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.xyzh.crontab.mapper.CrontabLogMapper;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @description 清理过期日志任务
|
||||
* @filename LogCleanTask.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Component("logCleanTask")
|
||||
public class LogCleanTask {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(LogCleanTask.class);
|
||||
|
||||
@Autowired
|
||||
private CrontabLogMapper logMapper;
|
||||
|
||||
/**
|
||||
* @description 执行日志清理,默认清理30天前的日志
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void execute() {
|
||||
execute("30");
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 执行日志清理
|
||||
* @param params 天数参数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void execute(String params) {
|
||||
logger.info("开始执行日志清理任务...");
|
||||
|
||||
try {
|
||||
int days = 30; // 默认30天
|
||||
if (params != null && !params.isEmpty()) {
|
||||
try {
|
||||
days = Integer.parseInt(params);
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("参数格式错误,使用默认值30天");
|
||||
}
|
||||
}
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.add(Calendar.DAY_OF_MONTH, -days);
|
||||
Date beforeDate = calendar.getTime();
|
||||
|
||||
int count = logMapper.cleanLogsByDate(beforeDate);
|
||||
|
||||
logger.info("日志清理任务执行完成,共清理{}条日志", count);
|
||||
} catch (Exception e) {
|
||||
logger.error("日志清理任务执行失败: ", e);
|
||||
throw new RuntimeException("日志清理任务执行失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.xyzh.crontab.task;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @description 系统数据统计任务
|
||||
* @filename SystemStatisticsTask.java
|
||||
* @author yslg
|
||||
* @copyright xyzh
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
@Component("systemStatisticsTask")
|
||||
public class SystemStatisticsTask {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SystemStatisticsTask.class);
|
||||
|
||||
/**
|
||||
* @description 执行系统数据统计
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void execute() {
|
||||
logger.info("开始执行系统数据统计任务...");
|
||||
|
||||
try {
|
||||
// TODO: 实现系统数据统计逻辑
|
||||
// 1. 统计用户数据
|
||||
// 2. 统计资源数据
|
||||
// 3. 统计访问数据
|
||||
// 4. 生成统计报告
|
||||
|
||||
Thread.sleep(1000); // 模拟执行
|
||||
|
||||
logger.info("系统数据统计任务执行完成");
|
||||
} catch (Exception e) {
|
||||
logger.error("系统数据统计任务执行失败: ", e);
|
||||
throw new RuntimeException("系统数据统计任务执行失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 执行带参数的统计任务
|
||||
* @param params 参数
|
||||
* @author yslg
|
||||
* @since 2025-10-25
|
||||
*/
|
||||
public void execute(String params) {
|
||||
logger.info("开始执行系统数据统计任务,参数: {}", params);
|
||||
execute();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
<?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="org.xyzh.crontab.mapper.CrontabLogMapper">
|
||||
|
||||
<!-- 结果映射 -->
|
||||
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.crontab.TbCrontabLog">
|
||||
<id column="id" property="ID" />
|
||||
<result column="task_id" property="taskId" />
|
||||
<result column="task_name" property="taskName" />
|
||||
<result column="task_group" property="taskGroup" />
|
||||
<result column="bean_name" property="beanName" />
|
||||
<result column="method_name" property="methodName" />
|
||||
<result column="method_params" property="methodParams" />
|
||||
<result column="execute_status" property="executeStatus" />
|
||||
<result column="execute_message" property="executeMessage" />
|
||||
<result column="exception_info" property="exceptionInfo" />
|
||||
<result column="start_time" property="startTime" />
|
||||
<result column="end_time" property="endTime" />
|
||||
<result column="execute_duration" property="executeDuration" />
|
||||
<result column="create_time" property="createTime" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
<result column="delete_time" property="deleteTime" />
|
||||
<result column="deleted" property="deleted" />
|
||||
</resultMap>
|
||||
|
||||
<!-- 字段列表 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, task_id, task_name, task_group, bean_name, method_name, method_params,
|
||||
execute_status, execute_message, exception_info, start_time, end_time,
|
||||
execute_duration, create_time, update_time, delete_time, deleted
|
||||
</sql>
|
||||
|
||||
<!-- 查询条件 -->
|
||||
<sql id="Base_Where_Clause">
|
||||
<where>
|
||||
<if test="filter != null">
|
||||
<if test="filter.ID != null and filter.ID != ''">
|
||||
AND id = #{filter.ID}
|
||||
</if>
|
||||
<if test="filter.taskId != null and filter.taskId != ''">
|
||||
AND task_id = #{filter.taskId}
|
||||
</if>
|
||||
<if test="filter.taskName != null and filter.taskName != ''">
|
||||
AND task_name LIKE CONCAT('%', #{filter.taskName}, '%')
|
||||
</if>
|
||||
<if test="filter.taskGroup != null and filter.taskGroup != ''">
|
||||
AND task_group = #{filter.taskGroup}
|
||||
</if>
|
||||
<if test="filter.beanName != null and filter.beanName != ''">
|
||||
AND bean_name = #{filter.beanName}
|
||||
</if>
|
||||
<if test="filter.executeStatus != null">
|
||||
AND execute_status = #{filter.executeStatus}
|
||||
</if>
|
||||
<if test="filter.deleted != null">
|
||||
AND deleted = #{filter.deleted}
|
||||
</if>
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 插入日志 -->
|
||||
<insert id="insertLog">
|
||||
INSERT INTO tb_crontab_log
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="log.ID != null">id,</if>
|
||||
<if test="log.taskId != null">task_id,</if>
|
||||
<if test="log.taskName != null">task_name,</if>
|
||||
<if test="log.taskGroup != null">task_group,</if>
|
||||
<if test="log.beanName != null">bean_name,</if>
|
||||
<if test="log.methodName != null">method_name,</if>
|
||||
<if test="log.methodParams != null">method_params,</if>
|
||||
<if test="log.executeStatus != null">execute_status,</if>
|
||||
<if test="log.executeMessage != null">execute_message,</if>
|
||||
<if test="log.exceptionInfo != null">exception_info,</if>
|
||||
<if test="log.startTime != null">start_time,</if>
|
||||
<if test="log.endTime != null">end_time,</if>
|
||||
<if test="log.executeDuration != null">execute_duration,</if>
|
||||
<if test="log.createTime != null">create_time,</if>
|
||||
deleted
|
||||
</trim>
|
||||
VALUES
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="log.ID != null">#{log.ID},</if>
|
||||
<if test="log.taskId != null">#{log.taskId},</if>
|
||||
<if test="log.taskName != null">#{log.taskName},</if>
|
||||
<if test="log.taskGroup != null">#{log.taskGroup},</if>
|
||||
<if test="log.beanName != null">#{log.beanName},</if>
|
||||
<if test="log.methodName != null">#{log.methodName},</if>
|
||||
<if test="log.methodParams != null">#{log.methodParams},</if>
|
||||
<if test="log.executeStatus != null">#{log.executeStatus},</if>
|
||||
<if test="log.executeMessage != null">#{log.executeMessage},</if>
|
||||
<if test="log.exceptionInfo != null">#{log.exceptionInfo},</if>
|
||||
<if test="log.startTime != null">#{log.startTime},</if>
|
||||
<if test="log.endTime != null">#{log.endTime},</if>
|
||||
<if test="log.executeDuration != null">#{log.executeDuration},</if>
|
||||
<if test="log.createTime != null">#{log.createTime},</if>
|
||||
0
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<!-- 根据ID查询日志 -->
|
||||
<select id="selectLogById" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_log
|
||||
WHERE id = #{logId} AND deleted = 0
|
||||
</select>
|
||||
|
||||
<!-- 根据任务ID查询日志列表 -->
|
||||
<select id="selectLogsByTaskId" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_log
|
||||
WHERE task_id = #{taskId} AND deleted = 0
|
||||
ORDER BY start_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据过滤条件查询日志列表 -->
|
||||
<select id="selectLogList" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_log
|
||||
<include refid="Base_Where_Clause" />
|
||||
ORDER BY start_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 分页查询日志列表 -->
|
||||
<select id="selectLogPage" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_log
|
||||
<include refid="Base_Where_Clause" />
|
||||
ORDER BY start_time DESC
|
||||
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
|
||||
</select>
|
||||
|
||||
<!-- 统计日志总数 -->
|
||||
<select id="countLogs" resultType="long">
|
||||
SELECT COUNT(*)
|
||||
FROM tb_crontab_log
|
||||
<include refid="Base_Where_Clause" />
|
||||
</select>
|
||||
|
||||
<!-- 删除日志(逻辑删除) -->
|
||||
<update id="deleteLog">
|
||||
UPDATE tb_crontab_log
|
||||
SET deleted = 1,
|
||||
delete_time = NOW()
|
||||
WHERE id = #{logId} AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 批量删除日志 -->
|
||||
<update id="batchDeleteLogs">
|
||||
UPDATE tb_crontab_log
|
||||
SET deleted = 1,
|
||||
delete_time = NOW()
|
||||
WHERE deleted = 0
|
||||
AND id IN
|
||||
<foreach collection="ids" item="id" open="(" separator="," close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<!-- 清理指定时间之前的日志 -->
|
||||
<update id="cleanLogsByDate">
|
||||
UPDATE tb_crontab_log
|
||||
SET deleted = 1,
|
||||
delete_time = NOW()
|
||||
WHERE deleted = 0
|
||||
AND create_time < #{beforeDate}
|
||||
</update>
|
||||
|
||||
<!-- 根据任务ID和执行状态查询日志 -->
|
||||
<select id="selectLogsByTaskIdAndStatus" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_log
|
||||
WHERE task_id = #{taskId}
|
||||
AND execute_status = #{executeStatus}
|
||||
AND deleted = 0
|
||||
ORDER BY start_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 查询最近的执行日志 -->
|
||||
<select id="selectRecentLogs" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_log
|
||||
WHERE task_id = #{taskId} AND deleted = 0
|
||||
ORDER BY start_time DESC
|
||||
LIMIT #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,188 @@
|
||||
<?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="org.xyzh.crontab.mapper.CrontabTaskMapper">
|
||||
|
||||
<!-- 结果映射 -->
|
||||
<resultMap id="BaseResultMap" type="org.xyzh.common.dto.crontab.TbCrontabTask">
|
||||
<id column="id" property="ID" />
|
||||
<result column="task_id" property="taskId" />
|
||||
<result column="task_name" property="taskName" />
|
||||
<result column="task_group" property="taskGroup" />
|
||||
<result column="bean_name" property="beanName" />
|
||||
<result column="method_name" property="methodName" />
|
||||
<result column="method_params" property="methodParams" />
|
||||
<result column="cron_expression" property="cronExpression" />
|
||||
<result column="status" property="status" />
|
||||
<result column="description" property="description" />
|
||||
<result column="concurrent" property="concurrent" />
|
||||
<result column="misfire_policy" property="misfirePolicy" />
|
||||
<result column="creator" property="creator" />
|
||||
<result column="updater" property="updater" />
|
||||
<result column="create_time" property="createTime" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
<result column="delete_time" property="deleteTime" />
|
||||
<result column="deleted" property="deleted" />
|
||||
</resultMap>
|
||||
|
||||
<!-- 字段列表 -->
|
||||
<sql id="Base_Column_List">
|
||||
id, task_id, task_name, task_group, bean_name, method_name, method_params,
|
||||
cron_expression, status, description, concurrent, misfire_policy,
|
||||
creator, updater, create_time, update_time, delete_time, deleted
|
||||
</sql>
|
||||
|
||||
<!-- 查询条件 -->
|
||||
<sql id="Base_Where_Clause">
|
||||
<where>
|
||||
<if test="filter != null">
|
||||
<if test="filter.ID != null and filter.ID != ''">
|
||||
AND id = #{filter.ID}
|
||||
</if>
|
||||
<if test="filter.taskId != null and filter.taskId != ''">
|
||||
AND task_id = #{filter.taskId}
|
||||
</if>
|
||||
<if test="filter.taskName != null and filter.taskName != ''">
|
||||
AND task_name LIKE CONCAT('%', #{filter.taskName}, '%')
|
||||
</if>
|
||||
<if test="filter.taskGroup != null and filter.taskGroup != ''">
|
||||
AND task_group = #{filter.taskGroup}
|
||||
</if>
|
||||
<if test="filter.beanName != null and filter.beanName != ''">
|
||||
AND bean_name = #{filter.beanName}
|
||||
</if>
|
||||
<if test="filter.methodName != null and filter.methodName != ''">
|
||||
AND method_name = #{filter.methodName}
|
||||
</if>
|
||||
<if test="filter.status != null">
|
||||
AND status = #{filter.status}
|
||||
</if>
|
||||
<if test="filter.deleted != null">
|
||||
AND deleted = #{filter.deleted}
|
||||
</if>
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 插入任务 -->
|
||||
<insert id="insertTask">
|
||||
INSERT INTO tb_crontab_task
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="task.ID != null">id,</if>
|
||||
<if test="task.taskId != null">task_id,</if>
|
||||
<if test="task.taskName != null">task_name,</if>
|
||||
<if test="task.taskGroup != null">task_group,</if>
|
||||
<if test="task.beanName != null">bean_name,</if>
|
||||
<if test="task.methodName != null">method_name,</if>
|
||||
<if test="task.methodParams != null">method_params,</if>
|
||||
<if test="task.cronExpression != null">cron_expression,</if>
|
||||
<if test="task.status != null">status,</if>
|
||||
<if test="task.description != null">description,</if>
|
||||
<if test="task.concurrent != null">concurrent,</if>
|
||||
<if test="task.misfirePolicy != null">misfire_policy,</if>
|
||||
<if test="task.creator != null">creator,</if>
|
||||
<if test="task.createTime != null">create_time,</if>
|
||||
deleted
|
||||
</trim>
|
||||
VALUES
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
<if test="task.ID != null">#{task.ID},</if>
|
||||
<if test="task.taskId != null">#{task.taskId},</if>
|
||||
<if test="task.taskName != null">#{task.taskName},</if>
|
||||
<if test="task.taskGroup != null">#{task.taskGroup},</if>
|
||||
<if test="task.beanName != null">#{task.beanName},</if>
|
||||
<if test="task.methodName != null">#{task.methodName},</if>
|
||||
<if test="task.methodParams != null">#{task.methodParams},</if>
|
||||
<if test="task.cronExpression != null">#{task.cronExpression},</if>
|
||||
<if test="task.status != null">#{task.status},</if>
|
||||
<if test="task.description != null">#{task.description},</if>
|
||||
<if test="task.concurrent != null">#{task.concurrent},</if>
|
||||
<if test="task.misfirePolicy != null">#{task.misfirePolicy},</if>
|
||||
<if test="task.creator != null">#{task.creator},</if>
|
||||
<if test="task.createTime != null">#{task.createTime},</if>
|
||||
0
|
||||
</trim>
|
||||
</insert>
|
||||
|
||||
<!-- 更新任务 -->
|
||||
<update id="updateTask">
|
||||
UPDATE tb_crontab_task
|
||||
<set>
|
||||
<if test="task.taskName != null">task_name = #{task.taskName},</if>
|
||||
<if test="task.taskGroup != null">task_group = #{task.taskGroup},</if>
|
||||
<if test="task.beanName != null">bean_name = #{task.beanName},</if>
|
||||
<if test="task.methodName != null">method_name = #{task.methodName},</if>
|
||||
<if test="task.methodParams != null">method_params = #{task.methodParams},</if>
|
||||
<if test="task.cronExpression != null">cron_expression = #{task.cronExpression},</if>
|
||||
<if test="task.status != null">status = #{task.status},</if>
|
||||
<if test="task.description != null">description = #{task.description},</if>
|
||||
<if test="task.concurrent != null">concurrent = #{task.concurrent},</if>
|
||||
<if test="task.misfirePolicy != null">misfire_policy = #{task.misfirePolicy},</if>
|
||||
<if test="task.updater != null">updater = #{task.updater},</if>
|
||||
update_time = NOW()
|
||||
</set>
|
||||
WHERE id = #{task.ID} AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 删除任务(逻辑删除) -->
|
||||
<update id="deleteTask">
|
||||
UPDATE tb_crontab_task
|
||||
SET deleted = 1,
|
||||
delete_time = NOW()
|
||||
WHERE id = #{taskId} AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 根据ID查询任务 -->
|
||||
<select id="selectTaskById" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_task
|
||||
WHERE id = #{taskId} AND deleted = 0
|
||||
</select>
|
||||
|
||||
<!-- 根据过滤条件查询任务列表 -->
|
||||
<select id="selectTaskList" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_task
|
||||
<include refid="Base_Where_Clause" />
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 分页查询任务列表 -->
|
||||
<select id="selectTaskPage" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_task
|
||||
<include refid="Base_Where_Clause" />
|
||||
ORDER BY create_time DESC
|
||||
LIMIT #{pageParam.pageSize} OFFSET #{pageParam.offset}
|
||||
</select>
|
||||
|
||||
<!-- 查询所有运行中的任务 -->
|
||||
<select id="selectRunningTasks" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_task
|
||||
WHERE status = 1 AND deleted = 0
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
|
||||
<!-- 更新任务状态 -->
|
||||
<update id="updateTaskStatus">
|
||||
UPDATE tb_crontab_task
|
||||
SET status = #{status},
|
||||
update_time = NOW()
|
||||
WHERE id = #{taskId} AND deleted = 0
|
||||
</update>
|
||||
|
||||
<!-- 根据Bean名称和方法名称查询任务 -->
|
||||
<select id="selectTaskByBeanAndMethod" resultMap="BaseResultMap">
|
||||
SELECT
|
||||
<include refid="Base_Column_List" />
|
||||
FROM tb_crontab_task
|
||||
WHERE bean_name = #{beanName}
|
||||
AND method_name = #{methodName}
|
||||
AND deleted = 0
|
||||
LIMIT 1
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user