From 9039a83732130921613eb7e781fac9d43ba247f1 Mon Sep 17 00:00:00 2001 From: janHe <975532442@qq.com> Date: Mon, 2 Sep 2019 17:57:27 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E5=BC=95=E5=85=A5quartz=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=20=E5=8F=AF=E4=BB=A5=E5=8A=A8=E6=80=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 10 +- .../test/common/listener/ConfigListener.java | 49 ++++++ .../controller/admin/QuartzController.java | 91 +++++++++++ .../java/com/fc/test/quartz/QuartzConfig.java | 29 ++++ .../com/fc/test/quartz/QuartzDefault.java | 81 ++++++++++ .../com/fc/test/quartz/QuartzScheduler.java | 150 ++++++++++++++++++ .../com/fc/test/quartz/job/TestQuartzJob.java | 22 +++ .../shiro/config/ShiroFilterMapFactory.java | 3 + 8 files changed, 434 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/fc/test/common/listener/ConfigListener.java create mode 100644 src/main/java/com/fc/test/controller/admin/QuartzController.java create mode 100644 src/main/java/com/fc/test/quartz/QuartzConfig.java create mode 100644 src/main/java/com/fc/test/quartz/QuartzDefault.java create mode 100644 src/main/java/com/fc/test/quartz/QuartzScheduler.java create mode 100644 src/main/java/com/fc/test/quartz/job/TestQuartzJob.java diff --git a/pom.xml b/pom.xml index f4937ac..4a8faa1 100644 --- a/pom.xml +++ b/pom.xml @@ -207,7 +207,15 @@ 1.8 system ${basedir}/lib/ueditor-1.1.2.jar - + + + + + + org.quartz-scheduler + quartz + 2.2.1 + diff --git a/src/main/java/com/fc/test/common/listener/ConfigListener.java b/src/main/java/com/fc/test/common/listener/ConfigListener.java new file mode 100644 index 0000000..4cc8e7a --- /dev/null +++ b/src/main/java/com/fc/test/common/listener/ConfigListener.java @@ -0,0 +1,49 @@ +package com.fc.test.common.listener; + +import com.fc.test.quartz.QuartzScheduler; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; +import java.util.HashMap; +import java.util.Map; + +/** + * @Auther: Jan 橙寂 + * @Date: 2019-7-1 11:06 + * @Description: + * @Version: 1.0 + */ +@WebListener +public class ConfigListener implements ServletContextListener { + + @Autowired + private QuartzScheduler scheduler; + private static Map conf = new HashMap<>(); + + public static Map getConf() { + return conf; + } + + @Override + public void contextDestroyed(ServletContextEvent arg0) { + conf.clear(); + } + + @Override + public void contextInitialized(ServletContextEvent evt) { + ServletContext sc = evt.getServletContext(); + + //项目发布,当前运行环境的绝对路径 + conf.put("realPath", sc.getRealPath("/").replaceFirst("/", "")); + + //servletContextPath,默认"" + conf.put("contextPath", sc.getContextPath()); + + //开启定时调度 + // scheduler.startJob(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/fc/test/controller/admin/QuartzController.java b/src/main/java/com/fc/test/controller/admin/QuartzController.java new file mode 100644 index 0000000..9e6980a --- /dev/null +++ b/src/main/java/com/fc/test/controller/admin/QuartzController.java @@ -0,0 +1,91 @@ +package com.fc.test.controller.admin; + +import com.fc.test.common.base.BaseController; +import com.fc.test.model.custom.TitleVo; +import com.fc.test.quartz.QuartzScheduler; +import io.swagger.annotations.Api; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +@Controller +@Api(value = "任务调度类") +@RequestMapping("quartz") +/** + * @Auther: Jan 橙寂 + * @Date: 2019-7-1 11:06 + * @Description: + * @Version: 1.0 + */ +public class QuartzController extends BaseController{ + + + @Autowired + private QuartzScheduler scheduler; + + + /** + * 调用这个方法开启任务调度 + * @param model + * @return + */ + @GetMapping("start") + @ResponseBody + public String start(Model model) + { + scheduler.startJob(); + return "success"; + } + + + /** + * 调用这个方法停止任务调度 + * @param model + * @return + */ + @GetMapping("stop") + @ResponseBody + public Object stop(Model model,String taskName,String groupName) + { + return scheduler.pauseJob(taskName,groupName); + + } + + + /** + * 调用这个方法继续任务调度 + * @param model + * @return + */ + @GetMapping("resume") + @ResponseBody + public Object resume(Model model,String taskName,String groupName) + { + return scheduler.resumeJob(taskName,groupName); + + } + + + /** + * 修改定时器 + * @param model + * @return + */ + @GetMapping("update") + @ResponseBody + public String update(Model model,String taskName,String groupName,String cron) + { + try { + scheduler.modifyJob(taskName,groupName,cron); + } catch (SchedulerException e) { + e.printStackTrace(); + return "fail"; + } + return "success"; + } + +} diff --git a/src/main/java/com/fc/test/quartz/QuartzConfig.java b/src/main/java/com/fc/test/quartz/QuartzConfig.java new file mode 100644 index 0000000..02ed832 --- /dev/null +++ b/src/main/java/com/fc/test/quartz/QuartzConfig.java @@ -0,0 +1,29 @@ +package com.fc.test.quartz; + +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.quartz.SchedulerFactory; +import org.quartz.impl.StdSchedulerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * @CLASSNAME QuartzConfig + * @Description Quartz配置类 + * @Auther Jan 橙寂 + * @DATE 2019/9/2 0002 15:21 + */ +@Configuration +public class QuartzConfig { + + /** + * 初始注入scheduler + * @return + * @throws SchedulerException + */ + @Bean + public Scheduler scheduler() throws SchedulerException{ + SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory(); + return schedulerFactoryBean.getScheduler(); + } +} diff --git a/src/main/java/com/fc/test/quartz/QuartzDefault.java b/src/main/java/com/fc/test/quartz/QuartzDefault.java new file mode 100644 index 0000000..bcc2419 --- /dev/null +++ b/src/main/java/com/fc/test/quartz/QuartzDefault.java @@ -0,0 +1,81 @@ +package com.fc.test.quartz; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.Scheduled; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * @CLASSNAME QuartzDefault + * @Description springboot 默认的定时调度配置(不需要任何包)但是不能动态的开启(关闭)或者添加 任务 + * @Auther Jan 橙寂 + * @DATE 2019/9/2 0002 14:46 + */ +@Configuration +//@EnableScheduling //开启定时调度的开关 +public class QuartzDefault { + + + //配置表达式 现在这个是每一分钟执行一次 + @Scheduled(cron = "0 0/1 * * * *") + public void timer(){ + //获取当前时间 + LocalDateTime localDateTime = LocalDateTime.now(); + System.out.println("当前时间为:" + localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + } + + + /*按顺序依次为 + 1 秒(0~59) + 2 分钟(0~59) + 3 小时(0~23) + 4 天(0~31) + 5 月(0~11) + 6 星期(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) + 7.年份(1970-2099) + 其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符。由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?. + 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 + 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 + 0 0 12 ? * WED 表示每个星期三中午12点 + "0 0 12 * * ?" 每天中午12点触发 + "0 15 10 ? * *" 每天上午10:15触发 + "0 15 10 * * ?" 每天上午10:15触发 + "0 15 10 * * ? *" 每天上午10:15触发 + "0 15 10 * * ? 2005" 2005年的每天上午10:15触发 + "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 + "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 + "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 + "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 + "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 + "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 + "0 15 10 15 * ?" 每月15日上午10:15触发 + "0 15 10 L * ?" 每月最后一日的上午10:15触发 + "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 + "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 + "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 + 有些子表达式能包含一些范围或列表 + 例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT” + “*”字符代表所有可能的值 + “/”字符用来指定数值的增量 + 例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟 + 在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样 + “?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值 + 当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?” + “L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写 + 如果在“L”前有具体的内容,它就具有其他的含义了。例如:“6L”表示这个月的倒数第6天 + 注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题 + W 字符代表着平日(Mon-Fri),并且仅能用于日域中。它用来指定离指定日的最近的一个平日。大部分的商业处理都是基于工作周的,所以 W 字符可能是非常重要的。 + 例如,日域中的 15W 意味着 "离该月15号的最近一个平日。" 假如15号是星期六,那么 trigger 会在14号(星期五)触发,因为星期四比星期一离15号更近。 + C:代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。 + 字段 允许值 允许的特殊字符 + 秒 0-59 , - * / + 分 0-59 , - * / + 小时 0-23 , - * / + 日期 1-31 , - * ? / L W C + 月份 1-12 或者 JAN-DEC , - * / + 星期 1-7 或者 SUN-SAT , - * ? / L C # + 年(可选) 留空, 1970-2099 , - * /*/ + + +} diff --git a/src/main/java/com/fc/test/quartz/QuartzScheduler.java b/src/main/java/com/fc/test/quartz/QuartzScheduler.java new file mode 100644 index 0000000..4261b14 --- /dev/null +++ b/src/main/java/com/fc/test/quartz/QuartzScheduler.java @@ -0,0 +1,150 @@ +package com.fc.test.quartz; + +import com.fc.test.quartz.job.TestQuartzJob; +import org.quartz.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import java.util.Date; + +/** + * @CLASSNAME QuartzConfig + * @Description Quartz配置类 + * @Auther Jan 橙寂 + * @DATE 2019/9/2 0002 15:21 + */ +@Configuration +public class QuartzScheduler { + + @Autowired + private Scheduler scheduler; + + //这个东西可以放在配置文件中 + //cron表达式 一分钟执行一次 + private final String TEST_CRON="0 0/1 * * * ?"; + + /** + * 开始工作 + */ + public void startJob() + { + try { + initTestJob("test","test"); + scheduler.start(); + + } catch (SchedulerException e) { + e.printStackTrace(); + System.out.println("任务掉度开启失败"); + } + + } + + /** + * 初始化一个任务 + * @param taskName + * @param groupName + * @throws SchedulerException + */ + private void initTestJob(String taskName,String groupName) throws SchedulerException { + if (!checkJobExists(taskName,groupName)) { + // 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例 + // JobDetail 是具体Job实例 + JobDetail jobDetail = JobBuilder.newJob(TestQuartzJob.class).withIdentity(taskName, groupName).build(); + // 基于表达式构建触发器 + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(TEST_CRON); + // CronTrigger表达式触发器 继承于Trigger + // TriggerBuilder 用于构建触发器实例 + CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskName, groupName) + .withSchedule(cronScheduleBuilder.withMisfireHandlingInstructionDoNothing()).build(); + scheduler.scheduleJob(jobDetail, cronTrigger); + } + } + + + + /** + * 修改某个任务的执行时间 + * + * @param name + * @param group + * @param cron 表达式 + * @return + * @throws SchedulerException + */ + public boolean modifyJob(String name, String group, String cron) throws SchedulerException { + Date date = null; + TriggerKey triggerKey = new TriggerKey(name, group); + CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); + if (cronTrigger != null) { + String oldTime = cronTrigger.getCronExpression(); + if (!oldTime.equalsIgnoreCase(cron)) { + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron); + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group) + .withSchedule(cronScheduleBuilder).build(); + date = scheduler.rescheduleJob(triggerKey, trigger); + } + } + return date==null?false:true; + } + + + /** + * 继续执行定时任务 + * @param taskName + * @param groupName + * @return + */ + public boolean resumeJob(String taskName, String groupName) { + boolean bl = false; + try { + //JobKey定义了job的名称和组别 + JobKey jobKey = JobKey.jobKey(taskName, groupName); + if (jobKey != null) { + //继续任务 + scheduler.resumeJob(jobKey); + bl = true; + } + } catch (SchedulerException e) { + System.out.println("继续调度任务异常:" + e); + } catch (Exception e) { + System.out.println("继续调度任务异常:" + e); + } + return bl; + } + + /** + * 暂停任务 + * @param taskName + * @param groupName + * @return + */ + public boolean pauseJob(String taskName, String groupName) { + boolean bl = false; + try { + //JobKey定义了job的名称和组别 + JobKey jobKey = JobKey.jobKey(taskName, groupName); + //暂停任务 + if (jobKey != null) { + scheduler.pauseJob(jobKey); + bl = true; + } + } catch (SchedulerException e) { + // getLog().info("暂停调度任务异常:" + e); + } catch (Exception e) { + // getLog().info("暂停调度任务异常:"+ e); + } + return bl; + } + + /** + * 判断定时任务是否已经存在 + * @param taskName + * @param groupName + * @return + * @throws SchedulerException + */ + public boolean checkJobExists(String taskName, String groupName) throws SchedulerException { + TriggerKey triggerKey = TriggerKey.triggerKey(taskName, groupName); + return scheduler.checkExists(triggerKey); + } +} diff --git a/src/main/java/com/fc/test/quartz/job/TestQuartzJob.java b/src/main/java/com/fc/test/quartz/job/TestQuartzJob.java new file mode 100644 index 0000000..4e84246 --- /dev/null +++ b/src/main/java/com/fc/test/quartz/job/TestQuartzJob.java @@ -0,0 +1,22 @@ +package com.fc.test.quartz.job; + +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * @CLASSNAME TestQuartzJob + * @Description 定时调度具体工作类 + * @Auther Jan 橙寂 + * @DATE 2019/9/2 0002 15:33 + */ +@Component +public class TestQuartzJob implements Job { + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + System.out.println(new Date()+"测试定时调度正在执行"); + } +} diff --git a/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java b/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java index c614831..c7f8cc1 100644 --- a/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java +++ b/src/main/java/com/fc/test/shiro/config/ShiroFilterMapFactory.java @@ -48,6 +48,9 @@ user:例如/admins/user/**=user没有参数表示必须存在用户,当登入 filterChainDefinitionMap.put("/druid/**", "anon"); //释放websocket请求 filterChainDefinitionMap.put("/websocket", "anon"); + + //任务调度暂时放开 + filterChainDefinitionMap.put("/quartz/**", "anon"); // //对所有页面进行认证 -- Gitee From 6a36e28d2d2a25069fcbd95f75e423e5384a2756 Mon Sep 17 00:00:00 2001 From: janHe <975532442@qq.com> Date: Mon, 2 Sep 2019 17:58:19 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=BC=95=E5=85=A5quartz=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=20=E5=8F=AF=E4=BB=A5=E5=8A=A8=E6=80=81=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-prod.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 495f0f1..f3a99e1 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -2,7 +2,7 @@ spring : datasource : driverClassName : com.mysql.jdbc.Driver - url : jdbc:mysql://192.168.1.28:13306/springbootv2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false + url : jdbc:mysql://localhost:3306/springbootv2?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false username : root password : root hikari: -- Gitee From 7795512ca4760d192295eb384dbfabf14231d5c8 Mon Sep 17 00:00:00 2001 From: janHe <975532442@qq.com> Date: Sun, 8 Sep 2019 10:58:44 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BA=86=E4=B8=8Bquartz?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=201.=E5=8F=AF=E5=8A=A8=E6=80=81=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=202.=E5=8F=AF=E4=BB=A5=E6=8C=87=E5=AE=9A=E7=94=B1spri?= =?UTF-8?q?ng=E7=AE=A1=E7=90=86=E7=9A=84=E7=B1=BB=E7=9A=84=E6=9F=90?= =?UTF-8?q?=E4=B8=AA=E6=96=B9=E6=B3=95=203.=E6=94=AF=E6=8C=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=BC=82=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/common/listener/ConfigListener.java | 6 +- .../test/common/quartz/AbstractQuartzJob.java | 105 +++++ .../fc/test/common/quartz/QuartzDefault.java | 81 ---- .../QuartzDisallowConcurrentExecution.java | 22 + .../common/quartz/QuartzJobExecution.java | 21 + .../test/common/quartz/QuartzScheduler.java | 167 ++++++-- .../test/common/quartz/ScheduleConstants.java | 66 +++ .../fc/test/common/quartz/entity/SysJob.java | 132 ++++++ .../test/common/quartz/entity/SysJobLog.java | 147 +++++++ .../test/common/quartz/job/TestQuartzJob.java | 21 - .../fc/test/common/quartz/task/RyTask.java | 33 ++ .../common/quartz/utils/JobInvokeUtil.java | 183 ++++++++ .../test/common/quartz/utils/SpringUtils.java | 114 +++++ .../test/common/quartz/utils/StringUtils.java | 400 ++++++++++++++++++ .../controller/admin/QuartzController.java | 49 +-- .../java/com/fc/test/quartz/QuartzConfig.java | 29 -- .../com/fc/test/quartz/QuartzDefault.java | 81 ---- .../com/fc/test/quartz/QuartzScheduler.java | 150 ------- .../com/fc/test/quartz/job/TestQuartzJob.java | 22 - 19 files changed, 1370 insertions(+), 459 deletions(-) create mode 100644 src/main/java/com/fc/test/common/quartz/AbstractQuartzJob.java delete mode 100644 src/main/java/com/fc/test/common/quartz/QuartzDefault.java create mode 100644 src/main/java/com/fc/test/common/quartz/QuartzDisallowConcurrentExecution.java create mode 100644 src/main/java/com/fc/test/common/quartz/QuartzJobExecution.java create mode 100644 src/main/java/com/fc/test/common/quartz/ScheduleConstants.java create mode 100644 src/main/java/com/fc/test/common/quartz/entity/SysJob.java create mode 100644 src/main/java/com/fc/test/common/quartz/entity/SysJobLog.java delete mode 100644 src/main/java/com/fc/test/common/quartz/job/TestQuartzJob.java create mode 100644 src/main/java/com/fc/test/common/quartz/task/RyTask.java create mode 100644 src/main/java/com/fc/test/common/quartz/utils/JobInvokeUtil.java create mode 100644 src/main/java/com/fc/test/common/quartz/utils/SpringUtils.java create mode 100644 src/main/java/com/fc/test/common/quartz/utils/StringUtils.java delete mode 100644 src/main/java/com/fc/test/quartz/QuartzConfig.java delete mode 100644 src/main/java/com/fc/test/quartz/QuartzDefault.java delete mode 100644 src/main/java/com/fc/test/quartz/QuartzScheduler.java delete mode 100644 src/main/java/com/fc/test/quartz/job/TestQuartzJob.java diff --git a/src/main/java/com/fc/test/common/listener/ConfigListener.java b/src/main/java/com/fc/test/common/listener/ConfigListener.java index 4cc8e7a..6b3761d 100644 --- a/src/main/java/com/fc/test/common/listener/ConfigListener.java +++ b/src/main/java/com/fc/test/common/listener/ConfigListener.java @@ -1,6 +1,6 @@ package com.fc.test.common.listener; -import com.fc.test.quartz.QuartzScheduler; +import com.fc.test.common.quartz.QuartzScheduler; import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.ServletContext; @@ -19,8 +19,6 @@ import java.util.Map; @WebListener public class ConfigListener implements ServletContextListener { - @Autowired - private QuartzScheduler scheduler; private static Map conf = new HashMap<>(); public static Map getConf() { @@ -42,8 +40,6 @@ public class ConfigListener implements ServletContextListener { //servletContextPath,默认"" conf.put("contextPath", sc.getContextPath()); - //开启定时调度 - // scheduler.startJob(); } } \ No newline at end of file diff --git a/src/main/java/com/fc/test/common/quartz/AbstractQuartzJob.java b/src/main/java/com/fc/test/common/quartz/AbstractQuartzJob.java new file mode 100644 index 0000000..701cbc2 --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/AbstractQuartzJob.java @@ -0,0 +1,105 @@ +package com.fc.test.common.quartz; + +import cn.hutool.core.exceptions.ExceptionUtil; +import com.fc.test.common.quartz.entity.SysJob; +import com.fc.test.common.quartz.entity.SysJobLog; +import com.fc.test.common.quartz.utils.StringUtils; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; + +import java.util.Date; + +/** + * @CLASSNAME AbstractQuartzJob + * @Description + * @Auther Jan 橙寂 + * @DATE 2019/9/5 0005 15:05 + */ + +public abstract class AbstractQuartzJob implements Job { + + private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class); + + /** + * 线程本地变量 + */ + private static ThreadLocal threadLocal = new ThreadLocal<>(); + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException + { + SysJob sysJob = new SysJob(); + BeanUtils.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysJob); + try + { + before(context, sysJob); + if (sysJob != null) + { + doExecute(context, sysJob); + } + after(context, sysJob, null); + } + catch (Exception e) + { + log.error("任务执行异常 - :", e); + after(context, sysJob, e); + } + } + + /** + * 执行前 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void before(JobExecutionContext context, SysJob sysJob) + { + threadLocal.set(new Date()); + } + + /** + * 执行后 + * + * @param context 工作执行上下文对象 + * @param sysJob 系统计划任务 + */ + protected void after(JobExecutionContext context, SysJob sysJob, Exception e) + { + Date startTime = threadLocal.get(); + threadLocal.remove(); + + final SysJobLog sysJobLog = new SysJobLog(); + sysJobLog.setJobName(sysJob.getJobName()); + sysJobLog.setJobGroup(sysJob.getJobGroup()); + sysJobLog.setInvokeTarget(sysJob.getInvokeTarget()); + sysJobLog.setStartTime(startTime); + sysJobLog.setEndTime(new Date()); + long runMs = sysJobLog.getEndTime().getTime() - sysJobLog.getStartTime().getTime(); + sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); + if (e != null) + { + sysJobLog.setStatus(ScheduleConstants.FAIL_STATUS); + String errorMsg = StringUtils.substring(ExceptionUtil.getMessage(e), 0, 2000); + sysJobLog.setExceptionInfo(errorMsg); + } + else + { + sysJobLog.setStatus(ScheduleConstants.SUCCESS_STATUS); + } + + // 这里获取service然后插入库中 + System.out.println(sysJob.toString()); + // SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog); + } + + /** + * 子类去实现 + * @param jobExecutionContext + * @param sysJob + */ + protected abstract void doExecute(JobExecutionContext jobExecutionContext, SysJob sysJob) throws Exception; +} diff --git a/src/main/java/com/fc/test/common/quartz/QuartzDefault.java b/src/main/java/com/fc/test/common/quartz/QuartzDefault.java deleted file mode 100644 index 4dab396..0000000 --- a/src/main/java/com/fc/test/common/quartz/QuartzDefault.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.fc.test.common.quartz; - -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.Scheduled; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -/** - * @CLASSNAME QuartzDefault - * @Description springboot 默认的定时调度配置(不需要任何包)但是不能动态的开启(关闭)或者添加 任务 - * @Auther Jan 橙寂 - * @DATE 2019/9/2 0002 14:46 - */ -@Configuration -//@EnableScheduling //开启定时调度的开关 -public class QuartzDefault { - - - //配置表达式 现在这个是每一分钟执行一次 - @Scheduled(cron = "0 0/1 * * * *") - public void timer(){ - //获取当前时间 - LocalDateTime localDateTime = LocalDateTime.now(); - System.out.println("当前时间为:" + localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); - } - - - /*按顺序依次为 - 1 秒(0~59) - 2 分钟(0~59) - 3 小时(0~23) - 4 天(0~31) - 5 月(0~11) - 6 星期(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) - 7.年份(1970-2099) - 其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符。由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?. - 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 - 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 - 0 0 12 ? * WED 表示每个星期三中午12点 - "0 0 12 * * ?" 每天中午12点触发 - "0 15 10 ? * *" 每天上午10:15触发 - "0 15 10 * * ?" 每天上午10:15触发 - "0 15 10 * * ? *" 每天上午10:15触发 - "0 15 10 * * ? 2005" 2005年的每天上午10:15触发 - "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 - "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 - "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 - "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 - "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 - "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 - "0 15 10 15 * ?" 每月15日上午10:15触发 - "0 15 10 L * ?" 每月最后一日的上午10:15触发 - "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 - "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 - "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 - 有些子表达式能包含一些范围或列表 - 例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT” - “*”字符代表所有可能的值 - “/”字符用来指定数值的增量 - 例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟 - 在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样 - “?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值 - 当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?” - “L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写 - 如果在“L”前有具体的内容,它就具有其他的含义了。例如:“6L”表示这个月的倒数第6天 - 注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题 - W 字符代表着平日(Mon-Fri),并且仅能用于日域中。它用来指定离指定日的最近的一个平日。大部分的商业处理都是基于工作周的,所以 W 字符可能是非常重要的。 - 例如,日域中的 15W 意味着 "离该月15号的最近一个平日。" 假如15号是星期六,那么 trigger 会在14号(星期五)触发,因为星期四比星期一离15号更近。 - C:代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。 - 字段 允许值 允许的特殊字符 - 秒 0-59 , - * / - 分 0-59 , - * / - 小时 0-23 , - * / - 日期 1-31 , - * ? / L W C - 月份 1-12 或者 JAN-DEC , - * / - 星期 1-7 或者 SUN-SAT , - * ? / L C # - 年(可选) 留空, 1970-2099 , - * /*/ - - -} diff --git a/src/main/java/com/fc/test/common/quartz/QuartzDisallowConcurrentExecution.java b/src/main/java/com/fc/test/common/quartz/QuartzDisallowConcurrentExecution.java new file mode 100644 index 0000000..2de836b --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/QuartzDisallowConcurrentExecution.java @@ -0,0 +1,22 @@ +package com.fc.test.common.quartz; + +import com.fc.test.common.quartz.entity.SysJob; +import com.fc.test.common.quartz.utils.JobInvokeUtil; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.JobExecutionContext; + +/** + * 定时任务处理(禁止并发执行) + * + * @author jan 橙寂 + * + */ +@DisallowConcurrentExecution +public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception + { + JobInvokeUtil.invokeMethod(sysJob); + } +} diff --git a/src/main/java/com/fc/test/common/quartz/QuartzJobExecution.java b/src/main/java/com/fc/test/common/quartz/QuartzJobExecution.java new file mode 100644 index 0000000..5038d34 --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/QuartzJobExecution.java @@ -0,0 +1,21 @@ +package com.fc.test.common.quartz; + +import com.fc.test.common.quartz.entity.SysJob; +import com.fc.test.common.quartz.utils.JobInvokeUtil; +import org.quartz.JobExecutionContext; + +/** + * 定时任务处理(允许并发执行) + * + * @author jan 橙寂 + * + */ +public class QuartzJobExecution extends AbstractQuartzJob +{ + @Override + protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception { + JobInvokeUtil.invokeMethod(sysJob); + } + + +} diff --git a/src/main/java/com/fc/test/common/quartz/QuartzScheduler.java b/src/main/java/com/fc/test/common/quartz/QuartzScheduler.java index d0748b9..aeae34d 100644 --- a/src/main/java/com/fc/test/common/quartz/QuartzScheduler.java +++ b/src/main/java/com/fc/test/common/quartz/QuartzScheduler.java @@ -1,11 +1,11 @@ package com.fc.test.common.quartz; +import com.fc.test.common.quartz.entity.SysJob; import org.quartz.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; -import com.fc.test.common.quartz.job.TestQuartzJob; -import java.util.Date; +import javax.annotation.PostConstruct; /** * @CLASSNAME QuartzConfig @@ -24,81 +24,123 @@ public class QuartzScheduler { private final String TEST_CRON="0 0/1 * * * ?"; /** - * 开始工作 + * 容器初始化时执行此方法 + * 也就是类初始化的时候 */ - public void startJob() - { - try { - initTestJob("test","test"); - scheduler.start(); - + @PostConstruct + public void init() throws SchedulerException { + //这一块可以从数据库中查 + for (int i=1;i<=5;i++) + { + SysJob job=new SysJob(); + job.setJobId(new Long(i)); + job.setJobName("测试工作"); + job.setJobGroup("quartz"); + job.setCronExpression("0 0/1 * * * ?"); + //并发执行 + job.setConcurrent("0"); + //0启用 + job.setStatus("0"); + //执行的job类 + job.setInvokeTarget("ryTask.runTask2(1,2l,'asa',true,2D)"); + try { + //防止因为数据问题重复创建 + if(checkJobExists(job)) + { + deleteJob(job); + } + createSchedule(job); } catch (SchedulerException e) { e.printStackTrace(); - System.out.println("任务掉度开启失败"); } + } + + start(); } /** - * 初始化一个任务 - * @param taskName - * @param groupName + * 启动定时器 + */ + public void start() +{ + try { + scheduler.start(); + } catch (SchedulerException e) { + e.printStackTrace(); + System.out.println("定时任务执行失败"); + } +} + + + /** + * 创建一个定时任务 + * @param job * @throws SchedulerException */ - private void initTestJob(String taskName,String groupName) throws SchedulerException { - if (!checkJobExists(taskName,groupName)) { + private void createSchedule(SysJob job) throws SchedulerException { + if (!checkJobExists(job)) { + //获取指定的job工作类 + Class jobClass = getQuartzJobClass(job); // 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例 // JobDetail 是具体Job实例 - JobDetail jobDetail = JobBuilder.newJob(TestQuartzJob.class).withIdentity(taskName, groupName).build(); + JobDetail jobDetail = JobBuilder.newJob((Class) jobClass).withIdentity(ScheduleConstants.TASK_PRE+job.getJobId(),job.getJobName()).build(); // 基于表达式构建触发器 CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(TEST_CRON); // CronTrigger表达式触发器 继承于Trigger // TriggerBuilder 用于构建触发器实例 - CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskName, groupName) + CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(ScheduleConstants.TASK_PRE+job.getJobId(),job.getJobName()) .withSchedule(cronScheduleBuilder.withMisfireHandlingInstructionDoNothing()).build(); + + //放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job); + scheduler.scheduleJob(jobDetail, cronTrigger); + + //如果这个工作的状态为1 + if (job.getStatus().equals("1")) + { + pauseJob(job); + } } } + /** - * 修改某个任务的执行时间 - * - * @param name - * @param group - * @param cron 表达式 + * 修改定时任务 + * @param job * @return * @throws SchedulerException */ - public boolean modifyJob(String name, String group, String cron) throws SchedulerException { - Date date = null; - TriggerKey triggerKey = new TriggerKey(name, group); - CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); - if (cronTrigger != null) { - String oldTime = cronTrigger.getCronExpression(); - if (!oldTime.equalsIgnoreCase(cron)) { - CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron); - CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group) - .withSchedule(cronScheduleBuilder).build(); - date = scheduler.rescheduleJob(triggerKey, trigger); + public boolean modifyJob(SysJob job) { + + try { + //先删除 + if(checkJobExists(job)) + { + deleteJob(job); } + createSchedule(job); + } catch (SchedulerException e) { + e.printStackTrace(); + return false; } - return date==null?false:true; + return true; } /** * 继续执行定时任务 - * @param taskName - * @param groupName + * @param job * @return */ - public boolean resumeJob(String taskName, String groupName) { + public boolean resumeJob(SysJob job) { boolean bl = false; try { //JobKey定义了job的名称和组别 - JobKey jobKey = JobKey.jobKey(taskName, groupName); + JobKey jobKey = JobKey.jobKey(ScheduleConstants.TASK_PRE+job.getJobId(), job.getJobGroup()); if (jobKey != null) { //继续任务 scheduler.resumeJob(jobKey); @@ -112,17 +154,39 @@ public class QuartzScheduler { return bl; } + /** + * 删除定时任务 + * @param job + * @return + */ + public boolean deleteJob(SysJob job) { + boolean bl = false; + try { + //JobKey定义了job的名称和组别 + JobKey jobKey = JobKey.jobKey(ScheduleConstants.TASK_PRE+job.getJobId(), job.getJobGroup()); + if (jobKey != null) { + //删除定时任务 + scheduler.deleteJob(jobKey); + bl = true; + } + } catch (SchedulerException e) { + System.out.println("删除调度任务异常:" + e); + } catch (Exception e) { + System.out.println("删除调度任务异常:" + e); + } + return bl; + } + /** * 暂停任务 - * @param taskName - * @param groupName + * @param job * @return */ - public boolean pauseJob(String taskName, String groupName) { + public boolean pauseJob(SysJob job) { boolean bl = false; try { //JobKey定义了job的名称和组别 - JobKey jobKey = JobKey.jobKey(taskName, groupName); + JobKey jobKey = JobKey.jobKey(ScheduleConstants.TASK_PRE+job.getJobId(), job.getJobGroup()); //暂停任务 if (jobKey != null) { scheduler.pauseJob(jobKey); @@ -138,13 +202,24 @@ public class QuartzScheduler { /** * 判断定时任务是否已经存在 - * @param taskName - * @param groupName + * @param job * @return * @throws SchedulerException */ - public boolean checkJobExists(String taskName, String groupName) throws SchedulerException { - TriggerKey triggerKey = TriggerKey.triggerKey(taskName, groupName); + public boolean checkJobExists(SysJob job) throws SchedulerException { + TriggerKey triggerKey = TriggerKey.triggerKey(ScheduleConstants.TASK_PRE+job.getJobId(), job.getJobGroup()); return scheduler.checkExists(triggerKey); } + + + /** + * 获取定时任务的具体执行类 + * @param sysJob + * @return + */ + private static Class getQuartzJobClass(SysJob sysJob) + { + boolean isConcurrent = "0".equals(sysJob.getConcurrent()); + return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class; + } } diff --git a/src/main/java/com/fc/test/common/quartz/ScheduleConstants.java b/src/main/java/com/fc/test/common/quartz/ScheduleConstants.java new file mode 100644 index 0000000..0344c98 --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/ScheduleConstants.java @@ -0,0 +1,66 @@ +package com.fc.test.common.quartz; + +/** + * 任务调度通用常量 + * + * @author jan 橙寂 + */ +public interface ScheduleConstants +{ + public static final String TASK_PRE = "TASK"; + + /** 执行目标key */ + public static final String TASK_PROPERTIES = "TASK_PROPERTIES"; + + /** 默认 */ + public static final String MISFIRE_DEFAULT = "0"; + + /** 立即触发执行 */ + public static final String MISFIRE_IGNORE_MISFIRES = "1"; + + /** 触发一次执行 */ + public static final String MISFIRE_FIRE_AND_PROCEED = "2"; + + /** 不触发立即执行 */ + public static final String MISFIRE_DO_NOTHING = "3"; + + /** + * 失败状态 + */ + public static final String FAIL_STATUS = "1"; + + /** + * 成功状态 + */ + public static final String SUCCESS_STATUS = "2"; + + + /** + * 任务的关闭的状态 + */ + public static final String STOP_STATUS = "1"; + + public enum Status + { + /** + * 正常 + */ + NORMAL("0"), + /** + * 暂停 + */ + PAUSE("1"); + + private String value; + + private Status(String value) + { + this.value = value; + } + + public String getValue() + { + return value; + } + } +} diff --git a/src/main/java/com/fc/test/common/quartz/entity/SysJob.java b/src/main/java/com/fc/test/common/quartz/entity/SysJob.java new file mode 100644 index 0000000..0f336e3 --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/entity/SysJob.java @@ -0,0 +1,132 @@ +package com.fc.test.common.quartz.entity; + + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.io.Serializable; +import java.util.Date; + +/** + * 定时任务调度表 sys_job + * + * @author Jan 橙寂 + */ +public class SysJob implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 任务ID */ + private Long jobId; + + /** 任务名称 */ + private String jobName; + + /** 任务组名 */ + private String jobGroup; + + /** 调用目标字符串 */ + private String invokeTarget; + + /** cron执行表达式 */ + private String cronExpression; + + /** cron计划策略 */ + private String misfirePolicy; + /** 是否并发执行(0允许 1禁止) */ + private String concurrent; + + /** 任务状态(0正常 1暂停) */ + private String status; + + public Long getJobId() + { + return jobId; + } + + public void setJobId(Long jobId) + { + this.jobId = jobId; + } + + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + @NotBlank(message = "调用目标字符串不能为空") + @Size(min = 0, max = 1000, message = "调用目标字符串长度不能超过500个字符") + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + @NotBlank(message = "Cron执行表达式不能为空") + @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符") + public String getCronExpression() + { + return cronExpression; + } + + public void setCronExpression(String cronExpression) + { + this.cronExpression = cronExpression; + } + + public Date getNextValidTime() + { + + return null; + } + + public String getMisfirePolicy() + { + return misfirePolicy; + } + + public void setMisfirePolicy(String misfirePolicy) + { + this.misfirePolicy = misfirePolicy; + } + + public String getConcurrent() + { + return concurrent; + } + + public void setConcurrent(String concurrent) + { + this.concurrent = concurrent; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + +} \ No newline at end of file diff --git a/src/main/java/com/fc/test/common/quartz/entity/SysJobLog.java b/src/main/java/com/fc/test/common/quartz/entity/SysJobLog.java new file mode 100644 index 0000000..ee9dbf0 --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/entity/SysJobLog.java @@ -0,0 +1,147 @@ +package com.fc.test.common.quartz.entity; + + +import java.io.Serializable; +import java.util.Date; + +/** + * 定时任务调度日志表 sys_job_log + * + * @author jan 橙寂 + */ +public class SysJobLog implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** ID */ + private Long jobLogId; + + /** 任务名称 */ + private String jobName; + + /** 任务组名 */ + private String jobGroup; + + /** 调用目标字符串 */ + private String invokeTarget; + + /** 日志信息 */ + private String jobMessage; + + /** 执行状态(0正常 1失败) */ + private String status; + + /** 异常信息 */ + private String exceptionInfo; + + /** 开始时间 */ + private Date startTime; + + /** 结束时间 */ + private Date endTime; + + public Long getJobLogId() + { + return jobLogId; + } + + public void setJobLogId(Long jobLogId) + { + this.jobLogId = jobLogId; + } + + public String getJobName() + { + return jobName; + } + + public void setJobName(String jobName) + { + this.jobName = jobName; + } + + public String getJobGroup() + { + return jobGroup; + } + + public void setJobGroup(String jobGroup) + { + this.jobGroup = jobGroup; + } + + public String getInvokeTarget() + { + return invokeTarget; + } + + public void setInvokeTarget(String invokeTarget) + { + this.invokeTarget = invokeTarget; + } + + public String getJobMessage() + { + return jobMessage; + } + + public void setJobMessage(String jobMessage) + { + this.jobMessage = jobMessage; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getExceptionInfo() + { + return exceptionInfo; + } + + public void setExceptionInfo(String exceptionInfo) + { + this.exceptionInfo = exceptionInfo; + } + + public Date getStartTime() + { + return startTime; + } + + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getEndTime() + { + return endTime; + } + + public void setEndTime(Date endTime) + { + this.endTime = endTime; + } + + @Override + public String toString() { + return "SysJobLog{" + + "jobLogId=" + jobLogId + + ", jobName='" + jobName + '\'' + + ", jobGroup='" + jobGroup + '\'' + + ", invokeTarget='" + invokeTarget + '\'' + + ", jobMessage='" + jobMessage + '\'' + + ", status='" + status + '\'' + + ", exceptionInfo='" + exceptionInfo + '\'' + + ", startTime=" + startTime + + ", endTime=" + endTime + + '}'; + } +} diff --git a/src/main/java/com/fc/test/common/quartz/job/TestQuartzJob.java b/src/main/java/com/fc/test/common/quartz/job/TestQuartzJob.java deleted file mode 100644 index f39dde1..0000000 --- a/src/main/java/com/fc/test/common/quartz/job/TestQuartzJob.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.fc.test.common.quartz.job; - -import org.quartz.Job; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; -import org.springframework.stereotype.Component; -import java.util.Date; - -/** - * @CLASSNAME TestQuartzJob - * @Description 定时调度具体工作类 - * @Auther Jan 橙寂 - * @DATE 2019/9/2 0002 15:33 - */ -@Component -public class TestQuartzJob implements Job { - @Override - public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - System.out.println(new Date()+"测试定时调度正在执行"); - } -} diff --git a/src/main/java/com/fc/test/common/quartz/task/RyTask.java b/src/main/java/com/fc/test/common/quartz/task/RyTask.java new file mode 100644 index 0000000..aebce01 --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/task/RyTask.java @@ -0,0 +1,33 @@ +package com.fc.test.common.quartz.task; + +import org.springframework.stereotype.Component; + +/** + * @CLASSNAME RyTask + * @Description 定时调度具体工作类 + * @Auther Jan 橙寂 + * @DATE 2019/9/2 0002 15:33 + */ +@Component("ryTask") +public class RyTask { + + /** + * 无参的任务 + */ + public void runTask1() + { + System.out.println("正在执行定时任务,无参方法"); + } + + /** + * 有参任务 + * 目前仅执行常见的数据类型 Integer Long 带L string 带 '' bool Double 带 d + * @param a + * @param b + */ + public void runTask2(Integer a,Long b,String c,Boolean d,Double e) + { + System.out.println("正在执行定时任务,带多个参数的方法"+a+" "+b+" "+c+" "+d+" "+e); + + } +} diff --git a/src/main/java/com/fc/test/common/quartz/utils/JobInvokeUtil.java b/src/main/java/com/fc/test/common/quartz/utils/JobInvokeUtil.java new file mode 100644 index 0000000..658605d --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/utils/JobInvokeUtil.java @@ -0,0 +1,183 @@ +package com.fc.test.common.quartz.utils; + + + +import com.fc.test.common.quartz.entity.SysJob; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; + +/** + * 任务执行工具 + * + * @author ruoyi + */ +public class JobInvokeUtil +{ + /** + * 执行方法 + * + * @param sysJob 系统任务 + */ + public static void invokeMethod(SysJob sysJob) throws Exception + { + String invokeTarget = sysJob.getInvokeTarget(); + String beanName = getBeanName(invokeTarget); + String methodName = getMethodName(invokeTarget); + List methodParams = getMethodParams(invokeTarget); + + if (!isValidClassName(beanName)) + { + Object bean = SpringUtils.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 (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) + { + Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams)); + method.invoke(bean, getMethodParamsValue(methodParams)); + } + else + { + Method method = bean.getClass().getDeclaredMethod(methodName); + method.invoke(bean); + } + } + + /** + * 校验是否为为class包名 + * + * @param str 名称 + * @return true是 false否 + */ + public static boolean isValidClassName(String invokeTarget) + { + return StringUtils.countMatches(invokeTarget, ".") > 1; + } + + /** + * 获取bean名称 + * + * @param invokeTarget 目标字符串 + * @return bean名称 + */ + public static String getBeanName(String invokeTarget) + { + String beanName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringBeforeLast(beanName, "."); + } + + /** + * 获取bean方法 + * + * @param invokeTarget 目标字符串 + * @return method方法 + */ + public static String getMethodName(String invokeTarget) + { + String methodName = StringUtils.substringBefore(invokeTarget, "("); + return StringUtils.substringAfterLast(methodName, "."); + } + + /** + * 获取method方法参数相关列表 + * + * @param invokeTarget 目标字符串 + * @return method方法相关参数列表 + */ + public static List getMethodParams(String invokeTarget) + { + String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); + if (StringUtils.isEmpty(methodStr)) + { + return null; + } + String[] methodParams = methodStr.split(","); + List classs = new LinkedList<>(); + for (int i = 0; i < methodParams.length; i++) + { + String str = StringUtils.trimToEmpty(methodParams[i]); + // String字符串类型,包含' + if (StringUtils.contains(str, "'")) + { + classs.add(new Object[] { StringUtils.replace(str, "'", ""), String.class }); + } + // boolean布尔类型,等于true或者false + else if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false")) + { + classs.add(new Object[] { Boolean.valueOf(str), Boolean.class }); + } + // long长整形,包含L + else if (StringUtils.containsIgnoreCase(str, "L")) + { + classs.add(new Object[] { Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class }); + } + // double浮点类型,包含D + else if (StringUtils.containsIgnoreCase(str, "D")) + { + classs.add(new Object[] { Double.valueOf(StringUtils.replaceIgnoreCase(str, "D", "")), Double.class }); + } + // 其他类型归类为整形 + else + { + classs.add(new Object[] { Integer.valueOf(str), Integer.class }); + } + } + return classs; + } + + /** + * 获取参数类型 + * + * @param methodParams 参数相关列表 + * @return 参数类型列表 + */ + public static Class[] getMethodParamsType(List methodParams) + { + Class[] classs = new Class[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Class) os[1]; + index++; + } + return classs; + } + + /** + * 获取参数值 + * + * @param methodParams 参数相关列表 + * @return 参数值列表 + */ + public static Object[] getMethodParamsValue(List methodParams) + { + Object[] classs = new Object[methodParams.size()]; + int index = 0; + for (Object[] os : methodParams) + { + classs[index] = (Object) os[0]; + index++; + } + return classs; + } +} diff --git a/src/main/java/com/fc/test/common/quartz/utils/SpringUtils.java b/src/main/java/com/fc/test/common/quartz/utils/SpringUtils.java new file mode 100644 index 0000000..cf83f25 --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/utils/SpringUtils.java @@ -0,0 +1,114 @@ +package com.fc.test.common.quartz.utils; + +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.stereotype.Component; + +/** + * spring工具类 方便在非spring管理环境中获取bean + * + * @author ruoyi + */ +@Component +public final class SpringUtils implements BeanFactoryPostProcessor +{ + /** Spring应用上下文环境 */ + private static ConfigurableListableBeanFactory beanFactory; + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException + { + SpringUtils.beanFactory = beanFactory; + } + + /** + * 获取对象 + * + * @param name + * @return Object 一个以所给名字注册的bean的实例 + * @throws org.springframework.beans.BeansException + * + */ + @SuppressWarnings("unchecked") + public static T getBean(String name) throws BeansException + { + return (T) beanFactory.getBean(name); + } + + /** + * 获取类型为requiredType的对象 + * + * @param clz + * @return + * @throws org.springframework.beans.BeansException + * + */ + public static T getBean(Class clz) throws BeansException + { + T result = (T) beanFactory.getBean(clz); + return result; + } + + /** + * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true + * + * @param name + * @return boolean + */ + public static boolean containsBean(String name) + { + return beanFactory.containsBean(name); + } + + /** + * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException) + * + * @param name + * @return boolean + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.isSingleton(name); + } + + /** + * @param name + * @return Class 注册对象的类型 + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static Class getType(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getType(name); + } + + /** + * 如果给定的bean名字在bean定义中有别名,则返回这些别名 + * + * @param name + * @return + * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException + * + */ + public static String[] getAliases(String name) throws NoSuchBeanDefinitionException + { + return beanFactory.getAliases(name); + } + + /** + * 获取aop代理对象 + * + * @param invoker + * @return + */ + @SuppressWarnings("unchecked") + public static T getAopProxy(T invoker) + { + return (T) AopContext.currentProxy(); + } +} diff --git a/src/main/java/com/fc/test/common/quartz/utils/StringUtils.java b/src/main/java/com/fc/test/common/quartz/utils/StringUtils.java new file mode 100644 index 0000000..2902cfb --- /dev/null +++ b/src/main/java/com/fc/test/common/quartz/utils/StringUtils.java @@ -0,0 +1,400 @@ +package com.fc.test.common.quartz.utils; + + +import cn.hutool.core.text.StrFormatter; + +import java.util.Collection; +import java.util.Map; + +/** + * 字符串工具类 + * + * @author ruoyi + */ +public class StringUtils extends org.apache.commons.lang3.StringUtils +{ + /** 空字符串 */ + private static final String NULLSTR = ""; + + /** 下划线 */ + private static final char SEPARATOR = '_'; + + /** + * 获取参数不为空值 + * + * @param value defaultValue 要判断的value + * @return value 返回值 + */ + public static T nvl(T value, T defaultValue) + { + return value != null ? value : defaultValue; + } + + /** + * * 判断一个Collection是否为空, 包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Collection coll) + { + return isNull(coll) || coll.isEmpty(); + } + + /** + * * 判断一个Collection是否非空,包含List,Set,Queue + * + * @param coll 要判断的Collection + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Collection coll) + { + return !isEmpty(coll); + } + + /** + * * 判断一个对象数组是否为空 + * + * @param objects 要判断的对象数组 + ** @return true:为空 false:非空 + */ + public static boolean isEmpty(Object[] objects) + { + return isNull(objects) || (objects.length == 0); + } + + /** + * * 判断一个对象数组是否非空 + * + * @param objects 要判断的对象数组 + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Object[] objects) + { + return !isEmpty(objects); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:为空 false:非空 + */ + public static boolean isEmpty(Map map) + { + return isNull(map) || map.isEmpty(); + } + + /** + * * 判断一个Map是否为空 + * + * @param map 要判断的Map + * @return true:非空 false:空 + */ + public static boolean isNotEmpty(Map map) + { + return !isEmpty(map); + } + + /** + * * 判断一个字符串是否为空串 + * + * @param str String + * @return true:为空 false:非空 + */ + public static boolean isEmpty(String str) + { + return isNull(str) || NULLSTR.equals(str.trim()); + } + + /** + * * 判断一个字符串是否为非空串 + * + * @param str String + * @return true:非空串 false:空串 + */ + public static boolean isNotEmpty(String str) + { + return !isEmpty(str); + } + + /** + * * 判断一个对象是否为空 + * + * @param object Object + * @return true:为空 false:非空 + */ + public static boolean isNull(Object object) + { + return object == null; + } + + /** + * * 判断一个对象是否非空 + * + * @param object Object + * @return true:非空 false:空 + */ + public static boolean isNotNull(Object object) + { + return !isNull(object); + } + + /** + * * 判断一个对象是否是数组类型(Java基本型别的数组) + * + * @param object 对象 + * @return true:是数组 false:不是数组 + */ + public static boolean isArray(Object object) + { + return isNotNull(object) && object.getClass().isArray(); + } + + /** + * 去空格 + */ + public static String trim(String str) + { + return (str == null ? "" : str.trim()); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @return 结果 + */ + public static String substring(final String str, int start) + { + if (str == null) + { + return NULLSTR; + } + + if (start < 0) + { + start = str.length() + start; + } + + if (start < 0) + { + start = 0; + } + if (start > str.length()) + { + return NULLSTR; + } + + return str.substring(start); + } + + /** + * 截取字符串 + * + * @param str 字符串 + * @param start 开始 + * @param end 结束 + * @return 结果 + */ + public static String substring(final String str, int start, int end) + { + if (str == null) + { + return NULLSTR; + } + + if (end < 0) + { + end = str.length() + end; + } + if (start < 0) + { + start = str.length() + start; + } + + if (end > str.length()) + { + end = str.length(); + } + + if (start > end) + { + return NULLSTR; + } + + if (start < 0) + { + start = 0; + } + if (end < 0) + { + end = 0; + } + + return str.substring(start, end); + } + + /** + * 格式化文本, {} 表示占位符
+ * 此方法只是简单将占位符 {} 按照顺序替换为参数
+ * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可
+ * 例:
+ * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
+ * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
+ * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
+ * + * @param template 文本模板,被替换的部分用 {} 表示 + * @param params 参数值 + * @return 格式化后的文本 + */ + public static String format(String template, Object... params) + { + if (isEmpty(params) || isEmpty(template)) + { + return template; + } + return StrFormatter.format(template, params); + } + + /** + * 下划线转驼峰命名 + */ + public static String toUnderScoreCase(String str) + { + if (str == null) + { + return null; + } + StringBuilder sb = new StringBuilder(); + // 前置字符是否大写 + boolean preCharIsUpperCase = true; + // 当前字符是否大写 + boolean curreCharIsUpperCase = true; + // 下一字符是否大写 + boolean nexteCharIsUpperCase = true; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (i > 0) + { + preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1)); + } + else + { + preCharIsUpperCase = false; + } + + curreCharIsUpperCase = Character.isUpperCase(c); + + if (i < (str.length() - 1)) + { + nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1)); + } + + if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) + { + sb.append(SEPARATOR); + } + else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) + { + sb.append(SEPARATOR); + } + sb.append(Character.toLowerCase(c)); + } + + return sb.toString(); + } + + /** + * 是否包含字符串 + * + * @param str 验证字符串 + * @param strs 字符串组 + * @return 包含返回true + */ + public static boolean inStringIgnoreCase(String str, String... strs) + { + if (str != null && strs != null) + { + for (String s : strs) + { + if (str.equalsIgnoreCase(trim(s))) + { + return true; + } + } + } + return false; + } + + /** + * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld + * + * @param name 转换前的下划线大写方式命名的字符串 + * @return 转换后的驼峰式命名的字符串 + */ + public static String convertToCamelCase(String name) + { + StringBuilder result = new StringBuilder(); + // 快速检查 + if (name == null || name.isEmpty()) + { + // 没必要转换 + return ""; + } + else if (!name.contains("_")) + { + // 不含下划线,仅将首字母大写 + return name.substring(0, 1).toUpperCase() + name.substring(1); + } + // 用下划线将原始字符串分割 + String[] camels = name.split("_"); + for (String camel : camels) + { + // 跳过原始字符串中开头、结尾的下换线或双重下划线 + if (camel.isEmpty()) + { + continue; + } + // 首字母大写 + result.append(camel.substring(0, 1).toUpperCase()); + result.append(camel.substring(1).toLowerCase()); + } + return result.toString(); + } + + /** + * 驼峰式命名法 例如:user_name->userName + */ + public static String toCamelCase(String s) + { + if (s == null) + { + return null; + } + s = s.toLowerCase(); + StringBuilder sb = new StringBuilder(s.length()); + boolean upperCase = false; + for (int i = 0; i < s.length(); i++) + { + char c = s.charAt(i); + + if (c == SEPARATOR) + { + upperCase = true; + } + else if (upperCase) + { + sb.append(Character.toUpperCase(c)); + upperCase = false; + } + else + { + sb.append(c); + } + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/fc/test/controller/admin/QuartzController.java b/src/main/java/com/fc/test/controller/admin/QuartzController.java index 9e6980a..6cc11d3 100644 --- a/src/main/java/com/fc/test/controller/admin/QuartzController.java +++ b/src/main/java/com/fc/test/controller/admin/QuartzController.java @@ -1,8 +1,9 @@ package com.fc.test.controller.admin; import com.fc.test.common.base.BaseController; +import com.fc.test.common.quartz.QuartzScheduler; +import com.fc.test.common.quartz.entity.SysJob; import com.fc.test.model.custom.TitleVo; -import com.fc.test.quartz.QuartzScheduler; import io.swagger.annotations.Api; import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; @@ -28,18 +29,6 @@ public class QuartzController extends BaseController{ private QuartzScheduler scheduler; - /** - * 调用这个方法开启任务调度 - * @param model - * @return - */ - @GetMapping("start") - @ResponseBody - public String start(Model model) - { - scheduler.startJob(); - return "success"; - } /** @@ -49,9 +38,9 @@ public class QuartzController extends BaseController{ */ @GetMapping("stop") @ResponseBody - public Object stop(Model model,String taskName,String groupName) + public Object stop(Model model, SysJob job) { - return scheduler.pauseJob(taskName,groupName); + return scheduler.pauseJob(job); } @@ -63,9 +52,9 @@ public class QuartzController extends BaseController{ */ @GetMapping("resume") @ResponseBody - public Object resume(Model model,String taskName,String groupName) + public Object resume(Model model,SysJob job) { - return scheduler.resumeJob(taskName,groupName); + return scheduler.resumeJob(job); } @@ -77,15 +66,27 @@ public class QuartzController extends BaseController{ */ @GetMapping("update") @ResponseBody - public String update(Model model,String taskName,String groupName,String cron) + public String update(Model model,SysJob job) { - try { - scheduler.modifyJob(taskName,groupName,cron); - } catch (SchedulerException e) { - e.printStackTrace(); - return "fail"; - } + + scheduler.modifyJob(job); + return "success"; } + + /** + * 删除定时器 + * @param model + * @return + */ + @GetMapping("delete") + @ResponseBody + public String delete(Model model,SysJob job) + { + + scheduler.deleteJob(job); + + return "success"; + } } diff --git a/src/main/java/com/fc/test/quartz/QuartzConfig.java b/src/main/java/com/fc/test/quartz/QuartzConfig.java deleted file mode 100644 index 02ed832..0000000 --- a/src/main/java/com/fc/test/quartz/QuartzConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.fc.test.quartz; - -import org.quartz.Scheduler; -import org.quartz.SchedulerException; -import org.quartz.SchedulerFactory; -import org.quartz.impl.StdSchedulerFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/** - * @CLASSNAME QuartzConfig - * @Description Quartz配置类 - * @Auther Jan 橙寂 - * @DATE 2019/9/2 0002 15:21 - */ -@Configuration -public class QuartzConfig { - - /** - * 初始注入scheduler - * @return - * @throws SchedulerException - */ - @Bean - public Scheduler scheduler() throws SchedulerException{ - SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory(); - return schedulerFactoryBean.getScheduler(); - } -} diff --git a/src/main/java/com/fc/test/quartz/QuartzDefault.java b/src/main/java/com/fc/test/quartz/QuartzDefault.java deleted file mode 100644 index bcc2419..0000000 --- a/src/main/java/com/fc/test/quartz/QuartzDefault.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.fc.test.quartz; - -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.Scheduled; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; - -/** - * @CLASSNAME QuartzDefault - * @Description springboot 默认的定时调度配置(不需要任何包)但是不能动态的开启(关闭)或者添加 任务 - * @Auther Jan 橙寂 - * @DATE 2019/9/2 0002 14:46 - */ -@Configuration -//@EnableScheduling //开启定时调度的开关 -public class QuartzDefault { - - - //配置表达式 现在这个是每一分钟执行一次 - @Scheduled(cron = "0 0/1 * * * *") - public void timer(){ - //获取当前时间 - LocalDateTime localDateTime = LocalDateTime.now(); - System.out.println("当前时间为:" + localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); - } - - - /*按顺序依次为 - 1 秒(0~59) - 2 分钟(0~59) - 3 小时(0~23) - 4 天(0~31) - 5 月(0~11) - 6 星期(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) - 7.年份(1970-2099) - 其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符。由于"月份中的日期"和"星期中的日期"这两个元素互斥的,必须要对其中一个设置?. - 0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 - 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 - 0 0 12 ? * WED 表示每个星期三中午12点 - "0 0 12 * * ?" 每天中午12点触发 - "0 15 10 ? * *" 每天上午10:15触发 - "0 15 10 * * ?" 每天上午10:15触发 - "0 15 10 * * ? *" 每天上午10:15触发 - "0 15 10 * * ? 2005" 2005年的每天上午10:15触发 - "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 - "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 - "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 - "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 - "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 - "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 - "0 15 10 15 * ?" 每月15日上午10:15触发 - "0 15 10 L * ?" 每月最后一日的上午10:15触发 - "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 - "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 - "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 - 有些子表达式能包含一些范围或列表 - 例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT” - “*”字符代表所有可能的值 - “/”字符用来指定数值的增量 - 例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟 - 在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样 - “?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值 - 当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?” - “L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写 - 如果在“L”前有具体的内容,它就具有其他的含义了。例如:“6L”表示这个月的倒数第6天 - 注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题 - W 字符代表着平日(Mon-Fri),并且仅能用于日域中。它用来指定离指定日的最近的一个平日。大部分的商业处理都是基于工作周的,所以 W 字符可能是非常重要的。 - 例如,日域中的 15W 意味着 "离该月15号的最近一个平日。" 假如15号是星期六,那么 trigger 会在14号(星期五)触发,因为星期四比星期一离15号更近。 - C:代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。 - 字段 允许值 允许的特殊字符 - 秒 0-59 , - * / - 分 0-59 , - * / - 小时 0-23 , - * / - 日期 1-31 , - * ? / L W C - 月份 1-12 或者 JAN-DEC , - * / - 星期 1-7 或者 SUN-SAT , - * ? / L C # - 年(可选) 留空, 1970-2099 , - * /*/ - - -} diff --git a/src/main/java/com/fc/test/quartz/QuartzScheduler.java b/src/main/java/com/fc/test/quartz/QuartzScheduler.java deleted file mode 100644 index 4261b14..0000000 --- a/src/main/java/com/fc/test/quartz/QuartzScheduler.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.fc.test.quartz; - -import com.fc.test.quartz.job.TestQuartzJob; -import org.quartz.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Configuration; - -import java.util.Date; - -/** - * @CLASSNAME QuartzConfig - * @Description Quartz配置类 - * @Auther Jan 橙寂 - * @DATE 2019/9/2 0002 15:21 - */ -@Configuration -public class QuartzScheduler { - - @Autowired - private Scheduler scheduler; - - //这个东西可以放在配置文件中 - //cron表达式 一分钟执行一次 - private final String TEST_CRON="0 0/1 * * * ?"; - - /** - * 开始工作 - */ - public void startJob() - { - try { - initTestJob("test","test"); - scheduler.start(); - - } catch (SchedulerException e) { - e.printStackTrace(); - System.out.println("任务掉度开启失败"); - } - - } - - /** - * 初始化一个任务 - * @param taskName - * @param groupName - * @throws SchedulerException - */ - private void initTestJob(String taskName,String groupName) throws SchedulerException { - if (!checkJobExists(taskName,groupName)) { - // 通过JobBuilder构建JobDetail实例,JobDetail规定只能是实现Job接口的实例 - // JobDetail 是具体Job实例 - JobDetail jobDetail = JobBuilder.newJob(TestQuartzJob.class).withIdentity(taskName, groupName).build(); - // 基于表达式构建触发器 - CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(TEST_CRON); - // CronTrigger表达式触发器 继承于Trigger - // TriggerBuilder 用于构建触发器实例 - CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskName, groupName) - .withSchedule(cronScheduleBuilder.withMisfireHandlingInstructionDoNothing()).build(); - scheduler.scheduleJob(jobDetail, cronTrigger); - } - } - - - - /** - * 修改某个任务的执行时间 - * - * @param name - * @param group - * @param cron 表达式 - * @return - * @throws SchedulerException - */ - public boolean modifyJob(String name, String group, String cron) throws SchedulerException { - Date date = null; - TriggerKey triggerKey = new TriggerKey(name, group); - CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); - if (cronTrigger != null) { - String oldTime = cronTrigger.getCronExpression(); - if (!oldTime.equalsIgnoreCase(cron)) { - CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron); - CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(name, group) - .withSchedule(cronScheduleBuilder).build(); - date = scheduler.rescheduleJob(triggerKey, trigger); - } - } - return date==null?false:true; - } - - - /** - * 继续执行定时任务 - * @param taskName - * @param groupName - * @return - */ - public boolean resumeJob(String taskName, String groupName) { - boolean bl = false; - try { - //JobKey定义了job的名称和组别 - JobKey jobKey = JobKey.jobKey(taskName, groupName); - if (jobKey != null) { - //继续任务 - scheduler.resumeJob(jobKey); - bl = true; - } - } catch (SchedulerException e) { - System.out.println("继续调度任务异常:" + e); - } catch (Exception e) { - System.out.println("继续调度任务异常:" + e); - } - return bl; - } - - /** - * 暂停任务 - * @param taskName - * @param groupName - * @return - */ - public boolean pauseJob(String taskName, String groupName) { - boolean bl = false; - try { - //JobKey定义了job的名称和组别 - JobKey jobKey = JobKey.jobKey(taskName, groupName); - //暂停任务 - if (jobKey != null) { - scheduler.pauseJob(jobKey); - bl = true; - } - } catch (SchedulerException e) { - // getLog().info("暂停调度任务异常:" + e); - } catch (Exception e) { - // getLog().info("暂停调度任务异常:"+ e); - } - return bl; - } - - /** - * 判断定时任务是否已经存在 - * @param taskName - * @param groupName - * @return - * @throws SchedulerException - */ - public boolean checkJobExists(String taskName, String groupName) throws SchedulerException { - TriggerKey triggerKey = TriggerKey.triggerKey(taskName, groupName); - return scheduler.checkExists(triggerKey); - } -} diff --git a/src/main/java/com/fc/test/quartz/job/TestQuartzJob.java b/src/main/java/com/fc/test/quartz/job/TestQuartzJob.java deleted file mode 100644 index 4e84246..0000000 --- a/src/main/java/com/fc/test/quartz/job/TestQuartzJob.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.fc.test.quartz.job; - -import org.quartz.Job; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; -import org.springframework.stereotype.Component; - -import java.util.Date; - -/** - * @CLASSNAME TestQuartzJob - * @Description 定时调度具体工作类 - * @Auther Jan 橙寂 - * @DATE 2019/9/2 0002 15:33 - */ -@Component -public class TestQuartzJob implements Job { - @Override - public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - System.out.println(new Date()+"测试定时调度正在执行"); - } -} -- Gitee