From 327f0df6a931bf08e09c55335f25556fcb8cb3d7 Mon Sep 17 00:00:00 2001 From: TinyAnts Date: Fri, 2 Dec 2022 14:14:34 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/like-admin/pom.xml | 8 +- .../mdd/admin/config/quartz/CronUtils.java | 54 +++++++ .../mdd/admin/config/quartz/InvokeUtils.java | 152 ++++++++++++++++++ .../mdd/admin/config/quartz/QuartzUtils.java | 104 ++++++++++++ .../admin/config/quartz/TaskConstants.java | 23 +++ .../quartz/exceution/AbstractQuartzJob.java | 81 ++++++++++ .../quartz/exceution/QuartzDisExecution.java | 19 +++ .../quartz/exceution/QuartzJobExecution.java | 17 ++ .../admin/controller/CrontabController.java | 7 +- .../java/com/mdd/admin/crontab/MyJob.java | 17 ++ .../mdd/admin/service/ICrontabService.java | 7 +- .../service/impl/CrontabServiceImpl.java | 52 +++++- .../admin/validate/CrontabCreateValidate.java | 13 +- .../admin/validate/CrontabUpdateValidate.java | 16 +- .../com/mdd/admin/vo/CrontabDetailVo.java | 18 ++- .../com/mdd/admin/vo/CrontabListedVo.java | 20 ++- .../java/com/mdd/common/entity/Crontab.java | 27 ++-- server/pom.xml | 16 ++ 18 files changed, 618 insertions(+), 33 deletions(-) create mode 100644 server/like-admin/src/main/java/com/mdd/admin/config/quartz/CronUtils.java create mode 100644 server/like-admin/src/main/java/com/mdd/admin/config/quartz/InvokeUtils.java create mode 100644 server/like-admin/src/main/java/com/mdd/admin/config/quartz/QuartzUtils.java create mode 100644 server/like-admin/src/main/java/com/mdd/admin/config/quartz/TaskConstants.java create mode 100644 server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/AbstractQuartzJob.java create mode 100644 server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzDisExecution.java create mode 100644 server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzJobExecution.java create mode 100644 server/like-admin/src/main/java/com/mdd/admin/crontab/MyJob.java diff --git a/server/like-admin/pom.xml b/server/like-admin/pom.xml index 6d3564a4..f6a85e82 100644 --- a/server/like-admin/pom.xml +++ b/server/like-admin/pom.xml @@ -36,10 +36,16 @@ sa-token-spring-boot-starter + cn.dev33 sa-token-dao-redis-jackson - 1.32.0 + + + + + org.quartz-scheduler + quartz diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/quartz/CronUtils.java b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/CronUtils.java new file mode 100644 index 00000000..00c05865 --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/CronUtils.java @@ -0,0 +1,54 @@ +package com.mdd.admin.config.quartz; + +import org.quartz.CronExpression; + +import java.text.ParseException; +import java.util.Date; + +/** + * 表达式工具 + */ +public class CronUtils { + + /** + * 验证表达式是否有效 + * + * @param cronExpression 表达式 + * @return true=有效,false=无效 + */ + public static boolean isValid(String cronExpression) { + return CronExpression.isValidExpression(cronExpression); + } + + /** + * 验证表达式消息无效给出有效性 + * + * @param cronExpression 表达式 + * @return null=有效, 其它=无效时的错误描述 + */ + public static String invalidMessage(String cronExpression) { + try { + new CronExpression(cronExpression); + return null; + } catch (ParseException pe) { + return pe.getMessage(); + } + } + + /** + * 下一个执行时间点 + * + * @param cronExpression n表达式 + * @return Date下次表达式执行时间 + */ + public static Date nextExecution(String cronExpression) + { + try { + CronExpression cron = new CronExpression(cronExpression); + return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); + } catch (ParseException e) { + throw new IllegalArgumentException(e.getMessage()); + } + } + +} diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/quartz/InvokeUtils.java b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/InvokeUtils.java new file mode 100644 index 00000000..04e1aebc --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/InvokeUtils.java @@ -0,0 +1,152 @@ +package com.mdd.admin.config.quartz; + +import com.mdd.common.entity.Crontab; +import com.mdd.common.utils.SpringUtil; +import com.mdd.common.utils.StringUtil; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; + +/** + * 执行工具 + */ +public class InvokeUtils { + + /** + * 执行方法 + * + * @param crontab 系统任务 + */ + public static void invokeMethod(Crontab crontab) throws Exception { + String invokeTarget = crontab.getCommand(); + String beanName = getBeanName(invokeTarget); + String methodName = getMethodName(invokeTarget); + List methodParams = getMethodParams(invokeTarget); + + if (!isValidClassName(beanName)) { + Object bean = SpringUtil.getBean(beanName); + invokeMethod(bean, methodName, methodParams); + } else { + Object bean = Class.forName(beanName).newInstance(); + invokeMethod(bean, methodName, methodParams); + } + } + + /** + * 调用任务方法 + * + * @param bean 目标对象 + * @param methodName 方法名称 + * @param methodParams 方法参数 + */ + private static void invokeMethod(Object bean, String methodName, List methodParams) + throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, + InvocationTargetException { + if (StringUtil.isNotNull(methodParams) && methodParams.size() > 0) { + Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams)); + method.invoke(bean, getMethodParamsValue(methodParams)); + } else { + Method method = bean.getClass().getMethod(methodName); + method.invoke(bean); + } + } + + + /** + * 校验是否为为class包名 + * + * @param invokeTarget 名称 + * @return true是 false否 + */ + public static boolean isValidClassName(String invokeTarget) { + return StringUtil.countMatches(invokeTarget, ".") > 1; + } + + /** + * 获取bean名称 + * + * @param invokeTarget 目标字符串 + * @return bean名称 + */ + public static String getBeanName(String invokeTarget) { + String beanName = StringUtil.substringBefore(invokeTarget, "("); + return StringUtil.substringBeforeLast(beanName, "."); + } + + /** + * 获取bean方法 + * + * @param invokeTarget 目标字符串 + * @return method方法 + */ + public static String getMethodName(String invokeTarget) { + String methodName = StringUtil.substringBefore(invokeTarget, "("); + return StringUtil.substringAfterLast(methodName, "."); + } + + /** + * 获取method方法参数相关列表 + * + * @param invokeTarget 目标字符串 + * @return method方法相关参数列表 + */ + public static List getMethodParams(String invokeTarget) { + String methodStr = StringUtil.substringBetween(invokeTarget, "(", ")"); + if (StringUtil.isEmpty(methodStr)) { + return null; + } + String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); + List clazz = new LinkedList<>(); + for (String methodParam : methodParams) { + String str = StringUtil.trimToEmpty(methodParam); + if (StringUtil.startsWithAny(str, "'", "\"")) { + clazz.add(new Object[]{StringUtil.substring(str, 1, str.length() - 1), String.class}); + } else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) { + clazz.add(new Object[]{Boolean.valueOf(str), Boolean.class}); + } else if (StringUtil.endsWith(str, "L")) { + clazz.add(new Object[]{Long.valueOf(StringUtil.substring(str, 0, str.length() - 1)), Long.class}); + } else if (StringUtil.endsWith(str, "D")) { + clazz.add(new Object[]{Double.valueOf(StringUtil.substring(str, 0, str.length() - 1)), Double.class}); + } else { + clazz.add(new Object[]{Integer.valueOf(str), Integer.class}); + } + } + return clazz; + } + + /** + * 获取参数类型 + * + * @param methodParams 参数相关列表 + * @return 参数类型列表 + */ + public static Class[] getMethodParamsType(List methodParams) { + Class[] clazz = new Class[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + clazz[index] = (Class) os[1]; + index++; + } + return clazz; + } + + /** + * 获取参数值 + * + * @param methodParams 参数相关列表 + * @return 参数值列表 + */ + public static Object[] getMethodParamsValue(List methodParams) { + Object[] clazz = new Object[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) { + clazz[index] = os[0]; + index++; + } + return clazz; + } + +} diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/quartz/QuartzUtils.java b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/QuartzUtils.java new file mode 100644 index 00000000..b93d50b1 --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/QuartzUtils.java @@ -0,0 +1,104 @@ +package com.mdd.admin.config.quartz; + +import com.mdd.admin.config.quartz.exceution.QuartzDisExecution; +import com.mdd.admin.config.quartz.exceution.QuartzJobExecution; +import com.mdd.common.entity.Crontab; +import com.mdd.common.utils.StringUtil; +import org.quartz.*; + +/** + * 计划任务工具 + */ +public class QuartzUtils { + + /** + * 得到quartz任务类 + * + * @param crontab 执行计划 + * @return 具体执行任务类 + */ + private static Class getQuartzJobClass(Crontab crontab) { + boolean isConcurrent = crontab.getConcurrent().equals(0); + return isConcurrent ? QuartzJobExecution.class : QuartzDisExecution.class; + } + + /** + * 构建任务对象Key + * + * @param jobId (任务ID) + * @param jobGroup (任务分组) + * @return JobKey + */ + public static JobKey getJobKey(Integer jobId, String jobGroup) { + return JobKey.jobKey(TaskConstants.TASK_CLASS_NAME + jobId, jobGroup); + } + + /** + * 构建触发对象Key + * + * @param jobId (任务ID) + * @param jobGroup (任务分组) + * @return TriggerKey + */ + public static TriggerKey getTriggerKey(Integer jobId, String jobGroup) { + return TriggerKey.triggerKey(TaskConstants.TASK_PROPERTIES + jobId, jobGroup); + } + + /** + * 创建定时任务 + * + * @param scheduler 调度器 + * @param job 任务 + * @throws SchedulerException 调度异常 + */ + public static void createScheduleJob(Scheduler scheduler, Crontab job) throws SchedulerException { + Integer jobId = job.getId(); + String jobGroup = job.getGroups(); + String expression = job.getRules(); + + // 构建任务 + Class jobClass = getQuartzJobClass(job); + JobDetail jobDetail = JobBuilder.newJob(jobClass) + .withIdentity(getJobKey(jobId, jobGroup)) + .build(); + + // 构建时间 + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(expression); + switch (job.getStrategy()) { + case 1: // 立即执行 + cronScheduleBuilder = cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires(); + break; + case 2: // 执行一次 + cronScheduleBuilder = cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed(); + break; + case 3: // 放弃执行 + cronScheduleBuilder = cronScheduleBuilder.withMisfireHandlingInstructionDoNothing(); + break; + } + + // 注入参数 + jobDetail.getJobDataMap().put(TaskConstants.TASK_PROPERTIES, job); + + // 构建目标 + CronTrigger trigger = TriggerBuilder.newTrigger() + .withIdentity(getTriggerKey(jobId, jobGroup)) + .withSchedule(cronScheduleBuilder) + .build(); + + // 如果存在则删除 + if (scheduler.checkExists(getJobKey(jobId, jobGroup))) { + scheduler.deleteJob(getJobKey(jobId, jobGroup)); + } + + // 如果过期则调度 + if (StringUtil.isNotNull(CronUtils.nextExecution(job.getRules()))) { + scheduler.scheduleJob(jobDetail, trigger); + } + + // 如果暂停则停止 + if (!job.getStatus().equals(TaskConstants.STATUS_RUN)) { + scheduler.pauseJob(getJobKey(jobId, jobGroup)); + } + } + +} diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/quartz/TaskConstants.java b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/TaskConstants.java new file mode 100644 index 00000000..87d18677 --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/TaskConstants.java @@ -0,0 +1,23 @@ +package com.mdd.admin.config.quartz; + +/** + * 计划任务常量 + */ +public class TaskConstants { + + /** 执行任务名 */ + public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME"; + + /** 执行目标键 */ + public static final String TASK_PROPERTIES = "TASK_PROPERTIES"; + + /** 状态: 运行 */ + public static final Integer STATUS_RUN = 1; + + /** 状态: 停止 */ + public static final Integer STATUS_STOP = 2; + + /** 状态: 失败 */ + public static final Integer STATUS_FAIL = 2; + +} diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/AbstractQuartzJob.java b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/AbstractQuartzJob.java new file mode 100644 index 00000000..04843bbe --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/AbstractQuartzJob.java @@ -0,0 +1,81 @@ +package com.mdd.admin.config.quartz.exceution; + +import com.mdd.admin.config.quartz.TaskConstants; +import com.mdd.common.entity.Crontab; +import com.mdd.common.mapper.CrontabMapper; +import com.mdd.common.utils.SpringUtil; +import com.mdd.common.utils.StringUtil; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; + +public abstract class AbstractQuartzJob implements Job { + + private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class); + + /** + * 线程本地变量 + */ + private static final ThreadLocal threadLocal = new ThreadLocal<>(); + + /** + * 执行 + * + * @param context 上下文 + */ + @Override + public void execute(JobExecutionContext context) { + Crontab crontab = new Crontab(); + BeanUtils.copyProperties(context.getMergedJobDataMap().get(TaskConstants.TASK_PROPERTIES), crontab); + try { + before(); + doExecute(context, crontab); + after(crontab, null); + } catch (Exception e) { + log.error("任务执行异常:", e); + after(crontab, e); + } + } + + /** + * 执行前 + */ + protected void before() { + threadLocal.set(System.currentTimeMillis()); + } + + /** + * 执行后 + * + * @param crontab 系统计划任务 + */ + protected void after(Crontab crontab, Exception e) + { + long startTime = threadLocal.get(); + long endTime = System.currentTimeMillis(); + threadLocal.remove(); + + crontab.setError(""); + crontab.setStartTime(startTime / 1000); + crontab.setEndTime(endTime / 1000); + crontab.setTaskTime(endTime - startTime); + if (StringUtil.isNotNull(e)) { + crontab.setError(e.getMessage()); + crontab.setStatus(TaskConstants.STATUS_FAIL); + } + + SpringUtil.getBean(CrontabMapper.class).updateById(crontab); + } + + /** + * 执行方法 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + * @throws Exception 执行过程中的异常 + */ + protected abstract void doExecute(JobExecutionContext context, Crontab sysJob) throws Exception; + +} diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzDisExecution.java b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzDisExecution.java new file mode 100644 index 00000000..c28b7854 --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzDisExecution.java @@ -0,0 +1,19 @@ +package com.mdd.admin.config.quartz.exceution; + +import com.mdd.admin.config.quartz.InvokeUtils; +import com.mdd.common.entity.Crontab; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; + +/** + * 禁止并发任务 + */ +@DisallowConcurrentExecution +public class QuartzDisExecution extends AbstractQuartzJob { + + @Override + protected void doExecute(JobExecutionContext context, Crontab crontab) throws Exception { + InvokeUtils.invokeMethod(crontab); + } + +} \ No newline at end of file diff --git a/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzJobExecution.java b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzJobExecution.java new file mode 100644 index 00000000..56f7e68e --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/config/quartz/exceution/QuartzJobExecution.java @@ -0,0 +1,17 @@ +package com.mdd.admin.config.quartz.exceution; + +import com.mdd.admin.config.quartz.InvokeUtils; +import com.mdd.common.entity.Crontab; +import org.quartz.JobExecutionContext; + +/** + * 允许并发任务 + */ +public class QuartzJobExecution extends AbstractQuartzJob { + + @Override + protected void doExecute(JobExecutionContext context, Crontab crontab) throws Exception { + InvokeUtils.invokeMethod(crontab); + } + +} diff --git a/server/like-admin/src/main/java/com/mdd/admin/controller/CrontabController.java b/server/like-admin/src/main/java/com/mdd/admin/controller/CrontabController.java index a6230238..c79a86f5 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/controller/CrontabController.java +++ b/server/like-admin/src/main/java/com/mdd/admin/controller/CrontabController.java @@ -10,6 +10,7 @@ import com.mdd.admin.vo.CrontabListedVo; import com.mdd.common.core.AjaxResult; import com.mdd.common.core.PageResult; import com.mdd.common.validator.annotation.IDMust; +import org.quartz.SchedulerException; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -56,7 +57,7 @@ public class CrontabController { * @return AjaxResult */ @PostMapping("/add") - public AjaxResult add(@Validated @RequestBody CrontabCreateValidate createValidate) { + public AjaxResult add(@Validated @RequestBody CrontabCreateValidate createValidate) throws SchedulerException { iCrontabService.add(createValidate); return AjaxResult.success(); } @@ -69,7 +70,7 @@ public class CrontabController { * @return AjaxResult */ @PostMapping("/edit") - public AjaxResult edit(@Validated @RequestBody CrontabUpdateValidate updateValidate) { + public AjaxResult edit(@Validated @RequestBody CrontabUpdateValidate updateValidate) throws SchedulerException { iCrontabService.edit(updateValidate); return AjaxResult.success(); } @@ -82,7 +83,7 @@ public class CrontabController { * @return AjaxResult */ @PostMapping("/del") - public AjaxResult del(@Validated @RequestBody IdValidate idValidate) { + public AjaxResult del(@Validated @RequestBody IdValidate idValidate) throws SchedulerException { iCrontabService.del(idValidate.getId()); return AjaxResult.success(); } diff --git a/server/like-admin/src/main/java/com/mdd/admin/crontab/MyJob.java b/server/like-admin/src/main/java/com/mdd/admin/crontab/MyJob.java new file mode 100644 index 00000000..3caee42f --- /dev/null +++ b/server/like-admin/src/main/java/com/mdd/admin/crontab/MyJob.java @@ -0,0 +1,17 @@ +package com.mdd.admin.crontab; + + +import org.springframework.stereotype.Component; + + +/** + * 工作类的具体实现,即需要定时执行的“某个事件” + */ +@Component("myJob") +public class MyJob { + + public void handle(String s) { + System.out.println("执行无参方法: " + s); + } + +} diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/ICrontabService.java b/server/like-admin/src/main/java/com/mdd/admin/service/ICrontabService.java index 8ef32110..89a7a178 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/service/ICrontabService.java +++ b/server/like-admin/src/main/java/com/mdd/admin/service/ICrontabService.java @@ -6,6 +6,7 @@ import com.mdd.admin.validate.commons.PageValidate; import com.mdd.admin.vo.CrontabDetailVo; import com.mdd.admin.vo.CrontabListedVo; import com.mdd.common.core.PageResult; +import org.quartz.SchedulerException; /** * 计划任务服务接口类 @@ -36,7 +37,7 @@ public interface ICrontabService { * @author fzr * @param createValidate 参数 */ - void add(CrontabCreateValidate createValidate); + void add(CrontabCreateValidate createValidate) throws SchedulerException; /** * 计划任务编辑 @@ -44,7 +45,7 @@ public interface ICrontabService { * @author fzr * @param updateValidate 参数 */ - void edit(CrontabUpdateValidate updateValidate); + void edit(CrontabUpdateValidate updateValidate) throws SchedulerException; /** * 计划任务删除 @@ -52,6 +53,6 @@ public interface ICrontabService { * @author fzr * @param id 主键 */ - void del(Integer id); + void del(Integer id) throws SchedulerException; } diff --git a/server/like-admin/src/main/java/com/mdd/admin/service/impl/CrontabServiceImpl.java b/server/like-admin/src/main/java/com/mdd/admin/service/impl/CrontabServiceImpl.java index e38b06f8..07a8d532 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/service/impl/CrontabServiceImpl.java +++ b/server/like-admin/src/main/java/com/mdd/admin/service/impl/CrontabServiceImpl.java @@ -3,6 +3,7 @@ package com.mdd.admin.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.mdd.admin.config.quartz.QuartzUtils; import com.mdd.admin.service.ICrontabService; import com.mdd.admin.validate.CrontabCreateValidate; import com.mdd.admin.validate.CrontabUpdateValidate; @@ -11,12 +12,15 @@ import com.mdd.admin.vo.CrontabDetailVo; import com.mdd.admin.vo.CrontabListedVo; import com.mdd.common.core.PageResult; import com.mdd.common.entity.Crontab; -import com.mdd.common.entity.server.Sys; import com.mdd.common.mapper.CrontabMapper; +import com.mdd.common.utils.TimeUtil; +import org.quartz.*; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; +import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.LinkedList; import java.util.List; @@ -27,9 +31,27 @@ import java.util.List; @Service public class CrontabServiceImpl implements ICrontabService { + @Resource + Scheduler scheduler; + @Resource CrontabMapper crontabMapper; + /** + * 项目启动初始化任务 + * + * @author fzr + * @throws SchedulerException 异常 + */ + @PostConstruct + public void init() throws SchedulerException { + scheduler.clear(); + List jobs = crontabMapper.selectList(new QueryWrapper().eq("is_delete", 0)); + for (Crontab crontab : jobs) { + QuartzUtils.createScheduleJob(scheduler, crontab); + } + } + /** * 计划任务列表 * @@ -52,6 +74,8 @@ public class CrontabServiceImpl implements ICrontabService { CrontabListedVo vo = new CrontabListedVo(); BeanUtils.copyProperties(crontab, vo); + vo.setStartTime(crontab.getStartTime()<=0?"-": TimeUtil.timestampToDate(crontab.getStartTime())); + vo.setEndTime(crontab.getEndTime()<=0?"-": TimeUtil.timestampToDate(crontab.getEndTime())); list.add(vo); } @@ -87,16 +111,21 @@ public class CrontabServiceImpl implements ICrontabService { * @param createValidate 参数 */ @Override - public void add(CrontabCreateValidate createValidate) { + @Transactional + public void add(CrontabCreateValidate createValidate) throws SchedulerException { Crontab crontab = new Crontab(); crontab.setName(createValidate.getName()); crontab.setCommand(createValidate.getCommand()); crontab.setRules(createValidate.getRules()); crontab.setStatus(createValidate.getStatus()); crontab.setRemark(createValidate.getRemark()); + crontab.setStrategy(createValidate.getStrategy()); + crontab.setConcurrent(createValidate.getConcurrent()); crontab.setCreateTime(System.currentTimeMillis() / 1000); crontab.setUpdateTime(System.currentTimeMillis() / 1000); crontabMapper.insert(crontab); + + QuartzUtils.createScheduleJob(scheduler, crontab); } /** @@ -106,7 +135,8 @@ public class CrontabServiceImpl implements ICrontabService { * @param updateValidate 参数 */ @Override - public void edit(CrontabUpdateValidate updateValidate) { + @Transactional + public void edit(CrontabUpdateValidate updateValidate) throws SchedulerException { Crontab crontab = crontabMapper.selectOne( new QueryWrapper() .eq("id", updateValidate.getId()) @@ -117,15 +147,27 @@ public class CrontabServiceImpl implements ICrontabService { crontab.setName(updateValidate.getName()); crontab.setCommand(updateValidate.getCommand()); + crontab.setGroups(updateValidate.getGroups()); crontab.setRules(updateValidate.getRules()); crontab.setStatus(updateValidate.getStatus()); crontab.setRemark(updateValidate.getRemark()); + crontab.setStrategy(updateValidate.getStrategy()); + crontab.setConcurrent(updateValidate.getConcurrent()); crontab.setUpdateTime(System.currentTimeMillis() / 1000); crontabMapper.updateById(crontab); + + QuartzUtils.createScheduleJob(scheduler, crontab); } + /** + * 计划任务删除 + * + * @author fzr + * @param id 主键 + */ @Override - public void del(Integer id) { + @Transactional + public void del(Integer id) throws SchedulerException { Crontab crontab = crontabMapper.selectOne( new QueryWrapper() .eq("id", id) @@ -137,6 +179,8 @@ public class CrontabServiceImpl implements ICrontabService { crontab.setIsDelete(1); crontab.setDeleteTime(System.currentTimeMillis() / 1000); crontabMapper.updateById(crontab); + + scheduler.deleteJob(QuartzUtils.getJobKey(crontab.getId(), crontab.getGroups())); } } diff --git a/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabCreateValidate.java b/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabCreateValidate.java index 1837b368..10157b90 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabCreateValidate.java +++ b/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabCreateValidate.java @@ -2,6 +2,7 @@ package com.mdd.admin.validate; import com.mdd.common.validator.annotation.IntegerContains; import lombok.Data; +import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotNull; import java.io.Serializable; @@ -20,9 +21,19 @@ public class CrontabCreateValidate implements Serializable { @NotNull(message = "rules参数缺失") private String rules; + @Length(max = 200, message = "remark参数不能超出200个字符") + private String remark; + + @NotNull(message = "status参数缺失") @IntegerContains(values = {1, 2, 3}, message = "status参数取值异常") private Integer status; - private String remark; + @NotNull(message = "strategy参数缺失") + @IntegerContains(values = {1, 2, 3}, message = "strategy参数取值异常") + private Integer strategy; + + @NotNull(message = "concurrent参数缺失") + @IntegerContains(values = {0, 1}, message = "concurrent参数取值异常") + private Integer concurrent; } diff --git a/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabUpdateValidate.java b/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabUpdateValidate.java index 8d4c2c68..e5096ee8 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabUpdateValidate.java +++ b/server/like-admin/src/main/java/com/mdd/admin/validate/CrontabUpdateValidate.java @@ -3,6 +3,7 @@ package com.mdd.admin.validate; import com.mdd.common.validator.annotation.IDMust; import com.mdd.common.validator.annotation.IntegerContains; import lombok.Data; +import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotNull; import java.io.Serializable; @@ -15,6 +16,9 @@ public class CrontabUpdateValidate implements Serializable { @IDMust(message = "id参数必传且需大于0") private Integer id; + @NotNull(message = "groups参数缺失") + private String groups; + @NotNull(message = "name参数缺失") private String name; @@ -24,9 +28,19 @@ public class CrontabUpdateValidate implements Serializable { @NotNull(message = "rules参数缺失") private String rules; + @Length(max = 200, message = "remark参数不能超出200个字符") + private String remark; + + @NotNull(message = "status参数缺失") @IntegerContains(values = {1, 2, 3}, message = "status参数取值异常") private Integer status; - private String remark; + @NotNull(message = "strategy参数缺失") + @IntegerContains(values = {1, 2, 3}, message = "strategy参数取值异常") + private Integer strategy; + + @NotNull(message = "concurrent参数缺失") + @IntegerContains(values = {0, 1}, message = "concurrent参数取值异常") + private Integer concurrent; } diff --git a/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabDetailVo.java b/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabDetailVo.java index 844a4b6c..ed9b31c0 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabDetailVo.java +++ b/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabDetailVo.java @@ -4,15 +4,23 @@ import lombok.Data; import java.io.Serializable; +/** + * 计划任务详情Vo + */ @Data public class CrontabDetailVo implements Serializable { private static final long serialVersionUID = 1L; - private Integer id; - private String name; - private String command; - private String rules; - private Integer status; + private Integer id; // 任务主键 + private String groups; // 任务分组 + private String name; // 任务名称 + private String command; // 执行命令 + private String rules; // 执行规则 + private String remark; // 备注信息 + private String error; // 错误信息 + private Integer status; // 执行状态: 1=正在运行, 2=任务停止, 3=发生错误 + private Integer strategy; // 执行策略: 1=立即执行, 2=执行一次, 3=放弃执行 + private Integer concurrent; // 并发执行: 0=否, 1=是 } diff --git a/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabListedVo.java b/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabListedVo.java index a8a5c0e3..adce440d 100644 --- a/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabListedVo.java +++ b/server/like-admin/src/main/java/com/mdd/admin/vo/CrontabListedVo.java @@ -4,15 +4,25 @@ import lombok.Data; import java.io.Serializable; +/** + * 计划任务列表Vo + */ @Data public class CrontabListedVo implements Serializable { private static final long serialVersionUID = 1L; - private Integer id; - private String name; - private String command; - private String rules; - private Integer status; + private Integer id; // 执行ID + private String groups; // 执行分组 + private String name; // 执行名称 + private String command; // 执行命令 + private String rules; // 执行规则 + private String error; // 错误信息 + private Integer status; // 执行状态: 1=正在运行, 2=任务停止, 3=发生错误 + private Integer strategy; // 执行策略: 1=立即执行, 2=执行一次, 3=放弃执行 + private Integer concurrent; // 并发执行: 0=否, 1=是 + private String startTime; // 开始时间 + private String endTime; // 结束时间 + private Long taskTime; // 执行耗时 } diff --git a/server/like-common/src/main/java/com/mdd/common/entity/Crontab.java b/server/like-common/src/main/java/com/mdd/common/entity/Crontab.java index 74938e8a..6b111bf0 100644 --- a/server/like-common/src/main/java/com/mdd/common/entity/Crontab.java +++ b/server/like-common/src/main/java/com/mdd/common/entity/Crontab.java @@ -15,15 +15,22 @@ public class Crontab implements Serializable { private static final long serialVersionUID = 1L; @TableId(value="id", type= IdType.AUTO) - private Integer id; // 主键 - private String name; // 任务名称 - private String command; // 任务命令 - private String rules; // 任务规则 - private String remark; // 备注信息 - private Integer status; // 执行状态:1=运行, 2-停止, 3=错误 - private Integer isDelete; // 是否删除: 0=否, 1=是 - private Long createTime; // 创建时间 - private Long updateTime; // 更新时间 - private Long deleteTime; // 删除时间 + private Integer id; // 主键 + private String name; // 任务名称 + private String groups; // 任务分组 + private String command; // 执行命令 + private String rules; // 执行规则 + private String remark; // 备注信息 + private String error; // 错误信息 + private Integer status; // 执行状态: 1=正在运行, 2=任务停止, 3=发生错误 + private Integer strategy; // 执行策略: 1=立即执行, 2=执行一次, 3=放弃执行 + private Integer concurrent; // 并发执行: 0=否, 1=是 + private Integer isDelete; // 是否删除: 0=否, 1=是 + private Long startTime; // 开始时间 + private Long endTime; // 结束时间 + private Long taskTime; // 任务耗时 + private Long createTime; // 创建时间 + private Long updateTime; // 更新时间 + private Long deleteTime; // 删除时间 } diff --git a/server/pom.xml b/server/pom.xml index f9510a62..3f6b82bf 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -42,7 +42,9 @@ 1.2.4 6.1.2 1.32.0 + 1.32.0 3.1.3 + 2.3.2 7.9.5 5.6.54 @@ -121,6 +123,20 @@ ${sa-token.version} + + + cn.dev33 + sa-token-dao-redis-jackson + ${sa-token-redis.version} + + + + + org.quartz-scheduler + quartz + ${quartz-scheduler.version} + + com.google.code.gson