yuanhao 2 vuotta sitten
vanhempi
commit
d6be6d756b

+ 16 - 0
in-cloud/pom.xml

@@ -89,6 +89,22 @@
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
 
+        <!-- quartz -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.mchange</groupId>
+            <artifactId>c3p0</artifactId>
+            <version>0.9.5.4</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

+ 21 - 4
in-cloud/src/main/java/com/jiayue/insu/incloud/controller/TestController.java

@@ -1,15 +1,17 @@
 package com.jiayue.insu.incloud.controller;
 
-import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.date.DateUtil;
 import com.jiayue.insu.common.core.util.R;
-import com.jiayue.insu.incloud.entity.User;
-import com.jiayue.insu.incloud.service.UserService;
+import com.jiayue.insu.incloud.entity.Quartz;
+import com.jiayue.insu.incloud.quartz.ScheduledTask;
+import org.quartz.SchedulerException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.text.ParseException;
+
 @RestController
 @RequestMapping("/test")
 public class TestController {
@@ -17,4 +19,19 @@ public class TestController {
     public R test(){
        return R.ok("ok");
    }
+
+    @Autowired
+    ScheduledTask scheduledTask;
+
+    @GetMapping("/job")
+    public R testJob() throws ClassNotFoundException, SchedulerException, ParseException {
+        Quartz quartz = new Quartz();
+        quartz.setExecuteClass("com.jiayue.insu.incloud.quartz.job.TestJob");
+        quartz.setCronExpression("30 0/1 * * * ?");
+        quartz.setJobName("testJob2");
+        quartz.setStartTime(DateUtil.current());
+        Class c = Class.forName(quartz.getExecuteClass());
+        scheduledTask.scheduleJob(c,quartz.getJobName(),quartz.getStartTime(),quartz.getCronExpression(),null);
+        return R.ok();
+    }
 }

+ 52 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/entity/Quartz.java

@@ -0,0 +1,52 @@
+package com.jiayue.insu.incloud.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * Quartz
+ *
+ * @author bizy
+ * @version 1.0
+ * @since 2018/12/7 16:22
+ */
+@TableName(value = "quartz")
+@Data
+public class Quartz {
+
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+    /*任务名称*/
+    private String jobName;
+    /*任务状态*/
+    private String jobState;
+    /*执行类*/
+    private String executeClass;
+    /*任务描述*/
+    private String description;
+    /*cron时间表达式或轮询时间*/
+    private String cronExpression;
+    /*类型*/
+    private String jobType;
+    /*开始时间*/
+    private Long startTime;
+
+    /**
+     * 场站标识
+     */
+    private String stationCode;
+
+    @TableField(value = "false")
+    private Date nextFireTime;//下次执行时间
+    @TableField(value = "false")
+    private Date prevFireTime;//上次执行时间
+    @TableField(value = "false")
+    private Date laetFireTime;//最后执行时间
+
+
+}

+ 234 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/quartz/ScheduledTask.java

@@ -0,0 +1,234 @@
+package com.jiayue.insu.incloud.quartz;
+
+import lombok.NonNull;
+import org.quartz.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
+import org.springframework.scheduling.quartz.JobDetailFactoryBean;
+import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
+import org.springframework.stereotype.Component;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Map;
+
+@Component
+public class ScheduledTask {
+
+    @Autowired
+    private Scheduler scheduler;
+    /**
+     * 创建或更新定时任务
+     *
+     * @param t                    定时任务执行类
+     * @param jobCode              任务标识(每个人任务标识为一)
+     * @param jobRunStartTime      任务执行开始时间,单位:毫秒
+     * @param jobRunRepeatInterval 任务重复执行间隔时间,单位:毫秒
+     * @param paramMap             任务参数
+     * @param <T>                  定时任务执行类必须继承BaseJob
+     * @throws SchedulerException 任务创建或更新异常
+     * @throws ParseException     cron表达式异常
+     */
+    public <T extends Job> void scheduleJob( Class<T> t,  final String jobCode,
+                                                 final Long jobRunStartTime,  final Long jobRunRepeatInterval,
+                                                final Map<String, Object> paramMap) throws SchedulerException, ParseException {
+        // 获取触发器
+        SimpleTrigger simpleTrigger = this.getSimpleTrigger(jobCode, jobRunStartTime, jobRunRepeatInterval, paramMap);
+        // 安排任务
+        this.scheduleJob(t, simpleTrigger, jobCode);
+        this.resumeJob(jobCode);// 启动任务
+    }
+
+    /**
+     * 创建或更新定时任务
+     *
+     * @param t               定时任务执行类
+     * @param jobCode         任务标识(每个人任务标识为一)
+     * @param jobRunStartTime 任务执行开始时间,单位:毫秒
+     * @param cronExpression  任务执行策略
+     * @param paramMap        任务参数
+     * @param <T>             定时任务执行类必须继承BaseJob
+     * @throws SchedulerException 任务创建或更新异常
+     * @throws ParseException     cron表达式异常
+     */
+    public <T extends Job> void scheduleJob( Class<T> t,  final String jobCode,
+                                                 final Long jobRunStartTime,  final String cronExpression, final Map<String, Object> paramMap)
+            throws SchedulerException, ParseException {
+        // 获取触发器
+        CronTrigger cronTrigger = this.getCronTrigger(jobCode, jobRunStartTime, cronExpression, paramMap);
+        // 安排任务
+        this.scheduleJob(t, cronTrigger, jobCode);
+        this.resumeJob(jobCode);// 启动任务
+    }
+
+    /**
+     * 安排定时任务
+     *
+     * @param t       定时任务执行类
+     * @param e       定时器
+     * @param jobCode 任务标识
+     * @param <T>     定时器实现类
+     * @param <E>     触发器实现类
+     * @throws SchedulerException 安排定时任务异常
+     * @throws ParseException     cron表达式异常
+     */
+    public <T extends Job, E extends Trigger> void scheduleJob( Class<T> t, @NonNull E e,
+                                                                    final String jobCode) throws SchedulerException, ParseException {
+        // 如果触发器已存在,则重新安排该任务,否则将创建新的任务安排
+        if (scheduler.checkExists(e.getKey())) {
+            scheduler.rescheduleJob(e.getKey(), e);
+        } else {
+            JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
+            jobDetailFactoryBean.setJobClass(t);
+            jobDetailFactoryBean.setName(jobCode);
+            jobDetailFactoryBean.afterPropertiesSet();
+            JobDetail jobDetail = jobDetailFactoryBean.getObject();
+            scheduler.scheduleJob(jobDetail, e);
+        }
+    }
+
+    /**
+     * 删除任务
+     *
+     * @param jobCode 任务标识
+     * @throws SchedulerException 任务删除异常
+     */
+    public void deleteJob( final String jobCode) throws SchedulerException {
+        JobKey jobKey = JobKey.jobKey(jobCode);
+        // 如果任务存在,则删除
+        if (scheduler.checkExists(jobKey))
+            scheduler.deleteJob(jobKey);
+    }
+
+    /**
+     * 暂停任务
+     *
+     * @param jobCode 任务标识
+     * @throws SchedulerException 任务暂停异常
+     */
+    public void pauseJob(final String jobCode) throws SchedulerException {
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobCode);
+        if (scheduler.checkExists(triggerKey))
+            scheduler.pauseTrigger(triggerKey);
+    }
+
+    /**
+     * 重启任务
+     *
+     * @param jobCode 任务标识
+     * @throws SchedulerException 任务重启异常
+     */
+    public void resumeJob(final String jobCode) throws SchedulerException {
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobCode);
+        if (scheduler.checkExists(triggerKey))
+            scheduler.resumeTrigger(triggerKey);
+    }
+
+    /**
+     * 获取触发器
+     *
+     * @param jobCode              触发器标识
+     * @param jobRunStartTime      开始执行时间, 单位:毫秒
+     * @param jobRunRepeatInterval 重复执行间隔, 单位:毫秒
+     * @param paramMap             触发器参数
+     * @return 触发器
+     * @throws SchedulerException 获取触发器异常
+     */
+    private SimpleTrigger getSimpleTrigger( final String jobCode, final Long jobRunStartTime,
+                                           final Long jobRunRepeatInterval, final Map<String, Object> paramMap) throws SchedulerException {
+        SimpleTriggerFactoryBean simpleTriggerFactoryBean = new SimpleTriggerFactoryBean();
+        if (paramMap != null)
+            simpleTriggerFactoryBean.setJobDataAsMap(paramMap);// 设置任务执行参数
+        simpleTriggerFactoryBean.setStartTime(new Date(jobRunStartTime));// 开始执行时间
+        simpleTriggerFactoryBean.setRepeatInterval(jobRunRepeatInterval);//重复执行间隔时间 单位毫秒
+        simpleTriggerFactoryBean.setName(jobCode);
+        simpleTriggerFactoryBean.setMisfireInstruction(
+                SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);// 定时任务失火后,将忽略未执行任务,继续下一次任务
+        simpleTriggerFactoryBean.afterPropertiesSet();
+        return simpleTriggerFactoryBean.getObject();
+    }
+
+    /**
+     * 获取触发器
+     *
+     * @param jobCode         触发器标识
+     * @param jobRunStartTime 开始执行时间,单位:毫秒
+     * @param cronExpression  执行策略表达式
+     * @param paramMap        触发器参数
+     * @return 触发器
+     * @throws SchedulerException 获取触发器异常
+     * @throws ParseException     执行策略表达式异常
+     */
+    private CronTrigger getCronTrigger(final String jobCode, final Long jobRunStartTime,
+                                       final String cronExpression, final Map<String, Object> paramMap)
+            throws SchedulerException, ParseException {
+        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
+        if (paramMap != null)
+            cronTriggerFactoryBean.setJobDataAsMap(paramMap);// 设置任务执行参数
+        cronTriggerFactoryBean.setStartTime(new Date(jobRunStartTime));// 开始执行时间
+        cronTriggerFactoryBean.setCronExpression(cronExpression);// 执行策略
+        cronTriggerFactoryBean.setName(jobCode);
+        cronTriggerFactoryBean
+                .setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);// 定时任务失火后,目前不执行,然后就按照正常的计划执行。
+        cronTriggerFactoryBean.afterPropertiesSet();
+        return cronTriggerFactoryBean.getObject();
+    }
+
+    /**
+     * 获取任务最后执行时间
+     *
+     * @param jobCode 任务标识
+     * @return 任务最后执行时间
+     * @throws SchedulerException 获取任务最后执行时间异常
+     */
+    public Date getJobPreviousFireTime(final String jobCode) throws SchedulerException {
+        TriggerKey triggerKey = new TriggerKey(jobCode);
+        Trigger trigger = this.scheduler.getTrigger(triggerKey);
+        if (trigger == null)
+            throw new SchedulerException(jobCode + "任务不存在!");
+        return trigger.getPreviousFireTime();
+    }
+
+    /**
+     * 获取任务下次执行时间
+     *
+     * @param jobCode 任务标识
+     * @return 任务下次执行时间
+     * @throws SchedulerException 获取任务下次执行时间异常
+     */
+    Date getJobNextFireTime( final String jobCode) throws SchedulerException {
+        TriggerKey triggerKey = new TriggerKey(jobCode);
+        Trigger trigger = this.scheduler.getTrigger(triggerKey);
+        if (trigger == null)
+            throw new SchedulerException(jobCode + "任务不存在!");
+        return trigger.getNextFireTime();
+    }
+
+    /**
+     * 获取任务状态
+     *
+     * @param jobCode 任务标识
+     * @return 任务状态,中文描述
+     * @throws SchedulerException 获取任务状态异常
+     */
+    public String getJobStatus( final String jobCode) throws SchedulerException {
+        TriggerKey triggerKey = new TriggerKey(jobCode);
+        String triggerStateName = this.scheduler.getTriggerState(triggerKey).name();
+        if ("NONE".equals(triggerStateName)) {// 不存在
+            return "不存在";
+        } else if ("NORMAL".equals(triggerStateName)) {// 正常
+            return "正常";
+        } else if ("PAUSED".equals(triggerStateName)) {// 暂停
+            return "暂停";
+        } else if ("COMPLETE".equals(triggerStateName)) {// 完成
+            return "完成";
+        } else if ("ERROR".equals(triggerStateName)) {// 错误
+            return "错误";
+        } else if ("BLOCKED".equals(triggerStateName)) {// 阻塞
+            return "阻塞";
+        }
+        return triggerStateName;
+    }
+
+
+}

+ 13 - 0
in-cloud/src/main/java/com/jiayue/insu/incloud/quartz/job/TestJob.java

@@ -0,0 +1,13 @@
+package com.jiayue.insu.incloud.quartz.job;
+
+import cn.hutool.core.date.DateUtil;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+public class TestJob implements Job {
+    @Override
+    public void execute(JobExecutionContext context) throws JobExecutionException {
+        System.out.println(DateUtil.now());
+    }
+}

+ 42 - 0
in-cloud/src/main/resources/bootstrap.yml

@@ -4,6 +4,48 @@ spring:
   profiles:
     active: local
 
+
+
+  quartz:
+    job-store-type: jdbc
+    # 是否等待任务执行完毕后,容器才会关闭
+    wait-for-jobs-to-complete-on-shutdown: true
+    scheduler-name: SpringBootDemoScheduler
+    properties:
+      org:
+        quartz:
+          scheduler:
+            instanceName: SC_Scheduler
+            instanceId: AUTO
+          threadPool:
+            # 线程数量
+            threadCount: 5
+            # 线程优先级
+            threadPriority: 5
+            # 线程池中线程名称的前缀
+            threadNamePrefix: test-thread
+            # 加载任务代码的ClassLoader是否从外部继承
+            threadsInheritContextClassLoaderOfInitializingThread: true
+
+          jobStore:
+
+            dataSource: incloud
+            # 最大能忍受的触发超时时间,如果超时则认为“失误”
+            misfireThreshold: 5000
+            # 选择JDBC的存储方式
+            class: org.quartz.impl.jdbcjobstore.JobStoreTX
+            # 类似于Hibernate的dialect,用于处理DB之间的差异,StdJDBCDelegate能满足大部分的DB(授权)
+            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
+            # 在调度流程的第一步,也就是拉取待即将触发的triggers时,是上锁的状态,即不会同时存在多个线程拉取到相同的trigger的情况,也就避免的重复调度的危险。参考:https://segmentfault.com/a/1190000015492260
+            acquireTriggersWithinLock: true
+
+          dataSource:
+            incloud:
+              driver: com.mysql.cj.jdbc.Driver
+              URL: jdbc:mysql://127.0.0.1:3306/incloud?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8
+              user: root
+              password: root
+
 server:
   port: 8801
 ---

+ 28 - 0
in-cloud/src/test/java/com/jiayue/insu/incloud/Test.java

@@ -0,0 +1,28 @@
+package com.jiayue.insu.incloud;
+
+
+import cn.hutool.core.date.DateUnit;
+import cn.hutool.core.date.DateUtil;
+import com.jiayue.insu.incloud.entity.Quartz;
+import com.jiayue.insu.incloud.quartz.ScheduledTask;
+import org.junit.runner.RunWith;
+import org.quartz.SchedulerException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.text.ParseException;
+
+
+@SpringBootTest
+
+@RunWith(SpringRunner.class)
+public class Test {
+    @Autowired
+    ScheduledTask scheduledTask;
+    @org.junit.Test
+    public void test() throws ClassNotFoundException, SchedulerException, ParseException {
+
+
+    }
+}

+ 7 - 0
pom.xml

@@ -55,6 +55,12 @@
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.1</version>
+        </dependency>
     </dependencies>
 
 
@@ -119,6 +125,7 @@
                 <version>${mybatis.plus.version}</version>
             </dependency>
 
+
         </dependencies>
     </dependencyManagement>