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<>();@Autowiredprivate 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: 定时任务销毁*/@Overridepublic 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;}@Overridepublic 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);}@Overridepublic 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);}@Overridepublic 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-";@Autowiredprivate CronTaskRegistrar cronTaskRegistrar;@Autowiredprivate 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);@Autowiredprivate ITbTtsJobService iTbTtsJobsService;@Autowiredprivate CronTaskRegistrar cronTaskRegistrar;/*** 项目启动后加载动态定时任务* @param args* @throws Exception*/@Overridepublic 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 {@Autowiredprivate 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);@Autowiredprivate TbTtsJobMapper tbTtsJobMapper;@Autowiredprivate CronTaskRegistrar cronTaskRegistrar;@Autowiredprivate IVehicleService iTbVehicleService;@Autowiredprivate IIssuanceSevice iIssuanceSevice;/*** @description: tts定时任务列表* @create: 2025/01/13 11:47* @param:* @return:*/@Overridepublic List<TbTtsJob> selectTtsJobList(TbTtsJob tbTtsJob) {tbTtsJob.setGroupId(getDeptId());List<TbTtsJob> tbTtsJobs = tbTtsJobMapper.selectTtsJobPageList(tbTtsJob);return tbTtsJobs;}@Overridepublic List<TbTtsJob> selectTtsJobList() {return tbTtsJobMapper.selectTtsJobList();}/*** @description: 新增定时任务* @create: 2025/01/10 14:07* @param:* @return:*/@Overridepublic 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;}@Overridepublic 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:*/@Overridepublic 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);}@Overridepublic TbTtsJob detail(Integer id) {TbTtsJob updateJob = tbTtsJobMapper.selectById(id);return updateJob;}/*** @description: 删除定时任务* @create: 2025/01/10 14:07* @param:* @return:*/@Overridepublic 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@Overridepublic 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 实现动态定时任务 简单实现 , 有需要的可以点赞 收藏哦

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IP协议特性

在网络层中&#xff0c;最重要的协议就是IP协议&#xff0c;IP协议也有几个特性&#xff0c;重要的有地址管理和路由选择。 1、地址管理 由于IPv4地址为4个字节&#xff0c;所以最多可以支持42亿个地址&#xff0c;但在现在&#xff0c;42亿明显不够用了。这就衍生出下面几个…

(DM)达梦数据库基本操作(持续更新)

1、连接达梦数据库 ./disql 用户明/"密码"IP端口或者域名 2、进入某个模式&#xff08;数据库,因达梦数据库没有库的概念&#xff0c;只有模式&#xff0c;可以将模式等同于库&#xff09; set schema 库名&#xff1b; 3、查表结构&#xff1b; SELECT COLUMN_NAM…

LabVIEW太赫兹二维扫描成像系统

使用LabVIEW设计太赫兹二维扫描成像系统。通过LabVIEW平台开发&#xff0c;结合硬件如太赫兹源、平移台、锁相放大器等&#xff0c;实现了高效、精准的成像功能。系统采用蛇形扫描方式&#xff0c;通过动态调整扫描参数&#xff0c;达到优化成像质量的目的。 ​ 项目背景 在非…

Spring 核心技术解析【纯干货版】- V:Spring 基础模块 Spring-Context 模块精讲

Spring 框架作为 Java 开发领域最流行的框架之一&#xff0c;其核心模块承载了大量企业级应用开发的基础功能。在 Spring 的核心模块中&#xff0c;Spring-Context 模块尤为重要&#xff0c;它不仅提供了应用上下文的管理功能&#xff0c;还扩展了事件驱动、国际化支持、资源加…

2025年国产化推进.NET跨平台应用框架推荐

2025年国产化推进.NET跨平台应用框架推荐 1. .NET MAUI NET MAUI是一个开源、免费&#xff08;MIT License&#xff09;的跨平台框架&#xff08;支持Android、iOS、macOS 和 Windows多平台运行&#xff09;&#xff0c;是 Xamarin.Forms 的进化版&#xff0c;从移动场景扩展到…

SQL注入漏洞之基础数据类型注入 字符 数字 搜索 XX 以及靶场实例哟

目录 基础数据类型SQL注入 字符类型注入 单引号双引号解释 案例练习: 数字类型注入 案例 搜索性注入: 案例 XX性注入: 语句 案例 基础SQL注入类型分类 基础数据类型SQL注入 字符类型注入 xxx or 11 # select id,email from member where usernamexx or 11 # --…

【ESP32】ESP32连接JY61P并通过WIFI发送给电脑

前言 手头上有个ESP32&#xff0c;发现有wifi功能&#xff0c;希望连接JY61P并通过WIFI把姿态数据发送给电脑 1.采用Arduino IDE编译器&#xff1b;需要安装ESP32的开发板管理器&#xff1b; 2.电脑接受数据是基于python的&#xff1b; 1. ESP32 连接手机WIFI #include <…

如何在data.table中处理缺失值

&#x1f4ca;&#x1f4bb;【R语言进阶】轻松搞定缺失值&#xff0c;让数据清洗更高效&#xff01; &#x1f44b; 大家好呀&#xff01;今天我要和大家分享一个超实用的R语言技巧——如何在data.table中处理缺失值&#xff0c;并且提供了一个自定义函数calculate_missing_va…

NodeJs如何做API接口单元测试? --【elpis全栈项目】

NodeJs API接口单元测试 api单元测试需要用到的 assert&#xff1a;断言库 (还要一些断言库比如:Chai)supertest&#xff1a; 模拟http请求 简单的例子&#xff1a; const express require(express); const supertest require(supertest); const assert require(assert);…

计算机视觉算法实战——无人机检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​ 1. 引言✨✨ 随着无人机技术的快速发展&#xff0c;无人机在农业、物流、监控等领域的应用越来越广泛。然而&#xff0c;无人机的滥用也带…

Node.js HTTP模块详解:创建服务器、响应请求与客户端请求

Node.js HTTP模块详解&#xff1a;创建服务器、响应请求与客户端请求 Node.js 的 http 模块是 Node.js 核心模块之一&#xff0c;它允许你创建 HTTP 服务器和客户端。以下是一些关键知识点和代码示例&#xff1a; 1. 创建 HTTP 服务器 使用 http.createServer() 方法可以创建…

华为支付接入规范

为了确保用户获得良好的支付体验&#xff0c;Payment Kit制定了相关接入设计规范&#xff0c;请开发者遵照执行&#xff0c;具体要求&#xff08;非强制性&#xff09;如下&#xff1a; 一、支付方式呈现 涉及支付公司名称&#xff0c;请统一使用&#xff1a;花瓣支付&#xff…

C语言-----扫雷游戏

扫雷游戏的功能说明 &#xff1a; • 使⽤控制台实现经典的扫雷游戏 • 游戏可以通过菜单实现继续玩或者退出游戏 • 扫雷的棋盘是9*9的格⼦ • 默认随机布置10个雷 • 可以排查雷&#xff1a; ◦ 如果位置不是雷&#xff0c;就显⽰周围有⼏个雷 ◦ 如果位置是雷&#xff0c;就…

Python人脸识别库DeepFace使用教程及源码解析

目录 一、DeepFace介绍 1、人脸库设计 2、DeepFace.find 3、DeepFace.verify 4、DeepFace.analyze 5、DeepFace.extract_faces 6、DeepFace.represent 7、DeepFace.stream 二、DeepFace二次开发 1、开发活体检测API 2、模型权重持久化 三、总结 一、DeepFace介绍 …

Java多线程的面试面试题及答案解析

什么是进程&#xff1f;什么是线程&#xff1f;有什么区别&#xff1f; 进程是系统资源分配的基本单位&#xff0c;拥有独立的地址空间。线程是 CPU 调度和分派的基本单位&#xff0c;是比进程更小的独立执行的单位&#xff0c;共享所在进程的内存空间等资源。一个进程可以包含…

三分钟简单了解一些HTML的标签和语法_02

1.a标签演示 点击然后跳转 代码加入title 2.图片链接 3.锚点链接 点击就会跳转的当前位置 4.a标签小知识补充 该实例会跳转到顶,锚点链接则会跳转到相应的锚点 5. 结果:直接跳转到该页面的锚点处 6. 在 HTML 中&#xff0c;<tr>标签表示表格中的行&#xff08;TableRow&…

多选multiple下拉框el-select回显问题(只显示后端返回id)

首先保证v-model的值对应options数据源里面的id <el-form-item prop"subclass" label"分类" ><el-select v-model"formData.subclass" multiple placeholder"请选择" clearable :disabled"!!formData.id"><e…

2025年数学建模美赛:A题分析(1)Testing Time: The Constant Wear On Stairs

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…

Qt——引用第三方SDK lib库的使用方法

【系列专栏】:博主结合工作实践输出的,解决实际问题的专栏,朋友们看过来! 《项目案例分享》 《极客DIY开源分享》 《嵌入式通用开发实战》 《C++语言开发基础总结》 《从0到1学习嵌入式Linux开发》 《QT开发实战》 《Android开发实战》 《实用硬件方案设计》 《结构建模设…

Java 反射与动态代理:实践中的应用与陷阱

Java 反射与动态代理&#xff1a;实践中的应用与陷阱 在现代Java应用中&#xff0c;反射和动态代理提供了强大的灵活性&#xff0c;但它们也带来了性能和复杂度上的挑战。本文将深入探讨这些技术在实际项目中的应用&#xff0c;分析它们可能导致的陷阱&#xff0c;并提供详细的…