SpringBoot-quartz配置页面可视化任务调度

你了解 Quartz 吗?


Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。

Quartz 可以与 J2EE 与 J2SE 应用程序相结合也可以单独使用。

Quartz 允许程序开发人员根据时间的间隔来调度作业。

Quartz 实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。

Quartz 核心概念


 我们需要明白 Quartz 的几个核心概念,这样理解起 Quartz 的原理就会变得简单了。

  1. Job 表示一个工作,要执行的具体内容。此接口中只有一个方法,如下:
    void execute(JobExecutionContext context) 
  2. JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
  3. Trigger 代表一个调度参数的配置,什么时候去调。
  4. Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。

Quartz的运行环境


  • Quartz 可以运行嵌入在另一个独立式应用程序。
  • Quartz 可以在应用程序服务器(或 servlet 容器)内被实例化,并且参与 XA 事务。
  • Quartz 可以作为一个独立的程序运行(其自己的 Java 虚拟机内),可以通过 RMI 使用。
  • Quartz 可以被实例化,作为独立的项目集群(负载平衡和故障转移功能),用于作业的执行。

业务代码

1.controller层

package com.csii.quartz.controller;

import com.csii.quartz.base.ResultCode;
import com.csii.quartz.service.ScheduleJobService;
import entities.ScheduleJobRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

import java.util.List;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 11:28
 * @description:
 * @modified By:
 * @version: $
 */
@RestController
@Api(tags = "定时器")
@Component
public class ScheduleJobController {

    @Autowired
    private ScheduleJobService scheduleJobService;

    @GetMapping(value = "/schedulejobnacos")
    public void getRegist() {
        System.out.println("=====================测试任务调度getRegist============================");
    }
    @PostMapping(value = "/schedulejobsave")
    @ApiOperation(value = "保存", notes = "保存")
    public ResultCode save(ScheduleJobRequest job) {
        scheduleJobService.saveJob(job);
        return ResultCode.SUCCESS;
    }

    @PostMapping(value = "/schedulejobupdate")
    @ApiOperation(value = "修改", notes = "修改")
    public ResultCode update(ScheduleJobRequest job) {
        scheduleJobService.updateJob(job);
        return ResultCode.SUCCESS;
    }

    @GetMapping(value = "/schedulejobrun")
    @ApiOperation(value = "执行任务", notes = "执行任务")
    public ResultCode run(@RequestParam(required = true) @ApiParam(value="id",required = true) List<Long> jobIds) {
        scheduleJobService.run(jobIds);
        return ResultCode.SUCCESS;
    }
    @GetMapping(value = "/schedulejobdel")
    @ApiOperation(value = "删除任务", notes = "删除任务")
    public ResultCode del(@RequestParam(required = true) @ApiParam(value="id",required = true)List<Long> jobIds) {
        scheduleJobService.deleteBatch(jobIds);
        return ResultCode.SUCCESS;
    }

    @GetMapping(value = "/schedulejobpause")
    @ApiOperation(value = "暂停任务", notes = "暂停任务")
    public ResultCode pause(@RequestParam(required = true) @ApiParam(value="id",required = true)List<Long> jobIds) {
        scheduleJobService.pause(jobIds);
        return ResultCode.SUCCESS;
    }

    @GetMapping(value = "/schedulejobresume")
    @ApiOperation(value = "恢复任务", notes = "恢复任务")
    public ResultCode resume(@RequestParam(required = true) @ApiParam(value="id",required = true)List<Long> jobIds) {
        scheduleJobService.resume(jobIds);
        return ResultCode.SUCCESS;
    }
}

2.service层

2.1 impl

ScheduleJobLogServiceImpl .java

package com.csii.quartz.service.impl;

import com.csii.quartz.dao.ScheduleJobLogMapper;
import com.csii.quartz.service.ScheduleJobLogService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import entities.ScheduleJobLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:58
 * @description:
 * @modified By:
 * @version: $
 */
@Service
public class ScheduleJobLogServiceImpl implements ScheduleJobLogService {


    @Override
    public PageInfo queryPage(Map<String, Object> params) {
    /*    Long jobId = Long.parseLong(params.get("jobId").toString());
        Integer page = Integer.parseInt(params.get("page").toString());
        Integer pageSize = Integer.parseInt(params.get("pageSize").toString());

        PageHelper.startPage(page,pageSize);
        ScheduleJobLogExample scheduleJobLogExample = new ScheduleJobLogExample();
        scheduleJobLogExample.createCriteria().andJobIdEqualTo(jobId);
        List<ScheduleJobLog> scheduleJobLogs = scheduleJobLogMapper.selectByExample(scheduleJobLogExample);*/
        PageInfo pageInfo = new PageInfo<>();
        return pageInfo;
    }



}

ScheduleJobServiceImpl .java

package com.csii.quartz.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.QueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.additional.update.impl.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.csii.quartz.base.Constant;
import com.csii.quartz.dao.ScheduleJobMapper;
import com.csii.quartz.service.ScheduleJobService;
import com.csii.quartz.utils.ScheduleUtils;
import entities.ScheduleJob;
import entities.ScheduleJobRequest;
import org.quartz.CronTrigger;
import org.quartz.Scheduler;
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.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:55
 * @description:
 * @modified By:
 * @version: $
 */
@Service
public class ScheduleJobServiceImpl extends ServiceImpl<ScheduleJobMapper, ScheduleJob> implements ScheduleJobService {


    @Autowired
    private Scheduler scheduler;

    @Autowired
    private ScheduleJobMapper scheduleJobMapper;



    /**
     * 项目启动时,初始化定时器
     */
    @PostConstruct
    public void init(){
        List<ScheduleJob> scheduleJobList = this.baseMapper.selectAll();
        for(ScheduleJob scheduleJob : scheduleJobList){
            CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getJobId());
            //如果不存在,则创建
            if(cronTrigger == null) {
                ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
            }else {
                ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
            }
        }
    }

  /*  @Override
    public PageInfo queryPage(Map<String, Object> params) {
        String beanName = (String)params.get("beanName");
        int page = Integer.parseInt(params.getOrDefault("page", "1").toString());
        int pageSize = Integer.parseInt(params.getOrDefault("pageSize", "10").toString());
        PageHelper.startPage(page,pageSize);
        ScheduleJobExample scheduleJobExample = new ScheduleJobExample();
        scheduleJobExample.createCriteria().andBeanNameLike(beanName);
        List<ScheduleJob> scheduleJobs = scheduleJobMapper.selectByExample(scheduleJobExample);
        PageInfo pageInfo = new PageInfo<>(scheduleJobs);
        return pageInfo;
    }*/

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveJob(ScheduleJobRequest scheduleJob) {
        ScheduleJob entity = buildEntity(scheduleJob);
        this.baseMapper.insert(entity);
        ScheduleUtils.createScheduleJob(scheduler, entity);
    }

    @Override
    public void updateJob(ScheduleJobRequest scheduleJob) {
        ScheduleJob entity = buildEntity(scheduleJob);
        ScheduleUtils.updateScheduleJob(scheduler, entity);
        this.baseMapper.updateByPrimaryKey(entity);
    }


  /* @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(ScheduleJob scheduleJob) {
        scheduleJob.setCreateTime(new Date());
        scheduleJob.setStatus(Byte.parseByte(Constant.NORMAL+""));
        scheduleJobMapper.insertSelective(scheduleJob);
        ScheduleUtils.createScheduleJob(scheduler, scheduleJob);
    }*/

    @Override
    public boolean saveBatch(Collection<ScheduleJob> entityList) {
        return false;
    }

    @Override
    public boolean saveOrUpdateBatch(Collection<ScheduleJob> entityList) {
        return false;
    }

    @Override
    public boolean update(Wrapper<ScheduleJob> updateWrapper) {
        return false;
    }


    @Override
    public boolean updateBatchById(Collection<ScheduleJob> entityList) {
        return false;
    }

    @Override
    public ScheduleJob getOne(Wrapper<ScheduleJob> queryWrapper) {
        return null;
    }

    @Override
    public <V> V getObj(Wrapper<ScheduleJob> queryWrapper, Function<? super Object, V> mapper) {
        return null;
    }

    @Override
    public int count() {
        return 0;
    }

    @Override
    public List<ScheduleJob> list() {
        return null;
    }

    @Override
    public IPage<ScheduleJob> page(IPage<ScheduleJob> page) {
        return null;
    }

    @Override
    public List<Map<String, Object>> listMaps() {
        return null;
    }

    @Override
    public List<Object> listObjs() {
        return null;
    }

    @Override
    public <V> List<V> listObjs(Function<? super Object, V> mapper) {
        return null;
    }

    @Override
    public List<Object> listObjs(Wrapper<ScheduleJob> queryWrapper) {
        return null;
    }

    @Override
    public IPage<Map<String, Object>> pageMaps(IPage<ScheduleJob> page) {
        return null;
    }

    @Override
    public QueryChainWrapper<ScheduleJob> query() {
        return null;
    }

    @Override
    public LambdaQueryChainWrapper<ScheduleJob> lambdaQuery() {
        return null;
    }

    @Override
    public UpdateChainWrapper<ScheduleJob> update() {
        return null;
    }

    @Override
    public LambdaUpdateChainWrapper<ScheduleJob> lambdaUpdate() {
        return null;
    }

   /* @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ScheduleJob scheduleJob) {
        ScheduleUtils.updateScheduleJob(scheduler, scheduleJob);
        scheduleJobMapper.updateByPrimaryKeySelective(scheduleJob);
    }*/

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(List<Long> jobIds) {
        for(Long jobId : jobIds){
            ScheduleUtils.deleteScheduleJob(scheduler, jobId);
        }


    }

    @Override
    public int updateBatch(List<Long>  jobIds, int status){

        for(Long jobId : jobIds){
            ScheduleJob record = new ScheduleJob();
            record.setJobId(jobId);
            record.setStatus(status);
           scheduleJobMapper.updateBatch( record);
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void run(List<Long> jobIds) {
        for(Long jobId : jobIds){
            ScheduleUtils.run(scheduler, scheduleJobMapper.selectByPrimaryKey(jobId));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pause(List<Long> jobIds) {
        for(Long jobId : jobIds){
            ScheduleUtils.pauseJob(scheduler, jobId);
        }

        updateBatch(jobIds, Constant.PAUSE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resume(List<Long> jobIds) {
        for(Long jobId : jobIds){
            ScheduleUtils.resumeJob(scheduler, jobId);
        }

        updateBatch(jobIds, Constant.NORMAL);
    }


    private ScheduleJob buildEntity(ScheduleJobRequest req){
        ScheduleJob entity = new ScheduleJob();
        if(req.getJobId() != null){
            entity.setJobId(req.getJobId());
        }else{
            entity.setCreateTime(new Date());
        }
        entity.setStatus(Constant.NORMAL);
        entity.setCronExpression(req.getCron());
        entity.setMethodName(req.getMethodName());
        entity.setBeanName(req.getName());
        entity.setParams(req.getParams());
        return entity;
    }
}

 

2.2 service接口

ScheduleJobService.java

package com.csii.quartz.service;

import com.github.pagehelper.PageInfo;
import entities.ScheduleJob;
import entities.ScheduleJobRequest;

import java.util.List;
import java.util.Map;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:50
 * @description:定时任务
 * @modified By:
 * @version: $
 */
public interface ScheduleJobService {



   /* PageInfo queryPage(Map<String, Object> params);*/

    /**
     * 保存定时任务
     */
    void saveJob(ScheduleJobRequest scheduleJob);

    /**
     * 更新定时任务
     */
    void updateJob(ScheduleJobRequest scheduleJob);

    /**
     * 批量删除定时任务
     */
    void deleteBatch(List<Long> jobIds);

    /**
     * 批量更新定时任务状态
     */
    int updateBatch(List<Long> jobIds, int status);

    /**
     * 立即执行
     */
    void run(List<Long> jobIds);

    /**
     * 暂停运行
     */
    void pause(List<Long> jobIds);

    /**
     * 恢复运行
     */
    void resume(List<Long> jobIds);



}
ScheduleJobLogService.java
package com.csii.quartz.service;

import com.github.pagehelper.PageInfo;

import java.util.Map;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:54
 * @description:定时任务日志
 * @modified By:
 * @version: 1.0$
 */
public interface ScheduleJobLogService {

    PageInfo queryPage(Map<String, Object> params);
}

 

3.dao层

ScheduleJobLogMapper.java
package com.csii.quartz.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import entities.ScheduleJobLog;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 11:12
 * @description:
 * @modified By:
 * @version: $
 */
@Mapper
@Repository
public interface ScheduleJobLogMapper extends BaseMapper<ScheduleJobLog> {

  /*  long countByExample(ScheduleJobLogExample example);

    int deleteByExample(ScheduleJobLogExample example);*/

    int deleteByPrimaryKey(Long logId);

    int insert(ScheduleJobLog record);

    int insertSelective(ScheduleJobLog record);


    ScheduleJobLog selectByPrimaryKey(Long logId);



    int updateByPrimaryKeySelective(ScheduleJobLog record);

    int updateByPrimaryKey(ScheduleJobLog record);


}
ScheduleJobMapper.java
package com.csii.quartz.dao;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import entities.ScheduleJob;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository
public interface ScheduleJobMapper extends BaseMapper<ScheduleJob> {
    int deleteByPrimaryKey(Long jobId);

    int insert(ScheduleJob record);

    int insertSelective(ScheduleJob record);

    ScheduleJob selectByPrimaryKey(Long jobId);

    int updateByPrimaryKeySelective(ScheduleJob record);

    int updateByPrimaryKey(ScheduleJob record);
    int updateBatch(ScheduleJob record);
    List<ScheduleJob> selectAll();
}

4.entits实体类

 

ScheduleJobRequest.java 保存修改时的参数
package entities;

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 12:04
 * @description:保存修改时的参数
 * @modified By:
 * @version: $
 */
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ScheduleJobRequest {

    @ApiModelProperty(value = "id(修改时为必须)")
    private Long JobId;

    @ApiModelProperty(value = "spring bean名称(大喇叭定时器默认horn)", required = true)
    private String name;

    @ApiModelProperty(value = "方法名(大喇叭定时器默认horn)", required = true)
    private String methodName;

    @ApiModelProperty(value = "参数(备注)", required = true)
    private String params;

    @ApiModelProperty(value = "定时器执行计划(0/10 * * * * ?  每隔10秒一次)", required = true)
    private String cron;
}
ScheduleJobLog.java 

 

package entities;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.util.Date;

@AllArgsConstructor
@NoArgsConstructor
public class ScheduleJobLog {
    private Long logId;

    private Long jobId;

    private String beanName;

    private String methodName;

    private String params;

    private Byte status;

    private String error;

    private Integer times;

    private Date createTime;

    public Long getLogId() {
        return logId;
    }

    public void setLogId(Long logId) {
        this.logId = logId;
    }

    public Long getJobId() {
        return jobId;
    }

    public void setJobId(Long jobId) {
        this.jobId = jobId;
    }

    public String getBeanName() {
        return beanName;
    }

    public void setBeanName(String beanName) {
        this.beanName = beanName == null ? null : beanName.trim();
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName == null ? null : methodName.trim();
    }

    public String getParams() {
        return params;
    }

    public void setParams(String params) {
        this.params = params == null ? null : params.trim();
    }

    public Byte getStatus() {
        return status;
    }

    public void setStatus(Byte status) {
        this.status = status;
    }

    public String getError() {
        return error;
    }

    public void setError(String error) {
        this.error = error == null ? null : error.trim();
    }

    public Integer getTimes() {
        return times;
    }

    public void setTimes(Integer times) {
        this.times = times;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

5.exception自定义异常

GenericException.java
package com.csii.quartz.exception;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/10 17:33
 * @description:自定义异常
 * @modified By:
 * @version: 1.0$
 */
public class GenericException extends RuntimeException{

    private static final long serialVersionUID = 1L;

    private String msg;
    private int code = 500;

    public GenericException(String msg) {
        super(msg);
        this.msg = msg;
    }

    public GenericException(String msg, Throwable e) {
        super(msg, e);
        this.msg = msg;
    }

    public GenericException(String msg, int code) {
        super(msg);
        this.msg = msg;
        this.code = code;
    }

    public GenericException(String msg, int code, Throwable e) {
        super(msg, e);
        this.msg = msg;
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }




}

 

GenericExceptionHandler.java
package com.csii.quartz.exception;

import com.csii.quartz.base.ResultDTO;
import com.csii.quartz.utils.ResultUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/10 17:47
 * @description:异常处理器
 * @modified By:
 * @version: $
 */

@RestControllerAdvice
@Slf4j
public class GenericExceptionHandler {



    /**
     * 处理自定义异常
     */
    @ExceptionHandler(GenericException.class)
    public ResultDTO handleRRException(GenericException e){
        if (e instanceof GenericException) {
            GenericException e1 = (GenericException) e;
            log.error(e1.getCode()+"");
            return ResultUtils.getResultDTO(e1.getCode(), e1.getMessage(), null);
        }
        log.error(e.getCause().getMessage());
        log.error(e.getMessage());

        return ResultUtils.getFail(null);

    }

    @ExceptionHandler(NoHandlerFoundException.class)
    public ResultDTO handlerNoFoundException(java.lang.Exception e) {
        log.error(e.getMessage(), e);
        return ResultUtils.getResultDTO(404, "路径不存在,请检查路径是否正确",null);
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public ResultDTO handleDuplicateKeyException(DuplicateKeyException e){
        log.error(e.getMessage(), e);
        return ResultUtils.getResultDTO(99,"数据库中已存在该记录",null);
    }



    @ExceptionHandler(java.lang.Exception.class)
    public ResultDTO handleException(java.lang.Exception e){
        log.error(e.getMessage(), e);
        return ResultUtils.getFail(null);
    }



}

 

6.utils工具类

ResultUtils.java 返回信息工具
package com.csii.quartz.utils;

import com.csii.quartz.base.ResultCode;
import com.csii.quartz.base.ResultDTO;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:18
 * @description:返回信息工具
 * @modified By:
 * @version: 1.0$
 */
public class ResultUtils {
    private ResultUtils() {
    }

    public static ResultDTO getSuccess(Object result) {
        return new ResultDTO(ResultCode.SUCCESS, result);
    }



    public static ResultDTO getFail(Object result) {
        return new ResultDTO(ResultCode.FAIL, result);
    }

    public static ResultDTO getParamError(Object result) {
        return new ResultDTO(ResultCode.PARAM_ERROR, result);
    }

    public static ResultDTO getResourceInvalid(Object result) {
        return new ResultDTO(ResultCode.RESOURCE_INVALID, result);
    }

    public static ResultDTO getTokenInvalid(Object result) {
        return new ResultDTO(ResultCode.TOKEN_INVALID, result);
    }

    public static ResultDTO getCustomErrordesc(String errorDesc, Object result) {
        return new ResultDTO(ResultCode.CUSTOM_ERRORDESC, errorDesc, result);
    }

    public static ResultDTO getResultDTO(int code, String errorDesc, Object result) {
        return new ResultDTO(code, errorDesc, result);
    }
}
ScheduleJobUtils.java 定时任务工具

 

package com.csii.quartz.utils;

import com.csii.quartz.base.Constant;
import com.csii.quartz.dao.ScheduleJobLogMapper;
import entities.ScheduleJob;
import entities.ScheduleJobLog;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:21
 * @description:定时任务工具
 * @modified By:
 * @version: 1.0$
 */
@Slf4j
@Component
public class ScheduleJobUtils extends QuartzJobBean {
    //返回一个线程池(这个线程池只有一个线程),这个线程
    //池可以在线程死后(或发生异常时)重新启动一个线程来替代原来的线程继续执行下去!
    private ExecutorService service = Executors.newSingleThreadExecutor();

    @Autowired
    private ScheduleJobLogMapper scheduleJobLogMapper;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        ScheduleJob scheduleJob = (ScheduleJob ) context.getMergedJobDataMap()
                .get(Constant.JOB_PARAM_KEY);

        //获取spring bean
//        ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService) SpringContextUtils.getBean("scheduleJobLogService");

        //数据库保存执行记录
        ScheduleJobLog jobLog = new ScheduleJobLog();
        jobLog.setJobId(scheduleJob.getJobId());
        jobLog.setBeanName(scheduleJob.getBeanName());
        jobLog.setMethodName(scheduleJob.getMethodName());
        jobLog.setParams(scheduleJob.getParams());
        jobLog.setCreateTime(new Date());

        //任务开始时间
        long startTime = System.currentTimeMillis();
        Byte zero = 0;

        Byte one=1;
        try {
            //执行任务
            log.info("任务准备执行,任务ID:" + scheduleJob.getJobId());
            ScheduleRunnable task = new ScheduleRunnable(scheduleJob.getBeanName(),
                    scheduleJob.getMethodName(), scheduleJob.getParams());
            Future<?> future = service.submit(task);

            future.get();

            //任务执行总时长
            long times = System.currentTimeMillis() - startTime;
            jobLog.setTimes((int)times);
            //任务状态    0:成功    1:失败
            jobLog.setStatus(zero);

            log.info("任务执行完毕,任务ID:" + scheduleJob.getJobId() + "  总共耗时:" + times + "毫秒");
        } catch (Exception e) {
            log.error("任务执行失败,任务ID:" + scheduleJob.getJobId(), e);

            //任务执行总时长
            long times = System.currentTimeMillis() - startTime;
            jobLog.setTimes((int)times);

            //任务状态    0:成功    1:失败
            jobLog.setStatus(one);
            jobLog.setError(StringUtils.substring(e.toString(), 0, 2000));
        }finally {
            scheduleJobLogMapper.insertSelective(jobLog);
        }
    }
}
ScheduleRunnable.java 执行定时任务实现
package com.csii.quartz.utils;

import java.lang.reflect.Method;

import com.csii.quartz.exception.GenericException;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.ReflectionUtils;
/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:27
 * @description:执行定时任务实现
 * @modified By:
 * @version: 1.0$
 */
public class ScheduleRunnable implements Runnable{

    private Object target;
    private Method method;
    private String params;

    public ScheduleRunnable(String beanName, String methodName, String params) throws NoSuchMethodException, SecurityException {
        this.target = SpringContextUtils.getBean(beanName);
        this.params = params;

        if(StringUtils.isNotBlank(params)){
            this.method = target.getClass().getDeclaredMethod(methodName, String.class);
        }else{
            this.method = target.getClass().getDeclaredMethod(methodName);
        }
    }

    @Override
    public void run() {
        try {
            ReflectionUtils.makeAccessible(method);
            if(StringUtils.isNotBlank(params)){
                method.invoke(target, params);
            }else{
                method.invoke(target);
            }
        }catch (java.lang.Exception e) {
            throw new GenericException("执行定时任务失败", e);
        }
    }




}
ScheduleUtils.java 定时任务工具类
package com.csii.quartz.utils;

import com.csii.quartz.base.Constant;
import com.csii.quartz.exception.GenericException;
import entities.ScheduleJob;
import org.quartz.*;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:31
 * @description:定时任务工具类
 * @modified By:
 * @version: 1.0$
 */
public class ScheduleUtils {


    private final static String JOB_NAME = "TASK_";

    /**
     * 获取触发器key
     */
    public static TriggerKey getTriggerKey(Long jobId) {
        return TriggerKey.triggerKey(JOB_NAME + jobId);
    }

    /**
     * 获取jobKey
     */
    public static JobKey getJobKey(Long jobId) {
        return JobKey.jobKey(JOB_NAME + jobId);
    }

    /**
     * 获取表达式触发器
     */
    public static CronTrigger getCronTrigger(Scheduler scheduler, Long jobId) {
        try {
            return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
        } catch (SchedulerException e) {
            throw new GenericException("获取定时任务CronTrigger出现异常", e);
        }
    }

    /**
     * 创建定时任务
     */
    public static void createScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) {
        try {
            //构建job信息
            JobDetail jobDetail = JobBuilder.newJob(ScheduleJobUtils.class).withIdentity(getJobKey(scheduleJob.getJobId())).build();

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            //按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getJobId())).withSchedule(scheduleBuilder).build();

            //放入参数,运行时的方法可以获取
            jobDetail.getJobDataMap().put(Constant.JOB_PARAM_KEY, scheduleJob);

            scheduler.scheduleJob(jobDetail, trigger);

            //暂停任务
            if(scheduleJob.getStatus() == Constant.PAUSE){
                pauseJob(scheduler, scheduleJob.getJobId());
            }
        } catch (SchedulerException e) {
            throw new GenericException("创建定时任务失败", e);
        }
    }

    /**
     * 更新定时任务
     */
    public static void updateScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) {
        try {
            TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId());

            //表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
                    .withMisfireHandlingInstructionDoNothing();

            CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId());

            //按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            //参数
            trigger.getJobDataMap().put(Constant.JOB_PARAM_KEY, scheduleJob);

            scheduler.rescheduleJob(triggerKey, trigger);

            //暂停任务
            if(scheduleJob.getStatus() == Constant.PAUSE){
                pauseJob(scheduler, scheduleJob.getJobId());
            }

        } catch (SchedulerException e) {
            throw new GenericException("更新定时任务失败", e);
        }
    }

    /**
     * 立即执行任务
     */
    public static void run(Scheduler scheduler, ScheduleJob scheduleJob) {
        try {
            //参数
            JobDataMap dataMap = new JobDataMap();
            dataMap.put(Constant.JOB_PARAM_KEY, scheduleJob);

            scheduler.triggerJob(getJobKey(scheduleJob.getJobId()), dataMap);
        } catch (SchedulerException e) {
            throw new GenericException("立即执行定时任务失败", e);
        }
    }

    /**
     * 暂停任务
     */
    public static void pauseJob(Scheduler scheduler, Long jobId) {
        try {
            scheduler.pauseJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new GenericException("暂停定时任务失败", e);
        }
    }

    /**
     * 恢复任务
     */
    public static void resumeJob(Scheduler scheduler, Long jobId) {
        try {
            scheduler.resumeJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new GenericException("恢复定时任务失败", e);
        }
    }

    /**
     * 删除定时任务
     */
    public static void deleteScheduleJob(Scheduler scheduler, Long jobId) {
        try {
            scheduler.deleteJob(getJobKey(jobId));
        } catch (SchedulerException e) {
            throw new GenericException("删除定时任务失败", e);
        }
    }



}
SpringContextUtils.java Context 工具类
package com.csii.quartz.utils;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/11 10:33
 * @description:Spring Context 工具类
 * @modified By:
 * @version: $
 */
@Component
public class SpringContextUtils implements ApplicationContextAware {


    public static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        SpringContextUtils.applicationContext = applicationContext;
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }

    public static <T> T getBean(String name, Class<T> requiredType) {
        return applicationContext.getBean(name, requiredType);
    }

    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    public static boolean isSingleton(String name) {
        return applicationContext.isSingleton(name);
    }

    public static Class<? extends Object> getType(String name) {
        return applicationContext.getType(name);
    }


}

7.base 通用、枚举定义

Constant.java 常量
package com.csii.quartz.base;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/10 17:03
 * @description:常量
 * @modified By:
 * @version: 1.0$
 */
public class Constant {
    /**
     * 任务调度参数key
     */
    public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
    /**
     * 定时任务状态
     *
     */
    /**
     * 正常
     */
    public static final int NORMAL = 0;
    /**
     * 暂停
     */
    public static final int PAUSE =1;
    /**
     * 删除
     */
    public static final int DEL =-1;
}
ResultCode.java 返回信息码
package com.csii.quartz.base;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/10 17:04
 * @description:返回信息码
 * @modified By:
 * @version: 1.0$
 */
@Getter
@AllArgsConstructor
public enum  ResultCode {

    SUCCESS(0,"操作成功"),
    FAIL(1, "操作失败,请联系管理员"),
    PARAM_ERROR(2, "参数值格式有误"),
    RESOURCE_INVALID(3, "资源无效"),
    TOKEN_INVALID(11, "授权码无效"),
    CUSTOM_ERRORDESC(99);
    private int Code;
    private String ErrorDesc;
    /**
     * 消息
     */
    private  String msg;
    ResultCode(int code, String errorDesc) {
        Code = code;
        ErrorDesc = errorDesc;
    }
    ResultCode(int code) {
        Code = code;
    }

    public int getCode() {
        return Code;
    }



    public void setCode(int code) {
        Code = code;
    }

    public String getErrorDesc() {
        return ErrorDesc;
    }

    public void setErrorDesc(String errorDesc) {
        ErrorDesc = errorDesc;
    }

}
ResultDTO.java 返回数据格式
package com.csii.quartz.base;

import java.io.Serializable;

/**
 * @author :renhuifeng
 * @date :Created in 2020/8/10 17:05
 * @description:返回数据格式
 * @modified By:
 * @version: 1.0$
 */
public class ResultDTO implements Serializable {

    private int code;

    private String msg;

    private Object data;

    private int count;
    public ResultDTO(ResultCode code, Object result) {
        this.code = code.getCode();
        this.msg = code.getErrorDesc();
        this.data = result;
    }

    public ResultDTO(ResultCode code, String errorDesc, Object result) {
        this.code = code.getCode();
        this.msg = errorDesc;
        this.data = result;
    }

    public ResultDTO(int code, String errorDesc, Object result) {
        this.code = code;
        this.msg = errorDesc;
        this.data = result;
    }
}

8.表结构

9.maven依赖 

需要表结构与maven依赖的评论留言

 

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
Spring Boot整合Quartz的配置步骤如下: 1. 添加依赖 在pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 配置Quartz 在application.properties文件中添加以下配置: ``` # Quartz配置 spring.quartz.job-store-type=jdbc spring.quartz.jdbc.initialize-schema=always spring.quartz.properties.org.quartz.scheduler.instanceName=MyScheduler spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate spring.quartz.properties.org.quartz.jobStore.dataSource=myDataSource spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ spring.quartz.properties.org.quartz.dataSource.myDataSource.driverClassName=com.mysql.jdbc.Driver spring.quartz.properties.org.quartz.dataSource.myDataSource.URL=jdbc:mysql://localhost:3306/quartz spring.quartz.properties.org.quartz.dataSource.myDataSource.username=root spring.quartz.properties.org.quartz.dataSource.myDataSource.password=root spring.quartz.properties.org.quartz.threadPool.threadCount=10 ``` 3. 创建Job 创建一个继承自QuartzJobBean的Job类,实现executeInternal方法,编写具体的业务逻辑。 ``` public class MyJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 业务逻辑 } } ``` 4. 创建Trigger 创建一个Trigger对象,指定Job的执行时间和执行频率。 ``` Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "myGroup") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(10) .repeatForever()) .build(); ``` 5. 创建Scheduler 创建一个Scheduler对象,将Job和Trigger添加到Scheduler中。 ``` Scheduler scheduler = new StdSchedulerFactory().getScheduler(); scheduler.start(); scheduler.scheduleJob(JobBuilder.newJob(MyJob.class) .withIdentity("myJob", "myGroup") .build(), trigger); ``` 以上就是Spring Boot整合Quartz的配置步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任错错

如果对您有帮助我很开心

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值