SpringBoot 实现动态管理定时任务 Job的动态操作(添加、修改、启停、执行、删除)以及界面展示和具体Job的创建与执行示例

SpringBoot 实现动态管理定时任务 Job的动态操作(添加、修改、启停、执行、删除)以及界面展示和具体Job的创建与执行示例

关键接口类: CronTaskRegistrar SchedulingRunnable

. 添加定时任务注册类,用来增加、删除定时任务


import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import java.util.concurrent.ScheduledFuture;

/**
 * @description: 添加定时任务注册类,用来增加、删除定时任务。
 **/
@Component
public class CronTaskRegistrar implements DisposableBean {

    public static final Map<Runnable, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
    public static final Map<String, Runnable> runnableMap = new ConcurrentHashMap<>();

    @Autowired
    private TaskScheduler taskScheduler;

    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }

    /**
     * 新增定时任务
     * @param task
     * @param cronExpression
     */
    public  void addCronTask(Runnable task, String cronExpression) {
        addCronTask(new CronTask(task, cronExpression));
    }

    public void addCronTask(CronTask cronTask) {
        if (cronTask != null) {
            Runnable task = cronTask.getRunnable();
            if (scheduledTasks.containsKey(task)) {
                removeCronTask(task);
            }
            scheduledTasks.put(task, scheduleCronTask(cronTask));
        }
    }


    /**
     * @description: 移除定时任务
     */
    public void removeCronTask(Runnable task) {
        ScheduledFuture<?> scheduledTask = scheduledTasks.get(task);
        if (scheduledTask != null) {
            scheduledTask.cancel(true);
            scheduledTasks.remove(task);
        }
    }

    public ScheduledFuture<?> scheduleCronTask(CronTask cronTask) {
        return this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
    }

    /**
    * @description: 定时任务销毁
    */
    @Override
    public void destroy() {
        for (ScheduledFuture<?> task : scheduledTasks.values()) {
            task.cancel(true);
        }
        scheduledTasks.clear();
    }
}

4、封装和执行定时任务


import com.yicheng.common.exception.UtilException;
import com.yicheng.common.utils.SpringContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Objects;


public class SchedulingRunnable implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);

    private String runnableName;

    private String beanName;

    private String methodName;

    private Object[] params;

    public SchedulingRunnable(String beanName, String methodName) {
        this(beanName, methodName, null);
    }

    public SchedulingRunnable(String runnableName, String beanName, String methodName, Object... params) {
        this.runnableName = runnableName;
        this.beanName = beanName;
        this.methodName = methodName;
        this.params = params;
    }

    @Override
    public void run() {
        logger.info("定时任务开始执行 - bean:{},方法:{},参数:{}", beanName, methodName, params);
        long startTime = System.currentTimeMillis();
        try {
            Object target = SpringContextUtils.getBean(beanName);
            Method method = null;
            if (null != params && params.length > 0) {
                Class<?>[] paramCls = new Class[params.length];
                for (int i = 0; i < params.length; i++) {
                    paramCls[i] = params[i].getClass();
                }
                method = target.getClass().getDeclaredMethod(methodName, paramCls);
            } else {
                method = target.getClass().getDeclaredMethod(methodName);
            }

            ReflectionUtils.makeAccessible(method);
            if (null != params && params.length > 0) {
                method.invoke(target, params);
            } else {
                method.invoke(target);
            }
        } catch (Exception ex) {
            logger.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", beanName, methodName, params), ex);
            throw new UtilException(ex);
        }
        long times = System.currentTimeMillis() - startTime;
        logger.info("定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒", beanName, methodName, params, times);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        SchedulingRunnable that = (SchedulingRunnable) o;
        if (params == null) {
            return beanName.equals(that.beanName) &&
                    methodName.equals(that.methodName) &&
                    that.params == null;
        }
        return beanName.equals(that.beanName) &&
                methodName.equals(that.methodName) &&
                params.equals(that.params);
    }

    @Override
    public int hashCode() {
        if (params == null) {
            return Objects.hash(beanName, methodName);
        }
        return Objects.hash(beanName, methodName, params);
    }
}

4、防止 冲突 重新配置 TaskScheduler

@Configuration
public class SchedulerConfig {

    @Bean()
    public TaskScheduler taskScheduler() {
        return new ConcurrentTaskScheduler();
    }
}

5、任务执行业务




import com.yicheng.base.service.IVehicleService;
import com.yicheng.business.instruction.service.IIssuanceSevice;
import com.yicheng.business.ttsjob.domain.TbTtsJob;
import com.yicheng.business.ttsjob.service.ITbTtsJobService;
import com.yicheng.common.scheduler.CronTaskRegistrar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * @className: DoTask
 * @description: tts任务处理线程
 * @creat: 2025/1/10 15:05
 */
@Component("doTask")
public class DoTask {
    private static final Logger logger = LoggerFactory.getLogger(DoTask.class);
    public static final String jobNamePrefix = "ttsJob-";
    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;
    @Autowired
    private ITbTtsJobService iTbTtsJobService;

    public DoTask() {

    }

    /**
     * 任务类型,1-立即执行,2-定时一次,3-每天固定时间执行
     *
     * @param runnableName
     * @param type
     * @param jobid
     */
    public void ttsSend(String runnableName, Integer type, Long jobid) {
        logger.info("即将执行ttsTask:type={}, jobid={}", type, jobid);
        TbTtsJob tbTtsJobs = iTbTtsJobService.getById(jobid);
        if (null == tbTtsJobs) {
            try {
                logger.info("未查询到ttsTask任务:type={}, jobid={},放弃执行", type, jobid);
                cronTaskRegistrar.removeCronTask(CronTaskRegistrar.runnableMap.get(runnableName));
                CronTaskRegistrar.runnableMap.remove(runnableName);
                return;
            }catch (Exception e){
                e.printStackTrace();
                return;
            }
        }
        if (tbTtsJobs.getStatus().intValue() == 1 || tbTtsJobs.getExecStatus().intValue() == 1) {
            // 任务未开启,直接结束,且清除任务
            cronTaskRegistrar.removeCronTask(CronTaskRegistrar.runnableMap.get(runnableName));
            CronTaskRegistrar.runnableMap.remove(runnableName);
        } else {
            if (tbTtsJobs.getType() == 1 || tbTtsJobs.getType() == 2) {
                tbTtsJobs.setExecStatus(1);
                tbTtsJobs.setStatus(1);
            }
            iTbTtsJobService.processJob(tbTtsJobs);
            logger.info("ttsTask任务进入执行队列:type={}, jobid={}", type, jobid);
        }
    }

}


创建表

CREATE TABLE `tb_tts_job` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(255) DEFAULT NULL COMMENT '任务名称',
  `content` text COMMENT '文本内容',
  `cron` varchar(255) DEFAULT NULL COMMENT '定时标识',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `status` int(1) DEFAULT NULL COMMENT '状态,1-未开启,0-已开启',
  `exec_status` int(2) DEFAULT NULL COMMENT '执行状态 0-生效 1-已关闭',
  `type` int(1) DEFAULT NULL COMMENT '任务类型,1-立即执行,2-定时一次,3-每天固定时间执行',
  `do_time` datetime DEFAULT NULL COMMENT '执行时间',
  `last_do_time` datetime DEFAULT NULL COMMENT '最近执行时间',
  `index_type` varchar(1) DEFAULT NULL COMMENT '指令类型',
  `run_time` varchar(20) DEFAULT NULL COMMENT '时间',
  `run_date_time` varchar(30) DEFAULT NULL COMMENT '日期',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='tts语音定时任务';

启动项目加载定时任务

package com.yicheng.web.controller.common;

import com.yicheng.business.ttsjob.domain.TbTtsJob;
import com.yicheng.business.ttsjob.service.ITbTtsJobService;
import com.yicheng.business.ttsjob.task.DoTask;
import com.yicheng.common.scheduler.CronTaskRegistrar;
import com.yicheng.common.scheduler.SchedulingRunnable;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 项目启动后加载动态定时任务
 */
@Slf4j
@Component
public class JobsLoader implements ApplicationRunner {
    private static final Logger logger = LoggerFactory.getLogger(JobsLoader.class);
    @Autowired
    private ITbTtsJobService iTbTtsJobsService;
    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;

    /**
     * 项目启动后加载动态定时任务
     * @param args
     * @throws Exception
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        ttsTaskLoader();
    }

    /**
    * @description: 加载定时发送任务
    * @create: 2025/01/10 15:50
    * @param:
    * @return:
    */
    public void ttsTaskLoader() {
        List<TbTtsJob> tbTtsJobs = iTbTtsJobsService.selectTtsJobList();
        tbTtsJobs.forEach(ttsJob -> {
            String runnableName = DoTask.jobNamePrefix + ttsJob.getId();
            SchedulingRunnable task = new SchedulingRunnable(runnableName, "doTask", "ttsSend", runnableName, ttsJob.getType(), ttsJob.getId());
            cronTaskRegistrar.addCronTask(task, ttsJob.getCron());
            CronTaskRegistrar.runnableMap.put(runnableName, task);
        });
        logger.info("启动加载动态定时任务[Job],共{}条", tbTtsJobs.size());
    }

}

任务的新增、和移除
Controller



import com.yicheng.business.ttsjob.domain.TbTtsJob;
import com.yicheng.business.ttsjob.service.ITbTtsJobService;
import com.yicheng.common.core.page.TableDataInfo;
import com.yicheng.common.core.controller.BaseController;
import com.yicheng.common.core.domain.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.text.ParseException;
import java.util.List;

/**
 * @className: TtsJobsController
 * @description: 定时指令下发控制器
 * @creat: 2025/1/10 14:06
 */
@RestController
@RequestMapping("/business/ttsJob")
public class TtsJobsController extends BaseController {

    @Autowired
    private ITbTtsJobService iTbTtsJobsService;


    /**
    * @description: tts定时任务列表
    * @create: 2025/01/13 11:47
    * @param:
    * @return:
    */
    @GetMapping("/list")
    public TableDataInfo list(TbTtsJob ttsJobs) {
        startPage();
        List<TbTtsJob> tbTtsJobs = iTbTtsJobsService.selectTtsJobList(ttsJobs);
        return getDataTable(tbTtsJobs);
    }


    /**
     * @description: 新增定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    @ResponseBody
    @PostMapping("/addJob")
    public R<Integer> addJob(@RequestBody TbTtsJob ttsJobs) {
        try {
            return R.ok(iTbTtsJobsService.addTtsJob(ttsJobs));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @description: 新增定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    @ResponseBody
    @PostMapping("/updateJob")
    public R<Integer> updateJob(@RequestBody TbTtsJob ttsJobs) {
        try {
            return R.ok(iTbTtsJobsService.update(ttsJobs));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }



    /**
     * @description: 启停定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */

    @ResponseBody
    @PutMapping("/changeStatus")
    public R changeStatus(@RequestBody TbTtsJob ttsJobs) throws ParseException {
        return R.ok(iTbTtsJobsService.open(ttsJobs));
    }


    /**
     * @description: 定时任务详情
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    @GetMapping("/detail/{id}")
    public R<TbTtsJob> detail(@PathVariable Integer id) {
        TbTtsJob tbTtsJob= iTbTtsJobsService.detail(id);
        return R.ok(tbTtsJob);
    }


    /**
     * @description: 删除定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    @DeleteMapping("/{id}")
    public R remove(@PathVariable Integer id) {
        return R.ok(iTbTtsJobsService.remove(id));
    }
}

service

import com.baomidou.mybatisplus.extension.service.IService;
import com.yicheng.business.ttsjob.domain.TbTtsJob;
import com.yicheng.business.ttsjob.domain.vo.TtsTaskVo;
import org.springframework.scheduling.annotation.Async;

import java.util.List;


/**
 * @className: ITbTtsJobService
 * @description: tts任务表服务接口
 * @creat: 2025/1/10 15:05
 */
public interface ITbTtsJobService extends IService<TbTtsJob> {

    /**
     * @description: tts定时任务列表
     * @create: 2025/01/13 11:47
     * @param:
     * @return:
     */
    List<TbTtsJob> selectTtsJobList(TbTtsJob tbTtsJob);



    List<TbTtsJob> selectTtsJobList();

    /**
     * @description: 新增定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    int addTtsJob(TbTtsJob tbTtsJob) throws Exception ;

    /**
     * @description: 新增定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    int update(TbTtsJob tbTtsJob) throws Exception ;

    /**
     * @description: 启停定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    int open(TbTtsJob tbTtsJob);


    /**
     * @description: 定时任务详情
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    TbTtsJob detail(Integer id);

    /**
     * @description: 删除定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    int remove(Integer id);


    void processJob(TbTtsJob tbTtsJobs);

}

impl

package com.yicheng.business.ttsjob.service.impl;


import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yicheng.base.service.IVehicleService;
import com.yicheng.business.instruction.domain.vo.textIssuanceRequset;
import com.yicheng.business.instruction.service.IIssuanceSevice;
import com.yicheng.business.ttsjob.domain.TbTtsJob;
import com.yicheng.business.ttsjob.mapper.TbTtsJobMapper;
import com.yicheng.business.ttsjob.service.ITbTtsJobService;
import com.yicheng.business.ttsjob.task.DoTask;
import com.yicheng.common.annotation.DataScope;
import com.yicheng.common.scheduler.CronTaskRegistrar;
import com.yicheng.common.scheduler.SchedulingRunnable;
import com.yicheng.common.utils.DateCronUtil;
import com.yicheng.common.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static com.yicheng.common.utils.SecurityUtils.*;


/**
 * tts语音定时任务Service业务层处理
 *
 * @author yicheng
 * @date 2025-01-10
 */
@Service
public class TbTtsJobServiceImpl extends ServiceImpl<TbTtsJobMapper, TbTtsJob> implements ITbTtsJobService {

    private static final Logger logger = LoggerFactory.getLogger(TbTtsJobServiceImpl.class);

    @Autowired
    private TbTtsJobMapper tbTtsJobMapper;

    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;

    @Autowired
    private IVehicleService iTbVehicleService;

    @Autowired
    private IIssuanceSevice iIssuanceSevice;

    /**
     * @description: tts定时任务列表
     * @create: 2025/01/13 11:47
     * @param:
     * @return:
     */
    @Override
    public List<TbTtsJob> selectTtsJobList(TbTtsJob tbTtsJob) {
        tbTtsJob.setGroupId(getDeptId());
        List<TbTtsJob> tbTtsJobs = tbTtsJobMapper.selectTtsJobPageList(tbTtsJob);
        return tbTtsJobs;
    }


    @Override
    public List<TbTtsJob> selectTtsJobList() {
        return tbTtsJobMapper.selectTtsJobList();
    }

    /**
     * @description: 新增定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    @Override
    public int addTtsJob(TbTtsJob ttsJobs) throws Exception {
        SimpleDateFormat sdfDt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
     
        // 任务类型,1-立即执行,2-定时一次,3-每天固定时间执行
        // 立即执行,默认2分钟后执行
        if (ttsJobs.getType() == 1) {
            ttsJobs.setStatus(0);
            ttsJobs.setExecStatus(0);
            Calendar beforeTime = Calendar.getInstance();
            // 30秒之后的时间
            beforeTime.add(Calendar.SECOND, 30);
            Date date = beforeTime.getTime();
            String cron = DateCronUtil.getCron(date);
            // spring task cron不支持年
            int index = cron.lastIndexOf(" ");
            cron = cron.substring(0, index);
            ttsJobs.setCron(cron);
            ttsJobs.setDoTime(date);
        } else if (ttsJobs.getType() == 2) {
            ttsJobs.setStatus(0);
            ttsJobs.setExecStatus(0);
            String oneceTime = ttsJobs.getRunDateTime();
            Date date = sdfDt.parse(oneceTime);
            String cron = DateCronUtil.getCron(date);
            // spring task cron不支持年
            int index = cron.lastIndexOf(" ");
            cron = cron.substring(0, index);
            ttsJobs.setCron(cron);
            ttsJobs.setDoTime(date);
        } else {
            ttsJobs.setStatus(0);
            ttsJobs.setExecStatus(0);
            String everyDayTime = ttsJobs.getRunTime();
            String timeStr = sdf.format(new Date()) + " " + everyDayTime;
            Date date = sdfDt.parse(timeStr);
            String cronTmp = DateCronUtil.getCron(date);
            String[] cronTmpArr = cronTmp.split(" ");
            String cron = cronTmpArr[0] + " " + cronTmpArr[1] + " " + cronTmpArr[2] + " * * ? *";
            // spring task cron不支持年
            int index = cron.lastIndexOf(" ");
            cron = cron.substring(0, index);
            ttsJobs.setCron(cron);
            ttsJobs.setRunTime(timeStr);
        }
        int result =tbTtsJobMapper.insert(ttsJobs);
        String runnableName = DoTask.jobNamePrefix + ttsJobs.getId();
        SchedulingRunnable task = new SchedulingRunnable(runnableName, "doTask", "ttsSend", runnableName, ttsJobs.getType(), ttsJobs.getId());
        cronTaskRegistrar.addCronTask(task, ttsJobs.getCron());
        CronTaskRegistrar.runnableMap.put(runnableName, task);
        logger.info("AddCronTask is OK!");
        return result;
    }

    @Override
    public int update(TbTtsJob ttsJobs) throws Exception {
        SimpleDateFormat sdfDt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 任务类型,1-立即执行,2-定时一次,3-每天固定时间执行
        // 立即执行,默认2分钟后执行
        if (ttsJobs.getType() == 1) {
            ttsJobs.setExecStatus(0);
            Calendar beforeTime = Calendar.getInstance();
            // 30秒之后的时间
            beforeTime.add(Calendar.SECOND, 30);
            Date date = beforeTime.getTime();
            String cron = DateCronUtil.getCron(date);
            // spring task cron不支持年
            int index = cron.lastIndexOf(" ");
            cron = cron.substring(0, index);
            ttsJobs.setCron(cron);
            ttsJobs.setDoTime(date);
        } else if (ttsJobs.getType() == 2) {
            ttsJobs.setExecStatus(0);
            String oneceTime = ttsJobs.getRunDateTime();
            Date date = sdfDt.parse(oneceTime);
            String cron = DateCronUtil.getCron(date);
            // spring task cron不支持年
            int index = cron.lastIndexOf(" ");
            cron = cron.substring(0, index);
            ttsJobs.setCron(cron);
            ttsJobs.setDoTime(date);
        } else {
            ttsJobs.setExecStatus(0);
            String everyDayTime = ttsJobs.getRunTime();
            String timeStr = sdf.format(new Date()) + " " + everyDayTime;
            Date date = sdfDt.parse(timeStr);
            String cronTmp = DateCronUtil.getCron(date);
            String[] cronTmpArr = cronTmp.split(" ");
            String cron = cronTmpArr[0] + " " + cronTmpArr[1] + " " + cronTmpArr[2] + " * * ? *";
            // spring task cron不支持年
            int index = cron.lastIndexOf(" ");
            cron = cron.substring(0, index);
            ttsJobs.setCron(cron);
            ttsJobs.setRunTime(timeStr);
        }
        if(ttsJobs.getStatus() == 0){
            String runnableName_del = DoTask.jobNamePrefix + ttsJobs.getId();
            cronTaskRegistrar.removeCronTask(CronTaskRegistrar.runnableMap.get(runnableName_del));
            CronTaskRegistrar.runnableMap.remove(runnableName_del);

            String runnableName = DoTask.jobNamePrefix + ttsJobs.getId();
            SchedulingRunnable task = new SchedulingRunnable(runnableName, "doTask", "ttsSend", runnableName, ttsJobs.getType(), ttsJobs.getId());
            cronTaskRegistrar.addCronTask(task, ttsJobs.getCron());
            CronTaskRegistrar.runnableMap.put(runnableName, task);
        }
        ttsJobs.setLastDoTime(null);
        int result =tbTtsJobMapper.updateById(ttsJobs);
        return result;
    }

    /**
     * @description: 启停定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    @Override
    public int open(TbTtsJob tbTtsJob) {
        TbTtsJob updateJob = tbTtsJobMapper.selectById(tbTtsJob.getId());
        try {
            if (tbTtsJob.getStatus().intValue() == 0) {
                String runnableName = DoTask.jobNamePrefix + updateJob.getId();
                SchedulingRunnable task = new SchedulingRunnable(runnableName, "doTask", "ttsSend", runnableName, updateJob.getType(), updateJob.getId());
                cronTaskRegistrar.addCronTask(task, updateJob.getCron());
                CronTaskRegistrar.runnableMap.put(runnableName, task);
            } else {
                String runnableName = DoTask.jobNamePrefix + updateJob.getId();
                cronTaskRegistrar.removeCronTask(CronTaskRegistrar.runnableMap.get(runnableName));
                CronTaskRegistrar.runnableMap.remove(runnableName);
            }
        }catch (Exception e) {
            logger.error("open error:{}", e);
        }
        updateJob.setStatus(tbTtsJob.getStatus());
        return tbTtsJobMapper.updateById(updateJob);
    }

    @Override
    public TbTtsJob detail(Integer id) {
        TbTtsJob updateJob = tbTtsJobMapper.selectById(id);
        return updateJob;
    }

    /**
     * @description: 删除定时任务
     * @create: 2025/01/10 14:07
     * @param:
     * @return:
     */
    @Override
    public int remove(Integer id) {
        try {
            TbTtsJob tbTtsJob = tbTtsJobMapper.selectById(id);
            String runnableName = DoTask.jobNamePrefix + tbTtsJob.getId();
            cronTaskRegistrar.removeCronTask(CronTaskRegistrar.runnableMap.get(runnableName));
            CronTaskRegistrar.runnableMap.remove(runnableName);
        }catch (Exception e){
            e.printStackTrace();
        }
        return tbTtsJobMapper.deleteById(id);
    }


    @Async
    @Override
    public void processJob(TbTtsJob tbTtsJobs) {
        String groupIdsString = tbTtsJobs.getGroupIds();
        Set<Long> groupIds = Arrays.stream(groupIdsString.split(","))
                .map(String::trim)
                .map(Long::parseLong)
                .collect(Collectors.toSet());
        List<String> commNos = iTbVehicleService.getCommNos(groupIds, tbTtsJobs.getVehicleType());
        textIssuanceRequset textRequset = new textIssuanceRequset();
        textRequset.setSendType(2);
        textRequset.setPhoneNo(commNos.stream().collect(Collectors.joining(",")));
        textRequset.setContent(tbTtsJobs.getContent());
        textRequset.setMessageType(Arrays.asList(3));
        tbTtsJobs.setLastDoTime(DateUtils.getNowDate());
        tbTtsJobMapper.updateById(tbTtsJobs);
        iIssuanceSevice.sendTextByTaskJob(textRequset);
        logger.info("Processing task is OK!");
    }
}

根据日期生成cron

package com.yicheng.common.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;


/**
 * @className: DateCronUtil
 * @description: 日期与cron表达式 转换工具类
 * @author: zhuYaqiang
 * @creat: 2025/1/10 14:06
 */
public class DateCronUtil {

    /**
     * 日期转化为cron表达式
     * @param date
     * @return
     */
    public static String getCron(Date  date){
        String dateFormat="ss mm HH dd MM ? yyyy";
        return  DateCronUtil.fmtDateToStr(date, dateFormat);
    }

    /**
     * cron表达式转为日期
     * @param cron
     * @return
     */
    public static Date getCronToDate(String cron) {
        String dateFormat="ss mm HH dd MM ? yyyy";
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        Date date = null;
        try {
            date = sdf.parse(cron);
        } catch (ParseException e) {
            return null;
        }
        return date;
    }

    /**
     * Description:格式化日期,String字符串转化为Date
     *
     * @param date
     * @param dtFormat
     *            例如:yyyy-MM-dd HH:mm:ss yyyyMMdd
     * @return
     */
    public static String fmtDateToStr(Date date, String dtFormat) {
        if (date == null) {
            return "";
        }
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat(dtFormat);
            return dateFormat.format(date);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }
}

前端页面截图
在这里插入图片描述

在这里插入图片描述

至此:springboot +scheduler+cron 实现动态定时任务 简单实现 , 有需要的可以点赞 收藏哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/958477.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LLMs的星辰大海:大语言模型的前世今生

文章目录 一. LLM 的演进&#xff1a;从规则到智能的跃迁 &#x1f4ab;1.1 语言模型的蹒跚起步 &#x1f476;1.2 RNN 与 LSTM&#xff1a;序列建模的尝试 &#x1f9d0;1.3 Transformer 的横空出世&#xff1a;自注意力机制的革命 &#x1f4a5;1.4 LLM &#xff1a;从预测到…

路由器旁挂三层网络实现SDWAN互联(爱快SD-WAN)

近期因公司新办公区建设&#xff0c;原有的爱快路由器的SDWAN功能实现分支之间互联的服务还需要继续使用。在原有的小型网络中&#xff0c;使用的爱快路由器当作网关设备&#xff0c;所以使用较为简单,如下图所示。 现变更网络拓扑为三层网络架构&#xff0c;但原有的SDWAN分支…

flutter_学习记录_00_环境搭建

1.参考文档 Mac端Flutter的环境配置看这一篇就够了 flutter的中文官方文档 2. 本人环境搭建的背景 本人的电脑的是Mac的&#xff0c;iOS开发&#xff0c;所以iOS开发环境本身是可用的&#xff1b;外加Mac电脑本身就会配置Java的环境。所以&#xff0c;后面剩下的就是&#x…

15_业务系统基类

创建脚本 SystemRoot.cs 因为 业务系统基类的子类 会涉及资源加载服务层ResSvc.cs 和 音乐播放服务层AudioSvc.cs 所以在业务系统基类 提取引用资源加载服务层ResSvc.cs 和 音乐播放服务层AudioSvc.cs 并调用单例初始化 using UnityEngine; // 功能 : 业务系统基类 public c…

docker 安装 redis 详解

在平常的开发工作中&#xff0c;我们经常会用到 redis&#xff0c;那么 docker 下应该如何安装 redis 呢&#xff1f;简单来说&#xff1a;第一步&#xff1a;拉取redis镜像&#xff1b;第二步&#xff1a;设置 redis.conf 配置文件&#xff1b;第三步&#xff1a;编写 docker-…

困境如雾路难寻,心若清明步自轻---2024年创作回顾

文章目录 前言博客创作回顾第一次被催更第一次获得证书周榜几篇博客互动最多的最满意的引发思考的 写博契机 碎碎念时也运也部分经验 尾 前言 今年三月份&#xff0c;我已写下一篇《近一年多个人总结》&#xff0c;当时还没开始写博客。四月份写博后&#xff0c;就顺手将那篇总…

综合与时序分析的设计约束(1)——静态时序分析简介

目录 1.绪论2.静态时序分析与动态时序分析3.时序约束在静态时序分析中的作用3.1.约束作为声明3.2. 约束作为断言3.3.约束作为指令3.4.约束作为异常3.5.约束的角色变化 4.STA需要正确约束5.时序路径起点和终点6.建立与保持6.1 建立时间6.2 保持时间6.3 裕度 7.SDC主要类型7.1 时…

【算法日记】从零开始认识动态规划(一)

挫折会来也会过去&#xff0c; 热泪会流下也会收起&#xff0c; 没有什么可以让我气馁的&#xff0c; 因为&#xff0c;我有着长长的一生。 --- 席慕蓉 《写给幸福》--- 从零开始认识动态规划 1 动态规划问题1.1 什么是动态规划算法1.2 动态规划算法如何Debug1.3 动态规划…

八股学习 微服务篇

微服务篇 常见面试内容Spring Cloud 常见组件注册中心Ribbon负载均衡策略服务雪崩 常见面试内容 Spring Cloud 常见组件 Spring Cloud有5个常见组件&#xff1a; Eureka/Nacos:注册中心&#xff1b;Ribbon:负载均衡&#xff1b;Feign:远程调用&#xff1b;Hystrix/Sentinel:服…

【矢量数据】2024年最新中国省市县乡四级矢量地图数据 [推广有奖]

中国四级矢量地图数据是当前地理信息系统&#xff08;GIS&#xff09;中广泛应用的重要资源&#xff0c;涉及国家级、省级、市级、县级及乡级行政区的空间信息。这些数据可应用于地图绘制、城市规划、政府决策及各类地理分析等领域 一、中国四级矢量地图数据的介绍 本分享数据…

力扣707题(2)——设计链表

#题目 #3,5和6的代码 今天看剩下几个题的代码&#xff0c;1,2,4的代码已经在上篇博客写过了想看的小伙伴移步到&#xff1a; 力扣707题——设计链表-CSDN博客 //第3题头插法 void addAtHead(int val){ //记录头结点ListNode nhead; //新节点的创建,并让它指向原本头结点的后…

JavaWeb 学习笔记 XML 和 Json 篇 | 020

今日推荐语 愿你遇见好天气,愿你的征途铺满了星星——圣埃克苏佩里 日期 学习内容 打卡编号2025年01月23日JavaWeb笔记 XML 和 Json 篇020 前言 哈喽&#xff0c;我是菜鸟阿康。 以下是我的学习笔记&#xff0c;既做打卡也做分享&#xff0c;希望对你也有所帮助…

c#实现当捕获异常时自动重启程序

首先&#xff0c;需要说明这并不是一个推荐的做法&#xff0c;只有在你确实有这样的需求时才考虑这么做。 以下是AI的回答&#xff0c;为什么不推荐这么做&#xff0c;供参考。 在C#中&#xff0c;如果你在catch语句中尝试重启程序自身&#xff0c;可能会遇到以下几个问题&…

Spring WebSocket 与 STOMP 协议结合实现私聊私信功能

目录 后端pom.xmlConfig配置类Controller类DTO 前端安装相关依赖websocketService.js接口javascripthtmlCSS 效果展示简单测试连接&#xff1a; 报错解决方法1、vue3 使用SockJS报错 ReferenceError: global is not defined 功能补充拓展1. 安全性和身份验证2. 异常处理3. 消息…

uniapp+Vue3(<script setup lang=“ts“>)模拟12306城市左右切换动画效果

效果图&#xff1a; 代码&#xff1a; <template><view class"container"><view class"left" :class"{ sliding: isSliding }" animationend"resetSliding">{{ placeA }}</view><view class"center…

缓存之美:万文详解 Caffeine 实现原理(下)

上篇文章&#xff1a;缓存之美&#xff1a;万文详解 Caffeine 实现原理&#xff08;上&#xff09; getIfPresent 现在我们对 put 方法有了基本了解&#xff0c;现在我们继续深入 getIfPresent 方法&#xff1a; public class TestReadSourceCode {Testpublic void doRead() …

Spring Security(maven项目) 3.0.2.6版本—总

通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往复以至无穷&#xf…

C++函数——fill

在C中&#xff0c;std::fill 是标准库提供的一个算法适用于几乎所有类型的容器&#xff0c;只要这些容器支持迭代器操作。具体来说&#xff0c;std::fill 的适用性取决于容器是否提供了满足其要求的迭代器类型&#xff0c;用于将指定范围内的所有元素设置为某个特定值。它是一个…

jmeter中对接口进行循环请求后获取相应数据

1、工作中遇到一个场景就是对某个单一接口进行循环请求&#xff0c;并需要获取每次请求后返回的相应数据&#xff1b; 2、首先就在jmeter对接口相关组件进行配置&#xff0c;需要组件有&#xff1a;循环控制器、CSV数据文件设置、计数器、访问接口、HTTP信息头管理器、正则表达…

豆包MarsCode 蛇年编程大作战 | 高效开发“蛇年运势预测系统”

&#x1f31f; 嗨&#xff0c;我是LucianaiB&#xff01; &#x1f30d; 总有人间一两风&#xff0c;填我十万八千梦。 &#x1f680; 路漫漫其修远兮&#xff0c;吾将上下而求索。 豆包MarsCode 蛇年编程大作战 | &#x1f40d; 蛇年运势预测 在线体验地址&#xff1a;蛇年…