使用的Pom文件

<!--quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
        </dependency>
        <!--定时任务需要依赖context模块-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

创建job和joblog数据库

 拷贝ruoyi job和joblog对应的Mapper

拷贝ruoyi里面的Util和Service

 按格式写任务类

 Controller类

package com.java.core.web.contrller.job;

import com.java.core.com.annotation.Log;
import com.java.core.com.constant.Constants;
import com.java.core.com.enums.BusinessType;
import com.java.core.com.exception.job.TaskException;
import com.java.core.com.page.TableDataInfo;
import com.java.core.com.utils.StringUtils;
import com.java.core.com.vo.HttpResult;
import com.java.core.entity.master.SysJob;
import com.java.core.quartz.util.CronUtils;
import com.java.core.quartz.util.ScheduleUtils;
import com.java.core.quartz.service.SysJobService;
import com.java.core.web.contrller.common.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.quartz.SchedulerException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.List;

/**
 * 调度任务信息操作处理
 *
 */
@Api(tags = {"调度任务"})
@RestController
@RequestMapping("job")
public class SysJobController extends BaseController {


    @Resource
    private SysJobService jobService;

    @ApiOperation(value = "获取任务列表")
    @Log(title = "调度任务", businessType = BusinessType.GET)
    @PreAuthorize("hasAuthority('sys:job:get')")
    @GetMapping(value = "/getList")
    public HttpResult getList(@RequestBody SysJob job){
        this.startPage();
        List<SysJob> list = jobService.selectJobList(job);
        TableDataInfo dataInfo = this.getDataTable(list);
        return HttpResult.ok(dataInfo.getRows(),dataInfo.getTotal());
    }

    @ApiOperation(value = "批量删除")
    @Log(title = "调度任务", businessType = BusinessType.DELETE)
    @PreAuthorize("hasAuthority('sys:job:delete')")
    @PostMapping(value = "/del")
    public HttpResult del(String ids) throws SchedulerException {
        jobService.deleteJobByIds(ids);
        return HttpResult.ok("删除成功");
    }
    @ApiOperation(value = "任务调度状态修改")
    @Log(title = "调度任务", businessType = BusinessType.UPDATE)
    @PreAuthorize("hasAuthority('sys:job:update')")
    @PostMapping(value = "/changeStatus")
    public HttpResult changeStatus(@RequestBody SysJob job) throws SchedulerException {
        SysJob newJob = jobService.selectJobById(job.getJobId());
        newJob.setStatus(job.getStatus());
        jobService.changeStatus(newJob);
        return HttpResult.ok("修改成功");
    }
    @ApiOperation(value = "任务调度立即执行一次")
    @Log(title = "调度任务", businessType = BusinessType.UPDATE)
    @PreAuthorize("hasAuthority('sys:job:update')")
    @PostMapping(value = "/run")
    public HttpResult run(@RequestBody SysJob job) throws SchedulerException {
        jobService.run(job);
        return HttpResult.ok("执行成功");
    }

    @ApiOperation(value = "新增保存调度")
    @Log(title = "调度任务", businessType = BusinessType.INSERT)
    @PreAuthorize("hasAuthority('sys:job:insert')")
    @PostMapping(value = "/insert")
    public HttpResult insert(@RequestBody SysJob job) throws TaskException, SchedulerException {
        if (!CronUtils.isValid(job.getCronExpression()))
        {
            return HttpResult.error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
        }
        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
        {
            return HttpResult.error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
        {
            return HttpResult.error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
        {
            return HttpResult.error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
        {
            return HttpResult.error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
        }
        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
        {
            return HttpResult.error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
        }
        job.setCreate_by((getUserId()));
        jobService.insertJob(job);
        return HttpResult.ok("操作成功");
    }
    @ApiOperation(value = "修改保存调度")
    @Log(title = "调度任务", businessType = BusinessType.UPDATE)
    @PreAuthorize("hasAuthority('sys:job:update')")
    @PostMapping(value = "/edit")
    public HttpResult edit(@RequestBody SysJob job) throws TaskException, SchedulerException {

        if (!CronUtils.isValid(job.getCronExpression()))
        {
            return HttpResult.error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
        }
        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
        {
            return HttpResult.error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
        {
            return HttpResult.error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
        {
            return HttpResult.error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
        }
        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
        {
            return HttpResult.error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
        }
        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
        {
            return HttpResult.error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
        }
        jobService.updateJob(job);
        return HttpResult.ok("操作成功");
    }

    @ApiOperation(value = "查询cron表达式近5次的执行时间")
    @Log(title = "调度任务", businessType = BusinessType.GET)
    @PreAuthorize("hasAuthority('sys:job:get')")
    @GetMapping(value = "/queryCronExpression")
    public HttpResult queryCronExpression(String cronExpression){
        if (jobService.checkCronExpressionIsValid(cronExpression))
        {
            List<String> dateList = CronUtils.getRecentTriggerTime(cronExpression);
            return HttpResult.ok(dateList);
        }
        else
        {
            return HttpResult.error("表达式无效");
        }
    }

}

项目启动后,内存版本就行可以运行了

Job日志记录类捕捉的地方

配置一个任务可以并发和不并发的类

/**
 * 定时任务处理(禁止并发执行)
 *
 *
 */
@DisallowConcurrentExecution
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
{
    @Override
    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
    {
        JobInvokeUtil.invokeMethod(sysJob);
    }
}
/**
 * 定时任务处理(允许并发执行)
 *
 *
 */
public class QuartzJobExecution extends AbstractQuartzJob
{
    @Override
    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
    {
        JobInvokeUtil.invokeMethod(sysJob);
    }
}

在创建任务的时候,动态创建这个任务是可并发任务还是不可并发任务

/**
     * 得到quartz任务类
     *
     * @param sysJob 执行计划
     * @return 具体执行任务类
     */
    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob)
    {
        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
    }

如果想把JOB存在数据数据库,则写个下面的类

package com.java.core.quartz.config;


import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.util.Properties;

/**
 * 定时任务配置(单机部署建议默认走内存,如需集群需要创建qrtz数据库表/打开类注释)
 *
 */
@Configuration
public class ScheduleConfig
{
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(@Qualifier("masterXADataSource") DataSource dataSource)
    {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);

        // quartz参数
        Properties prop = new Properties();
        prop.put("org.quartz.scheduler.instanceName", "DefaultQuartzScheduler");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        // 线程池配置
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "20");
        prop.put("org.quartz.threadPool.threadPriority", "5");
        // 存储方式使用JobStoreTX,也就是数据库
        prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
        // 集群配置
        prop.put("org.quartz.jobStore.isClustered", "true");
        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");

        // sqlserver 启用
        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
        factory.setQuartzProperties(prop);

        factory.setSchedulerName("QuartzScheduler");
        // 延时启动
        factory.setStartupDelay(1);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        // 可选,QuartzScheduler
        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
        factory.setOverwriteExistingJobs(true);
        // 设置自动启动,默认为true
        factory.setAutoStartup(true);

        return factory;
    }
}
masterXADataSource 的配置

 

 

 

Logo

快速构建 Web 应用程序

更多推荐