SpringBoot Quartz 定时服务
创始人
2025-05-30 19:12:53
0

开发环境: IDEA 2022.1.4+ MSSQL

                SpringBoot+Mybatis+Quartz

还在搞整application.yml集成Mybatis设置以及SQL查询,暂未找到满意资料,代码候补。

代码地址: 候补

目录

1. 概述

2. 依赖及设置

        2.1 Quartz表

        2.2 MSSQL单独建表

        2.3 Maven添加Quartz依赖

        2.4 Application.yml配置数据源、Quartz设置

3. 代码实现

        3.1 定义定时任务类参数QuartzJob

        3.2 定义带参任务类SysmJob

        3.3 定义任务接口IQuartzJobService

        3.4 定义任务接口QuartzJobServiceImpl

        3.5 定义空值类QuartzJobController

4. 使用POSTMAN测试

        4.1 新增-启动

         4.2 更新-启动

 5. 结语


1. 概述

        在项目开发中,服务后台经常用到定时服务处理数据,像前段时间做的涉医实名就诊接口,就需要定时上传数据,在当前学习SpringBoot的基础上,在网上了解下解决方案,觉得Quartz不错,就想搞一搞,在网上找到了某位大佬的源码(SpringBoot+Mybatis-Plus+Quartz),我本地使用的是Mybatis,不大想用Mybatis-Plus,就得借鉴下大佬源码进行学习。

        涉及定时任务,肯定有相关的接口参数,这类参数,就可以通过Quartz进行参数传递。最终效果如下:

          

        本文对主要实现进行简单说明:

2. 依赖及设置

        2.1 Quartz表

        Quartz带有自己的表结构,这个在网上有很多,可以在网上直接查找,表的结构说明也可以在网上查找。我本地使用MSSQL,就修改了下脚本,在MSSQL里执行。效果如下:

        

        2.2 MSSQL单独建表

        方便操作测试,就在MSSQL单独建表来存储定时任务信息。

SET ANSI_NULLS ON
GOSET QUOTED_IDENTIFIER ON
GOSET ANSI_PADDING ON
GOCREATE TABLE [dbo].[TB_QUARTZ_JOB]([id] [int] IDENTITY(1,1) NOT NULL,[createby] [varchar](32) NOT NULL,[createtime] [datetime] NOT NULL,[jobclassname] [varchar](255) NOT NULL,[cronexpression] [varchar](255) NOT NULL,[parameter] [varchar](255) NULL,[description] [varchar](255) NOT NULL,CONSTRAINT [PK_TB_QUARTZ_JOB] PRIMARY KEY CLUSTERED 
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]GOSET ANSI_PADDING OFF
GO

        2.3 Maven添加Quartz依赖

        org.springframework.bootspring-boot-starter-quartz2.6.5

        2.4 Application.yml配置数据源、Quartz设置

        quartz的job-store-type设置为jdbc,设置这个后,就需要设置数据源datasource, 定时任务的设置才能保存到Quartz表中。

        关于org.quartz.jonstore.class的设置有区别,spring 2.5.x之前是另一个设置,我当前是spring 2.6.5,就设置的这个。

spring:# quartz定时任务配置quartz:# 数据库存储方式job-store-type: jdbcorg:quartz:jobStore:class: org.springframework.scheduling.quartz.LocalDataSourceJobStore#配置数据源datasource:url: jdbc:sqlserver://127.0.0.1:1433;SelectMethod=cursor;databaseName=EFMISusername: sapassword: 123qwe,.driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver

3. 代码实现

        主要的类说明如下如箭头所示:

               

        3.1 定义定时任务类参数QuartzJob

        其实Quartz是带有基础表的,如果直接去查那些表,感觉有点麻烦。就直接新建一个表(2.2 MSSQL单独建表)来存储如下类信息。

        主要说明:

        1. jobclassname 是任务的全路径,比如"com.ceaning.crudp.quartz.SysmJob"(见上图结构)

        2. parameter参数,我想着使用json格式来存储,毕竟一个接口对应的参数是比较多的。

/*** 服务后端定时任务类*/
@Data
public class QuartzJob {/*** id 自增*/private int id;/*** 任务类名(当主键用)*/private String jobclassname;/*** 创建人*/private String createby;/*** corn表达式*/private String cronexpression;/*** 任务参数*/private String parameter;/*** 任务描述*/private String description;/*** 创建时间*/@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date createtime;}

        3.2 定义带参任务类SysmJob

        此时方便看效果,任务里直接打印当前接口参数(json)。

@Slf4j
@DisallowConcurrentExecution//定义不能同时并发执行相同的JobDetail
public class SysmJob implements Job {@Autowiredprivate IQuartzJobService service;/*** 创建任务时候设置的json参数*/private String parameter;public void setParameter(String parameter) {this.parameter = parameter;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println(CommonConstant.FMR_DATE_19.format(new Date())+ parameter);if (1==1){return;}}}

        3.3 定义任务接口IQuartzJobService

        接口还是按大佬的想法来整,新增-启动、更新-启动、删除-停止。我在整理Quartz接口时候,我发现有好些接口,比如 resume***、pause***等。 我就不想整的太复杂了, 简单点好。

public interface IQuartzJobService {/*** 新增并启动* @param quartzJob* @return*/boolean addAndScheduleJob(QuartzJob quartzJob);/*** 更新并启动* @param quartzJob* @return*/boolean updateAndScheduleJob(QuartzJob quartzJob) throws SchedulerException;/*** 删除并停止* @param quartzJob* @return*/boolean deleteAndStopJob(QuartzJob quartzJob) throws SchedulerException;
}

        3.4 定义任务接口QuartzJobServiceImpl

        这里要注意的是,schedulerAdd方法中,一句" usingJobData("parameter", parameter) ", 这个参数名必须和类SysmJob的属性parameter一样。如果不想把参数整合成一个json集合,就可以使用usingJonData进行多次加入,感觉有点麻烦了,一次性加入好点。

@Slf4j
@Service
public class QuartzJobServiceImpl implements IQuartzJobService {@Autowiredprivate Scheduler scheduler;/*** 根据任务类别获取类* @param jobclassname* @return* @throws Exception*/private static Job getClass(String jobclassname) throws Exception{Class cls= Class.forName(jobclassname);return (Job)cls.newInstance();}/*** 调度器中新增任务* @param jobclassname* @param cronexpression* @param parameter*/private boolean schedulerAdd(String jobclassname, String cronexpression, String parameter){boolean bRet= false;try{scheduler.start();JobDetail detail= JobBuilder.newJob(getClass(jobclassname).getClass()).withIdentity(jobclassname).usingJobData("parameter", parameter).build();CronScheduleBuilder scheduleBuilder= CronScheduleBuilder.cronSchedule(cronexpression);CronTrigger trigger= TriggerBuilder.newTrigger().withIdentity(jobclassname).withSchedule(scheduleBuilder).build();scheduler.scheduleJob(detail,trigger);bRet= true;} catch (SchedulerException e){e.printStackTrace();} catch (RuntimeException e){e.printStackTrace();} catch (Exception e){e.printStackTrace();}return bRet;}/*** 从调度器中删除任务* @param jobclassname*/private boolean schedulerDelete(String jobclassname){boolean bRet= false;try{scheduler.pauseTrigger(TriggerKey.triggerKey(jobclassname));scheduler.unscheduleJob(TriggerKey.triggerKey(jobclassname));scheduler.deleteJob(JobKey.jobKey(jobclassname));bRet= true;}catch (Exception e){log.error(e.getMessage(), e);}return bRet;}/*** 保存&启动定时任务* @param quartzJob* @return*/@Overridepublic boolean addAndScheduleJob(QuartzJob quartzJob) {boolean bRet= false;this.schedulerAdd(quartzJob.getJobclassname().trim(), quartzJob.getCronexpression().trim(), quartzJob.getParameter().trim());bRet= true;return bRet;}/*** 编辑&启动定时任务* @param quartzJob* @return*/@Overridepublic boolean updateAndScheduleJob(QuartzJob quartzJob) throws SchedulerException{boolean bRet= false;schedulerDelete(quartzJob.getJobclassname());bRet= schedulerAdd(quartzJob.getJobclassname().trim(), quartzJob.getCronexpression().trim(), quartzJob.getParameter());return bRet;}/*** 删除&停止定时任务* @param quartzJob* @return*/@Overridepublic boolean deleteAndStopJob(QuartzJob quartzJob) {return schedulerDelete(quartzJob.getJobclassname().trim());}}

        3.5 定义空值类QuartzJobController

@Slf4j
@RestController
@RequestMapping("/api")
public class QuartzJobController {@Autowiredprivate QuartzJobServiceImpl service;private boolean crud(SysEnum.crudopr opr, QuartzJob quartzJob){boolean bRet= false;int iRet= 0;SqlSession sqlSession= null;try{sqlSession= MybatisUtils.getSqlSession();QuartzJobMapper mapper= sqlSession.getMapper(QuartzJobMapper.class);switch (opr){case insert:iRet= mapper.add(quartzJob);break;case update:iRet= mapper.update(quartzJob);break;case delete:iRet= mapper.delete(quartzJob);break;default:iRet= 0;}if (iRet>0){sqlSession.commit();bRet= true;} else{sqlSession.rollback();}} catch (Exception e){e.printStackTrace();} finally {if (sqlSession!= null){sqlSession.close();}}return bRet;}@GetMapping("/task/getList")public Result getJobList(){Map> map= new HashMap>();List list= new ArrayList();SqlSession sqlSession= null;try{sqlSession= MybatisUtils.getSqlSession();QuartzJobMapper mapper= sqlSession.getMapper(QuartzJobMapper.class);list= mapper.getList();map.put("data", list);return Result.ok(map);} catch (Exception e){e.printStackTrace();} finally {if (sqlSession!= null){sqlSession.close();}}return Result.error(CommonConstant.SC_INTERNAL_SERVER_ERROR_500,"操作失败!");}@GetMapping("/task/findById")public QuartzJob findById(int id){QuartzJob quartzJob= null;SqlSession sqlSession= null;try{sqlSession= MybatisUtils.getSqlSession();QuartzJobMapper mapper= sqlSession.getMapper(QuartzJobMapper.class);quartzJob= mapper.findById(id);} catch (Exception e){e.printStackTrace();} finally {if (sqlSession!= null){sqlSession.close();}}return quartzJob;}@PostMapping("/task/addAndScheduleJob")public Result addAndScheduleJob(@RequestBody QuartzJob quartzJob){boolean bRet= service.addAndScheduleJob(quartzJob);if (bRet) {bRet= crud(SysEnum.crudopr.insert, quartzJob);if (bRet) {return Result.ok(quartzJob);} else {if (crud(SysEnum.crudopr.delete,quartzJob)){return Result.error("[addJob].[addAndScheduleJob]操作失败!");} else {return Result.error("[addJob].[addAndScheduleJob].[crud]操作失败!");}}} else {return Result.error("[addJob].[crud]操作失败!");}}@PostMapping("/task/updateAndScheduleJob")public Result updateAndScheduleJob(@RequestBody QuartzJob quartzJob) throws SchedulerException{boolean bRet= false;QuartzJob job= findById(quartzJob.getId());if (job== null){return Result.error("[updateJob].[findById]无有效记录!");}//优先处理服务bRet= service.updateAndScheduleJob(quartzJob);if (bRet) {//服务启动成功后 才允许修改业务数据if (crud(SysEnum.crudopr.update, quartzJob)) {return Result.ok("操作成功!");} else {return Result.ok("[updateAndScheduleJob].[crud]操作失败!");}} else {return Result.error("[updateAndScheduleJob]操作失败!");}}@PostMapping("/task/deleteAndStopJob")public Result deleteAndStopJob(@RequestBody QuartzJob quartzJob){boolean bRet= false;QuartzJob job= findById(quartzJob.getId());if (job== null){return Result.error("[deleteJob].[findById]无有效记录!");}//优先处理服务bRet= service.deleteAndStopJob(quartzJob);if (bRet) {//服务启动成功后 才允许删除业务数据if (crud(SysEnum.crudopr.delete, quartzJob)) {return Result.ok("操作成功!");} else {return Result.ok("[deleteJob].[deleteAndStopJob].[crud]操作失败!");}} else {return Result.error("[deleteJob].[deleteAndStopJob]操作失败!");}}}

4. 使用POSTMAN测试

        4.1 新增-启动

        新增任务的Cron表达式设置为一分钟一次执行

         4.2 更新-启动

        更新任务的Cron表达式修改为两分钟一次执行

 

 5. 结语

        对Quartz进行简单的认识及使用。

相关内容

热门资讯

每周股票复盘:传音控股(688... 截至2025年7月25日收盘,传音控股(688036)报收于76.2元,较上周的74.69元上涨2....
上海第六批土拍收官:全国单价地... 观点网7月25日,为期两日的上海六批次8宗地土拍落下帷幕,热度再创新高。 第二日出让的3宗地块分布于...
“国补”来了!第三批690亿元... 关注我们哦! 国家发展改革委下达今年第三批690亿元超长期特别国债支持消费品以旧换新资金 2025年...
和讯投顾黄杰:股市最近应该买阴... 今天怎么操作?和讯投顾黄杰分析,今天的策略是尾盘低吸科技低吸小票,或者明天低吸科技低吸小票,这是我的...
市场监管总局:已暂停充电宝及电... 7月25日,市场监管总局消息,从2024年开始将充电宝及其关键部件锂电池纳入CCC认证管理,近日正组...
门店“转卖”会员,把消费者当什... 预付式消费以其便捷与优惠在健身、教培、美容等行业广泛应用。针对预付式消费门店完全“跑路”的情况,相关...
财政部:上半年共发行超长期特别... 上证报中国证券网讯(记者 李苑)财政部国库支付中心副主任唐龙生25日在财政部新闻发布会上表示,上半年...
调查:A股、美股、黄金即将发生... 来源:华尔街情报圈 一系列即将发生的事件可能会扰乱日趋平静的市况,下周市场将有很多事情需要消化。 ...
运行总体平稳 支出力度加大 新华社北京7月25日电(申铖 欧阳剑环)财政部25日发布的上半年财政收支半年报显示,今年以来,财政运...
情暖老党员!日照银行东港中心支... 大众网记者 陈璐 日照报道 为传承党的优良传统,践行社会责任,近日,日照银行东港中心支行党委组织党员...
石头扫地机二次上市虽不性感,但... 来源:晚点LatePost 虽然扫地机已与机器人概念脱钩,但国内品牌商正与持续增长的确定性挂钩...
交易限额!两大交易所出手,焦煤... 当下最火爆的两个期货品种——焦煤、碳酸锂,7月25日都迎来了交易限额要求。 7月25日,根据交易所通...
晶方科技涨0.90%,成交额8... 来源:新浪证券-红岸工作室 7月25日,晶方科技涨0.90%,成交额8.73亿元,换手率4.65%,...
新央企中国雅江集团,董事长、总... 中国三峡集团网站消息,7月19日,中国三峡集团董事长、党组书记刘伟平在西藏林芝与 中国雅江集团董事长...
人身险预定利率研究值再下调 保... 7月25日,中国保险行业协会公布最新普通型人身保险产品预定利率研究值,1.99%的数值较上一期下调了...
近半数投顾机构被罚,超六成涉虚... 文/王占全 导语 2025年证券投顾行业再掀监管风暴!黑龙江证监局日前对容维公司开出年内第二张罚单,...
新一轮Meme股热潮迎微妙转折... 高盛集团交易部门周五表示,新一轮Meme股热潮推动一批小型公司股价大涨后,其客户对押注无盈利科技股下...
增持未在规定时间内停止交易!荣... 浙江省证监局近日发布关于对浙江荣盛控股集团有限公司采取出具警示函措施的决定。 经查,荣盛控股集团于...
72岁“稀土大王”蒋泉龙被踢出... 红星资本局7月25日消息,近期,A股稀土板块行情持续火热,热度也蔓延到了港股。不过,港股上市公司、家...
上半年30个省份“半年报”出炉... 贝壳财经原创出品 记者 张晓翀 任婉晴 任娇 董怡楠 编辑 陈莉 截至7月25日发稿时,全国30个...