diff --git a/ym-schedule-task/pom.xml b/ym-schedule-task/pom.xml
new file mode 100644
index 0000000..9e491d0
--- /dev/null
+++ b/ym-schedule-task/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ ym-pass
+ com.cnbm
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ ym-schedule-task
+
+
+ 8
+ 8
+ 2.3.2
+
+
+
+
+ com.cnbm
+ ym-common
+ 1.0-SNAPSHOT
+
+
+ com.cnbm
+ ym-admin
+ 1.0-SNAPSHOT
+
+
+ org.quartz-scheduler
+ quartz
+ ${quartz.version}
+
+
+ com.mchange
+ c3p0
+
+
+ com.zaxxer
+ HikariCP-java6
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/config/ScheduleConfig.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/config/ScheduleConfig.java
new file mode 100644
index 0000000..a2c7744
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/config/ScheduleConfig.java
@@ -0,0 +1,58 @@
+package com.cnbm.scheduletask.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+
+import javax.sql.DataSource;
+import java.util.Properties;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:30 PM
+ * @Version 1.0
+ */
+@Configuration
+public class ScheduleConfig {
+
+ @Bean
+ public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
+ SchedulerFactoryBean factory = new SchedulerFactoryBean();
+ factory.setDataSource(dataSource);
+
+ //quartz参数
+ Properties prop = new Properties();
+ prop.put("org.quartz.scheduler.instanceName", "RenrenScheduler");
+ prop.put("org.quartz.scheduler.instanceId", "AUTO");
+ //线程池配置
+ prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
+ prop.put("org.quartz.threadPool.threadCount", "20");
+ prop.put("org.quartz.threadPool.threadPriority", "5");
+ //JobStore配置
+ prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
+ //集群配置
+ prop.put("org.quartz.jobStore.isClustered", "true");
+ prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
+ prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
+
+ prop.put("org.quartz.jobStore.misfireThreshold", "12000");
+ prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
+ prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
+
+ //PostgreSQL数据库,需要打开此注释
+ //prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
+
+ factory.setQuartzProperties(prop);
+
+ factory.setSchedulerName("RenrenScheduler");
+ //延时启动
+ factory.setStartupDelay(30);
+ factory.setApplicationContextSchedulerContextKey("applicationContextKey");
+ //可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
+ factory.setOverwriteExistingJobs(true);
+ //设置自动启动,默认为true
+ factory.setAutoStartup(true);
+
+ return factory;
+ }
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/controller/ScheduleJobController.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/controller/ScheduleJobController.java
new file mode 100644
index 0000000..31b0dbe
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/controller/ScheduleJobController.java
@@ -0,0 +1,125 @@
+package com.cnbm.scheduletask.controller;
+
+import com.cnbm.admin.annotation.LogOperation;
+import com.cnbm.common.constant.Constant;
+import com.cnbm.common.page.PageData;
+import com.cnbm.common.utils.Result;
+import com.cnbm.common.validator.ValidatorUtils;
+import com.cnbm.common.validator.group.AddGroup;
+import com.cnbm.common.validator.group.DefaultGroup;
+import com.cnbm.common.validator.group.UpdateGroup;
+import com.cnbm.scheduletask.dto.ScheduleJobDTO;
+import com.cnbm.scheduletask.service.ScheduleJobService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.Map;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/24 8:57 AM
+ * @Version 1.0
+ */
+@RestController
+@RequestMapping("/sys/schedule")
+@Api(tags="定时任务")
+public class ScheduleJobController {
+ @Autowired
+ private ScheduleJobService scheduleJobService;
+
+ @GetMapping("page")
+ @ApiOperation("分页")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = Constant.PAGE, value = "当前页码,从1开始", paramType = "query", required = true, dataTypeClass=Integer.class) ,
+ @ApiImplicitParam(name = Constant.LIMIT, value = "每页显示记录数", paramType = "query",required = true, dataTypeClass=Integer.class) ,
+ @ApiImplicitParam(name = Constant.ORDER_FIELD, value = "排序字段", paramType = "query", dataTypeClass=String.class) ,
+ @ApiImplicitParam(name = Constant.ORDER, value = "排序方式,可选值(asc、desc)", paramType = "query", dataTypeClass=String.class) ,
+ @ApiImplicitParam(name = "beanName", value = "beanName", paramType = "query", dataTypeClass=String.class)
+ })
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:page')")
+ public Result> page(@ApiIgnore @RequestParam Map params){
+ PageData page = scheduleJobService.page(params);
+
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("{id}")
+ @ApiOperation("信息")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:info')")
+ public Result info(@PathVariable("id") Long id){
+ ScheduleJobDTO schedule = scheduleJobService.get(id);
+
+ return new Result().ok(schedule);
+ }
+
+ @PostMapping
+ @ApiOperation("保存")
+ @LogOperation("保存")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:save')")
+ public Result save(@RequestBody ScheduleJobDTO dto){
+ ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);
+
+ scheduleJobService.save(dto);
+
+ return new Result();
+ }
+
+ @PutMapping
+ @ApiOperation("修改")
+ @LogOperation("修改")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:update')")
+ public Result update(@RequestBody ScheduleJobDTO dto){
+ ValidatorUtils.validateEntity(dto, UpdateGroup.class, DefaultGroup.class);
+
+ scheduleJobService.update(dto);
+
+ return new Result();
+ }
+
+ @DeleteMapping
+ @ApiOperation("删除")
+ @LogOperation("删除")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:delete')")
+ public Result delete(@RequestBody Long[] ids){
+ scheduleJobService.deleteBatch(ids);
+
+ return new Result();
+ }
+
+ @PutMapping("/run")
+ @ApiOperation("立即执行")
+ @LogOperation("立即执行")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:run')")
+ public Result run(@RequestBody Long[] ids){
+ scheduleJobService.run(ids);
+
+ return new Result();
+ }
+
+ @PutMapping("/pause")
+ @ApiOperation("暂停")
+ @LogOperation("暂停")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:pause')")
+ public Result pause(@RequestBody Long[] ids){
+ scheduleJobService.pause(ids);
+
+ return new Result();
+ }
+
+ @PutMapping("/resume")
+ @ApiOperation("恢复")
+ @LogOperation("恢复")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:resume')")
+ public Result resume(@RequestBody Long[] ids){
+ scheduleJobService.resume(ids);
+
+ return new Result();
+ }
+
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/controller/ScheduleJobLogController.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/controller/ScheduleJobLogController.java
new file mode 100644
index 0000000..073fb63
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/controller/ScheduleJobLogController.java
@@ -0,0 +1,55 @@
+package com.cnbm.scheduletask.controller;
+
+import com.cnbm.common.constant.Constant;
+import com.cnbm.common.page.PageData;
+import com.cnbm.common.utils.Result;
+import com.cnbm.scheduletask.dto.ScheduleJobLogDTO;
+import com.cnbm.scheduletask.service.ScheduleJobLogService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.Map;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/24 8:58 AM
+ * @Version 1.0
+ */
+@RestController
+@RequestMapping("/sys/scheduleLog")
+@Api(tags="定时任务日志")
+public class ScheduleJobLogController {
+ @Autowired
+ private ScheduleJobLogService scheduleJobLogService;
+
+ @GetMapping("page")
+ @ApiOperation("分页")
+ @ApiImplicitParams({
+ @ApiImplicitParam(name = Constant.PAGE, value = "当前页码,从1开始", paramType = "query", required = true, dataTypeClass=Integer.class) ,
+ @ApiImplicitParam(name = Constant.LIMIT, value = "每页显示记录数", paramType = "query",required = true, dataTypeClass=Integer.class) ,
+ @ApiImplicitParam(name = Constant.ORDER_FIELD, value = "排序字段", paramType = "query", dataTypeClass=String.class) ,
+ @ApiImplicitParam(name = Constant.ORDER, value = "排序方式,可选值(asc、desc)", paramType = "query", dataTypeClass=String.class) ,
+ @ApiImplicitParam(name = "jobId", value = "jobId", paramType = "query", dataType="String")
+ })
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:log')")
+ public Result> page(@ApiIgnore @RequestParam Map params){
+ PageData page = scheduleJobLogService.page(params);
+
+ return new Result>().ok(page);
+ }
+
+ @GetMapping("{id}")
+ @ApiOperation("信息")
+ @PreAuthorize("@ex.hasAuthority('sys:schedule:log')")
+ public Result info(@PathVariable("id") Long id){
+ ScheduleJobLogDTO log = scheduleJobLogService.get(id);
+
+ return new Result().ok(log);
+ }
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dao/ScheduleJobDao.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dao/ScheduleJobDao.java
new file mode 100644
index 0000000..64cf74b
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dao/ScheduleJobDao.java
@@ -0,0 +1,21 @@
+package com.cnbm.scheduletask.dao;
+
+import com.cnbm.common.dao.BaseDao;
+import com.cnbm.scheduletask.entity.ScheduleJobEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Map;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:48 PM
+ * @Version 1.0
+ */
+@Mapper
+public interface ScheduleJobDao extends BaseDao {
+
+ /**
+ * 批量更新状态
+ */
+ int updateBatch(Map map);
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dao/ScheduleJobLogDao.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dao/ScheduleJobLogDao.java
new file mode 100644
index 0000000..0fd5289
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dao/ScheduleJobLogDao.java
@@ -0,0 +1,15 @@
+package com.cnbm.scheduletask.dao;
+
+import com.cnbm.common.dao.BaseDao;
+import com.cnbm.scheduletask.entity.ScheduleJobLogEntity;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:48 PM
+ * @Version 1.0
+ */
+@Mapper
+public interface ScheduleJobLogDao extends BaseDao {
+
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dto/ScheduleJobDTO.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dto/ScheduleJobDTO.java
new file mode 100644
index 0000000..d8e65b4
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dto/ScheduleJobDTO.java
@@ -0,0 +1,56 @@
+package com.cnbm.scheduletask.dto;
+
+import com.cnbm.common.validator.group.AddGroup;
+import com.cnbm.common.validator.group.DefaultGroup;
+import com.cnbm.common.validator.group.UpdateGroup;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Null;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:49 PM
+ * @Version 1.0
+ */
+@Data
+@ApiModel(value = "定时任务")
+public class ScheduleJobDTO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ @Null(message="{id.null}", groups = AddGroup.class)
+ @NotNull(message="{id.require}", groups = UpdateGroup.class)
+ private Long id;
+
+ @ApiModelProperty(value = "spring bean名称")
+ @NotBlank(message = "{schedule.bean.require}", groups = DefaultGroup.class)
+ private String beanName;
+
+ @ApiModelProperty(value = "参数")
+ private String params;
+
+ @ApiModelProperty(value = "cron表达式")
+ @NotBlank(message = "{schedule.cron.require}", groups = DefaultGroup.class)
+ private String cronExpression;
+
+ @ApiModelProperty(value = "任务状态 0:暂停 1:正常")
+ @Range(min=0, max=1, message = "{schedule.status.range}", groups = DefaultGroup.class)
+ private Integer status;
+
+ @ApiModelProperty(value = "备注")
+ private String remark;
+
+ @ApiModelProperty(value = "创建时间")
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ private Date createDate;
+
+}
+
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dto/ScheduleJobLogDTO.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dto/ScheduleJobLogDTO.java
new file mode 100644
index 0000000..d77859b
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/dto/ScheduleJobLogDTO.java
@@ -0,0 +1,45 @@
+package com.cnbm.scheduletask.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:49 PM
+ * @Version 1.0
+ */
+@Data
+@ApiModel(value = "定时任务日志")
+public class ScheduleJobLogDTO implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty(value = "id")
+ private Long id;
+
+ @ApiModelProperty(value = "任务id")
+ private Long jobId;
+
+ @ApiModelProperty(value = "spring bean名称")
+ private String beanName;
+
+ @ApiModelProperty(value = "参数")
+ private String params;
+
+ @ApiModelProperty(value = "任务状态 0:失败 1:成功")
+ private Integer status;
+
+ @ApiModelProperty(value = "失败信息")
+ private String error;
+
+ @ApiModelProperty(value = "耗时(单位:毫秒)")
+ private Integer times;
+
+ @ApiModelProperty(value = "创建时间")
+ private Date createDate;
+
+}
+
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/entity/ScheduleJobEntity.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/entity/ScheduleJobEntity.java
new file mode 100644
index 0000000..c624fe5
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/entity/ScheduleJobEntity.java
@@ -0,0 +1,53 @@
+package com.cnbm.scheduletask.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.cnbm.common.entity.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:47 PM
+ * @Version 1.0
+ */
+@Data
+@EqualsAndHashCode(callSuper=false)
+@TableName("schedule_job")
+public class ScheduleJobEntity extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * spring bean名称
+ */
+ private String beanName;
+ /**
+ * 参数
+ */
+ private String params;
+ /**
+ * cron表达式
+ */
+ private String cronExpression;
+ /**
+ * 任务状态 0:暂停 1:正常
+ */
+ private Integer status;
+ /**
+ * 备注
+ */
+ private String remark;
+ /**
+ * 更新者
+ */
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ private Long updater;
+ /**
+ * 更新时间
+ */
+ @TableField(fill = FieldFill.INSERT_UPDATE)
+ private Date updateDate;
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/entity/ScheduleJobLogEntity.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/entity/ScheduleJobLogEntity.java
new file mode 100644
index 0000000..ff0e7ab
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/entity/ScheduleJobLogEntity.java
@@ -0,0 +1,54 @@
+package com.cnbm.scheduletask.entity;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:47 PM
+ * @Version 1.0
+ */
+@Data
+@TableName("schedule_job_log")
+public class ScheduleJobLogEntity implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId
+ private Long id;
+ /**
+ * 任务id
+ */
+ private Long jobId;
+ /**
+ * spring bean名称
+ */
+ private String beanName;
+ /**
+ * 参数
+ */
+ private String params;
+ /**
+ * 任务状态 0:失败 1:成功
+ */
+ private Integer status;
+ /**
+ * 失败信息
+ */
+ private String error;
+ /**
+ * 耗时(单位:毫秒)
+ */
+ private Integer times;
+ /**
+ * 创建时间
+ */
+ private Date createDate;
+
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/init/JobCommandLineRunner.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/init/JobCommandLineRunner.java
new file mode 100644
index 0000000..38168a5
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/init/JobCommandLineRunner.java
@@ -0,0 +1,39 @@
+package com.cnbm.scheduletask.init;
+
+import com.cnbm.scheduletask.dao.ScheduleJobDao;
+import com.cnbm.scheduletask.entity.ScheduleJobEntity;
+import com.cnbm.scheduletask.utils.ScheduleUtils;
+import org.quartz.CronTrigger;
+import org.quartz.Scheduler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:46 PM
+ * @Version 1.0
+ */
+@Component
+public class JobCommandLineRunner implements CommandLineRunner {
+ @Autowired
+ private Scheduler scheduler;
+ @Autowired
+ private ScheduleJobDao scheduleJobDao;
+
+ @Override
+ public void run(String... args) {
+ List scheduleJobList = scheduleJobDao.selectList(null);
+ for(ScheduleJobEntity scheduleJob : scheduleJobList){
+ CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getId());
+ //如果不存在,则创建
+ if(cronTrigger == null) {
+ ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
+ }else {
+ ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
+ }
+ }
+ }
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/ScheduleJobLogService.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/ScheduleJobLogService.java
new file mode 100644
index 0000000..4ff4ffd
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/ScheduleJobLogService.java
@@ -0,0 +1,20 @@
+package com.cnbm.scheduletask.service;
+
+import com.cnbm.common.page.PageData;
+import com.cnbm.common.service.BaseService;
+import com.cnbm.scheduletask.dto.ScheduleJobLogDTO;
+import com.cnbm.scheduletask.entity.ScheduleJobLogEntity;
+
+import java.util.Map;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:44 PM
+ * @Version 1.0
+ */
+public interface ScheduleJobLogService extends BaseService {
+
+ PageData page(Map params);
+
+ ScheduleJobLogDTO get(Long id);
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/ScheduleJobService.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/ScheduleJobService.java
new file mode 100644
index 0000000..a8faea3
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/ScheduleJobService.java
@@ -0,0 +1,56 @@
+package com.cnbm.scheduletask.service;
+
+import com.cnbm.common.page.PageData;
+import com.cnbm.common.service.BaseService;
+import com.cnbm.scheduletask.dto.ScheduleJobDTO;
+import com.cnbm.scheduletask.entity.ScheduleJobEntity;
+
+import java.util.Map;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:43 PM
+ * @Version 1.0
+ */
+public interface ScheduleJobService extends BaseService {
+
+ PageData page(Map params);
+
+ ScheduleJobDTO get(Long id);
+
+ /**
+ * 保存定时任务
+ */
+ void save(ScheduleJobDTO dto);
+
+ /**
+ * 更新定时任务
+ */
+ void update(ScheduleJobDTO dto);
+
+ /**
+ * 批量删除定时任务
+ */
+ void deleteBatch(Long[] ids);
+
+ /**
+ * 批量更新定时任务状态
+ */
+ int updateBatch(Long[] ids, int status);
+
+ /**
+ * 立即执行
+ */
+ void run(Long[] ids);
+
+ /**
+ * 暂停运行
+ */
+ void pause(Long[] ids);
+
+ /**
+ * 恢复运行
+ */
+ void resume(Long[] ids);
+}
+
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/impl/ScheduleJobLogServiceImpl.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/impl/ScheduleJobLogServiceImpl.java
new file mode 100644
index 0000000..0dedb9e
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/impl/ScheduleJobLogServiceImpl.java
@@ -0,0 +1,51 @@
+package com.cnbm.scheduletask.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.cnbm.common.constant.Constant;
+import com.cnbm.common.page.PageData;
+import com.cnbm.common.service.impl.BaseServiceImpl;
+import com.cnbm.common.utils.ConvertUtils;
+import com.cnbm.scheduletask.dao.ScheduleJobLogDao;
+import com.cnbm.scheduletask.dto.ScheduleJobLogDTO;
+import com.cnbm.scheduletask.entity.ScheduleJobLogEntity;
+import com.cnbm.scheduletask.service.ScheduleJobLogService;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:46 PM
+ * @Version 1.0
+ */
+@Service
+public class ScheduleJobLogServiceImpl extends BaseServiceImpl implements ScheduleJobLogService {
+
+ @Override
+ public PageData page(Map params) {
+ IPage page = baseDao.selectPage(
+ getPage(params, Constant.CREATE_DATE, false),
+ getWrapper(params)
+ );
+ return getPageData(page, ScheduleJobLogDTO.class);
+ }
+
+ private QueryWrapper getWrapper(Map params){
+ String jobId = (String)params.get("jobId");
+
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.eq(StringUtils.isNotBlank(jobId), "job_id", jobId);
+
+ return wrapper;
+ }
+
+ @Override
+ public ScheduleJobLogDTO get(Long id) {
+ ScheduleJobLogEntity entity = baseDao.selectById(id);
+
+ return ConvertUtils.sourceToTarget(entity, ScheduleJobLogDTO.class);
+ }
+
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/impl/ScheduleJobServiceImpl.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/impl/ScheduleJobServiceImpl.java
new file mode 100644
index 0000000..253f3e2
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/service/impl/ScheduleJobServiceImpl.java
@@ -0,0 +1,127 @@
+package com.cnbm.scheduletask.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.cnbm.common.constant.Constant;
+import com.cnbm.common.page.PageData;
+import com.cnbm.common.service.impl.BaseServiceImpl;
+import com.cnbm.common.utils.ConvertUtils;
+import com.cnbm.scheduletask.dao.ScheduleJobDao;
+import com.cnbm.scheduletask.dto.ScheduleJobDTO;
+import com.cnbm.scheduletask.entity.ScheduleJobEntity;
+import com.cnbm.scheduletask.service.ScheduleJobService;
+import com.cnbm.scheduletask.utils.ScheduleUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.quartz.Scheduler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:45 PM
+ * @Version 1.0
+ */
+@Service
+public class ScheduleJobServiceImpl extends BaseServiceImpl implements ScheduleJobService {
+ @Autowired
+ private Scheduler scheduler;
+
+ @Override
+ public PageData page(Map params) {
+ IPage page = baseDao.selectPage(
+ getPage(params, Constant.CREATE_DATE, false),
+ getWrapper(params)
+ );
+ return getPageData(page, ScheduleJobDTO.class);
+ }
+
+ @Override
+ public ScheduleJobDTO get(Long id) {
+ ScheduleJobEntity entity = baseDao.selectById(id);
+
+ return ConvertUtils.sourceToTarget(entity, ScheduleJobDTO.class);
+ }
+
+ private QueryWrapper getWrapper(Map params){
+ String beanName = (String)params.get("beanName");
+
+ QueryWrapper wrapper = new QueryWrapper<>();
+ wrapper.like(StringUtils.isNotBlank(beanName), "bean_name", beanName);
+
+ return wrapper;
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void save(ScheduleJobDTO dto) {
+ ScheduleJobEntity entity = ConvertUtils.sourceToTarget(dto, ScheduleJobEntity.class);
+
+ entity.setStatus(Constant.ScheduleStatus.NORMAL.getValue());
+ this.insert(entity);
+
+ ScheduleUtils.createScheduleJob(scheduler, entity);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void update(ScheduleJobDTO dto) {
+ ScheduleJobEntity entity = ConvertUtils.sourceToTarget(dto, ScheduleJobEntity.class);
+
+ ScheduleUtils.updateScheduleJob(scheduler, entity);
+
+ this.updateById(entity);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteBatch(Long[] ids) {
+ for(Long id : ids){
+ ScheduleUtils.deleteScheduleJob(scheduler, id);
+ }
+
+ //删除数据
+ this.deleteBatchIds(Arrays.asList(ids));
+ }
+
+ @Override
+ public int updateBatch(Long[] ids, int status){
+ Map map = new HashMap<>(2);
+ map.put("ids", ids);
+ map.put("status", status);
+ return baseDao.updateBatch(map);
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void run(Long[] ids) {
+ for(Long id : ids){
+ ScheduleUtils.run(scheduler, this.selectById(id));
+ }
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void pause(Long[] ids) {
+ for(Long id : ids){
+ ScheduleUtils.pauseJob(scheduler, id);
+ }
+
+ updateBatch(ids, Constant.ScheduleStatus.PAUSE.getValue());
+ }
+
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void resume(Long[] ids) {
+ for(Long id : ids){
+ ScheduleUtils.resumeJob(scheduler, id);
+ }
+
+ updateBatch(ids, Constant.ScheduleStatus.NORMAL.getValue());
+ }
+
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/task/ITask.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/task/ITask.java
new file mode 100644
index 0000000..c375dd9
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/task/ITask.java
@@ -0,0 +1,16 @@
+package com.cnbm.scheduletask.task;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:41 PM
+ * @Version 1.0
+ */
+public interface ITask {
+
+ /**
+ * 执行定时任务接口
+ *
+ * @param params 参数,多参数使用JSON数据
+ */
+ void run(String params);
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/task/TestTask.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/task/TestTask.java
new file mode 100644
index 0000000..0eb2c1b
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/task/TestTask.java
@@ -0,0 +1,20 @@
+package com.cnbm.scheduletask.task;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:41 PM
+ * @Version 1.0
+ */
+@Component("testTask")
+public class TestTask implements ITask{
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ @Override
+ public void run(String params){
+ logger.debug("TestTask定时任务正在执行,参数为:{}", params);
+ }
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/utils/ScheduleJob.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/utils/ScheduleJob.java
new file mode 100644
index 0000000..f7871ec
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/utils/ScheduleJob.java
@@ -0,0 +1,70 @@
+package com.cnbm.scheduletask.utils;
+
+import com.cnbm.common.constant.Constant;
+import com.cnbm.common.exception.ExceptionUtils;
+import com.cnbm.common.utils.SpringContextUtils;
+import com.cnbm.scheduletask.entity.ScheduleJobEntity;
+import com.cnbm.scheduletask.entity.ScheduleJobLogEntity;
+import com.cnbm.scheduletask.service.ScheduleJobLogService;
+import org.quartz.JobExecutionContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+import java.lang.reflect.Method;
+import java.util.Date;
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:38 PM
+ * @Version 1.0
+ */
+public class ScheduleJob extends QuartzJobBean {
+ private Logger logger = LoggerFactory.getLogger(getClass());
+
+ @Override
+ protected void executeInternal(JobExecutionContext context) {
+ ScheduleJobEntity scheduleJob = (ScheduleJobEntity) context.getMergedJobDataMap().
+ get(ScheduleUtils.JOB_PARAM_KEY);
+
+ //数据库保存执行记录
+ ScheduleJobLogEntity log = new ScheduleJobLogEntity();
+ log.setJobId(scheduleJob.getId());
+ log.setBeanName(scheduleJob.getBeanName());
+ log.setParams(scheduleJob.getParams());
+ log.setCreateDate(new Date());
+
+ //任务开始时间
+ long startTime = System.currentTimeMillis();
+
+ try {
+ //执行任务
+ logger.info("任务准备执行,任务ID:{}", scheduleJob.getId());
+ Object target = SpringContextUtils.getBean(scheduleJob.getBeanName());
+ Method method = target.getClass().getDeclaredMethod("run", String.class);
+ method.invoke(target, scheduleJob.getParams());
+
+ //任务执行总时长
+ long times = System.currentTimeMillis() - startTime;
+ log.setTimes((int)times);
+ //任务状态
+ log.setStatus(Constant.SUCCESS);
+
+ logger.info("任务执行完毕,任务ID:{} 总共耗时:{} 毫秒", scheduleJob.getId(), times);
+ } catch (Exception e) {
+ logger.error("任务执行失败,任务ID:{}", scheduleJob.getId(), e);
+
+ //任务执行总时长
+ long times = System.currentTimeMillis() - startTime;
+ log.setTimes((int)times);
+
+ //任务状态
+ log.setStatus(Constant.FAIL);
+ log.setError(ExceptionUtils.getErrorStackTrace(e));
+ }finally {
+ //获取spring bean
+ ScheduleJobLogService scheduleJobLogService = SpringContextUtils.getBean(ScheduleJobLogService.class);
+ scheduleJobLogService.insert(log);
+ }
+ }
+}
diff --git a/ym-schedule-task/src/main/java/com/cnbm/scheduletask/utils/ScheduleUtils.java b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/utils/ScheduleUtils.java
new file mode 100644
index 0000000..00b57de
--- /dev/null
+++ b/ym-schedule-task/src/main/java/com/cnbm/scheduletask/utils/ScheduleUtils.java
@@ -0,0 +1,154 @@
+package com.cnbm.scheduletask.utils;
+
+import com.cnbm.common.constant.Constant;
+import com.cnbm.common.exception.ErrorCode;
+import com.cnbm.common.exception.RenException;
+import com.cnbm.scheduletask.entity.ScheduleJobEntity;
+import org.quartz.*;
+
+
+/**
+ * @Author weihongyang
+ * @Date 2022/6/23 4:40 PM
+ * @Version 1.0
+ */
+public class ScheduleUtils {
+ private final static String JOB_NAME = "TASK_";
+ /**
+ * 任务调度参数key
+ */
+ public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
+
+ /**
+ * 获取触发器key
+ */
+ public static TriggerKey getTriggerKey(Long jobId) {
+ return TriggerKey.triggerKey(JOB_NAME + jobId);
+ }
+
+ /**
+ * 获取jobKey
+ */
+ public static JobKey getJobKey(Long jobId) {
+ return JobKey.jobKey(JOB_NAME + jobId);
+ }
+
+ /**
+ * 获取表达式触发器
+ */
+ public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) {
+ try {
+ return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
+ } catch (SchedulerException e) {
+ throw new RenException(ErrorCode.JOB_ERROR, e);
+ }
+ }
+
+ /**
+ * 创建定时任务
+ */
+ public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
+ try {
+ //构建job信息
+ JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getId())).build();
+
+ //表达式调度构建器
+ CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
+ .withMisfireHandlingInstructionDoNothing();
+
+ //按新的cronExpression表达式构建一个新的trigger
+ CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getId())).withSchedule(scheduleBuilder).build();
+
+ //放入参数,运行时的方法可以获取
+ jobDetail.getJobDataMap().put(JOB_PARAM_KEY, scheduleJob);
+
+ scheduler.scheduleJob(jobDetail, trigger);
+
+ //暂停任务
+ if(scheduleJob.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()){
+ pauseJob(scheduler, scheduleJob.getId());
+ }
+ } catch (SchedulerException e) {
+ throw new RenException(ErrorCode.JOB_ERROR, e);
+ }
+ }
+
+ /**
+ * 更新定时任务
+ */
+ public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
+ try {
+ TriggerKey triggerKey = getTriggerKey(scheduleJob.getId());
+
+ //表达式调度构建器
+ CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
+ .withMisfireHandlingInstructionDoNothing();
+
+ CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getId());
+
+ //按新的cronExpression表达式重新构建trigger
+ trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
+
+ //参数
+ trigger.getJobDataMap().put(JOB_PARAM_KEY, scheduleJob);
+
+ scheduler.rescheduleJob(triggerKey, trigger);
+
+ //暂停任务
+ if(scheduleJob.getStatus() == Constant.ScheduleStatus.PAUSE.getValue()){
+ pauseJob(scheduler, scheduleJob.getId());
+ }
+
+ } catch (SchedulerException e) {
+ throw new RenException(ErrorCode.JOB_ERROR, e);
+ }
+ }
+
+ /**
+ * 立即执行任务
+ */
+ public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
+ try {
+ //参数
+ JobDataMap dataMap = new JobDataMap();
+ dataMap.put(JOB_PARAM_KEY, scheduleJob);
+
+ scheduler.triggerJob(getJobKey(scheduleJob.getId()), dataMap);
+ } catch (SchedulerException e) {
+ throw new RenException(ErrorCode.JOB_ERROR, e);
+ }
+ }
+
+ /**
+ * 暂停任务
+ */
+ public static void pauseJob(Scheduler scheduler, Long jobId) {
+ try {
+ scheduler.pauseJob(getJobKey(jobId));
+ } catch (SchedulerException e) {
+ throw new RenException(ErrorCode.JOB_ERROR, e);
+ }
+ }
+
+ /**
+ * 恢复任务
+ */
+ public static void resumeJob(Scheduler scheduler, Long jobId) {
+ try {
+ scheduler.resumeJob(getJobKey(jobId));
+ } catch (SchedulerException e) {
+ throw new RenException(ErrorCode.JOB_ERROR, e);
+ }
+ }
+
+ /**
+ * 删除定时任务
+ */
+ public static void deleteScheduleJob(Scheduler scheduler, Long jobId) {
+ try {
+ scheduler.deleteJob(getJobKey(jobId));
+ } catch (SchedulerException e) {
+ throw new RenException(ErrorCode.JOB_ERROR, e);
+ }
+ }
+}