Browse Source

添加任务调度

niu 1 year ago
parent
commit
ea04346e68
24 changed files with 1876 additions and 0 deletions
  1. 13 0
      nb-service/web-service/pom.xml
  2. 55 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/constant/Constants.java
  3. 74 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/constant/ScheduleConstants.java
  4. 34 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/exception/TaskException.java
  5. 71 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/mapper/SysJobMapper.java
  6. 71 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/po/SysJobPO.java
  7. 105 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/service/ISysJobService.java
  8. 114 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/service/impl/SysJobServiceImpl.java
  9. 68 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/mapper/SysJobLogMapper.java
  10. 58 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/po/SysJobLogPO.java
  11. 59 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/service/ISysJobLogService.java
  12. 89 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/service/impl/SysJobLogServiceImpl.java
  13. 22 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/task/NpTask.java
  14. 107 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/AbstractQuartzJob.java
  15. 110 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/BeanUtils.java
  16. 67 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/CronUtils.java
  17. 41 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/ExceptionUtil.java
  18. 182 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/JobInvokeUtil.java
  19. 21 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/QuartzDisallowConcurrentExecution.java
  20. 19 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/QuartzJobExecution.java
  21. 130 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/ScheduleUtils.java
  22. 157 0
      nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/SpringUtils.java
  23. 97 0
      nb-service/web-service/src/main/resources/mapper/quartz/SysJobLogMapper.xml
  24. 112 0
      nb-service/web-service/src/main/resources/mapper/quartz/SysJobMapper.xml

+ 13 - 0
nb-service/web-service/pom.xml

@@ -87,5 +87,18 @@
             <artifactId>easy-captcha</artifactId>
         </dependency>
 
+        <!-- 引入 Quartz 依赖-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-quartz</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+
+
     </dependencies>
 </project>

+ 55 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/constant/Constants.java

@@ -0,0 +1,55 @@
+package com.nb.web.service.quartz.constant;
+
+/**
+ * 通用常量信息
+ * 
+ * @author ruoyi
+ */
+public class Constants {
+
+    /**
+     * http请求
+     */
+    public static final String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    public static final String HTTPS = "https://";
+
+    /**
+     * 通用成功标识
+     */
+    public static final String SUCCESS = "1";
+
+    /**
+     * 通用失败标识
+     */
+    public static final String FAIL = "0";
+
+    /**
+     * RMI 远程方法调用
+     */
+    public static final String LOOKUP_RMI = "rmi:";
+
+    /**
+     * LDAP 远程方法调用
+     */
+    public static final String LOOKUP_LDAP = "ldap:";
+
+    /**
+     * LDAPS 远程方法调用
+     */
+    public static final String LOOKUP_LDAPS = "ldaps:";
+
+    /**
+     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+     */
+    public static final String[] JOB_WHITELIST_STR = { "cn.tr" };
+
+    /**
+     * 定时任务违规的字符
+     */
+    public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+            "org.springframework", "org.apache" };
+}

+ 74 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/constant/ScheduleConstants.java

@@ -0,0 +1,74 @@
+package com.nb.web.service.quartz.constant;
+
+/**
+ * 任务调度通用常量
+ * 
+ * @author ruoyi
+ */
+public class ScheduleConstants
+{
+    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+    /** 执行目标key */
+    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+    /** 默认 */
+    public static final String MISFIRE_DEFAULT = "0";
+
+    /** 立即触发执行 */
+    public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+    /** 触发一次执行 */
+    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+    /** 不触发立即执行 */
+    public static final String MISFIRE_DO_NOTHING = "3";
+
+    public enum Status
+    {
+        /**
+         * 正常
+         */
+        NORMAL("0"),
+        /**
+         * 暂停
+         */
+        PAUSE("1");
+
+        private String value;
+
+        private Status(String value)
+        {
+            this.value = value;
+        }
+
+        public String getValue()
+        {
+            return value;
+        }
+    }
+
+    public enum Type
+    {
+        /**
+         * 用户自定义任务
+         */
+        CUSTOM("CUSTOM"),
+        /**
+         * 数据对接任务
+         */
+        JOINT_JOB("JOINT_JOB");
+
+        private String value;
+
+        private Type(String value)
+        {
+            this.value = value;
+        }
+
+        public String getValue()
+        {
+            return value;
+        }
+    }
+}

+ 34 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/exception/TaskException.java

@@ -0,0 +1,34 @@
+package com.nb.web.service.quartz.exception;
+
+/**
+ * 计划策略异常
+ * 
+ * @author ruoyi
+ */
+public class TaskException extends Exception
+{
+    private static final long serialVersionUID = 1L;
+
+    private Code code;
+
+    public TaskException(String msg, Code code)
+    {
+        this(msg, code, null);
+    }
+
+    public TaskException(String msg, Code code, Exception nestedEx)
+    {
+        super(msg, nestedEx);
+        this.code = code;
+    }
+
+    public Code getCode()
+    {
+        return code;
+    }
+
+    public enum Code
+    {
+        TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE
+    }
+}

+ 71 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/mapper/SysJobMapper.java

@@ -0,0 +1,71 @@
+package com.nb.web.service.quartz.job.mapper;
+
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 调度任务信息 数据层
+ * 
+ * @author npy
+ * @create 2024-08-26-8:30
+ */
+@Mapper
+public interface SysJobMapper
+{
+    /**
+     * 查询调度任务日志集合
+     * 
+     * @param job 调度信息
+     * @return 操作日志集合
+     */
+    public List<SysJobPO> selectJobList(SysJobPO job);
+
+    /**
+     * 查询所有调度任务
+     * 
+     * @return 调度任务列表
+     */
+    public List<SysJobPO> selectJobAll();
+
+    /**
+     * 通过调度ID查询调度任务信息
+     * 
+     * @param jobId 调度ID
+     * @return 角色对象信息
+     */
+    public SysJobPO selectJobById(Long jobId);
+
+    /**
+     * 通过调度ID删除调度任务信息
+     * 
+     * @param jobId 调度ID
+     * @return 结果
+     */
+    public int deleteJobById(Long jobId);
+
+    /**
+     * 批量删除调度任务信息
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteJobByIds(Long[] ids);
+
+    /**
+     * 修改调度任务信息
+     * 
+     * @param job 调度任务信息
+     * @return 结果
+     */
+    public int updateJob(SysJobPO job);
+
+    /**
+     * 新增调度任务信息
+     * 
+     * @param job 调度任务信息
+     * @return 结果
+     */
+    public int insertJob(SysJobPO job);
+}

+ 71 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/po/SysJobPO.java

@@ -0,0 +1,71 @@
+package com.nb.web.service.quartz.job.po;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.Date;
+
+/**
+ * 定时任务调度表实体
+ *
+ * @author npy
+ * @create 2024-08-26-8:30
+ **/
+@Data
+@TableName("sys_job")
+@ToString
+public class SysJobPO {
+
+    /** 任务ID */
+    @TableId
+    @ApiModelProperty(value = "任务ID", position = 1)
+    private String jobId;
+
+    /** 任务名称 */
+    @ApiModelProperty(value = "任务名称", position = 2)
+    private String jobName;
+
+    /** 任务组名 */
+    @ApiModelProperty(value = "任务组名", position = 3)
+    private String jobGroup;
+
+    /** 调用目标字符串 */
+    @ApiModelProperty(value = "调用目标字符串", position = 4)
+    private String invokeTarget;
+
+    /** cron执行表达式 */
+    @ApiModelProperty(value = "cron执行表达式", position = 5)
+    private String cronExpression;
+
+    /** 计划执行错误策略(1立即执行 2执行一次 3放弃执行) */
+    @ApiModelProperty(value = "计划执行错误策略(1立即执行 2执行一次 3放弃执行)", position = 6)
+    private String misfirePolicy;
+
+    /** 是否并发执行(0允许 1禁止) */
+    @ApiModelProperty(value = "是否并发执行(0允许 1禁止)", position = 7)
+    private Boolean concurrent;
+
+    /** 状态(0正常 1暂停) */
+    @ApiModelProperty(value = "状态(0正常 1暂停)", position = 8)
+    private String status;
+
+    private String type;
+
+    private String jointJobId;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date createTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date updateTime;
+
+    private String createBy;
+
+    private String updateBy;
+
+    private String remark;
+}

+ 105 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/service/ISysJobService.java

@@ -0,0 +1,105 @@
+package com.nb.web.service.quartz.job.service;
+
+
+import com.nb.web.service.quartz.exception.TaskException;
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import org.quartz.SchedulerException;
+
+import java.util.List;
+
+/**
+ * 定时任务调度信息信息 服务层
+ * 
+ * @author npy
+ * @create 2024-08-26-8:30
+ */
+public interface ISysJobService
+{
+    /**
+     * 获取quartz调度器的计划任务
+     * 
+     * @param job 调度信息
+     * @return 调度任务集合
+     */
+    public List<SysJobPO> selectJobList(SysJobPO job);
+
+    /**
+     * 通过调度任务ID查询调度信息
+     * 
+     * @param jobId 调度任务ID
+     * @return 调度任务对象信息
+     */
+    public SysJobPO selectJobById(Long jobId);
+
+    /**
+     * 暂停任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int pauseJob(SysJobPO job) throws SchedulerException;
+
+    /**
+     * 恢复任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int resumeJob(SysJobPO job) throws SchedulerException;
+
+    /**
+     * 删除任务后,所对应的trigger也将被删除
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int deleteJob(SysJobPO job) throws SchedulerException;
+
+    /**
+     * 批量删除调度信息
+     * 
+     * @param jobIds 需要删除的任务ID
+     * @return 结果
+     */
+    public void deleteJobByIds(Long[] jobIds) throws SchedulerException;
+
+    /**
+     * 任务调度状态修改
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int changeStatus(SysJobPO job) throws SchedulerException;
+
+    /**
+     * 立即运行任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public boolean run(SysJobPO job) throws SchedulerException;
+
+    /**
+     * 新增任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int insertJob(SysJobPO job) throws SchedulerException, TaskException;
+
+    /**
+     * 更新任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int updateJob(SysJobPO job) throws SchedulerException, TaskException;
+
+    /**
+     * 校验cron表达式是否有效
+     * 
+     * @param cronExpression 表达式
+     * @return 结果
+     */
+    public boolean checkCronExpressionIsValid(String cronExpression);
+}

+ 114 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/job/service/impl/SysJobServiceImpl.java

@@ -0,0 +1,114 @@
+package com.nb.web.service.quartz.job.service.impl;
+
+import com.nb.web.service.quartz.constant.ScheduleConstants;
+import com.nb.web.service.quartz.exception.TaskException;
+import com.nb.web.service.quartz.job.mapper.SysJobMapper;
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import com.nb.web.service.quartz.job.service.ISysJobService;
+import com.nb.web.service.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 javax.annotation.PostConstruct;
+import java.util.Collections;
+import java.util.List;
+
+/**
+@author npy
+@create 2024-08-26-8:54
+*/
+@Service
+public class SysJobServiceImpl implements ISysJobService {
+
+    @Autowired
+    private Scheduler scheduler;
+
+    @Autowired
+    private SysJobMapper jobMapper;
+
+
+    /**
+     * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
+     */
+    @PostConstruct
+    public void init() throws SchedulerException, TaskException
+    {
+        scheduler.clear();
+        List<SysJobPO> jobList = jobMapper.selectJobAll();
+        for (SysJobPO job : jobList)
+        {
+            ScheduleUtils.createScheduleJob(scheduler, job);
+        }
+    }
+    @Override
+    public List<SysJobPO> selectJobList(SysJobPO job) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public SysJobPO selectJobById(Long jobId) {
+        return null;
+    }
+
+    @Override
+    public int pauseJob(SysJobPO job) throws SchedulerException {
+        return 0;
+    }
+
+    @Override
+    public int resumeJob(SysJobPO job) throws SchedulerException {
+        return 0;
+    }
+
+    @Override
+    public int deleteJob(SysJobPO job) throws SchedulerException {
+        return 0;
+    }
+
+    @Override
+    public void deleteJobByIds(Long[] jobIds) throws SchedulerException {
+
+    }
+
+    @Override
+    public int changeStatus(SysJobPO job) throws SchedulerException {
+        return 0;
+    }
+
+    @Override
+    public boolean run(SysJobPO job) throws SchedulerException {
+        boolean result = false;
+        Long jobId = Long.valueOf(job.getJobId());
+        String jobGroup = job.getJobGroup();
+        SysJobPO properties = jobMapper.selectJobById(jobId);
+        // 参数
+        JobDataMap dataMap = new JobDataMap();
+        dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
+        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
+        if (scheduler.checkExists(jobKey))
+        {
+            result = true;
+            scheduler.triggerJob(jobKey, dataMap);
+        }
+        return result;
+    }
+
+    @Override
+    public int insertJob(SysJobPO job) throws SchedulerException, TaskException {
+        return 0;
+    }
+
+    @Override
+    public int updateJob(SysJobPO job) throws SchedulerException, TaskException {
+        return 0;
+    }
+
+    @Override
+    public boolean checkCronExpressionIsValid(String cronExpression) {
+        return false;
+    }
+}

+ 68 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/mapper/SysJobLogMapper.java

@@ -0,0 +1,68 @@
+package com.nb.web.service.quartz.jobLog.mapper;
+
+import com.nb.web.service.quartz.jobLog.po.SysJobLogPO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 调度任务日志信息 数据层
+ * 
+ * @author npy
+ * @create 2024-08-26-8:30
+ */
+@Mapper
+public interface SysJobLogMapper
+{
+    /**
+     * 获取quartz调度器日志的计划任务
+     * 
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    public List<SysJobLogPO> selectJobLogList(SysJobLogPO jobLog);
+
+    /**
+     * 查询所有调度任务日志
+     *
+     * @return 调度任务日志列表
+     */
+    public List<SysJobLogPO> selectJobLogAll();
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     * 
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    public SysJobLogPO selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     * 
+     * @param jobLog 调度日志信息
+     * @return 结果
+     */
+    public int insertJobLog(SysJobLogPO jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     * 
+     * @param logIds 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     * 
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    public int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    public void cleanJobLog();
+}

+ 58 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/po/SysJobLogPO.java

@@ -0,0 +1,58 @@
+package com.nb.web.service.quartz.jobLog.po;
+
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.ToString;
+
+import java.util.Date;
+
+/**
+ * 定时任务调度日志表实体
+ *
+ * @author npy
+ * @create 2024-08-26-8:30
+ **/
+@Data
+@TableName("sys_job_log")
+@ToString
+public class SysJobLogPO {
+
+    /** 任务日志ID */
+    @ApiModelProperty(value = "任务日志ID", position = 1)
+    private String id;
+
+    /** 任务名称 */
+    @ApiModelProperty(value = "任务名称", position = 2)
+    private String jobName;
+
+    /** 任务组名 */
+    @ApiModelProperty(value = "任务组名", position = 3)
+    private String jobGroup;
+
+    /** 调用目标字符串 */
+    @ApiModelProperty(value = "调用目标字符串", position = 4)
+    private String invokeTarget;
+
+    /** 日志信息 */
+    @ApiModelProperty(value = "日志信息", position = 5)
+    private String jobMessage;
+
+    /** 执行状态(1正常 0失败) */
+    @ApiModelProperty(value = "执行状态(1正常 0失败)", position = 6)
+    private String status;
+
+    /** 异常信息 */
+    @ApiModelProperty(value = "异常信息", position = 7)
+    private String exceptionInfo;
+
+    @ApiModelProperty(value = "执行开始时间", position = 8)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date startTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @ApiModelProperty(value = "执行结束时间", position = 9)
+    private Date endTime;
+}

+ 59 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/service/ISysJobLogService.java

@@ -0,0 +1,59 @@
+package com.nb.web.service.quartz.jobLog.service;
+
+
+import com.nb.web.service.quartz.jobLog.po.SysJobLogPO;
+
+import java.util.List;
+
+/**
+ * 定时任务调度日志信息信息 服务层
+ * 
+ * @author npy
+ * @create 2024-08-26-8:30
+ */
+public interface ISysJobLogService
+{
+    /**
+     * 获取quartz调度器日志的计划任务
+     * 
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    public List<SysJobLogPO> selectJobLogList(SysJobLogPO jobLog);
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     * 
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    public SysJobLogPO selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     * 
+     * @param jobLog 调度日志信息
+     */
+    public void addJobLog(SysJobLogPO jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     * 
+     * @param logIds 需要删除的日志ID
+     * @return 结果
+     */
+    public int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     * 
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    public int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    public void cleanJobLog();
+}

+ 89 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/jobLog/service/impl/SysJobLogServiceImpl.java

@@ -0,0 +1,89 @@
+package com.nb.web.service.quartz.jobLog.service.impl;
+
+import com.nb.web.service.quartz.jobLog.mapper.SysJobLogMapper;
+import com.nb.web.service.quartz.jobLog.po.SysJobLogPO;
+import com.nb.web.service.quartz.jobLog.service.ISysJobLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 定时任务调度日志信息 服务层
+ * 
+ * @author npy
+ * @create 2024-08-26-8:30
+ */
+@Service
+public class SysJobLogServiceImpl implements ISysJobLogService
+{
+    @Autowired
+    private SysJobLogMapper jobLogMapper;
+
+    /**
+     * 获取quartz调度器日志的计划任务
+     *
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    @Override
+    public List<SysJobLogPO> selectJobLogList(SysJobLogPO jobLog)
+    {
+        return jobLogMapper.selectJobLogList(jobLog);
+    }
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     *
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    @Override
+    public SysJobLogPO selectJobLogById(Long jobLogId)
+    {
+        return jobLogMapper.selectJobLogById(jobLogId);
+    }
+
+    /**
+     * 新增任务日志
+     * 
+     * @param jobLog 调度日志信息
+     */
+    @Override
+    public void addJobLog(SysJobLogPO jobLog)
+    {
+        jobLogMapper.insertJobLog(jobLog);
+    }
+
+    /**
+     * 批量删除调度日志信息
+     *
+     * @param logIds 需要删除的数据ID
+     * @return 结果
+     */
+    @Override
+    public int deleteJobLogByIds(Long[] logIds)
+    {
+        return jobLogMapper.deleteJobLogByIds(logIds);
+    }
+
+    /**
+     * 删除任务日志
+     *
+     * @param jobId 调度日志ID
+     */
+    @Override
+    public int deleteJobLogById(Long jobId)
+    {
+        return jobLogMapper.deleteJobLogById(jobId);
+    }
+
+    /**
+     * 清空任务日志
+     */
+    @Override
+    public void cleanJobLog()
+    {
+        jobLogMapper.cleanJobLog();
+    }
+}

+ 22 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/task/NpTask.java

@@ -0,0 +1,22 @@
+package com.nb.web.service.quartz.task;
+
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+
+/**
+import java.util.Date;
+
+ * @author npy
+ * @create 2024-08-26-8:30
+ */
+@Component("npTask")
+public class NpTask {
+    public static void npParams(String params) {
+        System.out.println("执行有参方法"+params);
+    }
+
+    public static void noParams() {
+        System.out.println("执行无参方法开始执行~~~~~~~~~~~~"+new Date());
+    }
+}

+ 107 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/AbstractQuartzJob.java

@@ -0,0 +1,107 @@
+package com.nb.web.service.quartz.util;
+
+import com.nb.web.service.quartz.constant.Constants;
+import com.nb.web.service.quartz.constant.ScheduleConstants;
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import com.nb.web.service.quartz.jobLog.po.SysJobLogPO;
+import com.nb.web.service.quartz.jobLog.service.ISysJobLogService;
+import org.apache.commons.lang3.StringUtils;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * 抽象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
+    {
+        SysJobPO sysJob = new SysJobPO();
+        BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
+        try
+        {
+            before(context, sysJob);
+            if (sysJob != null)
+            {
+                doExecute(context, sysJob);
+            }
+            after(context, sysJob, null);
+        }
+        catch (Exception e)
+        {
+            log.error("任务执行异常  - :", e);
+            after(context, sysJob, e);
+        }
+    }
+
+    /**
+     * 执行前
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob 系统计划任务
+     */
+    protected void before(JobExecutionContext context, SysJobPO sysJob)
+    {
+        threadLocal.set(new Date());
+    }
+
+    /**
+     * 执行后
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob 系统计划任务
+     */
+    protected void after(JobExecutionContext context, SysJobPO sysJob, Exception e)
+    {
+        Date startTime = threadLocal.get();
+        threadLocal.remove();
+
+        final SysJobLogPO sysJobLog = new SysJobLogPO();
+        sysJobLog.setJobName(sysJob.getJobName());
+        sysJobLog.setJobGroup(sysJob.getJobGroup());
+        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
+        sysJobLog.setStartTime(startTime);
+        sysJobLog.setEndTime(new Date());
+        long runMs = sysJobLog.getEndTime().getTime() - sysJobLog.getStartTime().getTime();
+        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
+        sysJobLog.setId(String.valueOf(UUID.randomUUID().toString().replace("-", "").substring(0, 16).hashCode()& 0xFFFF));
+        if (e != null)
+        {
+            sysJobLog.setStatus(Constants.FAIL);
+            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(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, SysJobPO sysJob) throws Exception;
+}

+ 110 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/BeanUtils.java

@@ -0,0 +1,110 @@
+package com.nb.web.service.quartz.util;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Bean 工具类
+ * 
+ * @author ruoyi
+ */
+public class BeanUtils extends org.springframework.beans.BeanUtils
+{
+    /** Bean方法名中属性名开始的下标 */
+    private static final int BEAN_METHOD_PROP_INDEX = 3;
+
+    /** * 匹配getter方法的正则表达式 */
+    private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
+
+    /** * 匹配setter方法的正则表达式 */
+    private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
+
+    /**
+     * Bean属性复制工具方法。
+     * 
+     * @param dest 目标对象
+     * @param src 源对象
+     */
+    public static void copyBeanProp(Object dest, Object src)
+    {
+        try
+        {
+            copyProperties(src, dest);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 获取对象的setter方法。
+     * 
+     * @param obj 对象
+     * @return 对象的setter方法列表
+     */
+    public static List<Method> getSetterMethods(Object obj)
+    {
+        // setter方法列表
+        List<Method> setterMethods = new ArrayList<Method>();
+
+        // 获取所有方法
+        Method[] methods = obj.getClass().getMethods();
+
+        // 查找setter方法
+
+        for (Method method : methods)
+        {
+            Matcher m = SET_PATTERN.matcher(method.getName());
+            if (m.matches() && (method.getParameterTypes().length == 1))
+            {
+                setterMethods.add(method);
+            }
+        }
+        // 返回setter方法列表
+        return setterMethods;
+    }
+
+    /**
+     * 获取对象的getter方法。
+     * 
+     * @param obj 对象
+     * @return 对象的getter方法列表
+     */
+
+    public static List<Method> getGetterMethods(Object obj)
+    {
+        // getter方法列表
+        List<Method> getterMethods = new ArrayList<Method>();
+        // 获取所有方法
+        Method[] methods = obj.getClass().getMethods();
+        // 查找getter方法
+        for (Method method : methods)
+        {
+            Matcher m = GET_PATTERN.matcher(method.getName());
+            if (m.matches() && (method.getParameterTypes().length == 0))
+            {
+                getterMethods.add(method);
+            }
+        }
+        // 返回getter方法列表
+        return getterMethods;
+    }
+
+    /**
+     * 检查Bean方法名中的属性名是否相等。<br>
+     * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。
+     * 
+     * @param m1 方法名1
+     * @param m2 方法名2
+     * @return 属性名一样返回true,否则返回false
+     */
+
+    public static boolean isMethodPropEquals(String m1, String m2)
+    {
+        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
+    }
+}

+ 67 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/CronUtils.java

@@ -0,0 +1,67 @@
+package com.nb.web.service.quartz.util;
+
+import org.quartz.CronExpression;
+
+import java.text.ParseException;
+import java.util.Date;
+
+/**
+ * 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 CharSequence getNextExecution(String cronExpression)
+    {
+        try
+        {
+            CronExpression cron = new CronExpression(cronExpression);
+            Date nextValidTime = cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
+            return (CharSequence) nextValidTime.toString();
+//            CronExpression cron = new CronExpression(cronExpression);
+//            return (CharSequence) cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
+        }
+        catch (ParseException e)
+        {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+}

+ 41 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/ExceptionUtil.java

@@ -0,0 +1,41 @@
+package com.nb.web.service.quartz.util;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 错误信息处理类。
+ *
+ * @author ruoyi
+ */
+public class ExceptionUtil
+{
+    /**
+     * 获取exception的详细错误信息。
+     */
+    public static String getExceptionMessage(Throwable e)
+    {
+        StringWriter sw = new StringWriter();
+        e.printStackTrace(new PrintWriter(sw, true));
+        return sw.toString();
+    }
+
+    public static String getRootErrorMessage(Exception e)
+    {
+        Throwable root = ExceptionUtils.getRootCause(e);
+        root = (root == null ? e : root);
+        if (root == null)
+        {
+            return "";
+        }
+        String msg = root.getMessage();
+        if (msg == null)
+        {
+            return "null";
+        }
+        return StringUtils.defaultString(msg);
+    }
+}

+ 182 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/JobInvokeUtil.java

@@ -0,0 +1,182 @@
+package com.nb.web.service.quartz.util;
+
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import org.apache.commons.lang3.StringUtils;
+
+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(SysJobPO 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).getDeclaredConstructor().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 (StringUtils.isNotEmpty((CharSequence) methodParams) && methodParams.size() > 0)
+        {
+            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
+            method.invoke(bean, getMethodParamsValue(methodParams));
+        }
+        else
+        {
+            Method method = bean.getClass().getMethod(methodName);
+            method.invoke(bean);
+        }
+    }
+
+    /**
+     * 校验是否为为class包名
+     * 
+     * @param invokeTarget 名称
+     * @return true是 false否
+     */
+    public static boolean isValidClassName(String invokeTarget)
+    {
+        return StringUtils.countMatches(invokeTarget, ".") > 1;
+    }
+
+    /**
+     * 获取bean名称
+     * 
+     * @param invokeTarget 目标字符串
+     * @return bean名称
+     */
+    public static String getBeanName(String invokeTarget)
+    {
+        String beanName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringBeforeLast(beanName, ".");
+    }
+
+    /**
+     * 获取bean方法
+     * 
+     * @param invokeTarget 目标字符串
+     * @return method方法
+     */
+    public static String getMethodName(String invokeTarget)
+    {
+        String methodName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringAfterLast(methodName, ".");
+    }
+
+    /**
+     * 获取method方法参数相关列表
+     * 
+     * @param invokeTarget 目标字符串
+     * @return method方法相关参数列表
+     */
+    public static List<Object[]> getMethodParams(String invokeTarget)
+    {
+        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
+        if (StringUtils.isEmpty(methodStr))
+        {
+            return null;
+        }
+        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
+        List<Object[]> classs = new LinkedList<>();
+        for (int i = 0; i < methodParams.length; i++)
+        {
+            String str = StringUtils.trimToEmpty(methodParams[i]);
+            // String字符串类型,以'或"开头
+            if (StringUtils.startsWithAny(str, "'", "\""))
+            {
+                classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class });
+            }
+            // boolean布尔类型,等于true或者false
+            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str))
+            {
+                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
+            }
+            // long长整形,以L结尾
+            else if (StringUtils.endsWith(str, "L"))
+            {
+                classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });
+            }
+            // double浮点类型,以D结尾
+            else if (StringUtils.endsWith(str, "D"))
+            {
+                classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), 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;
+    }
+}

+ 21 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/QuartzDisallowConcurrentExecution.java

@@ -0,0 +1,21 @@
+package com.nb.web.service.quartz.util;
+
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.JobExecutionContext;
+
+/**
+ * 定时任务处理(禁止并发执行)
+ * 
+ * @author ruoyi
+ *
+ */
+@DisallowConcurrentExecution
+public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
+{
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJobPO sysJob) throws Exception
+    {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}

+ 19 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/QuartzJobExecution.java

@@ -0,0 +1,19 @@
+package com.nb.web.service.quartz.util;
+
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import org.quartz.JobExecutionContext;
+
+/**
+ * 定时任务处理(允许并发执行)
+ * 
+ * @author ruoyi
+ *
+ */
+public class QuartzJobExecution extends AbstractQuartzJob
+{
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJobPO sysJob) throws Exception
+    {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}

+ 130 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/ScheduleUtils.java

@@ -0,0 +1,130 @@
+package com.nb.web.service.quartz.util;
+
+import com.nb.web.service.quartz.constant.Constants;
+import com.nb.web.service.quartz.constant.ScheduleConstants;
+import com.nb.web.service.quartz.exception.TaskException;
+import com.nb.web.service.quartz.job.po.SysJobPO;
+import org.apache.commons.lang3.StringUtils;
+import org.quartz.*;
+
+/**
+ * 定时任务工具类
+ * 
+ * @author ruoyi
+ *
+ */
+public class ScheduleUtils
+{
+    /**
+     * 得到quartz任务类
+     *
+     * @param sysJob 执行计划
+     * @return 具体执行任务类
+     */
+    private static Class<? extends Job> getQuartzJobClass(SysJobPO 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, SysJobPO job) throws SchedulerException, TaskException
+    {
+        Class<? extends Job> jobClass = getQuartzJobClass(job);
+        // 构建job信息
+        Long jobId = Long.valueOf(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));
+        }
+
+        // 判断任务是否过期
+        if (StringUtils.isNotEmpty(CronUtils.getNextExecution(job.getCronExpression())))
+        {
+            // 执行调度任务
+            scheduler.scheduleJob(jobDetail, trigger);
+        }
+
+        // 暂停任务
+        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))
+        {
+            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+    }
+
+    /**
+     * 设置定时任务策略
+     */
+    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJobPO 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", TaskException.Code.CONFIG_ERROR);
+        }
+    }
+
+    /**
+     * 检查包名是否为白名单配置
+     * 
+     * @param invokeTarget 目标字符串
+     * @return 结果
+     */
+    public static boolean whiteList(String invokeTarget)
+    {
+        String packageName = StringUtils.substringBefore(invokeTarget, "(");
+        int count = StringUtils.countMatches(packageName, ".");
+        if (count > 1)
+        {
+            return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
+        }
+        Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
+        String beanPackageName = obj.getClass().getPackage().getName();
+        return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
+                && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
+    }
+}

+ 157 - 0
nb-service/web-service/src/main/java/com/nb/web/service/quartz/util/SpringUtils.java

@@ -0,0 +1,157 @@
+package com.nb.web.service.quartz.util;
+
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring工具类 方便在非spring管理环境中获取bean
+ * 
+ * @author ruoyi
+ */
+@Component
+public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware 
+{
+    /** Spring应用上下文环境 */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException 
+    {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
+    {
+        SpringUtils.applicationContext = applicationContext;
+    }
+
+    /**
+     * 获取对象
+     *
+     * @param name
+     * @return Object 一个以所给名字注册的bean的实例
+     * @throws BeansException
+     *
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) throws BeansException
+    {
+        return (T) beanFactory.getBean(name);
+    }
+
+    /**
+     * 获取类型为requiredType的对象
+     *
+     * @param clz
+     * @return
+     * @throws BeansException
+     *
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException
+    {
+        T result = (T) beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name)
+    {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
+     *
+     * @param name
+     * @return boolean
+     * @throws NoSuchBeanDefinitionException
+     *
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 注册对象的类型
+     * @throws NoSuchBeanDefinitionException
+     *
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+     *
+     * @param name
+     * @return
+     * @throws NoSuchBeanDefinitionException
+     *
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 获取aop代理对象
+     * 
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker)
+    {
+        return (T) AopContext.currentProxy();
+    }
+
+    /**
+     * 获取当前的环境配置,无配置返回null
+     *
+     * @return 当前的环境配置
+     */
+    public static String[] getActiveProfiles()
+    {
+        return applicationContext.getEnvironment().getActiveProfiles();
+    }
+
+    /**
+     * 获取当前的环境配置,当有多个环境配置时,只获取第一个
+     *
+     * @return 当前的环境配置
+     */
+//    public static String getActiveProfile()
+//    {
+//        final String[] activeProfiles = getActiveProfiles();
+//        return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
+//    }
+
+    /**
+     * 获取配置文件中的值
+     *
+     * @param key 配置文件的key
+     * @return 当前的配置文件的值
+     *
+     */
+    public static String getRequiredProperty(String key)
+    {
+        return applicationContext.getEnvironment().getRequiredProperty(key);
+    }
+}

+ 97 - 0
nb-service/web-service/src/main/resources/mapper/quartz/SysJobLogMapper.xml

@@ -0,0 +1,97 @@
+<?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.nb.web.service.quartz.jobLog.mapper.SysJobLogMapper">
+
+	<resultMap type="com.nb.web.service.quartz.jobLog.po.SysJobLogPO" id="SysJobLogResult">
+		<id     property="id"       column="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="startTime"     column="start_time"     />
+		<result property="endTime"     column="end_time"     />
+	</resultMap>
+	
+	<sql id="selectJobLogVo">
+        select id, job_name, job_group, invoke_target, job_message, status, exception_info, start_time, end_time
+		from sys_job_log
+    </sql>
+	
+	<select id="selectJobLogList" parameterType="com.nb.web.service.quartz.jobLog.po.SysJobLogPO" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+		<where>
+			<if test="jobName != null and jobName != ''">
+				AND job_name like concat('%', #{jobName}, '%')
+			</if>
+			<if test="jobGroup != null and jobGroup != ''">
+				AND job_group = #{jobGroup}
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+			<if test="invokeTarget != null and invokeTarget != ''">
+				AND invoke_target like concat('%', #{invokeTarget}, '%')
+			</if>
+			<if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
+				and date_format(start_time,'%Y%m%d') &gt;= date_format(#{params.beginTime},'%Y%m%d')
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
+				and date_format(start_time,'%Y%m%d') &lt;= date_format(#{params.endTime},'%Y%m%d')
+			</if>
+		</where>
+		order by start_time desc
+	</select>
+	
+	<select id="selectJobLogAll" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+	</select>
+	
+	<select id="selectJobLogById" parameterType="Long" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+		where id = #{id}
+	</select>
+	
+	<delete id="deleteJobLogById" parameterType="Long">
+ 		delete from sys_job_log where id = #{id}
+ 	</delete>
+ 	
+ 	<delete id="deleteJobLogByIds" parameterType="Long">
+ 		delete from sys_job_log where id in
+ 		<foreach collection="array" item="id" open="(" separator="," close=")">
+ 			#{id}
+        </foreach> 
+ 	</delete>
+ 	
+ 	<update id="cleanJobLog">
+        truncate table sys_job_log
+    </update>
+ 	
+ 	<insert id="insertJobLog" parameterType="com.nb.web.service.quartz.jobLog.po.SysJobLogPO">
+ 		insert into sys_job_log(
+ 			<if test="id != null and id != 0">id,</if>
+ 			<if test="jobName != null and jobName != ''">job_name,</if>
+ 			<if test="jobGroup != null and jobGroup != ''">job_group,</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if>
+ 			<if test="jobMessage != null and jobMessage != ''">job_message,</if>
+ 			<if test="status != null and status != ''">status,</if>
+ 			<if test="exceptionInfo != null and exceptionInfo != ''">exception_info,</if>
+ 			start_time,
+ 		    end_time
+ 		)values(
+ 			<if test="id != null and id != 0">#{id},</if>
+ 			<if test="jobName != null and jobName != ''">#{jobName},</if>
+ 			<if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if>
+ 			<if test="jobMessage != null and jobMessage != ''">#{jobMessage},</if>
+ 			<if test="status != null and status != ''">#{status},</if>
+ 			<if test="exceptionInfo != null and exceptionInfo != ''">#{exceptionInfo},</if>
+ 			sysdate(),
+ 		    sysdate()
+ 		)
+	</insert>
+
+</mapper> 

+ 112 - 0
nb-service/web-service/src/main/resources/mapper/quartz/SysJobMapper.xml

@@ -0,0 +1,112 @@
+<?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.nb.web.service.quartz.job.mapper.SysJobMapper">
+
+	<resultMap type="com.nb.web.service.quartz.job.po.SysJobPO" 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="type"         column="type"          />
+		<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>
+	
+	<sql id="selectJobVo">
+        select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark 
+		from sys_job
+    </sql>
+	
+	<select id="selectJobList" parameterType="com.nb.web.service.quartz.job.po.SysJobPO" resultMap="SysJobResult">
+		<include refid="selectJobVo"/>
+		<where>
+			<if test="jobName != null and jobName != ''">
+				AND job_name like concat('%', #{jobName}, '%')
+			</if>
+			<if test="jobGroup != null and jobGroup != ''">
+				AND job_group = #{jobGroup}
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+			<if test="invokeTarget != null and invokeTarget != ''">
+				AND invoke_target like concat('%', #{invokeTarget}, '%')
+			</if>
+		</where>
+	</select>
+	
+	<select id="selectJobAll" resultMap="SysJobResult">
+		<include refid="selectJobVo"/>
+	</select>
+	
+	<select id="selectJobById" parameterType="Long" resultMap="SysJobResult">
+		<include refid="selectJobVo"/>
+		where job_id = #{jobId}
+	</select>
+	
+	<delete id="deleteJobById" parameterType="Long">
+ 		delete from sys_job where job_id = #{jobId}
+ 	</delete>
+ 	
+ 	<delete id="deleteJobByIds" parameterType="Long">
+ 		delete from sys_job where job_id in
+ 		<foreach collection="array" item="jobId" open="(" separator="," close=")">
+ 			#{jobId}
+        </foreach> 
+ 	</delete>
+ 	
+ 	<update id="updateJob" parameterType="com.nb.web.service.quartz.job.po.SysJobPO">
+ 		update sys_job
+ 		<set>
+ 			<if test="jobName != null and jobName != ''">job_name = #{jobName},</if>
+ 			<if test="jobGroup != null and jobGroup != ''">job_group = #{jobGroup},</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target = #{invokeTarget},</if>
+ 			<if test="cronExpression != null and cronExpression != ''">cron_expression = #{cronExpression},</if>
+ 			<if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy = #{misfirePolicy},</if>
+ 			<if test="concurrent != null and concurrent != ''">concurrent = #{concurrent},</if>
+ 			<if test="status !=null">status = #{status},</if>
+ 			<if test="remark != null and remark != ''">remark = #{remark},</if>
+ 			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			update_time = sysdate()
+ 		</set>
+ 		where job_id = #{jobId}
+	</update>
+ 	
+ 	<insert id="insertJob" parameterType="com.nb.web.service.quartz.job.po.SysJobPO" useGeneratedKeys="true" keyProperty="jobId">
+ 		insert into sys_job(
+ 			<if test="jobId != null and jobId != 0">job_id,</if>
+ 			<if test="jobName != null and jobName != ''">job_name,</if>
+ 			<if test="jobGroup != null and jobGroup != ''">job_group,</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if>
+ 			<if test="cronExpression != null and cronExpression != ''">cron_expression,</if>
+ 			<if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy,</if>
+ 			<if test="concurrent != null and concurrent != ''">concurrent,</if>
+ 			<if test="status != null and status != ''">status,</if>
+ 			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			create_time
+ 		)values(
+ 			<if test="jobId != null and jobId != 0">#{jobId},</if>
+ 			<if test="jobName != null and jobName != ''">#{jobName},</if>
+ 			<if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if>
+ 			<if test="cronExpression != null and cronExpression != ''">#{cronExpression},</if>
+ 			<if test="misfirePolicy != null and misfirePolicy != ''">#{misfirePolicy},</if>
+ 			<if test="concurrent != null and concurrent != ''">#{concurrent},</if>
+ 			<if test="status != null and status != ''">#{status},</if>
+ 			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			sysdate()
+ 		)
+	</insert>
+
+</mapper>