初始化
This commit is contained in:
		| @ -0,0 +1,13 @@ | ||||
| package com.ruoyi.quartz.config; | ||||
|  | ||||
| import org.springframework.context.annotation.Configuration; | ||||
|  | ||||
| /** | ||||
|  * 定时任务配置 | ||||
|  * | ||||
|  * @author Lion Li | ||||
|  */ | ||||
| @Configuration | ||||
| public class ScheduleConfig { | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,144 @@ | ||||
| package com.ruoyi.quartz.controller; | ||||
|  | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.constant.Constants; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.exception.job.TaskException; | ||||
| import com.ruoyi.common.utils.SecurityUtils; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
| import com.ruoyi.quartz.service.ISysJobService; | ||||
| import com.ruoyi.quartz.util.CronUtils; | ||||
| import org.quartz.SchedulerException; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 调度任务信息操作处理 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| @RestController | ||||
| @RequestMapping("/monitor/job") | ||||
| public class SysJobController extends BaseController | ||||
| { | ||||
|     @Autowired | ||||
|     private ISysJobService jobService; | ||||
|  | ||||
|     /** | ||||
|      * 查询定时任务列表 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo list(SysJob sysJob) | ||||
|     { | ||||
|         return jobService.selectPageJobList(sysJob); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 导出定时任务列表 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:export')") | ||||
|     @Log(title = "定时任务", businessType = BusinessType.EXPORT) | ||||
|     @GetMapping("/export") | ||||
|     public AjaxResult export(SysJob sysJob) | ||||
|     { | ||||
|         List<SysJob> list = jobService.selectJobList(sysJob); | ||||
|         ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class); | ||||
|         return util.exportExcel(list, "定时任务"); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取定时任务详细信息 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:query')") | ||||
|     @GetMapping(value = "/{jobId}") | ||||
|     public AjaxResult getInfo(@PathVariable("jobId") Long jobId) | ||||
|     { | ||||
|         return AjaxResult.success(jobService.selectJobById(jobId)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增定时任务 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:add')") | ||||
|     @Log(title = "定时任务", businessType = BusinessType.INSERT) | ||||
|     @PostMapping | ||||
|     public AjaxResult add(@RequestBody SysJob sysJob) throws SchedulerException, TaskException | ||||
|     { | ||||
|         if (!CronUtils.isValid(sysJob.getCronExpression())) | ||||
|         { | ||||
|             return AjaxResult.error("新增任务'" + sysJob.getJobName() + "'失败,Cron表达式不正确"); | ||||
|         } | ||||
|         else if (StrUtil.containsIgnoreCase(sysJob.getInvokeTarget(), Constants.LOOKUP_RMI)) | ||||
|         { | ||||
|             return AjaxResult.error("新增任务'" + sysJob.getJobName() + "'失败,目标字符串不允许'rmi://'调用"); | ||||
|         } | ||||
|         sysJob.setCreateBy(SecurityUtils.getUsername()); | ||||
|         return toAjax(jobService.insertJob(sysJob)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 修改定时任务 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:edit')") | ||||
|     @Log(title = "定时任务", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping | ||||
|     public AjaxResult edit(@RequestBody SysJob sysJob) throws SchedulerException, TaskException | ||||
|     { | ||||
|         if (!CronUtils.isValid(sysJob.getCronExpression())) | ||||
|         { | ||||
|             return AjaxResult.error("修改任务'" + sysJob.getJobName() + "'失败,Cron表达式不正确"); | ||||
|         } | ||||
|         else if (StrUtil.containsIgnoreCase(sysJob.getInvokeTarget(), Constants.LOOKUP_RMI)) | ||||
|         { | ||||
|             return AjaxResult.error("修改任务'" + sysJob.getJobName() + "'失败,目标字符串不允许'rmi://'调用"); | ||||
|         } | ||||
|         sysJob.setUpdateBy(SecurityUtils.getUsername()); | ||||
|         return toAjax(jobService.updateJob(sysJob)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 定时任务状态修改 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')") | ||||
|     @Log(title = "定时任务", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/changeStatus") | ||||
|     public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException | ||||
|     { | ||||
|         SysJob newJob = jobService.selectJobById(job.getJobId()); | ||||
|         newJob.setStatus(job.getStatus()); | ||||
|         return toAjax(jobService.changeStatus(newJob)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 定时任务立即执行一次 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')") | ||||
|     @Log(title = "定时任务", businessType = BusinessType.UPDATE) | ||||
|     @PutMapping("/run") | ||||
|     public AjaxResult run(@RequestBody SysJob job) throws SchedulerException | ||||
|     { | ||||
|         jobService.run(job); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除定时任务 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:remove')") | ||||
|     @Log(title = "定时任务", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{jobIds}") | ||||
|     public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException | ||||
|     { | ||||
|         jobService.deleteJobByIds(jobIds); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,85 @@ | ||||
| package com.ruoyi.quartz.controller; | ||||
|  | ||||
| import com.ruoyi.common.annotation.Log; | ||||
| import com.ruoyi.common.core.controller.BaseController; | ||||
| import com.ruoyi.common.core.domain.AjaxResult; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.enums.BusinessType; | ||||
| import com.ruoyi.common.utils.poi.ExcelUtil; | ||||
| import com.ruoyi.quartz.domain.SysJobLog; | ||||
| import com.ruoyi.quartz.service.ISysJobLogService; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.security.access.prepost.PreAuthorize; | ||||
| import org.springframework.web.bind.annotation.*; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 调度日志操作处理 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| @RestController | ||||
| @RequestMapping("/monitor/jobLog") | ||||
| public class SysJobLogController extends BaseController | ||||
| { | ||||
|     @Autowired | ||||
|     private ISysJobLogService jobLogService; | ||||
|  | ||||
|     /** | ||||
|      * 查询定时任务调度日志列表 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:list')") | ||||
|     @GetMapping("/list") | ||||
|     public TableDataInfo list(SysJobLog sysJobLog) | ||||
|     { | ||||
|         return jobLogService.selectPageJobLogList(sysJobLog); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 导出定时任务调度日志列表 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:export')") | ||||
|     @Log(title = "任务调度日志", businessType = BusinessType.EXPORT) | ||||
|     @GetMapping("/export") | ||||
|     public AjaxResult export(SysJobLog sysJobLog) | ||||
|     { | ||||
|         List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog); | ||||
|         ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class); | ||||
|         return util.exportExcel(list, "调度日志"); | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * 根据调度编号获取详细信息 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:query')") | ||||
|     @GetMapping(value = "/{configId}") | ||||
|     public AjaxResult getInfo(@PathVariable Long jobLogId) | ||||
|     { | ||||
|         return AjaxResult.success(jobLogService.selectJobLogById(jobLogId)); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * 删除定时任务调度日志 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:remove')") | ||||
|     @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE) | ||||
|     @DeleteMapping("/{jobLogIds}") | ||||
|     public AjaxResult remove(@PathVariable Long[] jobLogIds) | ||||
|     { | ||||
|         return toAjax(jobLogService.deleteJobLogByIds(jobLogIds)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 清空定时任务调度日志 | ||||
|      */ | ||||
|     @PreAuthorize("@ss.hasPermi('monitor:job:remove')") | ||||
|     @Log(title = "调度日志", businessType = BusinessType.CLEAN) | ||||
|     @DeleteMapping("/clean") | ||||
|     public AjaxResult clean() | ||||
|     { | ||||
|         jobLogService.cleanJobLog(); | ||||
|         return AjaxResult.success(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										134
									
								
								ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| package com.ruoyi.quartz.domain; | ||||
|  | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import com.baomidou.mybatisplus.annotation.*; | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||||
| import com.ruoyi.common.annotation.Excel; | ||||
| import com.ruoyi.common.annotation.Excel.ColumnType; | ||||
| import com.ruoyi.common.constant.ScheduleConstants; | ||||
| import com.ruoyi.quartz.util.CronUtils; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import lombok.experimental.Accessors; | ||||
|  | ||||
| import javax.validation.constraints.NotBlank; | ||||
| import javax.validation.constraints.Size; | ||||
| import java.io.Serializable; | ||||
| import java.util.Date; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 定时任务调度表 sys_job | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
|  | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| @Accessors(chain = true) | ||||
| @TableName("sys_job") | ||||
| public class SysJob implements Serializable { | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** | ||||
|      * 任务ID | ||||
|      */ | ||||
|     @Excel(name = "任务序号", cellType = ColumnType.NUMERIC) | ||||
|     @TableId(value = "job_id", type = IdType.AUTO) | ||||
|     private Long jobId; | ||||
|  | ||||
|     /** | ||||
|      * 任务名称 | ||||
|      */ | ||||
|     @NotBlank(message = "任务名称不能为空") | ||||
|     @Size(min = 0, max = 64, message = "任务名称不能超过64个字符") | ||||
|     @Excel(name = "任务名称") | ||||
|     private String jobName; | ||||
|  | ||||
|     /** | ||||
|      * 任务组名 | ||||
|      */ | ||||
|     @Excel(name = "任务组名") | ||||
|     private String jobGroup; | ||||
|  | ||||
|     /** | ||||
|      * 调用目标字符串 | ||||
|      */ | ||||
|     @NotBlank(message = "调用目标字符串不能为空") | ||||
|     @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符") | ||||
|     @Excel(name = "调用目标字符串") | ||||
|     private String invokeTarget; | ||||
|  | ||||
|     /** | ||||
|      * cron执行表达式 | ||||
|      */ | ||||
|     @NotBlank(message = "Cron执行表达式不能为空") | ||||
|     @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符") | ||||
|     @Excel(name = "执行表达式 ") | ||||
|     private String cronExpression; | ||||
|  | ||||
|     /** | ||||
|      * cron计划策略 | ||||
|      */ | ||||
|     @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行") | ||||
|     private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT; | ||||
|  | ||||
|     /** | ||||
|      * 是否并发执行(0允许 1禁止) | ||||
|      */ | ||||
|     @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止") | ||||
|     private String concurrent; | ||||
|  | ||||
|     /** | ||||
|      * 任务状态(0正常 1暂停) | ||||
|      */ | ||||
|     @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停") | ||||
|     private String status; | ||||
|  | ||||
|     /** | ||||
|      * 创建者 | ||||
|      */ | ||||
|     @TableField(fill = FieldFill.INSERT) | ||||
|     private String createBy; | ||||
|  | ||||
|     /** | ||||
|      * 创建时间 | ||||
|      */ | ||||
|     @TableField(fill = FieldFill.INSERT) | ||||
|     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||||
|     private Date createTime; | ||||
|  | ||||
|     /** | ||||
|      * 更新者 | ||||
|      */ | ||||
|     @TableField(fill = FieldFill.INSERT_UPDATE) | ||||
|     private String updateBy; | ||||
|  | ||||
|     /** | ||||
|      * 更新时间 | ||||
|      */ | ||||
|     @TableField(fill = FieldFill.INSERT_UPDATE) | ||||
|     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||||
|     private Date updateTime; | ||||
|  | ||||
|     /** | ||||
|      * 备注 | ||||
|      */ | ||||
|     private String remark; | ||||
|  | ||||
|     /** | ||||
|      * 请求参数 | ||||
|      */ | ||||
|     @TableField(exist = false) | ||||
|     private Map<String, Object> params = new HashMap<>(); | ||||
|  | ||||
|     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||||
|     public Date getNextValidTime() { | ||||
|         if (StrUtil.isNotEmpty(cronExpression)) { | ||||
|             return CronUtils.getNextExecution(cronExpression); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,78 @@ | ||||
| package com.ruoyi.quartz.domain; | ||||
|  | ||||
| import com.baomidou.mybatisplus.annotation.*; | ||||
| import com.fasterxml.jackson.annotation.JsonFormat; | ||||
| import com.ruoyi.common.annotation.Excel; | ||||
| import lombok.Data; | ||||
| import lombok.NoArgsConstructor; | ||||
| import lombok.experimental.Accessors; | ||||
|  | ||||
| import java.util.Date; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 定时任务调度日志表 sys_job_log | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
|  | ||||
| @Data | ||||
| @NoArgsConstructor | ||||
| @Accessors(chain = true) | ||||
| @TableName("sys_job_log") | ||||
| public class SysJobLog | ||||
| { | ||||
|     private static final long serialVersionUID = 1L; | ||||
|  | ||||
|     /** ID */ | ||||
|     @Excel(name = "日志序号") | ||||
|     @TableId(value = "job_log_id", type = IdType.AUTO) | ||||
|     private Long jobLogId; | ||||
|  | ||||
|     /** 任务名称 */ | ||||
|     @Excel(name = "任务名称") | ||||
|     private String jobName; | ||||
|  | ||||
|     /** 任务组名 */ | ||||
|     @Excel(name = "任务组名") | ||||
|     private String jobGroup; | ||||
|  | ||||
|     /** 调用目标字符串 */ | ||||
|     @Excel(name = "调用目标字符串") | ||||
|     private String invokeTarget; | ||||
|  | ||||
|     /** 日志信息 */ | ||||
|     @Excel(name = "日志信息") | ||||
|     private String jobMessage; | ||||
|  | ||||
|     /** 执行状态(0正常 1失败) */ | ||||
|     @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败") | ||||
|     private String status; | ||||
|  | ||||
|     /** 异常信息 */ | ||||
|     @Excel(name = "异常信息") | ||||
|     private String exceptionInfo; | ||||
|  | ||||
|     /** | ||||
|      * 创建时间 | ||||
|      */ | ||||
|     @TableField(fill = FieldFill.INSERT) | ||||
|     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") | ||||
|     private Date createTime; | ||||
|  | ||||
|     /** | ||||
|      * 请求参数 | ||||
|      */ | ||||
|     @TableField(exist = false) | ||||
|     private Map<String, Object> params = new HashMap<>(); | ||||
|  | ||||
|     /** 开始时间 */ | ||||
|     @TableField(exist = false) | ||||
|     private Date startTime; | ||||
|  | ||||
|     /** 停止时间 */ | ||||
|     @TableField(exist = false) | ||||
|     private Date stopTime; | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,13 @@ | ||||
| package com.ruoyi.quartz.mapper; | ||||
|  | ||||
| import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; | ||||
| import com.ruoyi.quartz.domain.SysJobLog; | ||||
|  | ||||
| /** | ||||
|  * 调度任务日志信息 数据层 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public interface SysJobLogMapper extends BaseMapperPlus<SysJobLog> { | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,13 @@ | ||||
| package com.ruoyi.quartz.mapper; | ||||
|  | ||||
| import com.ruoyi.common.core.mybatisplus.core.BaseMapperPlus; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
|  | ||||
| /** | ||||
|  * 调度任务信息 数据层 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public interface SysJobMapper extends BaseMapperPlus<SysJob> { | ||||
|  | ||||
| } | ||||
| @ -0,0 +1,62 @@ | ||||
| package com.ruoyi.quartz.service; | ||||
|  | ||||
| import com.ruoyi.common.core.mybatisplus.core.IServicePlus; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.quartz.domain.SysJobLog; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 定时任务调度日志信息信息 服务层 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public interface ISysJobLogService extends IServicePlus<SysJobLog> { | ||||
|  | ||||
|  | ||||
|     TableDataInfo<SysJobLog> selectPageJobLogList(SysJobLog jobLog); | ||||
|  | ||||
|     /** | ||||
|      * 获取quartz调度器日志的计划任务 | ||||
|      * | ||||
|      * @param jobLog 调度日志信息 | ||||
|      * @return 调度任务日志集合 | ||||
|      */ | ||||
|     public List<SysJobLog> selectJobLogList(SysJobLog jobLog); | ||||
|  | ||||
|     /** | ||||
|      * 通过调度任务日志ID查询调度信息 | ||||
|      * | ||||
|      * @param jobLogId 调度任务日志ID | ||||
|      * @return 调度任务日志对象信息 | ||||
|      */ | ||||
|     public SysJobLog selectJobLogById(Long jobLogId); | ||||
|  | ||||
|     /** | ||||
|      * 新增任务日志 | ||||
|      * | ||||
|      * @param jobLog 调度日志信息 | ||||
|      */ | ||||
|     public void addJobLog(SysJobLog jobLog); | ||||
|  | ||||
|     /** | ||||
|      * 批量删除调度日志信息 | ||||
|      * | ||||
|      * @param logIds 需要删除的日志ID | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int deleteJobLogByIds(Long[] logIds); | ||||
|  | ||||
|     /** | ||||
|      * 删除任务日志 | ||||
|      * | ||||
|      * @param jobId 调度日志ID | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int deleteJobLogById(Long jobId); | ||||
|  | ||||
|     /** | ||||
|      * 清空任务日志 | ||||
|      */ | ||||
|     public void cleanJobLog(); | ||||
| } | ||||
| @ -0,0 +1,106 @@ | ||||
| package com.ruoyi.quartz.service; | ||||
|  | ||||
| import com.ruoyi.common.core.mybatisplus.core.IServicePlus; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.exception.job.TaskException; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
| import org.quartz.SchedulerException; | ||||
|  | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 定时任务调度信息信息 服务层 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public interface ISysJobService extends IServicePlus<SysJob> { | ||||
|     /** | ||||
|      * 获取quartz调度器的计划任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 调度任务集合 | ||||
|      */ | ||||
|     public TableDataInfo<SysJob> selectPageJobList(SysJob job); | ||||
|  | ||||
|     public List<SysJob> selectJobList(SysJob job); | ||||
|  | ||||
|     /** | ||||
|      * 通过调度任务ID查询调度信息 | ||||
|      * | ||||
|      * @param jobId 调度任务ID | ||||
|      * @return 调度任务对象信息 | ||||
|      */ | ||||
|     public SysJob selectJobById(Long jobId); | ||||
|  | ||||
|     /** | ||||
|      * 暂停任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int pauseJob(SysJob job) throws SchedulerException; | ||||
|  | ||||
|     /** | ||||
|      * 恢复任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int resumeJob(SysJob job) throws SchedulerException; | ||||
|  | ||||
|     /** | ||||
|      * 删除任务后,所对应的trigger也将被删除 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int deleteJob(SysJob job) throws SchedulerException; | ||||
|  | ||||
|     /** | ||||
|      * 批量删除调度信息 | ||||
|      * | ||||
|      * @param jobIds 需要删除的任务ID | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public void deleteJobByIds(Long[] jobIds) throws SchedulerException; | ||||
|  | ||||
|     /** | ||||
|      * 任务调度状态修改 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int changeStatus(SysJob job) throws SchedulerException; | ||||
|  | ||||
|     /** | ||||
|      * 立即运行任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public void run(SysJob job) throws SchedulerException; | ||||
|  | ||||
|     /** | ||||
|      * 新增任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int insertJob(SysJob job) throws SchedulerException, TaskException; | ||||
|  | ||||
|     /** | ||||
|      * 更新任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public int updateJob(SysJob job) throws SchedulerException, TaskException; | ||||
|  | ||||
|     /** | ||||
|      * 校验cron表达式是否有效 | ||||
|      * | ||||
|      * @param cronExpression 表达式 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     public boolean checkCronExpressionIsValid(String cronExpression); | ||||
| } | ||||
| @ -0,0 +1,114 @@ | ||||
| package com.ruoyi.quartz.service.impl; | ||||
|  | ||||
| import cn.hutool.core.lang.Validator; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.utils.PageUtils; | ||||
| import com.ruoyi.quartz.domain.SysJobLog; | ||||
| import com.ruoyi.quartz.mapper.SysJobLogMapper; | ||||
| import com.ruoyi.quartz.service.ISysJobLogService; | ||||
| import org.springframework.stereotype.Service; | ||||
|  | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| /** | ||||
|  * 定时任务调度日志信息 服务层 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| @Service | ||||
| public class SysJobLogServiceImpl extends ServicePlusImpl<SysJobLogMapper, SysJobLog> implements ISysJobLogService { | ||||
|  | ||||
|     @Override | ||||
|     public TableDataInfo<SysJobLog> selectPageJobLogList(SysJobLog jobLog) { | ||||
|         Map<String, Object> params = jobLog.getParams(); | ||||
|         LambdaQueryWrapper<SysJobLog> lqw = new LambdaQueryWrapper<SysJobLog>() | ||||
|                 .like(StrUtil.isNotBlank(jobLog.getJobName()), SysJobLog::getJobName, jobLog.getJobName()) | ||||
|                 .eq(StrUtil.isNotBlank(jobLog.getJobGroup()), SysJobLog::getJobGroup, jobLog.getJobGroup()) | ||||
|                 .eq(StrUtil.isNotBlank(jobLog.getStatus()), SysJobLog::getStatus, jobLog.getStatus()) | ||||
|                 .like(StrUtil.isNotBlank(jobLog.getInvokeTarget()), SysJobLog::getInvokeTarget, jobLog.getInvokeTarget()) | ||||
|                 .apply(Validator.isNotEmpty(params.get("beginTime")), | ||||
|                         "date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')", | ||||
|                         params.get("beginTime")) | ||||
|                 .apply(Validator.isNotEmpty(params.get("endTime")), | ||||
|                         "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')", | ||||
|                         params.get("endTime")); | ||||
|         return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取quartz调度器日志的计划任务 | ||||
|      * | ||||
|      * @param jobLog 调度日志信息 | ||||
|      * @return 调度任务日志集合 | ||||
|      */ | ||||
|     @Override | ||||
|     public List<SysJobLog> selectJobLogList(SysJobLog jobLog) { | ||||
|         Map<String, Object> params = jobLog.getParams(); | ||||
|         return list(new LambdaQueryWrapper<SysJobLog>() | ||||
|                 .like(StrUtil.isNotBlank(jobLog.getJobName()), SysJobLog::getJobName, jobLog.getJobName()) | ||||
|                 .eq(StrUtil.isNotBlank(jobLog.getJobGroup()), SysJobLog::getJobGroup, jobLog.getJobGroup()) | ||||
|                 .eq(StrUtil.isNotBlank(jobLog.getStatus()), SysJobLog::getStatus, jobLog.getStatus()) | ||||
|                 .like(StrUtil.isNotBlank(jobLog.getInvokeTarget()), SysJobLog::getInvokeTarget, jobLog.getInvokeTarget()) | ||||
|                 .apply(Validator.isNotEmpty(params.get("beginTime")), | ||||
|                         "date_format(create_time,'%y%m%d') >= date_format({0},'%y%m%d')", | ||||
|                         params.get("beginTime")) | ||||
|                 .apply(Validator.isNotEmpty(params.get("endTime")), | ||||
|                         "date_format(create_time,'%y%m%d') <= date_format({0},'%y%m%d')", | ||||
|                         params.get("endTime"))); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 通过调度任务日志ID查询调度信息 | ||||
|      * | ||||
|      * @param jobLogId 调度任务日志ID | ||||
|      * @return 调度任务日志对象信息 | ||||
|      */ | ||||
|     @Override | ||||
|     public SysJobLog selectJobLogById(Long jobLogId) { | ||||
|         return getById(jobLogId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增任务日志 | ||||
|      * | ||||
|      * @param jobLog 调度日志信息 | ||||
|      */ | ||||
|     @Override | ||||
|     public void addJobLog(SysJobLog jobLog) { | ||||
|         baseMapper.insert(jobLog); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 批量删除调度日志信息 | ||||
|      * | ||||
|      * @param logIds 需要删除的数据ID | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     @Override | ||||
|     public int deleteJobLogByIds(Long[] logIds) { | ||||
|         return baseMapper.deleteBatchIds(Arrays.asList(logIds)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除任务日志 | ||||
|      * | ||||
|      * @param jobId 调度日志ID | ||||
|      */ | ||||
|     @Override | ||||
|     public int deleteJobLogById(Long jobId) { | ||||
|         return baseMapper.deleteById(jobId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 清空任务日志 | ||||
|      */ | ||||
|     @Override | ||||
|     public void cleanJobLog() { | ||||
|         remove(new LambdaQueryWrapper<>()); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,246 @@ | ||||
| package com.ruoyi.quartz.service.impl; | ||||
|  | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | ||||
| import com.ruoyi.common.constant.ScheduleConstants; | ||||
| import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl; | ||||
| import com.ruoyi.common.core.page.TableDataInfo; | ||||
| import com.ruoyi.common.exception.job.TaskException; | ||||
| import com.ruoyi.common.utils.PageUtils; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
| import com.ruoyi.quartz.mapper.SysJobMapper; | ||||
| import com.ruoyi.quartz.service.ISysJobService; | ||||
| import com.ruoyi.quartz.util.CronUtils; | ||||
| import com.ruoyi.quartz.util.ScheduleUtils; | ||||
| import org.quartz.JobDataMap; | ||||
| import org.quartz.JobKey; | ||||
| import org.quartz.Scheduler; | ||||
| import org.quartz.SchedulerException; | ||||
| import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.stereotype.Service; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|  | ||||
| import javax.annotation.PostConstruct; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 定时任务调度信息 服务层 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| @Service | ||||
| public class SysJobServiceImpl extends ServicePlusImpl<SysJobMapper, SysJob> implements ISysJobService { | ||||
|     @Autowired | ||||
|     private Scheduler scheduler; | ||||
|  | ||||
|     /** | ||||
|      * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据) | ||||
|      */ | ||||
|     @PostConstruct | ||||
|     public void init() throws SchedulerException, TaskException { | ||||
|         scheduler.clear(); | ||||
|         List<SysJob> jobList = list(); | ||||
|         for (SysJob job : jobList) { | ||||
|             ScheduleUtils.createScheduleJob(scheduler, job); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public TableDataInfo<SysJob> selectPageJobList(SysJob job) { | ||||
|         LambdaQueryWrapper<SysJob> lqw = new LambdaQueryWrapper<SysJob>() | ||||
|                 .like(StrUtil.isNotBlank(job.getJobName()), SysJob::getJobName, job.getJobName()) | ||||
|                 .eq(StrUtil.isNotBlank(job.getJobGroup()), SysJob::getJobGroup, job.getJobGroup()) | ||||
|                 .eq(StrUtil.isNotBlank(job.getStatus()), SysJob::getStatus, job.getStatus()) | ||||
|                 .like(StrUtil.isNotBlank(job.getInvokeTarget()), SysJob::getInvokeTarget, job.getInvokeTarget()); | ||||
|         return PageUtils.buildDataInfo(page(PageUtils.buildPage(), lqw)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取quartz调度器的计划任务列表 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      * @return | ||||
|      */ | ||||
|     @Override | ||||
|     public List<SysJob> selectJobList(SysJob job) { | ||||
|         return list(new LambdaQueryWrapper<SysJob>() | ||||
|                 .like(StrUtil.isNotBlank(job.getJobName()), SysJob::getJobName, job.getJobName()) | ||||
|                 .eq(StrUtil.isNotBlank(job.getJobGroup()), SysJob::getJobGroup, job.getJobGroup()) | ||||
|                 .eq(StrUtil.isNotBlank(job.getStatus()), SysJob::getStatus, job.getStatus()) | ||||
|                 .like(StrUtil.isNotBlank(job.getInvokeTarget()), SysJob::getInvokeTarget, job.getInvokeTarget())); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 通过调度任务ID查询调度信息 | ||||
|      * | ||||
|      * @param jobId 调度任务ID | ||||
|      * @return 调度任务对象信息 | ||||
|      */ | ||||
|     @Override | ||||
|     public SysJob selectJobById(Long jobId) { | ||||
|         return getById(jobId); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 暂停任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public int pauseJob(SysJob job) throws SchedulerException { | ||||
|         Long jobId = job.getJobId(); | ||||
|         String jobGroup = job.getJobGroup(); | ||||
|         job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); | ||||
|         int rows = baseMapper.updateById(job); | ||||
|         if (rows > 0) { | ||||
|             scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); | ||||
|         } | ||||
|         return rows; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 恢复任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public int resumeJob(SysJob job) throws SchedulerException { | ||||
|         Long jobId = job.getJobId(); | ||||
|         String jobGroup = job.getJobGroup(); | ||||
|         job.setStatus(ScheduleConstants.Status.NORMAL.getValue()); | ||||
|         int rows = baseMapper.updateById(job); | ||||
|         if (rows > 0) { | ||||
|             scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup)); | ||||
|         } | ||||
|         return rows; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 删除任务后,所对应的trigger也将被删除 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public int deleteJob(SysJob job) throws SchedulerException { | ||||
|         Long jobId = job.getJobId(); | ||||
|         String jobGroup = job.getJobGroup(); | ||||
|         int rows = baseMapper.deleteById(jobId); | ||||
|         if (rows > 0) { | ||||
|             scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup)); | ||||
|         } | ||||
|         return rows; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 批量删除调度信息 | ||||
|      * | ||||
|      * @param jobIds 需要删除的任务ID | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public void deleteJobByIds(Long[] jobIds) throws SchedulerException { | ||||
|         for (Long jobId : jobIds) { | ||||
|             SysJob job = getById(jobId); | ||||
|             deleteJob(job); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 任务调度状态修改 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public int changeStatus(SysJob job) throws SchedulerException { | ||||
|         int rows = 0; | ||||
|         String status = job.getStatus(); | ||||
|         if (ScheduleConstants.Status.NORMAL.getValue().equals(status)) { | ||||
|             rows = resumeJob(job); | ||||
|         } else if (ScheduleConstants.Status.PAUSE.getValue().equals(status)) { | ||||
|             rows = pauseJob(job); | ||||
|         } | ||||
|         return rows; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 立即运行任务 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public void run(SysJob job) throws SchedulerException { | ||||
|         Long jobId = job.getJobId(); | ||||
|         String jobGroup = job.getJobGroup(); | ||||
|         SysJob properties = selectJobById(job.getJobId()); | ||||
|         // 参数 | ||||
|         JobDataMap dataMap = new JobDataMap(); | ||||
|         dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties); | ||||
|         scheduler.triggerJob(ScheduleUtils.getJobKey(jobId, jobGroup), dataMap); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 新增任务 | ||||
|      * | ||||
|      * @param job 调度信息 调度信息 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public int insertJob(SysJob job) throws SchedulerException, TaskException { | ||||
|         job.setStatus(ScheduleConstants.Status.PAUSE.getValue()); | ||||
|         int rows = baseMapper.insert(job); | ||||
|         if (rows > 0) { | ||||
|             ScheduleUtils.createScheduleJob(scheduler, job); | ||||
|         } | ||||
|         return rows; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 更新任务的时间表达式 | ||||
|      * | ||||
|      * @param job 调度信息 | ||||
|      */ | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public int updateJob(SysJob job) throws SchedulerException, TaskException { | ||||
|         SysJob properties = selectJobById(job.getJobId()); | ||||
|         int rows = baseMapper.updateById(job); | ||||
|         if (rows > 0) { | ||||
|             updateSchedulerJob(job, properties.getJobGroup()); | ||||
|         } | ||||
|         return rows; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 更新任务 | ||||
|      * | ||||
|      * @param job      任务对象 | ||||
|      * @param jobGroup 任务组名 | ||||
|      */ | ||||
|     public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException { | ||||
|         Long jobId = job.getJobId(); | ||||
|         // 判断是否存在 | ||||
|         JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup); | ||||
|         if (scheduler.checkExists(jobKey)) { | ||||
|             // 防止创建时存在数据问题 先移除,然后在执行创建操作 | ||||
|             scheduler.deleteJob(jobKey); | ||||
|         } | ||||
|         ScheduleUtils.createScheduleJob(scheduler, job); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验cron表达式是否有效 | ||||
|      * | ||||
|      * @param cronExpression 表达式 | ||||
|      * @return 结果 | ||||
|      */ | ||||
|     @Override | ||||
|     public boolean checkCronExpressionIsValid(String cronExpression) { | ||||
|         return CronUtils.isValid(cronExpression); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| package com.ruoyi.quartz.task; | ||||
|  | ||||
| import cn.hutool.core.lang.Console; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import org.springframework.stereotype.Component; | ||||
|  | ||||
| /** | ||||
|  * 定时任务调度测试 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| @Component("ryTask") | ||||
| public class RyTask | ||||
| { | ||||
|     public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) | ||||
|     { | ||||
|         Console.log(StrUtil.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i)); | ||||
|     } | ||||
|  | ||||
|     public void ryParams(String params) | ||||
|     { | ||||
|         Console.log("执行有参方法:" + params); | ||||
|     } | ||||
|  | ||||
|     public void ryNoParams() | ||||
|     { | ||||
|         Console.log("执行无参方法"); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,109 @@ | ||||
| package com.ruoyi.quartz.util; | ||||
|  | ||||
| import cn.hutool.core.bean.BeanUtil; | ||||
| import cn.hutool.core.exceptions.ExceptionUtil; | ||||
| import cn.hutool.core.lang.Validator; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import com.ruoyi.common.constant.Constants; | ||||
| import com.ruoyi.common.constant.ScheduleConstants; | ||||
| import com.ruoyi.common.utils.spring.SpringUtils; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
| import com.ruoyi.quartz.domain.SysJobLog; | ||||
| import com.ruoyi.quartz.service.ISysJobLogService; | ||||
| import org.quartz.Job; | ||||
| import org.quartz.JobExecutionContext; | ||||
| import org.quartz.JobExecutionException; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| import java.util.Date; | ||||
|  | ||||
| /** | ||||
|  * 抽象quartz调用 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public abstract class AbstractQuartzJob implements Job | ||||
| { | ||||
|     private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class); | ||||
|  | ||||
|     /** | ||||
|      * 线程本地变量 | ||||
|      */ | ||||
|     private static ThreadLocal<Date> threadLocal = new ThreadLocal<>(); | ||||
|  | ||||
|     @Override | ||||
|     public void execute(JobExecutionContext context) throws JobExecutionException | ||||
|     { | ||||
|         SysJob sysJob = new SysJob(); | ||||
|         BeanUtil.copyProperties(context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES),sysJob); | ||||
|         try | ||||
|         { | ||||
|             before(context, sysJob); | ||||
|             if (Validator.isNotNull(sysJob)) | ||||
|             { | ||||
|                 doExecute(context, sysJob); | ||||
|             } | ||||
|             after(context, sysJob, null); | ||||
|         } | ||||
|         catch (Exception e) | ||||
|         { | ||||
|             log.error("任务执行异常  - :", e); | ||||
|             after(context, sysJob, e); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行前 | ||||
|      * | ||||
|      * @param context 工作执行上下文对象 | ||||
|      * @param sysJob 系统计划任务 | ||||
|      */ | ||||
|     protected void before(JobExecutionContext context, SysJob sysJob) | ||||
|     { | ||||
|         threadLocal.set(new Date()); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行后 | ||||
|      * | ||||
|      * @param context 工作执行上下文对象 | ||||
|      * @param sysJob 系统计划任务 | ||||
|      */ | ||||
|     protected void after(JobExecutionContext context, SysJob sysJob, Exception e) | ||||
|     { | ||||
|         Date startTime = threadLocal.get(); | ||||
|         threadLocal.remove(); | ||||
|  | ||||
|         final SysJobLog sysJobLog = new SysJobLog(); | ||||
|         sysJobLog.setJobName(sysJob.getJobName()); | ||||
|         sysJobLog.setJobGroup(sysJob.getJobGroup()); | ||||
|         sysJobLog.setInvokeTarget(sysJob.getInvokeTarget()); | ||||
|         sysJobLog.setStartTime(startTime); | ||||
|         sysJobLog.setStopTime(new Date()); | ||||
|         long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime(); | ||||
|         sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒"); | ||||
|         if (e != null) | ||||
|         { | ||||
|             sysJobLog.setStatus(Constants.FAIL); | ||||
|             String errorMsg = StrUtil.sub(ExceptionUtil.stacktraceToString(e), 0, 2000); | ||||
|             sysJobLog.setExceptionInfo(errorMsg); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             sysJobLog.setStatus(Constants.SUCCESS); | ||||
|         } | ||||
|  | ||||
|         // 写入数据库当中 | ||||
|         SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 执行方法,由子类重载 | ||||
|      * | ||||
|      * @param context 工作执行上下文对象 | ||||
|      * @param sysJob 系统计划任务 | ||||
|      * @throws Exception 执行过程中的异常 | ||||
|      */ | ||||
|     protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception; | ||||
| } | ||||
| @ -0,0 +1,63 @@ | ||||
| package com.ruoyi.quartz.util; | ||||
|  | ||||
| import java.text.ParseException; | ||||
| import java.util.Date; | ||||
| import org.quartz.CronExpression; | ||||
|  | ||||
| /** | ||||
|  * cron表达式工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  * | ||||
|  */ | ||||
| public class CronUtils | ||||
| { | ||||
|     /** | ||||
|      * 返回一个布尔值代表一个给定的Cron表达式的有效性 | ||||
|      * | ||||
|      * @param cronExpression Cron表达式 | ||||
|      * @return boolean 表达式是否有效 | ||||
|      */ | ||||
|     public static boolean isValid(String cronExpression) | ||||
|     { | ||||
|         return CronExpression.isValidExpression(cronExpression); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回一个字符串值,表示该消息无效Cron表达式给出有效性 | ||||
|      * | ||||
|      * @param cronExpression Cron表达式 | ||||
|      * @return String 无效时返回表达式错误描述,如果有效返回null | ||||
|      */ | ||||
|     public static String getInvalidMessage(String cronExpression) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             new CronExpression(cronExpression); | ||||
|             return null; | ||||
|         } | ||||
|         catch (ParseException pe) | ||||
|         { | ||||
|             return pe.getMessage(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 返回下一个执行时间根据给定的Cron表达式 | ||||
|      * | ||||
|      * @param cronExpression Cron表达式 | ||||
|      * @return Date 下次Cron表达式执行时间 | ||||
|      */ | ||||
|     public static Date getNextExecution(String cronExpression) | ||||
|     { | ||||
|         try | ||||
|         { | ||||
|             CronExpression cron = new CronExpression(cronExpression); | ||||
|             return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis())); | ||||
|         } | ||||
|         catch (ParseException e) | ||||
|         { | ||||
|             throw new IllegalArgumentException(e.getMessage()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,184 @@ | ||||
| package com.ruoyi.quartz.util; | ||||
|  | ||||
| import cn.hutool.core.lang.Validator; | ||||
| import cn.hutool.core.util.StrUtil; | ||||
| import com.ruoyi.common.utils.spring.SpringUtils; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
|  | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| import java.util.LinkedList; | ||||
| import java.util.List; | ||||
|  | ||||
| /** | ||||
|  * 任务执行工具 | ||||
|  * | ||||
|  * @author ruoyi | ||||
|  */ | ||||
| public class JobInvokeUtil | ||||
| { | ||||
|     /** | ||||
|      * 执行方法 | ||||
|      * | ||||
|      * @param sysJob 系统任务 | ||||
|      */ | ||||
|     public static void invokeMethod(SysJob sysJob) throws Exception | ||||
|     { | ||||
|         String invokeTarget = sysJob.getInvokeTarget(); | ||||
|         String beanName = getBeanName(invokeTarget); | ||||
|         String methodName = getMethodName(invokeTarget); | ||||
|         List<Object[]> methodParams = getMethodParams(invokeTarget); | ||||
|  | ||||
|         if (!isValidClassName(beanName)) | ||||
|         { | ||||
|             Object bean = SpringUtils.getBean(beanName); | ||||
|             invokeMethod(bean, methodName, methodParams); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             Object bean = Class.forName(beanName).newInstance(); | ||||
|             invokeMethod(bean, methodName, methodParams); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 调用任务方法 | ||||
|      * | ||||
|      * @param bean 目标对象 | ||||
|      * @param methodName 方法名称 | ||||
|      * @param methodParams 方法参数 | ||||
|      */ | ||||
|     private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams) | ||||
|             throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, | ||||
|             InvocationTargetException | ||||
|     { | ||||
|         if (Validator.isNotNull(methodParams) && methodParams.size() > 0) | ||||
|         { | ||||
|             Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams)); | ||||
|             method.invoke(bean, getMethodParamsValue(methodParams)); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             Method method = bean.getClass().getDeclaredMethod(methodName); | ||||
|             method.invoke(bean); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 校验是否为为class包名 | ||||
|      *  | ||||
|      * @param str 名称 | ||||
|      * @return true是 false否 | ||||
|      */ | ||||
|     public static boolean isValidClassName(String invokeTarget) | ||||
|     { | ||||
|         return StrUtil.count(invokeTarget, ".") > 1; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取bean名称 | ||||
|      *  | ||||
|      * @param invokeTarget 目标字符串 | ||||
|      * @return bean名称 | ||||
|      */ | ||||
|     public static String getBeanName(String invokeTarget) | ||||
|     { | ||||
|         String beanName = StrUtil.subBefore(invokeTarget, "(",false); | ||||
|         return StrUtil.subBefore(beanName, ".",true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取bean方法 | ||||
|      *  | ||||
|      * @param invokeTarget 目标字符串 | ||||
|      * @return method方法 | ||||
|      */ | ||||
|     public static String getMethodName(String invokeTarget) | ||||
|     { | ||||
|         String methodName = StrUtil.subBefore(invokeTarget, "(",false); | ||||
|         return StrUtil.subAfter(methodName, ".",true); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取method方法参数相关列表 | ||||
|      *  | ||||
|      * @param invokeTarget 目标字符串 | ||||
|      * @return method方法相关参数列表 | ||||
|      */ | ||||
|     public static List<Object[]> getMethodParams(String invokeTarget) | ||||
|     { | ||||
|         String methodStr = StrUtil.subBetween(invokeTarget, "(", ")"); | ||||
|         if (StrUtil.isEmpty(methodStr)) | ||||
|         { | ||||
|             return null; | ||||
|         } | ||||
|         String[] methodParams = methodStr.split(","); | ||||
|         List<Object[]> classs = new LinkedList<>(); | ||||
|         for (int i = 0; i < methodParams.length; i++) | ||||
|         { | ||||
|             String str = StrUtil.trimToEmpty(methodParams[i]); | ||||
|             // String字符串类型,包含' | ||||
|             if (StrUtil.contains(str, "'")) | ||||
|             { | ||||
|                 classs.add(new Object[] { StrUtil.replace(str, "'", ""), String.class }); | ||||
|             } | ||||
|             // boolean布尔类型,等于true或者false | ||||
|             else if (StrUtil.equals(str, "true") || StrUtil.equalsIgnoreCase(str, "false")) | ||||
|             { | ||||
|                 classs.add(new Object[] { Boolean.valueOf(str), Boolean.class }); | ||||
|             } | ||||
|             // long长整形,包含L | ||||
|             else if (StrUtil.containsIgnoreCase(str, "L")) | ||||
|             { | ||||
|                 classs.add(new Object[] { Long.valueOf(StrUtil.replaceIgnoreCase(str, "L", "")), Long.class }); | ||||
|             } | ||||
|             // double浮点类型,包含D | ||||
|             else if (StrUtil.containsIgnoreCase(str, "D")) | ||||
|             { | ||||
|                 classs.add(new Object[] { Double.valueOf(StrUtil.replaceIgnoreCase(str, "D", "")), Double.class }); | ||||
|             } | ||||
|             // 其他类型归类为整形 | ||||
|             else | ||||
|             { | ||||
|                 classs.add(new Object[] { Integer.valueOf(str), Integer.class }); | ||||
|             } | ||||
|         } | ||||
|         return classs; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取参数类型 | ||||
|      *  | ||||
|      * @param methodParams 参数相关列表 | ||||
|      * @return 参数类型列表 | ||||
|      */ | ||||
|     public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) | ||||
|     { | ||||
|         Class<?>[] classs = new Class<?>[methodParams.size()]; | ||||
|         int index = 0; | ||||
|         for (Object[] os : methodParams) | ||||
|         { | ||||
|             classs[index] = (Class<?>) os[1]; | ||||
|             index++; | ||||
|         } | ||||
|         return classs; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 获取参数值 | ||||
|      *  | ||||
|      * @param methodParams 参数相关列表 | ||||
|      * @return 参数值列表 | ||||
|      */ | ||||
|     public static Object[] getMethodParamsValue(List<Object[]> methodParams) | ||||
|     { | ||||
|         Object[] classs = new Object[methodParams.size()]; | ||||
|         int index = 0; | ||||
|         for (Object[] os : methodParams) | ||||
|         { | ||||
|             classs[index] = (Object) os[0]; | ||||
|             index++; | ||||
|         } | ||||
|         return classs; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,21 @@ | ||||
| package com.ruoyi.quartz.util; | ||||
|  | ||||
| import org.quartz.DisallowConcurrentExecution; | ||||
| import org.quartz.JobExecutionContext; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
|  | ||||
| /** | ||||
|  * 定时任务处理(禁止并发执行) | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  * | ||||
|  */ | ||||
| @DisallowConcurrentExecution | ||||
| public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob | ||||
| { | ||||
|     @Override | ||||
|     protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception | ||||
|     { | ||||
|         JobInvokeUtil.invokeMethod(sysJob); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,19 @@ | ||||
| package com.ruoyi.quartz.util; | ||||
|  | ||||
| import org.quartz.JobExecutionContext; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
|  | ||||
| /** | ||||
|  * 定时任务处理(允许并发执行) | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  * | ||||
|  */ | ||||
| public class QuartzJobExecution extends AbstractQuartzJob | ||||
| { | ||||
|     @Override | ||||
|     protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception | ||||
|     { | ||||
|         JobInvokeUtil.invokeMethod(sysJob); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,113 @@ | ||||
| package com.ruoyi.quartz.util; | ||||
|  | ||||
| import org.quartz.CronScheduleBuilder; | ||||
| import org.quartz.CronTrigger; | ||||
| import org.quartz.Job; | ||||
| import org.quartz.JobBuilder; | ||||
| import org.quartz.JobDetail; | ||||
| import org.quartz.JobKey; | ||||
| import org.quartz.Scheduler; | ||||
| import org.quartz.SchedulerException; | ||||
| import org.quartz.TriggerBuilder; | ||||
| import org.quartz.TriggerKey; | ||||
| import com.ruoyi.common.constant.ScheduleConstants; | ||||
| import com.ruoyi.common.exception.job.TaskException; | ||||
| import com.ruoyi.common.exception.job.TaskException.Code; | ||||
| import com.ruoyi.quartz.domain.SysJob; | ||||
|  | ||||
| /** | ||||
|  * 定时任务工具类 | ||||
|  *  | ||||
|  * @author ruoyi | ||||
|  * | ||||
|  */ | ||||
| public class ScheduleUtils | ||||
| { | ||||
|     /** | ||||
|      * 得到quartz任务类 | ||||
|      * | ||||
|      * @param sysJob 执行计划 | ||||
|      * @return 具体执行任务类 | ||||
|      */ | ||||
|     private static Class<? extends Job> getQuartzJobClass(SysJob sysJob) | ||||
|     { | ||||
|         boolean isConcurrent = "0".equals(sysJob.getConcurrent()); | ||||
|         return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建任务触发对象 | ||||
|      */ | ||||
|     public static TriggerKey getTriggerKey(Long jobId, String jobGroup) | ||||
|     { | ||||
|         return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 构建任务键对象 | ||||
|      */ | ||||
|     public static JobKey getJobKey(Long jobId, String jobGroup) | ||||
|     { | ||||
|         return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 创建定时任务 | ||||
|      */ | ||||
|     public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException | ||||
|     { | ||||
|         Class<? extends Job> jobClass = getQuartzJobClass(job); | ||||
|         // 构建job信息 | ||||
|         Long jobId = job.getJobId(); | ||||
|         String jobGroup = job.getJobGroup(); | ||||
|         JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build(); | ||||
|  | ||||
|         // 表达式调度构建器 | ||||
|         CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression()); | ||||
|         cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder); | ||||
|  | ||||
|         // 按新的cronExpression表达式构建一个新的trigger | ||||
|         CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)) | ||||
|                 .withSchedule(cronScheduleBuilder).build(); | ||||
|  | ||||
|         // 放入参数,运行时的方法可以获取 | ||||
|         jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job); | ||||
|  | ||||
|         // 判断是否存在 | ||||
|         if (scheduler.checkExists(getJobKey(jobId, jobGroup))) | ||||
|         { | ||||
|             // 防止创建时存在数据问题 先移除,然后在执行创建操作 | ||||
|             scheduler.deleteJob(getJobKey(jobId, jobGroup)); | ||||
|         } | ||||
|  | ||||
|         scheduler.scheduleJob(jobDetail, trigger); | ||||
|  | ||||
|         // 暂停任务 | ||||
|         if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) | ||||
|         { | ||||
|             scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 设置定时任务策略 | ||||
|      */ | ||||
|     public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb) | ||||
|             throws TaskException | ||||
|     { | ||||
|         switch (job.getMisfirePolicy()) | ||||
|         { | ||||
|             case ScheduleConstants.MISFIRE_DEFAULT: | ||||
|                 return cb; | ||||
|             case ScheduleConstants.MISFIRE_IGNORE_MISFIRES: | ||||
|                 return cb.withMisfireHandlingInstructionIgnoreMisfires(); | ||||
|             case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED: | ||||
|                 return cb.withMisfireHandlingInstructionFireAndProceed(); | ||||
|             case ScheduleConstants.MISFIRE_DO_NOTHING: | ||||
|                 return cb.withMisfireHandlingInstructionDoNothing(); | ||||
|             default: | ||||
|                 throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() | ||||
|                         + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,18 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" ?> | ||||
| <!DOCTYPE mapper | ||||
| PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||||
| "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||||
| <mapper namespace="com.ruoyi.quartz.mapper.SysJobLogMapper"> | ||||
|  | ||||
| 	<resultMap type="SysJobLog" id="SysJobLogResult"> | ||||
| 		<id     property="jobLogId"       column="job_log_id"      /> | ||||
| 		<result property="jobName"        column="job_name"        /> | ||||
| 		<result property="jobGroup"       column="job_group"       /> | ||||
| 		<result property="invokeTarget"   column="invoke_target"   /> | ||||
| 		<result property="jobMessage"     column="job_message"     /> | ||||
| 		<result property="status"         column="status"          /> | ||||
| 		<result property="exceptionInfo"  column="exception_info"  /> | ||||
| 		<result property="createTime"     column="create_time"     /> | ||||
| 	</resultMap> | ||||
|  | ||||
| </mapper>  | ||||
| @ -0,0 +1,23 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" ?> | ||||
| <!DOCTYPE mapper | ||||
| PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||||
| "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||||
| <mapper namespace="com.ruoyi.quartz.mapper.SysJobMapper"> | ||||
|  | ||||
| 	<resultMap type="SysJob" id="SysJobResult"> | ||||
| 		<id     property="jobId"          column="job_id"          /> | ||||
| 		<result property="jobName"        column="job_name"        /> | ||||
| 		<result property="jobGroup"       column="job_group"       /> | ||||
| 		<result property="invokeTarget"   column="invoke_target"   /> | ||||
| 		<result property="cronExpression" column="cron_expression" /> | ||||
| 		<result property="misfirePolicy"  column="misfire_policy"  /> | ||||
| 		<result property="concurrent"     column="concurrent"      /> | ||||
| 		<result property="status"         column="status"          /> | ||||
| 		<result property="createBy"       column="create_by"       /> | ||||
| 		<result property="createTime"     column="create_time"     /> | ||||
| 		<result property="updateBy"       column="update_by"       /> | ||||
| 		<result property="updateTime"     column="update_time"     /> | ||||
| 		<result property="remark"         column="remark"          /> | ||||
| 	</resultMap> | ||||
|  | ||||
| </mapper>  | ||||
							
								
								
									
										16
									
								
								ruoyi-quartz/src/main/resources/rebel.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								ruoyi-quartz/src/main/resources/rebel.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
|  | ||||
| <!-- | ||||
|   This is the JRebel configuration file. It maps the running application to your IDE workspace, enabling JRebel reloading for this project. | ||||
|   Refer to https://manuals.jrebel.com/jrebel/standalone/config.html for more information. | ||||
| --> | ||||
| <application generated-by="intellij" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_3.xsd"> | ||||
|  | ||||
| 	<id>ruoyi-quartz</id> | ||||
|  | ||||
| 	<classpath> | ||||
| 		<dir name="E:/intellijWork/old-tress-sys/ruoyi-quartz/target/classes"> | ||||
| 		</dir> | ||||
| 	</classpath> | ||||
|  | ||||
| </application> | ||||
		Reference in New Issue
	
	Block a user
	 zt
					zt