lixueqiang il y a 6 mois
Parent
commit
aa8056a49d
38 fichiers modifiés avec 2529 ajouts et 1 suppressions
  1. 1 1
      docker-compose.yml
  2. 4 0
      lxq-admin/pom.xml
  3. 13 0
      lxq-quartz/Dockerfile
  4. 146 0
      lxq-quartz/pom.xml
  5. 50 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/AutowireCapableBeanJobFactory.java
  6. 63 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqInitQuartzJob.java
  7. 124 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqQuartzConfig.java
  8. 35 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqQuartzCustomizerConfig.java
  9. 50 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqQuartzFactory.java
  10. 46 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/QuartzInvokeFactory.java
  11. 63 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/constants/JobTypeQuartzEnum.java
  12. 94 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/constants/SkyQuartzEnum.java
  13. 316 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/controller/SysJobController.java
  14. 49 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/controller/SysJobLogController.java
  15. 162 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/entity/SysJob.java
  16. 130 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/entity/SysJobLog.java
  17. 36 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobEvent.java
  18. 49 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobListener.java
  19. 33 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobLogEvent.java
  20. 48 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobLogListener.java
  21. 35 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/exception/TaskException.java
  22. 33 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/mapper/SysJobLogMapper.java
  23. 33 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/mapper/SysJobMapper.java
  24. 31 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/SysJobLogService.java
  25. 31 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/SysJobService.java
  26. 39 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/impl/SysJobLogServiceImpl.java
  27. 39 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/impl/SysJobServiceImpl.java
  28. 34 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/task/RestTaskDemo.java
  29. 43 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/task/SpringBeanTaskDemo.java
  30. 19 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/ITaskInvoke.java
  31. 62 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/JarTaskInvoke.java
  32. 87 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/JavaClassTaskInvoke.java
  33. 50 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/RestTaskInvoke.java
  34. 80 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/SpringBeanTaskInvoke.java
  35. 50 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/TaskInvokFactory.java
  36. 99 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/TaskInvokUtil.java
  37. 244 0
      lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/TaskUtil.java
  38. 8 0
      pom.xml

+ 1 - 1
docker-compose.yml

@@ -2,7 +2,7 @@ version: '3'
 services:
 
   lxq-mysql:
-    image: mysql:8.0.32
+    image: mysql:8.0.36
     environment:
       MYSQL_ROOT_HOST: "%"
       MYSQL_ROOT_PASSWORD: root

+ 4 - 0
lxq-admin/pom.xml

@@ -23,6 +23,10 @@
             <groupId>com.lxq</groupId>
             <artifactId>lxq-system</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.lxq</groupId>
+            <artifactId>lxq-quartz</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.tomcat.embed</groupId>
             <artifactId>tomcat-embed-core</artifactId>

+ 13 - 0
lxq-quartz/Dockerfile

@@ -0,0 +1,13 @@
+FROM alibabadragonwell/dragonwell:17-anolis
+
+WORKDIR /sky-quartz
+
+ARG JAR_FILE=target/sky-quartz.jar
+
+COPY ${JAR_FILE} app.jar
+
+EXPOSE 4000
+
+ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms128m -Xmx256m -Djava.security.egd=file:/dev/./urandom"
+
+CMD sleep 60; java $JAVA_OPTS -jar app.jar

+ 146 - 0
lxq-quartz/pom.xml

@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <groupId>com.lxq</groupId>
+        <artifactId>lxq</artifactId>
+        <version>3.5.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>lxq-quartz</artifactId>
+    <packaging>jar</packaging>
+
+    <description>基于quartz后台定时任务模块</description>
+
+    <dependencies>
+        <!--日志处理-->
+        <dependency>
+            <groupId>com.lxq</groupId>
+            <artifactId>lxq-common-log</artifactId>
+        </dependency>
+        <!--mybatis-->
+        <dependency>
+            <groupId>com.lxq</groupId>
+            <artifactId>lxq-common-mybatis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
+        </dependency>
+        <!--数据库-->
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+        </dependency>
+        <!-- quartz 模块 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.lxq</groupId>
+            <artifactId>lxq-system</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+            <!--打包java路径下的静态文件-->
+            <resource>
+                <directory>src/main/java</directory>
+                <filtering>false</filtering>
+                <includes>
+                    <include>**/*.xml</include>
+                </includes>
+            </resource>
+        </resources>
+        <plugins>
+            <!--该插件的作用是打包spring-boot的jar包-->
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <!--不排除的话,systemScope的依赖包会自动被此插件打包进xxx.jar\BOOT-INF\lib,和外部依赖产生冲突 -->
+                    <includeSystemScope>false</includeSystemScope>
+                    <skip>false</skip>
+                    <!--分离Jar包-->
+                    <layout>ZIP</layout>
+                    <includes>
+                        <include>
+                            <groupId>nothing</groupId>
+                            <artifactId>nothing</artifactId>
+                        </include>
+                    </includes>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <!-- 该插件的作用是复制依赖的jar包到指定的文件夹里 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${project.build.directory}/lib/</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <!-- 该插件的作用是复制指定的文件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <!-- 复制配置文件 -->
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <resources>
+                                <!--复制资源文件到外部,注意这里先不做filtering处理,防止某些静态文件损坏-->
+                                <resource>
+                                    <filtering>false</filtering>
+                                    <directory>src/main/resources</directory>
+                                    <includes>
+                                        <include>**/*</include>
+                                    </includes>
+                                </resource>
+                                <!--仅针对配置文件filtering处理(占位符@@等)-->
+                                <resource>
+                                    <directory>src/main/resources</directory>
+                                    <filtering>true</filtering>
+                                    <includes>
+                                        <include>*.xml</include>
+                                        <include>*.yml</include>
+                                        <include>*.properties</include>
+                                    </includes>
+                                </resource>
+                            </resources>
+                            <outputDirectory>${project.build.directory}/config</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 50 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/AutowireCapableBeanJobFactory.java

@@ -0,0 +1,50 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.config;
+
+import org.quartz.JobKey;
+import org.quartz.spi.TriggerFiredBundle;
+import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
+import org.springframework.scheduling.quartz.SpringBeanJobFactory;
+import org.springframework.util.Assert;
+
+/**
+ * @author LXQ
+ */
+class AutowireCapableBeanJobFactory extends SpringBeanJobFactory {
+
+	private final AutowireCapableBeanFactory beanFactory;
+
+	AutowireCapableBeanJobFactory(AutowireCapableBeanFactory beanFactory) {
+		Assert.notNull(beanFactory, "Bean factory must not be null");
+		this.beanFactory = beanFactory;
+	}
+
+	@Override
+	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
+		Object jobInstance = super.createJobInstance(bundle);
+		this.beanFactory.autowireBean(jobInstance);
+
+		// 此处必须注入 beanName 不然sentinel 报错
+		JobKey jobKey = bundle.getTrigger().getJobKey();
+		String beanName = jobKey + jobKey.getName();
+		this.beanFactory.initializeBean(jobInstance, beanName);
+		return jobInstance;
+	}
+
+}

+ 63 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqInitQuartzJob.java

@@ -0,0 +1,63 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.config;
+
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import com.lxq.daemon.quartz.service.SysJobService;
+import com.lxq.daemon.quartz.util.TaskUtil;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Scheduler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author LXQ
+ * <p>
+ * 初始化加载定时任务
+ */
+@Slf4j
+@Configuration
+@AllArgsConstructor
+public class LxqInitQuartzJob {
+
+	private final SysJobService sysJobService;
+
+	private final TaskUtil taskUtil;
+
+	private final Scheduler scheduler;
+
+	@Bean
+	public void customize() {
+		sysJobService.list().forEach(sysjob -> {
+			if (SkyQuartzEnum.JOB_STATUS_RELEASE.getType().equals(sysjob.getJobStatus())) {
+				taskUtil.removeJob(sysjob, scheduler);
+			}
+			else if (SkyQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysjob.getJobStatus())) {
+				taskUtil.resumeJob(sysjob, scheduler);
+			}
+			else if (SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysjob.getJobStatus())) {
+				taskUtil.pauseJob(sysjob, scheduler);
+			}
+			else {
+				taskUtil.removeJob(sysjob, scheduler);
+			}
+		});
+	}
+
+}

+ 124 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqQuartzConfig.java

@@ -0,0 +1,124 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.config;
+
+import org.quartz.Calendar;
+import org.quartz.JobDetail;
+import org.quartz.Scheduler;
+import org.quartz.Trigger;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.quartz.QuartzProperties;
+import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * @author LXQ
+ */
+@EnableAsync
+@Configuration
+@ConditionalOnClass({ Scheduler.class, SchedulerFactoryBean.class })
+@EnableConfigurationProperties({ QuartzProperties.class })
+public class LxqQuartzConfig {
+
+	private final QuartzProperties properties;
+
+	private final List<SchedulerFactoryBeanCustomizer> customizers;
+
+	private final JobDetail[] jobDetails;
+
+	private final Map<String, Calendar> calendars;
+
+	private final Trigger[] triggers;
+
+	private final ApplicationContext applicationContext;
+
+	public LxqQuartzConfig(QuartzProperties properties,
+						   ObjectProvider<List<SchedulerFactoryBeanCustomizer>> customizers, ObjectProvider<JobDetail[]> jobDetails,
+						   ObjectProvider<Map<String, Calendar>> calendars, ObjectProvider<Trigger[]> triggers,
+						   ApplicationContext applicationContext) {
+		this.properties = properties;
+		this.customizers = customizers.getIfAvailable();
+		this.jobDetails = jobDetails.getIfAvailable();
+		this.calendars = calendars.getIfAvailable();
+		this.triggers = triggers.getIfAvailable();
+		this.applicationContext = applicationContext;
+	}
+
+	@Bean
+	@ConditionalOnMissingBean
+	public SchedulerFactoryBean quartzScheduler() {
+		SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
+		schedulerFactoryBean
+			.setJobFactory(new AutowireCapableBeanJobFactory(this.applicationContext.getAutowireCapableBeanFactory()));
+		if (!this.properties.getProperties().isEmpty()) {
+			schedulerFactoryBean.setQuartzProperties(this.asProperties(this.properties.getProperties()));
+		}
+
+		if (this.jobDetails != null && this.jobDetails.length > 0) {
+			schedulerFactoryBean.setJobDetails(this.jobDetails);
+		}
+
+		if (this.calendars != null && !this.calendars.isEmpty()) {
+			schedulerFactoryBean.setCalendars(this.calendars);
+		}
+
+		if (this.triggers != null && this.triggers.length > 0) {
+			schedulerFactoryBean.setTriggers(this.triggers);
+		}
+
+		this.customize(schedulerFactoryBean);
+		return schedulerFactoryBean;
+	}
+
+	private Properties asProperties(Map<String, String> source) {
+		Properties properties = new Properties();
+		properties.putAll(source);
+		return properties;
+	}
+
+	private void customize(SchedulerFactoryBean schedulerFactoryBean) {
+		if (this.customizers != null) {
+
+			for (SchedulerFactoryBeanCustomizer customizer : this.customizers) {
+				customizer.customize(schedulerFactoryBean);
+			}
+		}
+
+	}
+
+	/**
+	 * 通过SchedulerFactoryBean获取Scheduler的实例
+	 * @return
+	 */
+	@Bean
+	public Scheduler scheduler() {
+		return quartzScheduler().getScheduler();
+	}
+
+}

+ 35 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqQuartzCustomizerConfig.java

@@ -0,0 +1,35 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.config;
+
+import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+
+/**
+ * @author LXQ
+ */
+@Configuration
+public class LxqQuartzCustomizerConfig implements SchedulerFactoryBeanCustomizer {
+
+	@Override
+	public void customize(SchedulerFactoryBean schedulerFactoryBean) {
+		schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(true);
+	}
+
+}

+ 50 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/LxqQuartzFactory.java

@@ -0,0 +1,50 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.config;
+
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import com.lxq.daemon.quartz.entity.SysJob;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * @author LXQ
+ *
+ * <p>
+ * 动态任务工厂
+ */
+@Slf4j
+@DisallowConcurrentExecution
+public class LxqQuartzFactory implements Job {
+
+	@Autowired
+	private QuartzInvokeFactory quartzInvokeFactory;
+
+	@Override
+	@SneakyThrows
+	public void execute(JobExecutionContext jobExecutionContext) {
+		SysJob sysJob = (SysJob) jobExecutionContext.getMergedJobDataMap()
+			.get(SkyQuartzEnum.SCHEDULE_JOB_KEY.getType());
+		quartzInvokeFactory.init(sysJob, jobExecutionContext.getTrigger());
+	}
+
+}

+ 46 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/config/QuartzInvokeFactory.java

@@ -0,0 +1,46 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.config;
+
+import com.lxq.daemon.quartz.entity.SysJob;
+import com.lxq.daemon.quartz.event.SysJobEvent;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.annotation.Aspect;
+import org.quartz.Trigger;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author LXQ
+ */
+@Slf4j
+@Aspect
+@Service
+@AllArgsConstructor
+public class QuartzInvokeFactory {
+
+	private final ApplicationEventPublisher publisher;
+
+	@SneakyThrows
+	void init(SysJob sysJob, Trigger trigger) {
+		publisher.publishEvent(new SysJobEvent(sysJob, trigger));
+	}
+
+}

+ 63 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/constants/JobTypeQuartzEnum.java

@@ -0,0 +1,63 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author LXQ
+ * @date 2021-03-14
+ * <p>
+ * 任务类型枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum JobTypeQuartzEnum {
+
+	/**
+	 * 反射java类
+	 */
+	JAVA("1", "反射java类"),
+
+	/**
+	 * spring bean 的方式
+	 */
+	SPRING_BEAN("2", "spring bean容器实例"),
+
+	/**
+	 * rest 调用
+	 */
+	REST("3", "rest调用"),
+
+	/**
+	 * jar
+	 */
+	JAR("4", "jar调用");
+
+	/**
+	 * 类型
+	 */
+	private final String type;
+
+	/**
+	 * 描述
+	 */
+	private final String description;
+
+}

+ 94 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/constants/SkyQuartzEnum.java

@@ -0,0 +1,94 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author LXQ
+ *
+ * <p>
+ * 定时任务枚举
+ */
+@Getter
+@AllArgsConstructor
+public enum SkyQuartzEnum {
+
+	/**
+	 * 错失执行策略默认
+	 */
+	MISFIRE_DEFAULT("0", "默认"),
+
+	/**
+	 * 错失执行策略-立即执行错失任务
+	 */
+	MISFIRE_IGNORE_MISFIRES("1", "立即执行错失任务"),
+
+	/**
+	 * 错失执行策略-触发一次执行周期执行
+	 */
+	MISFIRE_FIRE_AND_PROCEED("2", "触发一次执行周期执行"),
+
+	/**
+	 * 错失执行策略-不触发执行周期执行
+	 */
+	MISFIRE_DO_NOTHING("3", "不触发周期执行"),
+
+	/**
+	 * 任务详细信息的key
+	 */
+	SCHEDULE_JOB_KEY("scheduleJob", "获取任务详细信息的key"),
+
+	/**
+	 * JOB执行状态:0执行成功
+	 */
+	JOB_LOG_STATUS_SUCCESS("0", "执行成功"),
+	/**
+	 * JOB执行状态:1执行失败
+	 */
+	JOB_LOG_STATUS_FAIL("1", "执行失败"),
+
+	/**
+	 * JOB状态:1已发布
+	 */
+	JOB_STATUS_RELEASE("1", "已发布"),
+	/**
+	 * JOB状态:2运行中
+	 */
+	JOB_STATUS_RUNNING("2", "运行中"),
+	/**
+	 * JOB状态:3暂停
+	 */
+	JOB_STATUS_NOT_RUNNING("3", "暂停"),
+	/**
+	 * JOB状态:4删除
+	 */
+	JOB_STATUS_DEL("4", "删除");
+
+	/**
+	 * 类型
+	 */
+	private final String type;
+
+	/**
+	 * 描述
+	 */
+	private final String description;
+
+}

+ 316 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/controller/SysJobController.java

@@ -0,0 +1,316 @@
+
+package com.lxq.daemon.quartz.controller;
+
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.lxq.common.core.util.R;
+import com.lxq.common.log.annotation.SysLog;
+import com.lxq.common.security.util.SecurityUtils;
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import com.lxq.daemon.quartz.entity.SysJob;
+import com.lxq.daemon.quartz.entity.SysJobLog;
+import com.lxq.daemon.quartz.service.SysJobLogService;
+import com.lxq.daemon.quartz.service.SysJobService;
+import com.lxq.daemon.quartz.util.TaskUtil;
+import com.lxq.common.excel.annotation.ResponseExcel;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.springframework.http.HttpHeaders;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author LXQ
+ * @date 2021-01-27 10:04:42
+ * <p>
+ * 定时任务管理
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/sysJob")
+@Tag(description = "sys-job", name = "定时任务")
+@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
+@Slf4j
+public class SysJobController {
+
+	private final SysJobService sysJobService;
+
+	private final SysJobLogService sysJobLogService;
+
+	private final TaskUtil taskUtil;
+
+	private final Scheduler scheduler;
+
+	/**
+	 * 定时任务分页查询
+	 * @param page 分页对象
+	 * @param sysJob 定时任务调度表
+	 */
+	@GetMapping("/page")
+	@Operation(description = "分页定时业务查询")
+	public R getSysJobPage(Page page, SysJob sysJob) {
+		LambdaQueryWrapper<SysJob> wrapper = Wrappers.<SysJob>lambdaQuery()
+			.like(StrUtil.isNotBlank(sysJob.getJobName()), SysJob::getJobName, sysJob.getJobName())
+			.like(StrUtil.isNotBlank(sysJob.getJobGroup()), SysJob::getJobGroup, sysJob.getJobGroup())
+			.eq(StrUtil.isNotBlank(sysJob.getJobStatus()), SysJob::getJobStatus, sysJob.getJobGroup())
+			.eq(StrUtil.isNotBlank(sysJob.getJobExecuteStatus()), SysJob::getJobExecuteStatus,
+					sysJob.getJobExecuteStatus());
+		return R.ok(sysJobService.page(page, wrapper));
+	}
+
+	/**
+	 * 通过id查询定时任务
+	 * @param id id
+	 * @return R
+	 */
+	@GetMapping("/{id}")
+	@Operation(description = "唯一标识查询定时任务")
+	public R getById(@PathVariable("id") Long id) {
+		return R.ok(sysJobService.getById(id));
+	}
+
+	/**
+	 * 新增定时任务
+	 * @param sysJob 定时任务调度表
+	 * @return R
+	 */
+	@SysLog("新增定时任务")
+	@PostMapping("add")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_add')")
+	@Operation(description = "新增定时任务")
+	public R save(@RequestBody SysJob sysJob) {
+		long count = sysJobService.count(
+				Wrappers.query(SysJob.builder().jobName(sysJob.getJobName()).jobGroup(sysJob.getJobGroup()).build()));
+
+		if (count > 0) {
+			return R.failed("任务重复,请检查此组内是否已包含同名任务");
+		}
+		sysJob.setJobStatus(SkyQuartzEnum.JOB_STATUS_RELEASE.getType());
+		sysJob.setCreateBy(SecurityUtils.getUser().getUsername());
+		return R.ok(sysJobService.save(sysJob));
+	}
+
+	/**
+	 * 修改定时任务
+	 * @param sysJob 定时任务调度表
+	 * @return R
+	 */
+	@SysLog("修改定时任务")
+	@PutMapping("update")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_edit')")
+	@Operation(description = "修改定时任务")
+	public R updateById(@RequestBody SysJob sysJob) {
+		sysJob.setUpdateBy(SecurityUtils.getUser().getUsername());
+		SysJob querySysJob = this.sysJobService.getById(sysJob.getJobId());
+		if (SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) {
+			// 如修改暂停的需更新调度器
+			this.taskUtil.addOrUpateJob(sysJob, scheduler);
+			sysJobService.updateById(sysJob);
+		}
+		else if (SkyQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) {
+			sysJobService.updateById(sysJob);
+		}
+		return R.ok();
+	}
+
+	/**
+	 * 通过id删除定时任务
+	 * @param id id
+	 * @return R
+	 */
+	@SysLog("删除定时任务")
+	@DeleteMapping("remove/{id}")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_del')")
+	@Operation(description = "唯一标识查询定时任务,暂停任务才能删除")
+	public R removeById(@PathVariable Long id) {
+		SysJob querySysJob = this.sysJobService.getById(id);
+		if (SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(querySysJob.getJobStatus())) {
+			this.taskUtil.removeJob(querySysJob, scheduler);
+			this.sysJobService.removeById(id);
+		}
+		else if (SkyQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) {
+			this.sysJobService.removeById(id);
+		}
+		else if (SkyQuartzEnum.JOB_STATUS_RUNNING.getType().equals(querySysJob.getJobStatus())) {
+			return R.failed("暂停任务才能删除");
+		}
+		return R.ok();
+	}
+
+	/**
+	 * 暂停全部定时任务
+	 */
+	@SysLog("暂停全部定时任务")
+	@PostMapping("/shutdownJobs")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_shutdown_job')")
+	@Operation(description = "暂停全部定时任务")
+	public R shutdownJobs() {
+		taskUtil.pauseJobs(scheduler);
+		long count = this.sysJobService.count(
+				new LambdaQueryWrapper<SysJob>().eq(SysJob::getJobStatus, SkyQuartzEnum.JOB_STATUS_RUNNING.getType()));
+		if (count <= 0) {
+			return R.ok("无正在运行定时任务");
+		}
+		else {
+			// 更新定时任务状态条件,运行状态2更新为暂停状态2
+			this.sysJobService.update(
+					SysJob.builder().jobStatus(SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()).build(),
+					new UpdateWrapper<SysJob>().lambda()
+						.eq(SysJob::getJobStatus, SkyQuartzEnum.JOB_STATUS_RUNNING.getType()));
+			return R.ok("暂停成功");
+		}
+	}
+
+	/**
+	 * 启动全部定时任务
+	 */
+	@SysLog("启动全部定时任务")
+	@PostMapping("/startJobs")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_start_job')")
+	@Operation(description = "启动全部定时任务")
+	public R startJobs() {
+		// 更新定时任务状态条件,暂停状态3更新为运行状态2
+		this.sysJobService.update(SysJob.builder().jobStatus(SkyQuartzEnum.JOB_STATUS_RUNNING.getType()).build(),
+				new UpdateWrapper<SysJob>().lambda()
+					.eq(SysJob::getJobStatus, SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType()));
+		taskUtil.startJobs(scheduler);
+		return R.ok();
+	}
+
+	/**
+	 * 刷新全部定时任务
+	 */
+	@SysLog("刷新全部定时任务")
+	@PostMapping("/refreshJobs")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_refresh_job')")
+	@Operation(description = "刷新全部定时任务")
+	public R refreshJobs() {
+		sysJobService.list().forEach((sysjob) -> {
+			if (SkyQuartzEnum.JOB_STATUS_RELEASE.getType().equals(sysjob.getJobStatus())
+					|| SkyQuartzEnum.JOB_STATUS_DEL.getType().equals(sysjob.getJobStatus())) {
+				taskUtil.removeJob(sysjob, scheduler);
+			}
+			else if (SkyQuartzEnum.JOB_STATUS_RUNNING.getType().equals(sysjob.getJobStatus())
+					|| SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType().equals(sysjob.getJobStatus())) {
+				taskUtil.addOrUpateJob(sysjob, scheduler);
+			}
+			else {
+				taskUtil.removeJob(sysjob, scheduler);
+			}
+		});
+		return R.ok();
+	}
+
+	/**
+	 * 启动定时任务
+	 * @param job 定时任务
+	 */
+	@SysLog("启动定时任务")
+	@PostMapping("/startJob")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_start_job')")
+	@Operation(description = "启动定时任务")
+	public R startJob(@RequestBody SysJob job) throws SchedulerException {
+		SysJob querySysJob = this.sysJobService.getById(job.getJobId());
+		if (querySysJob == null) {
+			return R.failed("无此定时任务,请确认");
+		}
+
+		// 如果定时任务不存在,强制状态为1已发布
+		if (!scheduler.checkExists(TaskUtil.getJobKey(querySysJob))) {
+			querySysJob.setJobStatus(SkyQuartzEnum.JOB_STATUS_RELEASE.getType());
+			log.warn("定时任务不在quartz中,任务id:{},强制状态为已发布并加入调度器", job.getJobId());
+		}
+
+		if (SkyQuartzEnum.JOB_STATUS_RELEASE.getType().equals(querySysJob.getJobStatus())) {
+			taskUtil.addOrUpateJob(querySysJob, scheduler);
+		}
+		else {
+			taskUtil.resumeJob(querySysJob, scheduler);
+		}
+		// 更新定时任务状态为运行状态2
+		this.sysJobService
+				.updateById(SysJob.builder().jobId(job.getJobId()).jobStatus(SkyQuartzEnum.JOB_STATUS_RUNNING.getType()).build());
+		return R.ok();
+	}
+
+	/**
+	 * 立刻执行定时任务
+	 * @param job 任务
+	 */
+	@SysLog("立刻执行定时任务")
+	@PostMapping("/runJob")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_run_job')")
+	@Operation(description = "立刻执行定时任务")
+	public R runJob(@RequestBody SysJob job) throws SchedulerException {
+		SysJob querySysJob = this.sysJobService.getById(job.getJobId());
+
+		// 执行定时任务前判定任务是否在quartz中
+		if (!scheduler.checkExists(TaskUtil.getJobKey(querySysJob))) {
+			querySysJob.setJobStatus(SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType());
+			log.warn("立刻执行定时任务-定时任务不在quartz中,任务id:{},强制状态为暂停并加入调度器", job.getJobId());
+			taskUtil.addOrUpateJob(querySysJob, scheduler);
+		}
+
+		return TaskUtil.runOnce(scheduler, querySysJob) ? R.ok() : R.failed();
+	}
+
+	/**
+	 * 暂停定时任务
+	 */
+	@SysLog("暂停定时任务")
+	@PostMapping("/shutdownJob")
+	@PreAuthorize("@pms.hasPermission('job_sys_job_shutdown_job')")
+	@Operation(description = "暂停定时任务")
+	public R shutdownJob(@RequestBody SysJob job) {
+		SysJob querySysJob = this.sysJobService.getById(job.getJobId());
+		// 更新定时任务状态条件,运行状态2更新为暂停状态3
+		this.sysJobService.updateById(SysJob.builder()
+			.jobId(querySysJob.getJobId())
+			.jobStatus(SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())
+			.build());
+		taskUtil.pauseJob(querySysJob, scheduler);
+		return R.ok();
+	}
+
+	/**
+	 * 唯一标识查询定时执行日志
+	 */
+	@GetMapping("/jobLog")
+	@Operation(description = "唯一标识查询定时执行日志")
+	public R getJobLog(Page<SysJobLog> page, SysJobLog sysJobLog) {
+		return R.ok(sysJobLogService.page(page, Wrappers.lambdaQuery(sysJobLog).orderByDesc(SysJobLog::getCreateTime)));
+	}
+
+	/**
+	 * 检验任务名称和任务组联合是否唯一
+	 */
+	@GetMapping("/isValidTaskName")
+	@Operation(description = "检验任务名称和任务组联合是否唯一")
+	public R isValidTaskName(@RequestParam String jobName, @RequestParam String jobGroup) {
+		return this.sysJobService
+			.count(Wrappers.query(SysJob.builder().jobName(jobName).jobGroup(jobGroup).build())) > 0
+					? R.failed("任务重复,请检查此组内是否已包含同名任务") : R.ok();
+	}
+
+	/**
+	 * 导出任务
+	 * @param sysJob
+	 */
+	@ResponseExcel
+	@GetMapping("/export")
+	@Operation(description = "导出任务")
+	public List<SysJob> export(SysJob sysJob) {
+		return sysJobService.list(Wrappers.query(sysJob));
+	}
+
+}

+ 49 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/controller/SysJobLogController.java

@@ -0,0 +1,49 @@
+package com.lxq.daemon.quartz.controller;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.lxq.common.core.util.R;
+import com.lxq.daemon.quartz.entity.SysJobLog;
+import com.lxq.daemon.quartz.service.SysJobLogService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.security.SecurityRequirement;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.AllArgsConstructor;
+import org.springframework.http.HttpHeaders;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * @author LXQ
+ * <p>
+ * 定时任务执行日志表
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/sysJobLog")
+@Tag(description = "sys-job-log", name = "定时任务日志")
+@SecurityRequirement(name = HttpHeaders.AUTHORIZATION)
+public class SysJobLogController {
+
+	private final SysJobLogService sysJobLogService;
+
+	/**
+	 * 分页查询
+	 *
+	 * @param page      分页对象
+	 * @param sysJobLog 定时任务执行日志表
+	 * @return {@link R }
+	 */
+	@GetMapping("/page")
+	@Operation(description = "分页定时任务日志查询")
+	public R getSysJobLogPage(Page<SysJobLog> page, SysJobLog sysJobLog) {
+		return R.ok(sysJobLogService.page(page, Wrappers.lambdaQuery(sysJobLog).orderByDesc(SysJobLog::getCreateTime)));
+	}
+
+	@DeleteMapping
+	@Operation(description = "批量删除日志")
+	public R deleteLogs(@RequestBody Long[] ids) {
+		return R.ok(sysJobLogService.removeBatchByIds(CollUtil.toList(ids)));
+	}
+
+}

+ 162 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/entity/SysJob.java

@@ -0,0 +1,162 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 定时任务调度表
+ *
+ * @author LXQ
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "定时任务")
+public class SysJob extends Model<SysJob> {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 任务id
+	 */
+	@TableId(value = "job_id", type = IdType.ASSIGN_ID)
+	private Long jobId;
+
+	/**
+	 * 任务名称
+	 */
+	private String jobName;
+
+	/**
+	 * 任务组名
+	 */
+	private String jobGroup;
+
+	/**
+	 * 组内执行顺利,值越大执行优先级越高,最大值9,最小值1
+	 */
+	private String jobOrder;
+
+	/**
+	 * 1、java类;2、spring bean名称;3、rest调用;4、jar调用;9其他
+	 */
+	private String jobType;
+
+	/**
+	 * job_type=3时,rest调用地址,仅支持rest get协议,需要增加String返回值,0成功,1失败;job_type=4时,jar路径;其它值为空
+	 */
+	private String executePath;
+
+	/**
+	 * job_type=1时,类完整路径;job_type=2时,spring bean名称;其它值为空
+	 */
+	private String className;
+
+	/**
+	 * 任务方法
+	 */
+	private String methodName;
+
+	/**
+	 * 参数值
+	 */
+	private String methodParamsValue;
+
+	/**
+	 * cron执行表达式
+	 */
+	private String cronExpression;
+
+	/**
+	 * 错失执行策略(1错失周期立即执行 2错失周期执行一次 3下周期执行)
+	 */
+	private String misfirePolicy;
+
+	/**
+	 * 1、多租户任务;2、非多租户任务
+	 */
+	private String jobTenantType;
+
+	/**
+	 * 状态(0、未发布;1、已发布;2、运行中;3、暂停;4、删除;)
+	 */
+	private String jobStatus;
+
+	/**
+	 * 状态(0正常 1异常)
+	 */
+	private String jobExecuteStatus;
+
+	/**
+	 * 创建者
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private String createBy;
+
+	/**
+	 * 更新者
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	private String updateBy;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private LocalDateTime createTime;
+
+	/**
+	 * 修改时间
+	 */
+	@TableField(fill = FieldFill.UPDATE)
+	private LocalDateTime updateTime;
+
+	/**
+	 * 首次执行时间
+	 */
+	private LocalDateTime startTime;
+
+	/**
+	 * 上次执行时间
+	 */
+	private LocalDateTime previousTime;
+
+	/**
+	 * 下次执行时间
+	 */
+	private LocalDateTime nextTime;
+
+	/**
+	 * 备注信息
+	 */
+	private String remark;
+
+}

+ 130 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/entity/SysJobLog.java

@@ -0,0 +1,130 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.extension.activerecord.Model;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 定时任务执行日志表
+ *
+ * @author LXQ
+ * @date 2021-01-27 13:40:20
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@Schema(description = "定时任务日志")
+public class SysJobLog extends Model<SysJobLog> {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 任务日志ID
+	 */
+	@TableId(value = "job_log_id", type = IdType.ASSIGN_ID)
+	private Long jobLogId;
+
+	/**
+	 * 任务id
+	 */
+	private Long jobId;
+
+	/**
+	 * 任务名称
+	 */
+	private String jobName;
+
+	/**
+	 * 任务组名
+	 */
+	private String jobGroup;
+
+	/**
+	 * 组内执行顺利,值越大执行优先级越高,最大值9,最小值1
+	 */
+	private String jobOrder;
+
+	/**
+	 * 1、java类;2、spring bean名称;3、rest调用;4、jar调用;9其他
+	 */
+	private String jobType;
+
+	/**
+	 * job_type=3时,rest调用地址,仅支持post协议;job_type=4时,jar路径;其它值为空
+	 */
+	private String executePath;
+
+	/**
+	 * job_type=1时,类完整路径;job_type=2时,spring bean名称;其它值为空
+	 */
+	private String className;
+
+	/**
+	 * 任务方法
+	 */
+	private String methodName;
+
+	/**
+	 * 参数值
+	 */
+	private String methodParamsValue;
+
+	/**
+	 * cron执行表达式
+	 */
+	private String cronExpression;
+
+	/**
+	 * 日志信息
+	 */
+	private String jobMessage;
+
+	/**
+	 * 执行状态(0正常 1失败)
+	 */
+	private String jobLogStatus;
+
+	/**
+	 * 执行时间
+	 */
+	private String executeTime;
+
+	/**
+	 * 异常信息
+	 */
+	private String exceptionInfo;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private LocalDateTime createTime;
+
+}

+ 36 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobEvent.java

@@ -0,0 +1,36 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.event;
+
+import com.lxq.daemon.quartz.entity.SysJob;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.quartz.Trigger;
+
+/**
+ * @author LXQ 定时任务多线程事件
+ */
+@Getter
+@AllArgsConstructor
+public class SysJobEvent {
+
+	private final SysJob sysJob;
+
+	private final Trigger trigger;
+
+}

+ 49 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobListener.java

@@ -0,0 +1,49 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.event;
+
+import com.lxq.daemon.quartz.entity.SysJob;
+import com.lxq.daemon.quartz.util.TaskInvokUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Trigger;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author LXQ 异步监听定时任务事件
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class SysJobListener {
+
+	private final TaskInvokUtil taskInvokUtil;
+
+	@Async
+	@Order
+	@EventListener(SysJobEvent.class)
+	public void comSysJob(SysJobEvent event) {
+		SysJob sysJob = event.getSysJob();
+		Trigger trigger = event.getTrigger();
+		taskInvokUtil.invokeMethod(sysJob, trigger);
+	}
+
+}

+ 33 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobLogEvent.java

@@ -0,0 +1,33 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.event;
+
+import com.lxq.daemon.quartz.entity.SysJobLog;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author LXQ 定时任务日志多线程事件
+ */
+@Getter
+@AllArgsConstructor
+public class SysJobLogEvent {
+
+	private final SysJobLog sysJobLog;
+
+}

+ 48 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/event/SysJobLogListener.java

@@ -0,0 +1,48 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.event;
+
+import com.lxq.daemon.quartz.entity.SysJobLog;
+import com.lxq.daemon.quartz.service.SysJobLogService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author LXQ 异步监听定时任务日志事件
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class SysJobLogListener {
+
+	private final SysJobLogService sysJobLogService;
+
+	@Async
+	@Order
+	@EventListener(SysJobLogEvent.class)
+	public void saveSysJobLog(SysJobLogEvent event) {
+		SysJobLog sysJobLog = event.getSysJobLog();
+		sysJobLogService.save(sysJobLog);
+		log.info("执行定时任务日志");
+	}
+
+}

+ 35 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/exception/TaskException.java

@@ -0,0 +1,35 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.exception;
+
+/**
+ * 定时任务异常
+ *
+ * @author LXQ
+ */
+public class TaskException extends Exception {
+
+	public TaskException() {
+		super();
+	}
+
+	public TaskException(String msg) {
+		super(msg);
+	}
+
+}

+ 33 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/mapper/SysJobLogMapper.java

@@ -0,0 +1,33 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.lxq.daemon.quartz.entity.SysJobLog;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 定时任务执行日志表
+ *
+ * @author LXQ
+ * @date 2021-01-27 13:40:20
+ */
+@Mapper
+public interface SysJobLogMapper extends BaseMapper<SysJobLog> {
+
+}

+ 33 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/mapper/SysJobMapper.java

@@ -0,0 +1,33 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.lxq.daemon.quartz.entity.SysJob;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 定时任务调度表
+ *
+ * @author LXQ
+ * @date 2021-01-27 10:04:42
+ */
+@Mapper
+public interface SysJobMapper extends BaseMapper<SysJob> {
+
+}

+ 31 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/SysJobLogService.java

@@ -0,0 +1,31 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.lxq.daemon.quartz.entity.SysJobLog;
+
+/**
+ * 定时任务执行日志表
+ *
+ * @author LXQ
+ * @date 2021-01-27 13:40:20
+ */
+public interface SysJobLogService extends IService<SysJobLog> {
+
+}

+ 31 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/SysJobService.java

@@ -0,0 +1,31 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.lxq.daemon.quartz.entity.SysJob;
+
+/**
+ * 定时任务调度表
+ *
+ * @author LXQ
+ * @date 2021-01-27 10:04:42
+ */
+public interface SysJobService extends IService<SysJob> {
+
+}

+ 39 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/impl/SysJobLogServiceImpl.java

@@ -0,0 +1,39 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.lxq.daemon.quartz.entity.SysJobLog;
+import com.lxq.daemon.quartz.mapper.SysJobLogMapper;
+import com.lxq.daemon.quartz.service.SysJobLogService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 定时任务执行日志表
+ *
+ * @author LXQ
+ * @date 2021-01-27 13:40:20
+ */
+@Slf4j
+@Service
+@AllArgsConstructor
+public class SysJobLogServiceImpl extends ServiceImpl<SysJobLogMapper, SysJobLog> implements SysJobLogService {
+
+}

+ 39 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/service/impl/SysJobServiceImpl.java

@@ -0,0 +1,39 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.lxq.daemon.quartz.entity.SysJob;
+import com.lxq.daemon.quartz.mapper.SysJobMapper;
+import com.lxq.daemon.quartz.service.SysJobService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 定时任务调度表
+ *
+ * @author LXQ
+ * @date 2021-01-27 10:04:42
+ */
+@Slf4j
+@Service
+@AllArgsConstructor
+public class SysJobServiceImpl extends ServiceImpl<SysJobMapper, SysJob> implements SysJobService {
+
+}

+ 34 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/task/RestTaskDemo.java

@@ -0,0 +1,34 @@
+package com.lxq.daemon.quartz.task;
+
+import com.lxq.common.core.util.R;
+import com.lxq.common.security.annotation.Inner;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDateTime;
+
+/**
+ * 用于测试REST风格调用的demo
+ *
+ * @author LXQ
+ * @date 2021/3/25
+ */
+@Slf4j
+@RestController
+@RequestMapping("/inner-job")
+public class RestTaskDemo {
+
+	/**
+	 * 测试REST风格调用定时任务的演示方法
+	 */
+	@Inner(value = false)
+	@GetMapping("/test/{param}")
+	public R demoMethod(@PathVariable("param") String param) {
+		log.info("测试于:{},传入参数{}", LocalDateTime.now(), param);
+		return R.ok();
+	}
+
+}

+ 43 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/task/SpringBeanTaskDemo.java

@@ -0,0 +1,43 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.task;
+
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author LXQ
+ */
+@Slf4j
+@Component("demo")
+public class SpringBeanTaskDemo {
+
+	/**
+	 * 测试Spring Bean的演示方法
+	 */
+	@SneakyThrows
+	public String demoMethod(String para) {
+		log.info("测试于:{},输入参数{}", LocalDateTime.now(), para);
+		return SkyQuartzEnum.JOB_LOG_STATUS_SUCCESS.getType();
+	}
+
+}

+ 19 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/ITaskInvoke.java

@@ -0,0 +1,19 @@
+package com.lxq.daemon.quartz.util;
+
+import com.lxq.daemon.quartz.exception.TaskException;
+import com.lxq.daemon.quartz.entity.SysJob;
+
+/**
+ * 定时任务反射实现接口类
+ *
+ * @author LXQ
+ */
+public interface ITaskInvoke {
+
+	/**
+	 * 执行反射方法
+	 * @param sysJob 配置类
+     */
+	void invokeMethod(SysJob sysJob) throws TaskException;
+
+}

+ 62 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/JarTaskInvoke.java

@@ -0,0 +1,62 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.util;
+
+import cn.hutool.core.util.StrUtil;
+import com.lxq.daemon.quartz.exception.TaskException;
+import com.lxq.daemon.quartz.entity.SysJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 定时任务可执行jar反射实现
+ *
+ * @author LXQ
+ */
+@Slf4j
+@Component("jarTaskInvoke")
+public class JarTaskInvoke implements ITaskInvoke {
+
+	@Override
+	public void invokeMethod(SysJob sysJob) throws TaskException {
+		ProcessBuilder processBuilder = new ProcessBuilder();
+		File jar = new File(sysJob.getExecutePath());
+		processBuilder.directory(jar.getParentFile());
+		List<String> commands = new ArrayList<>();
+		commands.add("java");
+		commands.add("-jar");
+		commands.add(sysJob.getExecutePath());
+		if (StrUtil.isNotEmpty(sysJob.getMethodParamsValue())) {
+			commands.add(sysJob.getMethodParamsValue());
+		}
+		processBuilder.command(commands);
+		try {
+			processBuilder.start();
+		}
+		catch (IOException e) {
+			log.error("定时任务jar反射执行异常,执行任务:{}", sysJob.getExecutePath());
+			throw new TaskException("定时任务jar反射执行异常,执行任务:" + sysJob.getExecutePath());
+		}
+	}
+
+}

+ 87 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/JavaClassTaskInvoke.java

@@ -0,0 +1,87 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.util;
+
+import cn.hutool.core.util.StrUtil;
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import com.lxq.daemon.quartz.exception.TaskException;
+import com.lxq.daemon.quartz.entity.SysJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * 定时任务java class反射实现
+ *
+ * @author LXQ
+ */
+@Component("javaClassTaskInvoke")
+@Slf4j
+public class JavaClassTaskInvoke implements ITaskInvoke {
+
+	@Override
+	public void invokeMethod(SysJob sysJob) throws TaskException {
+		Object obj;
+		Class clazz;
+		Method method;
+		Object returnValue;
+		try {
+			if (StrUtil.isNotEmpty(sysJob.getMethodParamsValue())) {
+				clazz = Class.forName(sysJob.getClassName());
+				obj = clazz.newInstance();
+				method = clazz.getDeclaredMethod(sysJob.getMethodName(), String.class);
+				returnValue = method.invoke(obj, sysJob.getMethodParamsValue());
+			}
+			else {
+				clazz = Class.forName(sysJob.getClassName());
+				obj = clazz.newInstance();
+				method = clazz.getDeclaredMethod(sysJob.getMethodName());
+				returnValue = method.invoke(obj);
+			}
+			if (StrUtil.isEmpty(returnValue.toString())
+					|| SkyQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(returnValue.toString())) {
+				log.error("定时任务javaClassTaskInvok异常,执行任务:{}", sysJob.getClassName());
+				throw new TaskException("定时任务javaClassTaskInvok业务执行失败,任务:" + sysJob.getClassName());
+			}
+		}
+		catch (ClassNotFoundException e) {
+			log.error("定时任务java反射类没有找到,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务java反射类没有找到,执行任务:" + sysJob.getClassName());
+		}
+		catch (IllegalAccessException e) {
+			log.error("定时任务java反射类异常,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务java反射类异常,执行任务:" + sysJob.getClassName());
+		}
+		catch (InstantiationException e) {
+			log.error("定时任务java反射类异常,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务java反射类异常,执行任务:" + sysJob.getClassName());
+		}
+		catch (NoSuchMethodException e) {
+			log.error("定时任务java反射执行方法名异常,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务java反射执行方法名异常,执行任务:" + sysJob.getClassName());
+		}
+		catch (InvocationTargetException e) {
+			log.error("定时任务java反射执行异常,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务java反射执行异常,执行任务:" + sysJob.getClassName());
+		}
+
+	}
+
+}

+ 50 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/RestTaskInvoke.java

@@ -0,0 +1,50 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.util;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpUtil;
+import com.lxq.daemon.quartz.exception.TaskException;
+import com.lxq.daemon.quartz.entity.SysJob;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 定时任务rest反射实现
+ *
+ * @author LXQ
+ */
+@Slf4j
+@AllArgsConstructor
+@Component("restTaskInvoke")
+public class RestTaskInvoke implements ITaskInvoke {
+
+	@Override
+	public void invokeMethod(SysJob sysJob) throws TaskException {
+		try {
+			HttpRequest request = HttpUtil.createGet(sysJob.getExecutePath());
+			request.execute();
+		}
+		catch (Exception e) {
+			log.error("定时任务restTaskInvoke异常,执行任务:{}", sysJob.getExecutePath());
+			throw new TaskException("定时任务restTaskInvoke业务执行失败,任务:" + sysJob.getExecutePath());
+		}
+	}
+
+}

+ 80 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/SpringBeanTaskInvoke.java

@@ -0,0 +1,80 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.util;
+
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.StrUtil;
+import com.lxq.common.core.util.SpringContextHolder;
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import com.lxq.daemon.quartz.entity.SysJob;
+import com.lxq.daemon.quartz.exception.TaskException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * 定时任务spring bean反射实现
+ *
+ * @author LXQ
+ */
+@Component("springBeanTaskInvoke")
+@Slf4j
+public class SpringBeanTaskInvoke implements ITaskInvoke {
+
+	@Override
+	public void invokeMethod(SysJob sysJob) throws TaskException {
+		Object target;
+		Method method;
+		Object returnValue;
+		// 通过Spring上下文去找 也有可能找不到
+		target = SpringContextHolder.getBean(sysJob.getClassName());
+		try {
+			if (StrUtil.isNotEmpty(sysJob.getMethodParamsValue())) {
+				method = target.getClass().getDeclaredMethod(sysJob.getMethodName(), String.class);
+				ReflectionUtils.makeAccessible(method);
+				returnValue = method.invoke(target, sysJob.getMethodParamsValue());
+			}
+			else {
+				method = target.getClass().getDeclaredMethod(sysJob.getMethodName());
+				ReflectionUtils.makeAccessible(method);
+				returnValue = method.invoke(target);
+			}
+			if (CharSequenceUtil.isEmpty(returnValue.toString())
+					|| SkyQuartzEnum.JOB_LOG_STATUS_FAIL.getType().equals(returnValue.toString())) {
+				log.error("定时任务springBeanTaskInvok异常,执行任务:{}", sysJob.getClassName());
+				throw new TaskException("定时任务springBeanTaskInvok业务执行失败,任务:" + sysJob.getClassName());
+			}
+		}
+		catch (NoSuchMethodException e) {
+			log.error("定时任务spring bean反射异常方法未找到,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务spring bean反射异常方法未找到,执行任务:" + sysJob.getClassName());
+		}
+		catch (IllegalAccessException e) {
+			log.error("定时任务spring bean反射异常,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务spring bean反射异常,执行任务:" + sysJob.getClassName());
+		}
+		catch (InvocationTargetException e) {
+			log.error("定时任务spring bean反射执行异常,执行任务:{}", sysJob.getClassName());
+			throw new TaskException("定时任务spring bean反射执行异常,执行任务:" + sysJob.getClassName());
+		}
+	}
+
+}

+ 50 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/TaskInvokFactory.java

@@ -0,0 +1,50 @@
+package com.lxq.daemon.quartz.util;
+
+import cn.hutool.core.util.StrUtil;
+import com.lxq.common.core.util.SpringContextHolder;
+import com.lxq.daemon.quartz.constants.JobTypeQuartzEnum;
+import com.lxq.daemon.quartz.exception.TaskException;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author 没秃顶的码农
+ * @version 1.0
+ * @date 2021/8/8 15:40 TaskInvok工厂类
+ */
+@Slf4j
+public class TaskInvokFactory {
+
+	/**
+	 * 根据对应jobType获取对应 invoker
+	 * @param jobType
+	 * @return
+	 * @throws TaskException
+	 */
+	public static ITaskInvoke getInvoker(String jobType) throws TaskException {
+		if (StrUtil.isBlank(jobType)) {
+			log.info("获取TaskInvok传递参数有误,jobType:{}", jobType);
+			throw new TaskException("");
+		}
+
+		ITaskInvoke iTaskInvoke = null;
+		if (JobTypeQuartzEnum.JAVA.getType().equals(jobType)) {
+			iTaskInvoke = SpringContextHolder.getBean("javaClassTaskInvoke");
+		}
+		else if (JobTypeQuartzEnum.SPRING_BEAN.getType().equals(jobType)) {
+			iTaskInvoke = SpringContextHolder.getBean("springBeanTaskInvoke");
+		}
+		else if (JobTypeQuartzEnum.REST.getType().equals(jobType)) {
+			iTaskInvoke = SpringContextHolder.getBean("restTaskInvoke");
+		}
+		else if (JobTypeQuartzEnum.JAR.getType().equals(jobType)) {
+			iTaskInvoke = SpringContextHolder.getBean("jarTaskInvoke");
+		}
+		else if (StrUtil.isBlank(jobType)) {
+			log.info("定时任务类型无对应反射方式,反射类型:{}", jobType);
+			throw new TaskException("");
+		}
+
+		return iTaskInvoke;
+	}
+
+}

+ 99 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/TaskInvokUtil.java

@@ -0,0 +1,99 @@
+package com.lxq.daemon.quartz.util;
+
+import cn.hutool.core.text.CharSequenceUtil;
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import com.lxq.daemon.quartz.exception.TaskException;
+import com.lxq.daemon.quartz.service.SysJobService;
+import com.lxq.daemon.quartz.entity.SysJob;
+import com.lxq.daemon.quartz.entity.SysJobLog;
+import com.lxq.daemon.quartz.event.SysJobLogEvent;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.CronTrigger;
+import org.quartz.Trigger;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.stereotype.Component;
+
+import java.time.ZoneId;
+import java.util.Date;
+
+/**
+ * 定时任务反射工具类
+ *
+ * @author LXQ
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class TaskInvokUtil {
+
+	private final ApplicationEventPublisher publisher;
+
+	private final SysJobService sysJobService;
+
+	@SneakyThrows
+	public void invokeMethod(SysJob sysJob, Trigger trigger) {
+
+		// 执行开始时间
+		long startTime;
+		// 执行结束时间
+		long endTime;
+		// 获取执行开始时间
+		startTime = System.currentTimeMillis();
+		// 更新定时任务表内的状态、执行时间、上次执行时间、下次执行时间等信息
+		SysJob updateSysjob = new SysJob();
+		updateSysjob.setJobId(sysJob.getJobId());
+		// 日志
+		SysJobLog sysJobLog = new SysJobLog();
+		sysJobLog.setJobId(sysJob.getJobId());
+		sysJobLog.setJobName(sysJob.getJobName());
+		sysJobLog.setJobGroup(sysJob.getJobGroup());
+		sysJobLog.setJobOrder(sysJob.getJobOrder());
+		sysJobLog.setJobType(sysJob.getJobType());
+		sysJobLog.setExecutePath(sysJob.getExecutePath());
+		sysJobLog.setClassName(sysJob.getClassName());
+		sysJobLog.setMethodName(sysJob.getMethodName());
+		sysJobLog.setMethodParamsValue(sysJob.getMethodParamsValue());
+		sysJobLog.setCronExpression(sysJob.getCronExpression());
+        try {
+            // 执行任务
+            ITaskInvoke iTaskInvoke = TaskInvokFactory.getInvoker(sysJob.getJobType());
+            // 确保租户上下文有值,使得当前线程中的多租户特性生效。
+            iTaskInvoke.invokeMethod(sysJob);
+            // 记录成功状态
+            sysJobLog.setJobMessage(SkyQuartzEnum.JOB_LOG_STATUS_SUCCESS.getDescription());
+            sysJobLog.setJobLogStatus(SkyQuartzEnum.JOB_LOG_STATUS_SUCCESS.getType());
+            // 任务表信息更新
+            updateSysjob.setJobExecuteStatus(SkyQuartzEnum.JOB_LOG_STATUS_SUCCESS.getType());
+        } catch (TaskException e) {
+            log.error("定时任务执行失败,任务名称:{};任务组名:{},cron执行表达式:{},执行时间:{}", sysJob.getJobName(), sysJob.getJobGroup(),
+                    sysJob.getCronExpression(), new Date());
+            log.error("报错信息", e);
+
+            // 记录失败状态
+            sysJobLog.setJobMessage(SkyQuartzEnum.JOB_LOG_STATUS_FAIL.getDescription());
+            sysJobLog.setJobLogStatus(SkyQuartzEnum.JOB_LOG_STATUS_FAIL.getType());
+            sysJobLog.setExceptionInfo(CharSequenceUtil.sub(e.getMessage(), 0, 2000));
+            // 任务表信息更新
+            updateSysjob.setJobExecuteStatus(SkyQuartzEnum.JOB_LOG_STATUS_FAIL.getType());
+        } finally {
+            // 记录执行时间 立刻执行使用的是simpleTeigger
+            if (trigger instanceof CronTrigger) {
+                updateSysjob
+                        .setStartTime(trigger.getStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
+                updateSysjob.setPreviousTime(
+                        trigger.getPreviousFireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
+                updateSysjob.setNextTime(
+                        trigger.getNextFireTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
+            }
+            // 记录执行时长
+            endTime = System.currentTimeMillis();
+            sysJobLog.setExecuteTime(String.valueOf(endTime - startTime));
+
+            publisher.publishEvent(new SysJobLogEvent(sysJobLog));
+            sysJobService.updateById(updateSysjob);
+        }
+	}
+
+}

+ 244 - 0
lxq-quartz/src/main/java/com/lxq/daemon/quartz/util/TaskUtil.java

@@ -0,0 +1,244 @@
+/*
+ *    Copyright (c) 2021-2025, LXQ All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * Neither the name of the com developer nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * Author: LXQ (609827073@qq.com)
+ */
+
+package com.lxq.daemon.quartz.util;
+
+import com.lxq.daemon.quartz.constants.SkyQuartzEnum;
+import com.lxq.daemon.quartz.config.LxqQuartzFactory;
+import com.lxq.daemon.quartz.entity.SysJob;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.*;
+import org.springframework.stereotype.Component;
+
+/**
+ * 定时任务的工具类
+ *
+ * @author LXQ
+ */
+@Slf4j
+@Component
+public class TaskUtil {
+
+	/**
+	 * 获取定时任务的唯一key
+	 * @param sysjob
+	 * @return
+	 */
+	public static JobKey getJobKey(SysJob sysjob) {
+		return JobKey.jobKey(sysjob.getJobName(), sysjob.getJobGroup());
+	}
+
+	/**
+	 * 获取定时任务触发器cron的唯一key
+	 * @param sysjob
+	 * @return
+	 */
+	public static TriggerKey getTriggerKey(SysJob sysjob) {
+		return TriggerKey.triggerKey(sysjob.getJobName(), sysjob.getJobGroup());
+	}
+
+	/**
+	 * 添加或更新定时任务
+	 * @param sysjob
+	 * @param scheduler
+	 */
+	public void addOrUpateJob(SysJob sysjob, Scheduler scheduler) {
+		CronTrigger trigger = null;
+		try {
+			JobKey jobKey = getJobKey(sysjob);
+			// 获得触发器
+			TriggerKey triggerKey = getTriggerKey(sysjob);
+			trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
+			// 判断触发器是否存在(如果存在说明之前运行过但是在当前被禁用了,如果不存在说明一次都没运行过)
+			if (trigger == null) {
+				// 新建一个工作任务 指定任务类型为串接进行的
+				JobDetail jobDetail = JobBuilder.newJob(LxqQuartzFactory.class).withIdentity(jobKey).build();
+				// 将任务信息添加到任务信息中
+				jobDetail.getJobDataMap().put(SkyQuartzEnum.SCHEDULE_JOB_KEY.getType(), sysjob);
+				// 将cron表达式进行转换
+				CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysjob.getCronExpression());
+				cronScheduleBuilder = this.handleCronScheduleMisfirePolicy(sysjob, cronScheduleBuilder);
+				// 创建触发器并将cron表达式对象给塞入
+				trigger = TriggerBuilder.newTrigger()
+					.withIdentity(triggerKey)
+					.withSchedule(cronScheduleBuilder)
+					.build();
+				// 在调度器中将触发器和任务进行组合
+				scheduler.scheduleJob(jobDetail, trigger);
+			}
+			else {
+				CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(sysjob.getCronExpression());
+				cronScheduleBuilder = this.handleCronScheduleMisfirePolicy(sysjob, cronScheduleBuilder);
+				// 按照新的规则进行
+				trigger = trigger.getTriggerBuilder()
+					.withIdentity(triggerKey)
+					.withSchedule(cronScheduleBuilder)
+					.build();
+				// 将任务信息更新到任务信息中
+				trigger.getJobDataMap().put(SkyQuartzEnum.SCHEDULE_JOB_KEY.getType(), sysjob);
+				// 重启
+				scheduler.rescheduleJob(triggerKey, trigger);
+			}
+			// 如任务状态为暂停
+			if (sysjob.getJobStatus().equals(SkyQuartzEnum.JOB_STATUS_NOT_RUNNING.getType())) {
+				this.pauseJob(sysjob, scheduler);
+			}
+		}
+		catch (SchedulerException e) {
+			log.error("添加或更新定时任务,失败信息:{}", e.getMessage());
+		}
+	}
+
+	/**
+	 * 立即执行一次任务
+	 */
+	public static boolean runOnce(Scheduler scheduler, SysJob sysJob) {
+		try {
+			// 参数
+			JobDataMap dataMap = new JobDataMap();
+			dataMap.put(SkyQuartzEnum.SCHEDULE_JOB_KEY.getType(), sysJob);
+
+			scheduler.triggerJob(getJobKey(sysJob), dataMap);
+		}
+		catch (SchedulerException e) {
+			log.error("立刻执行定时任务,失败信息:{}", e.getMessage());
+			return false;
+		}
+
+		return true;
+	}
+
+	/**
+	 * 暂停定时任务
+	 * @param sysjob
+	 * @param scheduler
+	 */
+	public void pauseJob(SysJob sysjob, Scheduler scheduler) {
+		try {
+			if (scheduler != null) {
+				scheduler.pauseJob(getJobKey(sysjob));
+			}
+		}
+		catch (SchedulerException e) {
+			log.error("暂停任务失败,失败信息:{}", e.getMessage());
+		}
+
+	}
+
+	/**
+	 * 恢复定时任务
+	 * @param sysjob
+	 * @param scheduler
+	 */
+	public void resumeJob(SysJob sysjob, Scheduler scheduler) {
+		try {
+			if (scheduler != null) {
+				scheduler.resumeJob(getJobKey(sysjob));
+			}
+		}
+		catch (SchedulerException e) {
+			log.error("恢复任务失败,失败信息:{}", e.getMessage());
+		}
+
+	}
+
+	/**
+	 * 移除定时任务
+	 * @param sysjob
+	 * @param scheduler
+	 */
+	public void removeJob(SysJob sysjob, Scheduler scheduler) {
+		try {
+			if (scheduler != null) {
+				// 停止触发器
+				scheduler.pauseTrigger(getTriggerKey(sysjob));
+				// 移除触发器
+				scheduler.unscheduleJob(getTriggerKey(sysjob));
+				// 删除任务
+				scheduler.deleteJob(getJobKey(sysjob));
+			}
+		}
+		catch (Exception e) {
+			log.error("移除定时任务失败,失败信息:{}", e.getMessage());
+		}
+	}
+
+	/**
+	 * 启动所有运行定时任务
+	 * @param scheduler
+	 */
+	public void startJobs(Scheduler scheduler) {
+		try {
+			if (scheduler != null) {
+				scheduler.resumeAll();
+			}
+		}
+		catch (SchedulerException e) {
+			log.error("启动所有运行定时任务失败,失败信息:{}", e.getMessage());
+		}
+	}
+
+	/**
+	 * 停止所有运行定时任务
+	 * @param scheduler
+	 */
+	public void pauseJobs(Scheduler scheduler) {
+		try {
+			if (scheduler != null) {
+				scheduler.pauseAll();
+			}
+		}
+		catch (Exception e) {
+			log.error("暂停所有运行定时任务失败,失败信息:{}", e.getMessage());
+		}
+	}
+
+	/**
+	 * 获取错失执行策略方法
+	 * @param sysJob
+	 * @param cronScheduleBuilder
+	 * @return
+	 */
+	private CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob sysJob,
+			CronScheduleBuilder cronScheduleBuilder) {
+		if (SkyQuartzEnum.MISFIRE_DEFAULT.getType().equals(sysJob.getMisfirePolicy())) {
+			return cronScheduleBuilder;
+		}
+		else if (SkyQuartzEnum.MISFIRE_IGNORE_MISFIRES.getType().equals(sysJob.getMisfirePolicy())) {
+			return cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
+		}
+		else if (SkyQuartzEnum.MISFIRE_FIRE_AND_PROCEED.getType().equals(sysJob.getMisfirePolicy())) {
+			return cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
+		}
+		else if (SkyQuartzEnum.MISFIRE_DO_NOTHING.getType().equals(sysJob.getMisfirePolicy())) {
+			return cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();
+		}
+		else {
+			return cronScheduleBuilder;
+		}
+	}
+
+	/**
+	 * 判断cron表达式是否正确
+	 * @param cronExpression
+	 * @return
+	 */
+	public boolean isValidCron(String cronExpression) {
+		return CronExpression.isValidExpression(cronExpression);
+	}
+
+}

+ 8 - 0
pom.xml

@@ -79,6 +79,7 @@
         <module>lxq-common</module>
         <module>lxq-system</module>
         <module>lxq-admin</module>
+        <module>lxq-quartz</module>
     </modules>
     <dependencyManagement>
         <dependencies>
@@ -132,11 +133,18 @@
                 <version>${alipay.version}</version>
             </dependency>
 
+            <!-- 系统模块 -->
             <dependency>
                 <groupId>com.lxq</groupId>
                 <artifactId>lxq-system</artifactId>
                 <version>${lxq.common.version}</version>
             </dependency>
+            <!-- 定时任务 -->
+            <dependency>
+                <groupId>com.lxq</groupId>
+                <artifactId>lxq-quartz</artifactId>
+                <version>${lxq.common.version}</version>
+            </dependency>
 
             <!--lxq 公共版本定义-->
             <dependency>