Quartz与SpringMVC的整合

简介

Quartz是一个完全由java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。这篇文章介绍了Quartz与SSM框架的整合,包括了持久化的方法和对于任务的一些简单操作。本文包括一个简单的由vuejs和ElementUI开发的前端任务管理页面,对于vuejs和ElementUI的用法,在我的另一篇文章Vue2.0+ElementUI+PageHelper实现的表格分页中进行了详细的介绍,并且有完整的代码可供参考,这里不再赘述。

正文

Quartz的引入

在pom.xml中加入如下代码:

<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.2.1</version></dependency><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId><version>2.2.1</version></dependency>   

在web.xml中,加入如下代码:

 <context-param><param-name>quartz:config-file</param-name><param-value>scan-quartz.properties</param-value></context-param><context-param><param-name>quartz:shutdown-on-unload</param-name><param-value>true</param-value></context-param><context-param><param-name>quartz:wait-on-shutdown</param-name><param-value>false</param-value></context-param><context-param><param-name>quartz:start-scheduler-on-load</param-name><param-value>true</param-value></context-param><listener><listener-class>org.quartz.ee.servlet.QuartzInitializerListener</listener-class></listener>

scan-quartz.properties是quartz的配置文件,我们需要在resouces目录下加入新建一个名字为scan-quartz.properties的文件,然后在里面加入

# 固定前缀org.quartz
# 主要分为scheduler、threadPool、jobStore、plugin等部分
#
#
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 5
# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = trueorg.quartz.jobStore.misfireThreshold = 5000# 默认存储在内存中
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

上面的最后一句话的作用是把任务内容存储在内存中。我们的程序是要做持久化任务,所以把上面的最后一句话注释掉,然后在下面加上

#持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.tablePrefix = QRTZ_org.quartz.jobStore.dataSource = qzDSorg.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driverorg.quartz.dataSource.qzDS.URL = jdbc:mysql://190.0.1.88:3306/hello_test?useUnicode=true&characterEncoding=UTF-8

org.quartz.dataSource.qzDS.user = rootorg.quartz.dataSource.qzDS.password = rootorg.quartz.dataSource.qzDS.maxConnections = 10

上面代码主要是做了一些数据库的连接配置,如果大家用过mybatis,这些应该都能看懂。不过,事先要在数据库里创建一些表。具体的做法是打开数据库客户端,连接到某个数据库,然后新建一个查询。如果你用到的是mysql数据库,那么执行以下代码:

#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;CREATE TABLE QRTZ_JOB_DETAILS(SCHED_NAME VARCHAR(120) NOT NULL,JOB_NAME  VARCHAR(200) NOT NULL,JOB_GROUP VARCHAR(200) NOT NULL,DESCRIPTION VARCHAR(250) NULL,JOB_CLASS_NAME   VARCHAR(250) NOT NULL,IS_DURABLE VARCHAR(1) NOT NULL,IS_NONCONCURRENT VARCHAR(1) NOT NULL,IS_UPDATE_DATA VARCHAR(1) NOT NULL,REQUESTS_RECOVERY VARCHAR(1) NOT NULL,JOB_DATA BLOB NULL,PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);CREATE TABLE QRTZ_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(200) NOT NULL,TRIGGER_GROUP VARCHAR(200) NOT NULL,JOB_NAME  VARCHAR(200) NOT NULL,JOB_GROUP VARCHAR(200) NOT NULL,DESCRIPTION VARCHAR(250) NULL,NEXT_FIRE_TIME BIGINT(13) NULL,PREV_FIRE_TIME BIGINT(13) NULL,PRIORITY INTEGER NULL,TRIGGER_STATE VARCHAR(16) NOT NULL,TRIGGER_TYPE VARCHAR(8) NOT NULL,START_TIME BIGINT(13) NOT NULL,END_TIME BIGINT(13) NULL,CALENDAR_NAME VARCHAR(200) NULL,MISFIRE_INSTR SMALLINT(2) NULL,JOB_DATA BLOB NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);CREATE TABLE QRTZ_SIMPLE_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(200) NOT NULL,TRIGGER_GROUP VARCHAR(200) NOT NULL,REPEAT_COUNT BIGINT(7) NOT NULL,REPEAT_INTERVAL BIGINT(12) NOT NULL,TIMES_TRIGGERED BIGINT(10) NOT NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_CRON_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(200) NOT NULL,TRIGGER_GROUP VARCHAR(200) NOT NULL,CRON_EXPRESSION VARCHAR(200) NOT NULL,TIME_ZONE_ID VARCHAR(80),PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_SIMPROP_TRIGGERS(          SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(200) NOT NULL,TRIGGER_GROUP VARCHAR(200) NOT NULL,STR_PROP_1 VARCHAR(512) NULL,STR_PROP_2 VARCHAR(512) NULL,STR_PROP_3 VARCHAR(512) NULL,INT_PROP_1 INT NULL,INT_PROP_2 INT NULL,LONG_PROP_1 BIGINT NULL,LONG_PROP_2 BIGINT NULL,DEC_PROP_1 NUMERIC(13,4) NULL,DEC_PROP_2 NUMERIC(13,4) NULL,BOOL_PROP_1 VARCHAR(1) NULL,BOOL_PROP_2 VARCHAR(1) NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_BLOB_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_NAME VARCHAR(200) NOT NULL,TRIGGER_GROUP VARCHAR(200) NOT NULL,BLOB_DATA BLOB NULL,PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_CALENDARS(SCHED_NAME VARCHAR(120) NOT NULL,CALENDAR_NAME  VARCHAR(200) NOT NULL,CALENDAR BLOB NOT NULL,PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS(SCHED_NAME VARCHAR(120) NOT NULL,TRIGGER_GROUP  VARCHAR(200) NOT NULL, PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);CREATE TABLE QRTZ_FIRED_TRIGGERS(SCHED_NAME VARCHAR(120) NOT NULL,ENTRY_ID VARCHAR(95) NOT NULL,TRIGGER_NAME VARCHAR(200) NOT NULL,TRIGGER_GROUP VARCHAR(200) NOT NULL,INSTANCE_NAME VARCHAR(200) NOT NULL,FIRED_TIME BIGINT(13) NOT NULL,SCHED_TIME BIGINT(13) NOT NULL,PRIORITY INTEGER NOT NULL,STATE VARCHAR(16) NOT NULL,JOB_NAME VARCHAR(200) NULL,JOB_GROUP VARCHAR(200) NULL,IS_NONCONCURRENT VARCHAR(1) NULL,REQUESTS_RECOVERY VARCHAR(1) NULL,PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);CREATE TABLE QRTZ_SCHEDULER_STATE(SCHED_NAME VARCHAR(120) NOT NULL,INSTANCE_NAME VARCHAR(200) NOT NULL,LAST_CHECKIN_TIME BIGINT(13) NOT NULL,CHECKIN_INTERVAL BIGINT(13) NOT NULL,PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);CREATE TABLE QRTZ_LOCKS(SCHED_NAME VARCHAR(120) NOT NULL,LOCK_NAME  VARCHAR(40) NOT NULL, PRIMARY KEY (SCHED_NAME,LOCK_NAME)
);commit;

如果是其他的数据库,可以从quartz官网下载完整的文档,然后在docs目录下的dbTables文件夹里找到对应的创建表的方法。

后台代码

先创建两个任务类HelloJob和NewJob

import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;  public class HelloJob implements Job {  private static Logger _log = LoggerFactory.getLogger(HelloJob.class);  public HelloJob() {  }  public void execute(JobExecutionContext context)  throws JobExecutionException {  _log.error("Hello Job执行时间: " + new Date());  }
}  

import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;  public class NewJob implements Job {  private static Logger _log = LoggerFactory.getLogger(HelloJob.class);  public NewJob() {  }  public void execute(JobExecutionContext context)  throws JobExecutionException {  _log.error("New Job执行时间: " + new Date());  }
}  

这两个任务类的执行都是简单的打印执行时间。 
接下来是Controller,首先是添加任务

@ResponseBody@RequestMapping(value="/addjob", method = RequestMethod.POST)public void addjob(@RequestParam(value="jobClassName")String jobClassName) throws Exception{           setJob(jobClassName);}public static void setJob(String jobClassName) throws Exception{// 通过SchedulerFactory获取一个调度器实例  SchedulerFactory sf = new StdSchedulerFactory();      Scheduler sched = sf.getScheduler();  // 启动调度器
        sched.start(); switch (jobClassName) {case "HelloJob":JobDetail job = newJob(HelloJob.class).withIdentity("HelloJob", "group1").build(); Trigger trigger = newTrigger().withIdentity("HelloJob", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();  sched.scheduleJob(job, trigger);  break;case "NewJob":JobDetail job2 = newJob(NewJob.class).withIdentity("NewJob", "group1").build(); Trigger trigger2 = newTrigger().withIdentity("NewJob", "group1").startNow().withSchedule(simpleSchedule().withIntervalInSeconds(10).repeatForever()).build();  sched.scheduleJob(job2, trigger2);  break;  default:break;}}

从前端接收一个名称参数,然后根据这个名称创建对应的任务实例。每个任务都有个触发器,这里两个任务都设置为每10秒钟运行一次,永久循环。每个任务实例都需要一个名称和组,对于两个任务实例来说,名称和组不能全部相同,因为它们在寻找任务实例中起到key的作用。

接下来是暂停任务。

 @ResponseBody@RequestMapping(value="/pausejob", method = RequestMethod.POST)public void pausejob(@RequestParam(value="jobClassName")String jobClassName) throws Exception{           jobPause(jobClassName);}public static void jobPause(String jobClassName) throws Exception{// 通过SchedulerFactory获取一个调度器实例  SchedulerFactory sf = new StdSchedulerFactory();               Scheduler sched = sf.getScheduler();  switch (jobClassName) {case "HelloJob":sched.pauseJob(JobKey.jobKey("HelloJob", "group1"));break;case "NewJob":sched.pauseJob(JobKey.jobKey("NewJob", "group1"));break;default:break;}                   }

可以看到上文通过jobkey找到了这个任务的实例,然后进行暂停操作。 
接下来恢复。

@ResponseBody@RequestMapping(value="/resumejob", method = RequestMethod.POST)public void resumejob(@RequestParam(value="jobClassName")String jobClassName) throws Exception{           jobresume(jobClassName);}public static void jobresume(String jobClassName) throws Exception{// 通过SchedulerFactory获取一个调度器实例  SchedulerFactory sf = new StdSchedulerFactory();               Scheduler sched = sf.getScheduler(); if(sched != null){switch (jobClassName) {case "HelloJob":sched.resumeJob(JobKey.jobKey("HelloJob", "group1"));break;case "NewJob":sched.resumeJob(JobKey.jobKey("NewJob", "group1"));break;default:break;}           }}

然后是删除操作。

 @ResponseBody@RequestMapping(value="/deletejob", method = RequestMethod.POST)public void deletejob(@RequestParam(value="jobClassName")String jobClassName) throws Exception{           jobdelete(jobClassName);}public static void jobdelete(String jobClassName) throws Exception{       // 通过SchedulerFactory获取一个调度器实例  SchedulerFactory sf = new StdSchedulerFactory();               Scheduler sched = sf.getScheduler(); switch (jobClassName) {case "HelloJob":sched.pauseTrigger(TriggerKey.triggerKey("HelloJob", "group1"));sched.unscheduleJob(TriggerKey.triggerKey("HelloJob", "group1"));sched.deleteJob(JobKey.jobKey("HelloJob", "group1"));break;case "NewJob":sched.pauseTrigger(TriggerKey.triggerKey("NewJob", "group1"));sched.unscheduleJob(TriggerKey.triggerKey("NewJob", "group1"));sched.deleteJob(JobKey.jobKey("NewJob", "group1"));break;default:break;}           }

删除操作前应该暂停该任务的触发器,并且停止该任务的执行。

最后是查询,这里用到了pageHelper插件,具体的也是写在了Vue2.0+ElementUI+PageHelper实现的表格分页中。

@ResponseBody@RequestMapping(value="/queryjob")public Map<String, Object> queryjob(@RequestParam(value="pageNum")Integer pageNum, @RequestParam(value="pageSize")Integer pageSize) {           Page<JobAndTrigger> jobAndTrigger = iJobAndTriggerService.getJobAndTriggerDetails(pageNum, pageSize);Map<String, Object> map = new HashMap<String, Object>();map.put("JobAndTrigger", jobAndTrigger);map.put("number", jobAndTrigger.getTotal());return map;}

这里主要的作用是将数据库里存储的关于任务和触发器的部分信息查询出来在前端显示。附上mybatis中的sql代码

<select id="getJobAndTriggerDetails" resultType="com.hdnav.core.entity.JobAndTrigger">SELECTqrtz_job_details.JOB_NAME,qrtz_job_details.JOB_GROUP,qrtz_job_details.JOB_CLASS_NAME,qrtz_triggers.TRIGGER_NAME,qrtz_triggers.TRIGGER_GROUP,qrtz_simple_triggers.REPEAT_INTERVAL,qrtz_simple_triggers.TIMES_TRIGGEREDFROMqrtz_job_detailsJOIN qrtz_triggersJOIN qrtz_simple_triggers ON qrtz_job_details.JOB_NAME = qrtz_triggers.JOB_NAMEAND qrtz_triggers.TRIGGER_NAME = qrtz_simple_triggers.TRIGGER_NAMEAND qrtz_triggers.TRIGGER_GROUP = qrtz_simple_triggers.TRIGGER_GROUP</select>

最后显示的效果如图所示

右键图片在新标签页打开图片可以看得更清晰。 
下面是控制台输出

[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:01:47 CST 2017
[com.hdnav.core.HelloJob] - Hello Job执行时间: Thu Apr 20 18:01:57 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:01:57 CST 2017
[com.hdnav.core.HelloJob] - Hello Job执行时间: Thu Apr 20 18:02:07 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:02:07 CST 2017
[com.hdnav.core.HelloJob] - Hello Job执行时间: Thu Apr 20 18:02:17 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:02:17 CST 2017
[com.hdnav.core.HelloJob] - Hello Job执行时间: Thu Apr 20 18:02:27 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:02:27 CST 2017
[com.hdnav.core.HelloJob] - Hello Job执行时间: Thu Apr 20 18:02:37 CST 2017

可以看到两个任务都是每隔10秒执行一次。 
若点击暂停,则该任务暂停执行。点击恢复则会恢复执行。 
若执行删除操作,则数据表内不再有该任务的数据,只有重新添加任务才会显示,不过所有的数据都会重置。

[com.hdnav.core.HelloJob] - Hello Job执行时间: Thu Apr 20 18:08:07 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:08:07 CST 2017
[com.hdnav.core.HelloJob] - Hello Job执行时间: Thu Apr 20 18:08:17 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:08:17 CST 2017
[com.hdnav.core.dao.JobAndTriggerMapper.getJobAndTriggerDetails] - ==>  Preparing: SELECT qrtz_job_details.JOB_NAME, qrtz_job_details.JOB_GROUP, qrtz_job_details.JOB_CLASS_NAME, qrtz_triggers.TRIGGER_NAME, qrtz_triggers.TRIGGER_GROUP, qrtz_simple_triggers.REPEAT_INTERVAL, qrtz_simple_triggers.TIMES_TRIGGERED FROM qrtz_job_details JOIN qrtz_triggers JOIN qrtz_simple_triggers ON qrtz_job_details.JOB_NAME = qrtz_triggers.JOB_NAME AND qrtz_triggers.TRIGGER_NAME = qrtz_simple_triggers.TRIGGER_NAME AND qrtz_triggers.TRIGGER_GROUP = qrtz_simple_triggers.TRIGGER_GROUP LIMIT 10
[com.hdnav.core.dao.JobAndTriggerMapper.getJobAndTriggerDetails] - ==> Parameters:
[com.hdnav.core.dao.JobAndTriggerMapper.getJobAndTriggerDetails] - <==      Total: 1
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:08:27 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:08:37 CST 2017
[com.hdnav.core.HelloJob] - New Job执行时间: Thu Apr 20 18:08:47 CST 2017

可以看到当执行删除HelloJob操作之后,控制台不再有指令。此时数据表中该条数据也被删除。

前端代码

前端代码比较简单,这里不再做过多的解释。

<html>
<head>
<meta charset="UTF-8"><title>QuartzDemo</title><link rel="stylesheet" href="/core/element-ui/lib/theme-default/index.css"><script src="./js/jquery-3.1.1.min.js"></script><script src="./js/json2.js"></script><script src="./js/vue.min.js"></script>  <script src="./js/vue-resource.js"></script><script src="./element-ui/lib/index.js"></script><style>      #top {background:#20A0FF;padding:5px;overflow:hidden}</style></head>
<body><div id="test">             <div id="top">          <el-button type="text" @click="search" style="color:white">查询</el-button>   <el-button type="text" @click="add" style="color:white">添加</el-button>  </span>                     </div>  <br/><div style="margin-top:15px">   <el-tableref="testTable"       :data="tableData"style="width:100%"border><el-table-columnprop="job_NAME"label="任务名称"sortableshow-overflow-tooltip></el-table-column><el-table-columnprop="job_GROUP"label="任务所在组"sortable></el-table-column><el-table-columnprop="job_CLASS_NAME"label="任务类名"sortable></el-table-column><el-table-columnprop="trigger_NAME"label="触发器名称"sortable></el-table-column><el-table-columnprop="trigger_GROUP"label="触发器所在组"sortable></el-table-column><el-table-columnprop="repeat_INTERVAL"label="触发间隔(毫秒)"sortable></el-table-column><el-table-columnprop="times_TRIGGERED"label="已触发次数"sortable></el-table-column><el-table-column label="操作"><template scope="scope"><el-buttonsize="small"type="warning"@click="handlePause(scope.$index, scope.row)">暂停</el-button><el-buttonsize="small"type="info"@click="handleResume(scope.$index, scope.row)">恢复</el-button><el-buttonsize="small"type="danger"@click="handleDelete(scope.$index, scope.row)">删除</el-button></template></el-table-column></el-table><div align="center"><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage":page-sizes="[10, 20, 30, 40]":page-size="pagesize"layout="total, sizes, prev, pager, next, jumper":total="totalCount"></el-pagination></div></div> </div><footer align="center"><p>&copy; Quartz 任务管理</p></footer><script>var vue = new Vue({         el:"#test",data: {       //表格当前页数据
                tableData: [],//请求的URLurl:'job/queryjob',//默认每页数据量pagesize: 10,               //当前页码currentPage: 1,//查询的页码start: 1,//默认数据总数totalCount: 1000,},methods: {//从服务器读取数据
                loadData: function(pageNum, pageSize){                  this.$http.get(this.url,{pageNum:pageNum, pageSize:pageSize}).then(function(res){this.tableData = res.data.JobAndTrigger;this.totalCount = res.data.number;},function(){console.log('failed');});                 },                              //单行删除
                handleDelete: function(index, row) {this.$http.post('job/deletejob',{"jobClassName":row.job_NAME},{emulateJSON: true}).then(function(res){this.loadData( this.currentPage, this.pagesize);},function(){console.log('failed');});},handlePause: function(index, row){this.$http.post('job/pausejob',{"jobClassName":row.job_NAME},{emulateJSON: true}).then(function(res){this.loadData( this.currentPage, this.pagesize);},function(){console.log('failed');});},handleResume: function(index, row){this.$http.post('job/resumejob',{"jobClassName":row.job_NAME},{emulateJSON: true}).then(function(res){this.loadData( this.currentPage, this.pagesize);},function(){console.log('failed');});},//搜索
                search: function(){this.loadData(this.currentPage, this.pagesize);},//添加
                add: function(){this.$prompt('请输入名称', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',}).then(({ value }) => {if(value==''||value==null)return;this.$http.post('job/addjob',{"jobClassName":value},{emulateJSON: true}).then(function(res){this.loadData(this.currentPage, this.pagesize);},function(){console.log('failed');});}).catch(() => {});},//每页显示数据量变更
                handleSizeChange: function(val) {this.pagesize = val;this.loadData(this.currentPage, this.pagesize);},//页码变更
                handleCurrentChange: function(val) {this.currentPage = val;this.loadData(this.currentPage, this.pagesize);},        },      });//载入数据
          vue.loadData(vue.currentPage, vue.pagesize);</script>  </body>
</html>

至此,一个简单的SSM框架与Quartz的整合工程便做好了。虽然是一个很简单的Demo,但是功能还算完整。对于人物的修改,后台的代码如下:

@ResponseBody@RequestMapping(value="/reschedulejob", method = RequestMethod.POST)public void rescheduleJob(@RequestParam(value="jobClassName")String jobClassName) throws Exception{           jobreschedule(jobClassName);}public static void jobreschedule(String jobClassName) throws Exception{       SchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, "group1");Trigger newTrigger = scheduler.getTrigger(triggerKey);scheduler.rescheduleJob(triggerKey, newTrigger);scheduler.start();}

当然这里的trigger可以重新自定义,达到修改任务的效果。不过和前端结合相对来说比较麻烦,所以没有写前端的代码。做这个Demo的主要目的是为了更直观的感受到Quartz的可持久化特性,并且与SpringMVC相结合,可以从一个简单的前端界面直接去操作和管理这些任务。

结束语

这个小小的Demo所展现出的功能只是quartz茫茫多的功能的冰山一角,不过quartz是一个比较简单易懂的开源框架,文档相对来说很全面,在企业级的web程序开发中也完全可以胜任。相对于这个小小的Demo,还有很多更强大的功能等待着我们去探索。

转载于:https://www.cnblogs.com/wlsblog/p/8042692.html

Spring+SpringMVC+mybatis+Quartz整合相关推荐

  1. Spring+SpringMVC+MyBatis+easyUI整合优化篇(十三)数据层优化-表规范、索引优化

    本文提要 最近写的几篇文章都是关于数据层优化方面的,这几天也在想还有哪些地方可以优化改进,结合日志和项目代码发现,关于数据层的优化,还是有几个方面可以继续修改的,代码方面,整合了druid数据源也开启 ...

  2. Spring+SpringMVC+MyBatis+easyUI整合优化篇(五)MockMvc服务端的单元测试

    日常啰嗦 承接前一篇文章<Spring+SpringMVC+MyBatis+easyUI整合优化篇(四)单元测试实例>,已经讲解了dao层和service层的单元测试,还有控制器这层也不能 ...

  3. SSM框架Spring+SpringMVC+MyBatis——详细整合教程

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 包括SQL Maps和Data Access Objects(DAO)MyBatis 消除了几乎所有的JDBC代码和参 ...

  4. Spring+SpringMVC+MyBatis+easyUI整合基础篇(一)项目简述及技术选型介绍

    作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 萌芽阶段 很久之前就开始打算整理一下自己的技术博客了,由于各种原因( ...

  5. springmvc连接mysql_挺详细的spring+springmvc+mybatis配置整合|含源代码

    大家好,我是雄雄,今天来带着大家来配置一下SSM(spring+springmvc+ mybatis)框架. 01 新建java web项目 直接在myeclipse中,新建一个web项目即可. 02 ...

  6. Spring+SpringMVC+Mybatis简单整合 图书管理项目 实现增删改查

    Spring+SpringMVC+Mybatis项目 tomcat7插件配置 <build><plugins><plugin><groupId>org. ...

  7. Spring+SpringMVC+Mybatis框架整合流程

    一:基本步骤 新建Maven项目,导入相关依赖.(推荐) ----–Mybatis配置 ------ 新建entity包,并根据数据库(表)新建相关实体类. 新建dao包,并根据业务创建必要的mapp ...

  8. 最详细的Spring+SpringMVC+Mybatis框架整合及mybatis分页讲解,适合初级者

    最详细的关于idea整合ssm框架讲解 一个关于brand(品牌)的项目 [ssm框架搭建源代码及mysql数据库数据]链接:https://pan.baidu.com/s/1eBogklK0rFLj ...

  9. spring,springmvc,mybatis基本整合(一)--xml文件配置方式(1)

    **这个整合.仅仅是最主要的整合,而且是xml配置文件的方式之中的一个,即当中的mybatis是採用非mapper接口的方式.(第二遍採用mapper接口方式.第三遍採用注解的方式:第四篇採用注解基于 ...

最新文章

  1. python Day5
  2. wxWidgets:wxSimpleHtmlListBox类用法
  3. python基础之删除文件及删除目录的方法
  4. java object.getclass_Java Object getClass() 方法
  5. SPFILE 、PFILE 的全面解读
  6. MVC架构 -- 初学试水选课管理系统
  7. 唱吧基于 MaxCompute 弥补自建体系的不足
  8. Linux操作系统下的多线程编程详细解析----条件变量pthread_cond_t那些事儿
  9. ORACLE VARCHAR2
  10. RabbitMQ死信队列和备份交换器总结
  11. jd反编译java_java反编译工具jd
  12. docker安装speedtest和宝塔面板
  13. 网易云音乐前端性能监控实践
  14. 图文演示戴尔win10重装系统步骤
  15. Excel VBA基础教程
  16. 怎么把ppt文字大小设置一致_学会这个方法,轻松制作海报级别的霓虹灯PPT!
  17. 浅谈tomcat优化
  18. jenkins+gitee 实现自动化部署项目到centos上
  19. u大师制作linux系统,u盘安装kali linux 检测不到cd romu大师u盘装win10
  20. 爬取糗事百科段子(xpath)

热门文章

  1. Django基础--4
  2. 码农人生-如何快速使用从未学过的语言实现项目开发-第002期博文
  3. 一步一步部署GlusterFS
  4. openCV+ASM+LBP+Gabor实现人脸识别(GT人脸库)
  5. (转自dflying chen)使用Anthem.NET 1.5中的FileUpload控件实现Ajax方式的文件上传
  6. Decoders Matter for Semantic Segmentation: Data-Dependent Decoding Enables Flexible Feature Aggregat
  7. Course 2: 单视图计量
  8. 特征匹配中OpenCV Dmatch类的用法解析以及非常详细的ORB特征提取与匹配解析
  9. 设置代理_PC客户端爬虫,这样设置代理就对了
  10. python列表生成式和map效率_Python列表生成式12个小功能,你常用哪几个?