serv-定时任务

This commit is contained in:
2025-10-25 18:46:54 +08:00
parent 5d211faee1
commit 485e1b8be4
29 changed files with 3391 additions and 6 deletions

View File

@@ -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;
}
}

View File

@@ -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());
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}
}

View File

@@ -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("已清除所有任务调度");
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}
}
}

View File

@@ -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();
}
}

View File

@@ -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 &lt; #{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>

View File

@@ -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>