表结构
CREATE TABLE `scheduled_task` (
`id` varchar(20) NOT NULL COMMENT 'id',
`name` varchar(255) DEFAULT NULL COMMENT '定时任务名称',
`task_type` varchar(100) DEFAULT NULL COMMENT '定时任务分类',
`task_describe` varchar(255) DEFAULT NULL COMMENT '定时任务描述',
`cron` varchar(50) NOT NULL COMMENT 'cron策略',
`method` varchar(10) NOT NULL COMMENT '请求方法',
`url` varchar(500) NOT NULL COMMENT '请求路径',
`enable` varchar(2) NOT NULL DEFAULT '0' COMMENT '是否启用定时任务',
`open_log` varchar(2) DEFAULT '0' COMMENT '是否开启日志',
`create_user` varchar(40) DEFAULT NULL COMMENT '创建人',
`create_time` varchar(40) DEFAULT NULL COMMENT '创建时间',
`update_user` varchar(40) DEFAULT NULL COMMENT '更新人',
`update_time` varchar(40) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_url` (`url`) BLOCK_SIZE 16384 LOCAL
) COMMENT = '定时任务调度表';
CREATE TABLE `scheduled_log` (
`id` varchar(20) NOT NULL COMMENT 'id',
`task_id` varchar(20) DEFAULT NULL COMMENT '定时任务ID',
`task_name` varchar(255) DEFAULT NULL COMMENT '定时任务名称',
`execute_status` varchar(40) DEFAULT NULL COMMENT '执行状态',
`content` longtext DEFAULT NULL COMMENT '内容',
`execute_time` varchar(40) DEFAULT NULL COMMENT '执行时间',
PRIMARY KEY (`id`)
) COMMENT = '定时任务调度日志表';
com.studioustiger.job.constant
public class JobConstant {
public static final String OPEN_SCHEDULE = "openSchedule";
public static final String CLOSE_SCHEDULE = "closeSchedule";
public static final String DELETE_SCHEDULE = "deleteSchedule";
}
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "task.log", ignoreUnknownFields = false)
public class LogProperties {
private boolean successOpen = true;
private boolean failOpen = true;
private int saveDays = 2;
}
com.studioustiger.job.entity
import lombok.Data;
import java.io.Serializable;
@Data
public class BaseDto implements Serializable {
private static final long serialVersionUID = -153746138274322843L;
private String createUser;
private String createTime;
private String updateUser;
private String updateTime;
}
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("scheduled_log")
public class ScheduleLogDto implements Serializable {
private static final long serialVersionUID = -153746138274322843L;
private String id;
private String taskId;
private String taskName;
private String executeStatus;
private String content;
private String executeTime;
}
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.springframework.scheduling.support.CronTrigger;
@Data
@TableName("scheduled_task")
public class ScheduleTaskDto extends BaseDto {
private String id;
private String name;
private String taskType;
private String taskDescribe;
private String cron;
private String method;
private String url;
private String enable;
private String openLog;
public CronTrigger toCronTrigger() {
return new CronTrigger(this.cron);
}
}
import lombok.Data;
@Data
public class ScheduleTaskPo extends BaseDto {
private String id;
private String name;
private String taskType;
private String taskDescribe;
private String cron;
private String method;
private String url;
private String enable;
private String openLog;
private String total;
}
com.studioustiger.job.mapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.studioustiger.job.entity.ScheduleLogDto;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ScheduleLogMapper extends BaseMapper<ScheduleLogDto> {
List<ScheduleLogDto> getPage();
int add(@Param("log") ScheduleLogDto log);
int clearLog(@Param("endTime") String endTime);
ScheduleLogDto latestLogByTask(@Param("taskId") String taskId);
ScheduleLogDto lastLog(String taskId, String executeTime);
ScheduleLogDto nextLog(String taskId, String executeTime);
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.studioustiger.job.mapper.ScheduleLogMapper">
<resultMap id="scheduleLogMap" type="com.studioustiger.job.entity.ScheduleLogDto">
<result column="id" property="id"/>
<result column="task_id" property="taskId"/>
<result column="task_name" property="taskName"/>
<result column="execute_status" property="executeStatus"/>
<result column="content" property="content"/>
<result column="execute_time" property="executeTime"/>
resultMap>
<select id="getPage" parameterType="string" resultMap="scheduleLogMap">
select
`id`,
`task_id`,
`task_name`,
`execute_status`,
`content`,
`execute_time`
from
`scheduled_log`
order by `name` desc, `execute_time` desc, id
select>
<insert id="add">
insert into `scheduled_log`(`id`,`task_id`,`task_name`,`execute_status`,`content`,`execute_time`)
values (
#{log.id},
#{log.taskId},
#{log.taskName},
#{log.executeStatus},
#{log.content},
#{log.executeTime}
)
insert>
<delete id="clearLog">
delete from
`scheduled_log`
where
`execute_time` <= #{endTime}
delete>
<select id="latestLogByTask" resultMap="scheduleLogMap">
select
`id`,
`task_id`,
`task_name`,
`execute_status`,
`content`,
`execute_time`
from
`scheduled_log`
where
`task_id` = #{taskId}
and execute_status = 'fail'
order by `execute_time` desc, `id` desc
limit 1
select>
<select id="lastLog" resultMap="scheduleLogMap">
select
`id`,
`task_id`,
`task_name`,
`execute_status`,
`content`,
`execute_time`
from
`scheduled_log`
where
`task_id` = #{taskId}
and `execute_time` > #{executeTime}
and `execute_status` = 'fail'
order by `execute_time` asc, `id` asc
limit 1
select>
<select id="nextLog" resultMap="scheduleLogMap">
select
`id`,
`task_id`,
`task_name`,
`execute_status`,
`content`,
`execute_time`
from
`scheduled_log`
where
`task_id` = #{taskId}
and `execute_time` < #{executeTime}
and `execute_status` = 'fail'
order by `execute_time` desc, `id` desc
limit 1
select>
mapper>
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.studioustiger.job.entity.ScheduleTaskDto;
import com.studioustiger.job.entity.ScheduleTaskPo;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ScheduleTaskMapper extends BaseMapper<ScheduleTaskDto> {
int add(@Param("task") ScheduleTaskDto task);
int update(@Param("task") ScheduleTaskDto task);
int getTotals(@Param("taskName") String taskName,
@Param("taskType") String taskType,
@Param("taskStatus") String taskStatus);
List<ScheduleTaskPo> getPage(@Param("current") Integer current,
@Param("size") Integer size,
@Param("taskName") String taskName,
@Param("taskType") String taskType,
@Param("taskStatus") String taskStatus);
int enableByIds(@Param("tasks") List<ScheduleTaskDto> tasks);
int disableByIds(@Param("tasks") List<ScheduleTaskDto> tasks);
int deleteByIds(@Param("ids") List<String> ids);
ScheduleTaskPo refreshResult(@Param("taskId")String taskId);
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.studioustiger.job.mapper.ScheduleTaskMapper">
<resultMap id="scheduleTaskMap" type="com.studioustiger.job.entity.ScheduleTaskPo">
<result column="id" property="id"/>
<result column="name" property="name"/>
<result column="task_type" property="taskType"/>
<result column="task_describe" property="taskDescribe"/>
<result column="url" property="url"/>
<result column="cron" property="cron"/>
<result column="method" property="method"/>
<result column="enable" property="enable"/>
<result column="open_log" property="openLog"/>
<result column="create_user" property="createUser"/>
<result column="create_time" property="createTime"/>
<result column="update_user" property="updateUser"/>
<result column="update_time" property="updateTime"/>
<result column="total" property="total"/>
resultMap>
<select id="getPage" parameterType="string" resultMap="scheduleTaskMap">
select
a.`id`,
a.`name`,
b.`dict_label` as task_type,
a.`task_describe`,
a.`url`,
a.`cron`,
a.`method`,
a.`enable`,
a.`open_log`,
a.`create_user`,
a.`create_time`,
a.`update_user`,
a.`update_time`,
concat(ifnull(c.fail_count,0),'/',ifnull(d.success_count,0)) as total
from
`scheduled_task` as a
left join `sys_dict` as b
on a.`task_type` = b.`dict_value`
and b.`code` = 'schedule_task'
and is_sealed = 0
and b.`del_flag` = 0
left join (select task_id, count(id) as fail_count from `scheduled_log` where `execute_status` = 'fail' group by task_id) c
on c.task_id = a.id
left join (select task_id, count(id) as success_count from `scheduled_log` where `execute_status` = 'success' group by task_id) d
on d.task_id = a.id
<where>
<if test="taskName != null and taskName != ''">
and a.`name` like concat('%',#{taskName},'%')
if>
<if test="taskType != null and taskType != ''">
and a.`task_type` like concat('%',#{taskType},'%')
if>
<if test="taskStatus != null and taskStatus != ''">
and a.`enable` like concat('%',#{taskStatus},'%')
if>
where>
order by a.`task_type` desc, a.`name` desc, `create_time` desc, id
<if test="current != null">
limit #{current} , #{size}
if>
select>
<select id="getTotals" parameterType="string" resultType="int">
select
count(*)
from
`scheduled_task`
<where>
<if test="taskName != null and taskName != ''">
and `name` like concat('%',#{taskName},'%')
if>
<if test="taskType != null and taskType != ''">
and `task_type` like concat('%',#{taskType},'%')
if>
<if test="taskStatus != null and taskStatus != ''">
and `enable` like concat('%',#{taskStatus},'%')
if>
where>
select>
<insert id="add">
insert into
`scheduled_task`(
`id`,
`name`,
`task_type`,
`task_describe`,
`url`,
`cron`,
`method`,
`enable`,
`open_log`,
`create_user`,
`create_time`
)
values (
#{task.id},
#{task.name},
#{task.taskType},
#{task.taskDescribe},
#{task.url},
#{task.cron},
#{task.method},
#{task.enable},
#{task.openLog},
#{task.createUser},
#{task.createTime}
)
insert>
<update id="update">
update
`scheduled_task`
set
`name` = #{task.name},
`task_type` = #{task.taskType},
`task_describe` = #{task.taskDescribe},
`url` = #{task.url},
`cron` = #{task.cron},
`method` = #{task.method},
`enable` = #{task.enable},
`open_log` = #{task.openLog},
`update_user` = #{task.updateUser},
`update_time` = #{task.updateTime}
where
`id` = #{task.id}
update>
<update id="enableByIds">
update
`scheduled_task`
set
`enable` = '1',
`update_user` = #{tasks[0].updateUser},
`update_time` = #{tasks[0].updateTime}
where
`id` in
<foreach collection="tasks" item="task" open="(" separator="," close=")">
#{task.id}
foreach>
update>
<update id="disableByIds">
update
`scheduled_task`
set
`enable` = '0',
`update_user` = #{tasks[0].updateUser},
`update_time` = #{tasks[0].updateTime}
where
`id` in
<foreach collection="tasks" item="task" open="(" separator="," close=")">
#{task.id}
foreach>
update>
<delete id="deleteByIds" parameterType="list">
delete from
`scheduled_task`
where
`id` in
<foreach collection="ids" item="val" open="(" separator="," close=")">
#{val}
foreach>
delete>
<select id="refreshResult" resultMap="scheduleTaskMap">
select
a.`id`,
a.`name`,
b.`dict_label` as task_type,
a.`task_describe`,
a.`url`,
a.`cron`,
a.`method`,
a.`enable`,
a.`open_log`,
a.`create_user`,
a.`create_time`,
a.`update_user`,
a.`update_time`,
concat(ifnull(c.fail_count,0),'/',ifnull(d.success_count,0)) as total
from
`scheduled_task` as a
left join `sys_dict` as b
on a.`task_type` = b.`dict_value`
and b.`code` = 'schedule_task'
and is_sealed = 0
and b.`del_flag` = 0
left join (select task_id, count(id) as fail_count from `scheduled_log` where `execute_status` = 'fail' group by task_id) c
on c.task_id = a.id
left join (select task_id, count(id) as success_count from `scheduled_log` where `execute_status` = 'success' group by task_id) d
on d.task_id = a.id
where a.id = #{taskId}
select>
mapper>
com.studioustiger.job.service
import com.baomidou.mybatisplus.extension.service.IService;
import com.studioustiger.job.entity.ScheduleTaskDto;
import com.studioustiger.job.entity.ScheduleTaskPo;
import java.util.List;
public interface ScheduleTaskService extends IService<ScheduleTaskDto> {
int add(ScheduleTaskDto scheduleTask);
int update(ScheduleTaskDto scheduleTask);
int getTotals(String taskName, String taskType, String taskStatus);
List<ScheduleTaskPo> getPage(Integer current, Integer size, String taskName, String taskType, String taskStatus);
int enableByIds(List<String> ids);
int disableByIds(List<String> ids);
int deleteByIds(List<String> ids);
ScheduleTaskPo refreshResult(String tasId);
}
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.studioustiger.core.tool.utils.DateUtil;
import com.studioustiger.dataapi.function.MeFunctions;
import com.studioustiger.job.entity.ScheduleTaskDto;
import com.studioustiger.job.entity.ScheduleTaskPo;
import com.studioustiger.job.mapper.ScheduleTaskMapper;
import com.studioustiger.job.service.ScheduleTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Service
public class ScheduleTaskServiceImpl extends ServiceImpl<ScheduleTaskMapper, ScheduleTaskDto> implements ScheduleTaskService {
@Autowired
ScheduleTaskMapper scheduleTaskMapper;
@Autowired
MeFunctions me;
public int add(ScheduleTaskDto scheduleTask){
String id = String.valueOf(me.nextId());
String createUser = String.valueOf(me.id());
String createTime = DateUtil.formatDateTime(new Date());
scheduleTask.setId(id);
scheduleTask.setEnable("0");
scheduleTask.setCreateUser(createUser);
scheduleTask.setCreateTime(createTime);
return scheduleTaskMapper.add(scheduleTask);
}
public int update(ScheduleTaskDto scheduleTask){
String updateUser = String.valueOf(me.id());
String updateTime = DateUtil.formatDateTime(new Date());
scheduleTask.setUpdateUser(updateUser);
scheduleTask.setUpdateTime(updateTime);
return scheduleTaskMapper.update(scheduleTask);
}
@Override
public int getTotals(String taskName, String taskType, String taskStatus) {
return scheduleTaskMapper.getTotals(taskName, taskType, taskStatus);
}
public List<ScheduleTaskPo> getPage(Integer current, Integer size, String taskName, String taskType, String taskStatus) {
return scheduleTaskMapper.getPage(current, size, taskName, taskType, taskStatus);
}
public int enableByIds(List<String> ids){
return scheduleTaskMapper.enableByIds(fillTaskInfo(ids));
}
public int disableByIds(List<String> ids){
return scheduleTaskMapper.disableByIds(fillTaskInfo(ids));
}
private List<ScheduleTaskDto> fillTaskInfo (List<String> ids) {
String updateUser = String.valueOf(me.id());
String updateTime = DateUtil.formatDateTime(new Date());
List<ScheduleTaskDto> tasks = new ArrayList<>();
ids.forEach(item -> {
ScheduleTaskDto task = new ScheduleTaskDto();
task.setId(item);
task.setUpdateUser(updateUser);
task.setUpdateTime(updateTime);
tasks.add(task);
});
return tasks;
}
public int deleteByIds(List<String> ids) {
return scheduleTaskMapper.deleteByIds(ids);
}
@Override
public ScheduleTaskPo refreshResult(String taskId) {
return scheduleTaskMapper.refreshResult(taskId);
}
}
import com.studioustiger.job.entity.ScheduleLogDto;
import java.util.List;
public interface ScheduleLogService {
List<ScheduleLogDto> getPage();
int add(ScheduleLogDto scheduleLog);
int clearLog(String endTime);
ScheduleLogDto latestLogByTask(String taskId);
ScheduleLogDto lastLog(String taskId, String executeTime);
ScheduleLogDto nextLog(String taskId, String executeTime);
}
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.studioustiger.job.entity.ScheduleLogDto;
import com.studioustiger.job.mapper.ScheduleLogMapper;
import com.studioustiger.job.service.ScheduleLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ScheduleLogServiceImpl extends ServiceImpl<ScheduleLogMapper, ScheduleLogDto> implements ScheduleLogService {
@Autowired
ScheduleLogMapper scheduleLogMapper;
@Override
public List<ScheduleLogDto> getPage() {
return scheduleLogMapper.getPage();
}
@Override
public int add(ScheduleLogDto scheduleLog) {
return scheduleLogMapper.add(scheduleLog);
}
@Override
public int clearLog(String endTime) {
return scheduleLogMapper.clearLog(endTime);
}
@Override
public ScheduleLogDto latestLogByTask(String taskId) {
return scheduleLogMapper.latestLogByTask(taskId);
}
@Override
public ScheduleLogDto lastLog(String taskId, String executeTime) {
return scheduleLogMapper.lastLog(taskId, executeTime);
}
@Override
public ScheduleLogDto nextLog(String taskId, String executeTime) {
return scheduleLogMapper.nextLog(taskId, executeTime);
}
}
com.studioustiger.job.executor
import com.studioustiger.job.entity.ScheduleTaskDto;
public interface TaskExecutor {
boolean execute(ScheduleTaskDto task);
}
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.studioustiger.core.tool.utils.DateUtil;
import com.qstudioustigeranmo.core.tool.utils.StringUtil;
import com.studioustiger.dataapi.function.MeFunctions;
import com.studioustiger.job.constant.JobConstant;
import com.studioustiger.job.constant.LogProperties;
import com.studioustiger.job.entity.ScheduleLogDto;
import com.studioustiger.job.entity.ScheduleTaskDto;
import com.studioustiger.job.executor.TaskExecutor;
import com.studioustiger.job.service.ScheduleLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
@Service
public class TaskExecutorImpl implements TaskExecutor {
private static final Log log = LogFactory.get(TaskExecutorImpl.class);
@Autowired
ScheduleLogService scheduleLogService;
@Autowired
MeFunctions me;
@Autowired
LogProperties logProperties;
@Override
public boolean execute(ScheduleTaskDto task) {
return this.doJob(task);
}
public boolean doJob(ScheduleTaskDto task) {
String message = null;
try {
log.info("定时任务[{}]执行成功", task.getName());
} catch (Exception e) {
log.error("定时任务[{}]执行失败", task.getName());
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
message = sw.toString();
} finally {
genLog(task, message);
}
return message == null;
}
private void genLog(ScheduleTaskDto task, String message){
String status = message == null ? "success" : "fail";
if (!logProperties.isFailOpen() && !logProperties.isSuccessOpen()) {
return;
}
if ("success".equals(status) && !logProperties.isSuccessOpen()) {
return;
}
if ("fail".equals(status) && !logProperties.isFailOpen()) {
return;
}
if ("0".equals(task.getOpenLog())) {
return;
}
try {
ScheduleLogDto scheduleLog = new ScheduleLogDto(
String.valueOf(me.nextId()),
task.getId(),
task.getName(),
status,
message,
DateUtil.formatDateTime(new Date())
);
scheduleLogService.add(scheduleLog);
} catch (Exception e) {
log.error("日志持久化错误");
}
}
}
com.studioustiger.job.config
import com.studioustiger.job.entity.ScheduleTaskDto;
import com.studioustiger.job.executor.TaskExecutor;
import org.springframework.stereotype.Component;
@Component
public class Worker implements Runnable {
private TaskExecutor taskExecutor;
private ScheduleTaskDto scheduleTask;
public Worker() {
}
public Worker(ScheduleTaskDto scheduleTask, TaskExecutor taskExecutor) {
this.scheduleTask = scheduleTask;
this.taskExecutor = taskExecutor;
}
public void run() {
taskExecutor.execute(scheduleTask);
}
}
import com.studioustiger.job.entity.ScheduleTaskDto;
import lombok.AllArgsConstructor;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.function.Consumer;
@AllArgsConstructor
@SpringBootConfiguration
public class TaskConfig {
@Bean(name = "scheduledFutureMap")
public Map<String, ScheduledFuture> scheduledFutureMap() {
return new ConcurrentHashMap<>();
}
@Bean(name = "operationMap")
public Map<String, Consumer<ScheduleTaskDto>> operationMap() {
return new ConcurrentHashMap<>();
}
@Bean(name = "threadPoolTaskScheduler")
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(Runtime.getRuntime().availableProcessors());
threadPoolTaskScheduler.setThreadNamePrefix("WorKerThread:");
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
threadPoolTaskScheduler.setAwaitTerminationSeconds(30);
return threadPoolTaskScheduler;
}
}
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.studioustiger.job.constant.JobConstant;
import com.studioustiger.job.entity.ScheduleTaskDto;
import com.studioustiger.job.executor.TaskExecutor;
import com.studioustiger.job.service.ScheduleTaskService;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ScheduledFuture;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@SpringBootConfiguration
@RequiredArgsConstructor
public class InitConfig {
private static final Log log = LogFactory.get(TaskConfig.class);
private final Map<String, ScheduledFuture> scheduledFutureMap;
private final Map<String, Consumer<ScheduleTaskDto>> operationMap;
private final ThreadPoolTaskScheduler threadPoolTaskScheduler;
private final ScheduleTaskService scheduleTaskService;
private final TaskExecutor taskExecutor;
@PostConstruct
public void initSchedule() {
List<ScheduleTaskDto> taskList = scheduleTaskService.list();
List<ScheduleTaskDto> enableTask = taskList.stream().filter(item -> "1".equals(item.getEnable())).collect(Collectors.toList());
enableTask.forEach(item -> {
Worker worker = new Worker(item, taskExecutor);
CronTrigger cronTrigger = item.toCronTrigger();
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(worker, cronTrigger);
scheduledFutureMap.put(item.getId(), schedule);
log.info("定时任务:[{}]初始化完成", item.getName());
});
initOperationMap();
}
private void initOperationMap() {
Consumer<ScheduleTaskDto> openSchedule = item -> {
String scheduleId = item.getId();
if (scheduledFutureMap.containsKey(scheduleId)) {
scheduledFutureMap.compute(scheduleId, (k, v) -> {
Optional.ofNullable(v).ifPresent(v0 -> v0.cancel(true));
Worker worker = new Worker(item, taskExecutor);
CronTrigger cronTrigger = item.toCronTrigger();
return threadPoolTaskScheduler.schedule(worker, cronTrigger);
});
}
else {
Worker worker = new Worker(item, taskExecutor);
if (worker != null) {
CronTrigger cronTrigger = item.toCronTrigger();
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(worker, cronTrigger);
scheduledFutureMap.put(scheduleId, schedule);
}
}
};
operationMap.put(JobConstant.OPEN_SCHEDULE, openSchedule);
log.info("定时任务操作注册表:[{}]初始化完成",JobConstant.OPEN_SCHEDULE);
Consumer<ScheduleTaskDto> closeSchedule = item -> {
String scheduleId = item.getId();
ScheduledFuture scheduledFuture = scheduledFutureMap.get(scheduleId);
Optional.ofNullable(scheduledFuture).ifPresent(schedule -> schedule.cancel(true));
};
operationMap.put(JobConstant.CLOSE_SCHEDULE, closeSchedule);
log.info("定时任务操作注册表:[{}]初始化完成",JobConstant.CLOSE_SCHEDULE);
Consumer<ScheduleTaskDto> deleteSchedule = item -> {
String scheduleId = item.getId();
ScheduledFuture scheduledFuture = scheduledFutureMap.get(scheduleId);
Optional.ofNullable(scheduledFuture).ifPresent(schedule -> schedule.cancel(true));
scheduledFutureMap.remove(scheduleId);
};
operationMap.put(JobConstant.DELETE_SCHEDULE, deleteSchedule);
log.info("定时任务操作注册表:[{}]初始化完成",JobConstant.DELETE_SCHEDULE);
}
}
com.studioustiger.job.scheduled
import com.studioustiger.job.constant.LogProperties;
import com.studioustiger.job.service.ScheduleLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
@Component
public class defaultScheduled {
@Autowired
ScheduleLogService scheduleLogService;
@Autowired
LogProperties logProperties;
@Scheduled(cron = "0 30 1 * * ?")
public void clearLog() {
String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(System.currentTimeMillis() - 86400000 * logProperties.getSaveDays());
scheduleLogService.clearLog(endTime);
}
}
com.studioustiger.job.controller
import com.studioustiger.core.tool.api.R;
import com.studioustiger.job.constant.JobConstant;
import com.studioustiger.job.entity.ScheduleTaskDto;
import com.studioustiger.job.entity.ScheduleTaskPo;
import com.studioustiger.job.executor.TaskExecutor;
import com.studioustiger.job.service.ScheduleLogService;
import com.studioustiger.job.service.ScheduleTaskService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Description;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@RestController
@RequestMapping(value = "/task")
public class TaskManagerController {
private final ScheduleTaskService scheduleTaskService;
private final ScheduleLogService scheduleLogService;
private final Map<String, Consumer<ScheduleTaskDto>> operationMap;
private final TaskExecutor taskExecutor;
@Description(value = "获取最新的错误日志")
@GetMapping(value = "/log/by-task-id")
public R latestLogByTask(@RequestParam("taskId") String taskId) {
return R.data(scheduleLogService.latestLogByTask(taskId));
}
@Description(value = "上一条日志")
@GetMapping(value = "/log/last")
public R lastLog(@RequestParam("taskId") String taskId,
@RequestParam("executeTime") String executeTime) {
return R.data(scheduleLogService.lastLog(taskId, executeTime));
}
@Description(value = "下一条日志")
@GetMapping(value = "/log/next")
public R nextLog(@RequestParam("taskId") String taskId,
@RequestParam("executeTime") String executeTime) {
return R.data(scheduleLogService.nextLog(taskId, executeTime));
}
@Description(value = "执行任务")
@GetMapping(value = "/execute")
public R execute(@RequestParam("id") String id) {
ScheduleTaskDto task = scheduleTaskService.getById(id);
boolean execute = taskExecutor.execute(task);
if (execute) {
return R.data("success");
}
return R.data("fail");
}
@Description(value = "刷新执行结果")
@GetMapping(value = "/refresh-result")
public R refreshResult(@RequestParam("id") String id) {
return R.data(scheduleTaskService.refreshResult(id));
}
@Description(value = "添加任务")
@PostMapping(value = "/add")
public R addTask(@RequestBody ScheduleTaskDto scheduleTask) {
if (!isValidCron(scheduleTask.getCron())) {
return R.fail("cron表达式校验失败");
}
scheduleTaskService.add(scheduleTask);
return R.success("操作成功");
}
@Description(value = "更新任务")
@PostMapping(value = "/update")
public R updateTask(@RequestBody ScheduleTaskDto scheduleTask) {
if (!isValidCron(scheduleTask.getCron())) {
return R.fail("cron表达式校验失败");
}
scheduleTaskService.update(scheduleTask);
if ("1".equals(scheduleTask.getEnable())) {
openSchedule(Arrays.asList(scheduleTask.getId()));
}
return R.success("操作成功");
}
@Description(value = "删除任务")
@PostMapping(value = "/delete")
public R deleteTask(@RequestBody List<String> ids) {
if (ids != null && ids.size() > 0) {
deleteSchedule(ids);
scheduleTaskService.deleteByIds(ids);
}
return R.success("操作成功");
}
@Description(value = "暂停任务")
@PostMapping(value = "/disable")
public R disableTask(@RequestBody List<String> ids) {
if (ids != null && ids.size() > 0) {
scheduleTaskService.disableByIds(ids);
closeSchedule(ids);
}
return R.success("操作成功");
}
@Description(value = "启动任务")
@PostMapping(value = "/enable")
public R enableTask(@RequestBody List<String> ids) {
if (ids != null && ids.size() > 0) {
scheduleTaskService.enableByIds(ids);
openSchedule(ids);
}
return R.success("操作成功");
}
@Description(value = "启动全部任务")
@GetMapping(value = "/enable-all")
public R enableAllTask() {
List<ScheduleTaskDto> list = scheduleTaskService.list();
if (list != null && list.size() >0) {
List<String> ids = list.stream().map(item -> item.getId()).collect(Collectors.toList());
openSchedule(ids);
}
return R.success("操作成功");
}
@Description(value = "关闭全部任务")
@GetMapping(value = "/disable-all")
public R disableAllTask() {
List<ScheduleTaskDto> list = scheduleTaskService.list();
if (list != null && list.size() >0) {
List<String> ids = list.stream().map(item -> item.getId()).collect(Collectors.toList());
closeSchedule(ids);
}
return R.success("操作成功");
}
@Description(value = "获取任务详情")
@GetMapping(value = "/detail")
public R taskDetail(@RequestParam("id") String id) {
return R.data(scheduleTaskService.getById(id));
}
@Description(value = "获取任务分页")
@GetMapping(value = "/page")
public R taskPage(@RequestParam(required = false, value = "current") Integer current,
@RequestParam(required = false, value = "size") Integer size,
@RequestParam(required = false, value = "taskName") String taskName,
@RequestParam(required = false, value = "taskType") String taskType,
@RequestParam(required = false, value = "taskStatus") String taskStatus) {
int total = scheduleTaskService.getTotals(taskName, taskType, taskStatus);
List<ScheduleTaskPo> page = scheduleTaskService.getPage((current - 1) * size, size, taskName, taskType, taskStatus);
Map pageRes = new LinkedHashMap<>();
int pages = total / size + (total % size == 0 ? 0: 1);
pageRes.put("pages",pages);
pageRes.put("records",page);
pageRes.put("size",size);
pageRes.put("current",current);
pageRes.put("total",total);
pageRes.put("optimizeCountSql",true);
pageRes.put("searchCount",true);
return R.data(pageRes);
}
@Description(value = "获取任务列表")
@GetMapping(value = "/list")
public R taskList() {
List<ScheduleTaskDto> list = scheduleTaskService.list();
return R.data(list);
}
private void openSchedule(List<String> ids) {
List<ScheduleTaskDto> taskList = scheduleTaskService.listByIds(ids);
if (taskList != null && taskList.size() > 0) {
taskList.forEach(item -> {
operationMap.get(JobConstant.OPEN_SCHEDULE).accept(item);
});
}
}
private void closeSchedule(List<String> ids) {
System.out.println(operationMap.toString());
List<ScheduleTaskDto> taskList = scheduleTaskService.listByIds(ids);
if (taskList != null && taskList.size() > 0) {
taskList.forEach(item -> {
operationMap.get(JobConstant.CLOSE_SCHEDULE).accept(item);
});
}
}
private void deleteSchedule(List<String> ids) {
List<ScheduleTaskDto> taskList = scheduleTaskService.listByIds(ids);
if (taskList != null && taskList.size() > 0) {
taskList.forEach(item -> {
operationMap.get(JobConstant.DELETE_SCHEDULE).accept(item);
});
}
}
private boolean isValidCron(String cronStr) {
return CronExpression.isValidExpression(cronStr);
}
}
效果图
抱歉,没有前端代码(我的前端是基于配置文件配出来的),大家使用elementUI搭即可。