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 = true org.quartz.jobStore.misfireThreshold = 5000 # 默認存儲在內存中 org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
上面的最后一句話的作用是把任務內容存儲在內存中。我們的程序是要做持久化任務,所以把上面的最后一句話注釋掉,然后在下面加上
#持久化 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.dataSource = qzDS org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver org.quartz.dataSource.qzDS.URL = jdbc:mysql://190.0.1.88:3306/hello_test?useUnicode=true&characterEncoding=UTF-8 org.quartz.dataSource.qzDS.user = root org.quartz.dataSource.qzDS.password = root org.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"> 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 </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-table ref="testTable" :data="tableData" style="width:100%" border > <el-table-column prop="job_NAME" label="任務名稱" sortable show-overflow-tooltip> </el-table-column> <el-table-column prop="job_GROUP" label="任務所在組" sortable> </el-table-column> <el-table-column prop="job_CLASS_NAME" label="任務類名" sortable> </el-table-column> <el-table-column prop="trigger_NAME" label="觸發器名稱" sortable> </el-table-column> <el-table-column prop="trigger_GROUP" label="觸發器所在組" sortable> </el-table-column> <el-table-column prop="repeat_INTERVAL" label="觸發間隔(毫秒)" sortable> </el-table-column> <el-table-column prop="times_TRIGGERED" label="已觸發次數" sortable> </el-table-column> <el-table-column label="操作"> <template scope="scope"> <el-button size="small" type="warning" @click="handlePause(scope.$index, scope.row)">暫停</el-button> <el-button size="small" type="info" @click="handleResume(scope.$index, scope.row)">恢復</el-button> <el-button size="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>© Quartz 任務管理</p> </footer> <script> var vue = new Vue({ el:"#test", data: { //表格當前頁數據 tableData: [], //請求的URL url:'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,還有很多更強大的功能等待着我們去探索。