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进行简单的认识及使用。

相关内容

热门资讯

在大吉订购APP订购交易亏损被...   近期,不少投资者反映在“大吉订购App”上投资白银、铂金等商品遭遇严重亏损。该平台宣称提供现货订...
铂银壹号APP商品订购交易亏损...   许多中小投资者误以为网上的“商品现货订购”是合规合法的理财渠道,殊不知这背后隐藏着巨大的合规风险...
兴鑫淘金APP贵金属订购交易亏...   白银、贵金属或其他商品类投资,除国家批准的正规期货交易场所及持牌期货公司外,市面上大量第三方交易...
铂银掘金APP无资质的违规平台...   铂银掘金等平台的投资者,往往是被“注册送现金”“充值返现券”“首单免亏”等广告话术吸引,进而下载...
八方淘金APP订购交易不合规,...   “八方淘金APP”“铂银掘金APP”“铂银壹号APP”等软件被指以“现货订购”为名,实际采用高杠...
在指尖订购APP订购商品亏损被...   指尖订购APP这类平台,表面是“订购交易”,实则是披着电商外衣的非法期货陷阱。绝大多数投资者被蒙...
在犀贝易购APP做商品订购交易...   市面上打着“现货投资”“贵金属交易”旗号的APP并不少,但真正合规、受监管的平台并不多。犀贝易购...
易达淘金APP虚假商品订购交易...   易达淘金APP存在严重的虚假宣传与违规交易行为。该平台打着“商品订购”的旗号,实则通过不合规的交...
大浪淘金APP白银订购亏损被骗...   大浪淘金APP最隐蔽的套路,在于其完全封闭的内盘交易系统。表面上,它宣称与国际贵金属市场接轨;实...
一品好购APP上订购白银出现亏...   一品好购APP原名“一品订购”,运营方为上海宝智未来信息技术有限公司。近期不少投资者反映在该平台...
九州订购APP贵金属订购投资骗...   九州订购APP正通过抖.音、快手、今日头条等平台大量投放投资广告,用“5元起投”“充值返现”“0...
坚锅淘金APP交易软件并不正规...   当前,市面上大量所谓的“现货商城订购”交易软件,早已偏离了正常的实物商品买卖,演变为高杠杆、高手...
斗金订购APP贵金属期货交易骗...   斗金订购APP的投资者往往被铺天盖地的广告宣传所诱导——注册即送现金、充值返现券等看似诱人的福利...
警惕!云启购APP违规经营,披...   "5元起投、充值返现、稳赚不赔"——这些诱人的广告语背后,可能是一个精心设计的金融陷阱。  近期...
量子淘金APP贵金属投资不合规...   "4元起投""充值返券""月入过万"——这些极具诱惑力的广告语在短视频平台、社交软件上铺天盖地。...
鑫汇智投APP贵金属商品订购骗...   鑫汇智投APP非法期货投资骗局,受害者在投资过程中根本不懂交易,也不去研究和验证这个平台是否正规...
矅光智策APP平台违规经营非法...   矅光智策APP对外宣称是“商城订购”“现货交易”,但查询其经营范围,并未显示具备开展现货期货交易...
黄金珠宝怎么选?内侧刻字都代表... 潮新闻客户端 记者 马焱 通讯员 任倩影 9月8日下午,“云游杭州 乐购金秋”——“浙城·浙放心”活...
原创 冰... 最近全球国债市场正在上演魔幻一幕: 美债、日债、欧债遭遇猛烈抛售,收益率冲到几十年新高,美国财政部都...
日韩股市开盘表现分化 上证报中国证券网讯 9月9日,日韩股市开盘表现分化,韩国综合指数开盘上涨0.26%,报6972.87...