【前言】因为项目需要后台动态调度远程服务的任务,其中动态调度选用Quartz调度框架,远程服务还是沿用原来的Hessian,整合到JFinal后台(客户端)。本文主要记录JFinal下的Quartz控制台搭建,实现任务新建、修改和启停基本功能。

【正文】
参考资料(来源:JFinal中使用QuartzManager实现动态定时任务)感谢JFinal社区@wangqian0628

先放一张成果图:

maven依赖(其他的就是JFinal项目通用依赖)

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

根据实际需求,对参考资料做了修改,以下是修改后的工具类:

package top.rushpeak.edu03.admin.util;import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;import java.util.List;import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;import top.rushpeak.edu03.admin.job.DynamicJob;//这个是后面的任务实现类public class QuartzManager {private Logger log = LogManager.getLogger(QuartzManager.class);private Scheduler scheduler = null;public QuartzManager() {try {scheduler = new StdSchedulerFactory().getScheduler();log.info("初始化调度器 ");} catch (SchedulerException ex) {log.error("初始化调度器=> [失败]:" + ex.getLocalizedMessage());}}//初始化启动任务public void initJob(){List<Record> jobs = Db.find("SELECT * FROM job_manager WHERE 1=1 AND is_enabled = 'Y'");for(Record job:jobs){if("Y".equals(job.getStr("is_enabled"))){String className = job.getStr("class");Class<? extends Job> jobClazz = null;try {jobClazz = Class.forName(className).asSubclass(Job.class);} catch (Exception e) {System.out.println(className+"没有继承job,e=="+e);log.error(className+"没有继承job,e=="+e);continue;}String name = job.getStr("name");String group = job.getStr("group");String cronExpression = job.getStr("cron_expression");this.addJob(name, group, jobClazz, cronExpression);}}this.start();}//添加任务public void addJob(String name, String group, Class<? extends Job> clazz, String cronExpression) {try {// 构造任务JobDetail job = newJob(clazz).withIdentity(name, group).build();// 构造任务触发器Trigger trg = newTrigger().withIdentity(name, group).withSchedule(cronSchedule(cronExpression)).build();// 将作业添加到调度器scheduler.scheduleJob(job, trg);log.info("创建作业=> [作业名称:" + name + " 作业组:" + group + "] ");System.out.println("创建作业=> [作业名称:" + name + " 作业组:" + group + "] ");} catch (SchedulerException e) {e.printStackTrace();log.error("创建作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");}}//移除任务public void removeJob(String name, String group) {try {TriggerKey tk = TriggerKey.triggerKey(name, group);scheduler.pauseTrigger(tk);// 停止触发器scheduler.unscheduleJob(tk);// 移除触发器JobKey jobKey = JobKey.jobKey(name, group);scheduler.deleteJob(jobKey);// 删除作业log.info("删除作业=> [作业名称:" + name + " 作业组:" + group + "] ");System.out.println("删除作业=> [作业名称:" + name + " 作业组:" + group + "] ");} catch (SchedulerException e) {e.printStackTrace();log.error("删除作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");}}public void start() {try {scheduler.start();log.info("启动调度器 ");System.out.println("启动调度器 ");} catch (SchedulerException e) {e.printStackTrace();log.error("启动调度器=> [失败]");}}public void shutdown() {try {scheduler.shutdown();log.info("停止调度器 ");System.out.println("停止调度器 ");} catch (SchedulerException e) {e.printStackTrace();log.error("停止调度器=> [失败]");}}//测试public static void main(String[] args) throws InterruptedException{QuartzManager qm = new QuartzManager();String name = "DynamicJobName";String group = "DynamicJobGroup";String cronExpression = "*/3 * * * * ?";String className = "top.rushpeak.edu03.admin.job.DynamicJob";Class<? extends Job> jobClazz = null;try {jobClazz = Class.forName(className).asSubclass(Job.class);} catch (Exception e) {System.out.println(className+"没有继承job,e=="+e);}if(jobClazz==null){System.exit(0);}qm.addJob(name, group, jobClazz, cronExpression);qm.start();Thread.sleep(7000);qm.removeJob(name, group);Thread.sleep(3000);String name2 = "DynamicJobName2";String group2 = "DynamicJobGroup2";String cronExpression2 = "*/3 * * * * ?";qm.addJob(name2, group2, DynamicJob.class, cronExpression2);Thread.sleep(9000);qm.shutdown();}
}

任务接口、实现类

package top.rushpeak.edu03.admin.job;import org.apache.log4j.Logger;public class AbstractJob {public static final Logger      LOG                 = Logger.getLogger(AbstractJob.class);
}
package top.rushpeak.edu03.admin.job;import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import top.rushpeak.edu03.admin.util.DateUtil;public class DynamicJob2 implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("任务2:"+DateUtil.dateFormat(new Date(), "yyyyMMddHHmmss"));}}
package top.rushpeak.edu03.admin.job;import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import top.rushpeak.edu03.admin.util.DateUtil;public class DynamicJob3 implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("任务3:"+DateUtil.dateFormat(new Date(), "yyyyMMddHHmmss"));}}

JFinalConfig的继承类中添加启动后初始任务管理器和关闭任务管理器

    @Overridepublic void afterJFinalStart() {super.afterJFinalStart();//加载定时任务数据库配置QuartzManager qm = new QuartzManager();qm.initJob();}@Overridepublic void beforeJFinalStop() {super.beforeJFinalStop();//关闭定时任务管理器QuartzManager qm = new QuartzManager();qm.shutdown();}

上面基本配置完成后,下面就是业务了。

任务表

CREATE TABLE `job_manager` (`id` int(10) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL DEFAULT '' COMMENT '任务名',`group` varchar(50) NOT NULL DEFAULT '' COMMENT '组名',`clazz` varchar(50) NOT NULL DEFAULT '' COMMENT '类名',`cron_expression` varchar(50) NOT NULL DEFAULT '' COMMENT '定时表达式',`is_enabled` char(1) NOT NULL DEFAULT 'N' COMMENT '是否开启',PRIMARY KEY (`id`),UNIQUE KEY `name` (`name`,`group`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

BaseController父类,通用方法

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.jfinal.core.Controller;public class BaseController extends Controller {public static final Logger      LOG                 = Logger.getLogger(BaseController.class);@SuppressWarnings("rawtypes")protected Map<String, Object> buildPagination(List list, Integer count) {return buildPagination(list, count, null);}@SuppressWarnings("rawtypes")protected Map<String, Object> buildPagination(List list, Integer count,List<Map<String, Object>> footer) {Map<String, Object> map = new HashMap<String, Object>();map.put("total", count);map.put("rows", list);if (footer != null)map.put("footer", footer);return map;}}

页面业务类

import java.sql.SQLException;
import org.quartz.Job;
import com.alibaba.druid.util.StringUtils;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.render.JsonRender;import top.rushpeak.edu03.admin.util.QuartzManager;
import top.rushpeak.edu03.admin.util.Result;public class JobmanageController extends BaseController {public void index() {render("index.html");}//获取任务信息public void post(){int pageNum = getParaToInt("page", 1);int rows = getParaToInt("rows", 30);String whereSql = " where 1=1 ";pageNum = pageNum > 0 ? pageNum : 1;Page<Record> page = Db.paginate(pageNum, rows, "select * "," from  job_manager" + whereSql + "order by id desc");setAttrs(buildPagination(page.getList(), page.getTotalRow()));render(new JsonRender().forIE());}//新增任务public void add(){System.out.println("add");String id = getPara("id");String name = getPara("name");String group = getPara("group");String clazz = getPara("clazz");String cron_expression = getPara("cron_expression");String is_enabled = getPara("is_enabled");try {Class<? extends Job>  jobClazz = Class.forName(clazz).asSubclass(Job.class);Record r = new Record();r.set("name", name);r.set("group", group);r.set("clazz", clazz);r.set("cron_expression", cron_expression);r.set("is_enabled", "N");if(StringUtils.isEmpty(id)){//新增Db.save("job_manager", "id",r);}else{//修改r.set("id", id);Db.update("job_manager", "id",r);}} catch (Exception e) {LOG.error("e=="+e);renderJson(Result.error("异常"));}renderJson(Result.OK);}//启用关停public void delete(){try {final String id = getPara("id");final Record r = Db.findById("job_manager", id);if(r!=null){//事务管理,确保数据库状态与任务管理器一致boolean bl = Db.tx(new IAtom() {  @Override  public boolean run() throws SQLException {  String name = r.getStr("name");String group = r.getStr("group");String clazz = r.getStr("clazz");String cron_expression = r.getStr("cron_expression");String is_enabled = r.getStr("is_enabled");String change_enable = "N".equals(is_enabled)?"Y":"N";r.set("is_enabled", change_enable);Db.update("job_manager", "id", r);Class<? extends Job> jobClazz;try {jobClazz = Class.forName(clazz).asSubclass(Job.class);} catch (ClassNotFoundException e) {LOG.error("job类异常:"+e);throw new RuntimeException("job类异常");}QuartzManager qm = new QuartzManager();if("Y".equals(r.getStr("is_enabled"))){try {qm.removeJob(r.getStr("name"), r.getStr("group"));                              } catch (Exception e) {LOG.error("removeJob_err:"+e);}qm.addJob(r.getStr("name"), r.getStr("group"), jobClazz, r.getStr("cron_expression"));}else{qm.removeJob(r.getStr("name"), r.getStr("group"));}return true;}  }); }} catch (Exception e) {LOG.error("e=="+e);renderJson(Result.error("异常"));}renderJson(Result.OK);}public void get(){Record r = null;try {String id = getPara("id");r = Db.findById("job_manager", id);} catch (Exception e) {LOG.error("e=="+e);renderJson(Result.error("异常"));}renderJson(Result.success(r));}
}

不规范的html,试验用的页面很粗糙。js和css很多走本地,没用cdn,不能直接用,抱歉,主题代码还是可以用的。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>JOB测试</title>
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="bookmark" href="/favicon.ico" type="image/x-icon" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<meta
    content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"name="viewport">
<link rel="stylesheet" href="/dist/css/bootstrap/bootstrap.min.css">
<link rel="stylesheet"href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.css">
<link rel="stylesheet"href="https://cdn.bootcss.com/ionicons/2.0.1/css/ionicons.min.css">
<link rel="stylesheet" href="/dist/css/adminlte/AdminLTE.min.css">
<link rel="stylesheet" href="dist/css/skins/skin-blue.min.css">
<link rel="stylesheet" type="text/css" href="/dist/easyui/themes/gray/easyui.css"></head>
<script src="/dist/plugins/jQuery/jquery-2.2.3.min.js"></script>
<script src="/dist/js/bootstrap.min.js"></script>
<script src="/dist/js/app.min.js"></script>
<script src="https://cdn.bootcss.com/layer/3.0.1/layer.min.js"></script>
<script type="text/javascript" src="/dist/easyui/jquery.easyui.min.js"></script>
<script src="http://code.jquery.com/jquery-migrate-1.1.1.js"></script>
<script type="text/javascript">$(document).ready(function() {var _toolbar = [ {id : 'btnRefresh',text : '刷新',iconCls : 'icon-reload',handler : function() {refresh();}}, '-', {id : 'btnAddItem',iconCls : 'icon-add',text : '添加',handler : function() {add();}} ];$('#datagrid').datagrid({title : '任务调度管理',url : '/jobmanage/post',toolbar : _toolbar,columns : [ [{field : 'id',title : 'ID',width : 50,align : 'center'},{field : 'name',title : '任务名',width : 100,align : 'center'},{field : 'group',title : '任务组名',width : 100,align : 'center'},{field : 'clazz',title : '类全名',width : 300,align : 'center'},{field : 'cron_expression',title : '定时表达式',width : 100,align : 'center'},{field : 'is_enabled',title : '是否启动',width : 100,align : 'center'},{field : 'action',title : '操作',width : 150,align : 'center',formatter : function(value, row,index) {var a = "<a href='javascript:update("+row.id+")'>修改</a> ";var b = "<a href='javascript:deleteItem("+row.id+")'>启停</a>";return a + "   " +b;}} ] ],pagination : true,rownumbers : true,pageSize : 20,rowStyler : function(index, row) {return "height:100px;";},singleSelect : true});$(document).on("click", ".addSubmitBtn", addSubmit);$(document).on("click", ".updateBtn", update);$(document).on("click", ".delBtn", deleteItem);});/* 刷新 */function refresh() {$('#datagrid').datagrid('reload');}/* 添加 */function add() {$("#showAddId").hide();$("#myModalLabel").text("新增");$("#add_id").val("");$("#add_name").val("");$("#add_group").val("");$("#add_clazz").val("");$("#add_cron_expression").val("");$("#add_is_enabled").val("");$("#myModal").modal("show");}/* 更新 */function update(id) {console.log("update");/* var id = $(this).data("id"); */var id = id;$("#myModalLabel").text("修改");$.post("/jobmanage/get", {id : id}, function(data) {if (data.result == "success") {$("#add_id").val(data.data.id);$("#add_name").val(data.data.name);$("#add_group").val(data.data.group);$("#add_clazz").val(data.data.clazz);$("#add_cron_expression").val(data.data.cron_expression);$("#add_is_enabled").val(data.data.is_enabled);} else {alert(data.message);}});$("#showAddId").show();$("#myModal").modal("show");}/* 添加修改提交 */function addSubmit() {var req_params = {};req_params.id = $("#add_id").val();req_params.name = $("#add_name").val();req_params.group = $("#add_group").val();req_params.clazz = $("#add_clazz").val();req_params.cron_expression = $("#add_cron_expression").val();req_params.is_enabled = $("#add_is_enabled").val();$.post('/jobmanage/add', req_params, function(data) {if (data.result == "success") {var title = $("#myModalLabel").text();layer.msg(title + "完成");$("#myModal").modal("hide");refresh();} else {alert(data.message);}});}/* 启停 */function deleteItem(id) {/* var id = $(this).data("id"); */if (!window.confirm("确认启停")) {return;}$.post("/jobmanage/delete", {id : id}, function(data) {if (data.result == "success") {layer.msg("启停完成");refresh();} else {alert(data.message);}});}/* 搜索 */function search() {var id = $('#search_id').val();var name = $('#search_name').val();var group = $('#search_group').val();var is_enabled = $('#search_is_enabled').val();$('#datagrid').datagrid('load', {"id" : id,"name" : name,"group" : group,"is_enabled" : is_enabled});}
</script><body><div id="p1" class="easyui-panel" title="查询"style="padding: 10px; background: #fafafa; margin-bottom: 10px;"iconCls="icon-sum" closable="false" collapsible="false" minimizable="false"maximizable="false">ID:<input id="search_id" name="search_id"class="txt_fm_mmp easyui-validatebox search"> 任务名:<input
            id="search_name" name="search_name"class="txt_fm_mmp easyui-validatebox search"> 任务组名:<input
            id="search_group" name="search_group"class="txt_fm_mmp easyui-validatebox search"> 是否启动:<input
            id="search_is_enabled" name="search_is_enabled"class="txt_fm_mmp easyui-validatebox search"> <a
            href="javascript:search();" class="easyui-linkbutton" plain="true"iconCls="icon-search">搜索</a></div><table id="datagrid"></table><div class="modal fade" id="myModal" tabindex="-1" role="dialog"aria-labelledby="myModalLabel" data-backdrop="false"><div class="modal-dialog" role="document"><div class="modal-content"><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button><h4 class="modal-title" id="myModalLabel">新增</h4></div><div class="modal-body"><form class="form-horizontal"><div class="form-group" style="display: none" id="showAddId"><label for="add_id" class="col-sm-2 control-label">id</label><div class="col-sm-10"><input type="text" class="form-control" id="add_id" placeholder="ID"readonly></div></div><div class="form-group"><label for="add_name" class="col-sm-2 control-label">任务名</label><div class="col-sm-10"><input type="text" class="form-control" id="add_name" placeholder="任务名"required></div></div><div class="form-group"><label for="add_group" class="col-sm-2 control-label">任务组名</label><div class="col-sm-10"><input type="text" class="form-control" id="add_group"placeholder="任务组名" required></div></div><div class="form-group"><label for="add_clazz" class="col-sm-2 control-label">类全名</label><div class="col-sm-10"><input type="text" class="form-control" id="add_clazz" placeholder="类全名"required></div></div><div class="form-group"><label for="add_cron_expression" class="col-sm-2 control-label">定时表达式</label><div class="col-sm-10"><input type="text" class="form-control" id="add_cron_expression"placeholder="定时表达式" required></div></div><div class="form-group" hidden="true"><label class="col-sm-2 control-label">是否启动</label><div class="col-sm-10"><select class="form-control" id="add_is_enabled"><option value="N">否</option><option value="Y">是</option></select></div></div></form></div><div class="modal-footer"><button type="button" class="btn btn-default" data-dismiss="modal">Close</button><button type="button" class="btn btn-primary addSubmitBtn">提交</button></div></div></div></div>
</body>
</html>

配置jfinal路由,这个根据项目结构写的,就没必要放我的码子。

完成以上,便可以开启localhost模式了。

【总结】写了一大堆,其实营养的东西没多少的。由于这些代码依附在某个项目里,不好拎出到单独项目,会有某些依赖遗漏。有需要请指出。

不知道GIF能不能看,就是两个任务启停启停的后台日志,哈哈

JFinal+Quartz动态任务调度控制台相关推荐

  1. quartz动态任务调度实现

    以maven工程为讲解例子: pom.xml <!--quartz--><dependency><groupId>org.quartz-scheduler</ ...

  2. Spring+quartz 动态任务调度

    需求是这样的:系统中会有很多的执行时间,三个或者四个这样,不确定,以后可能是五个!当用户在页面添加执行时间时,我们后台也要对应执行用户添加的时间. 数据库设计: DROP TABLE IF EXIST ...

  3. Spring boot2集成quartz动态任务管理+Web UI

    Dynamic Quartz ​ 最近在公司实习,发现公司有一套spring+Quartz的动态任务管理系统.可以使用Web界面进行任务动态的创建.删除.停止.运行和修改.刚好最近在学习spring ...

  4. 任务调度开源框架Quartz动态添加、修改和删除定时任务

    Quartz 是个开源的作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制.Quartz框架包含了调度器监听.作业和触发器监听.你可以配置作业和触发器监听为全局监听或者是特定于 ...

  5. ASP.NET MVC5 实现基于Quartz.NET任务调度

    ASP.NET MVC5 实现基于Quartz.NET任务调度 工作之余.技术?.记是不可能记住的. 只有写点东西 才能维持得了生活这样子的.好早就像写一篇关于任务调度的文章.终究是太懒了 一.Qua ...

  6. java quartz 动态执行,浅谈SpringBoot集成Quartz动态定时任务

    SpringBoot自带schedule 沿用的springboot少xml配置的优良传统,本身支持表达式等多种定时任务 注意在程序启动的时候加上@EnableScheduling @Schedule ...

  7. Quartz动态添加,修改,删除任务(暂停,任务状态,恢复,最近触发时间)

    首页 博客 学院 下载 图文课 论坛 APP 问答 商城 VIP会员 活动 招聘 ITeye GitChat 写博客 小程序 消息 登录注册 关闭 quartz_Cron表达式一分钟教程 09-05 ...

  8. Spring Boot集成Quartz动态实现数据库任务

    1. Quartz简介 1.1. 什么是Quartz Quartz是一个开源的任务调度框架.作用是基于定时.定期的策略来执行任务. 它是OpenSymphony开源组织在Job scheduling领 ...

  9. Spring+Quartz定时任务调度

    Spring+Quartz定时任务调度   2011/5 zqhxuyuan@gmail.com 参考文章: http://www.iteye.com/topic/399980 ­ org.sprin ...

最新文章

  1. 百度也出分享(百度分享)
  2. HDU 1824 Let's go home
  3. CAD中dwg转dxf
  4. 前端php解密,转发:RSA实现JS前端加密,PHP后端解密
  5. ie8下showmodaldialog页面回传会打开新页面的问题
  6. 建信01. 间隔删除链表结点
  7. OAuth和OpenID的区别
  8. python 3d游戏脚本_3ds Max python脚本编写及部分API介绍
  9. python房屋租赁系统的设计与实现_毕业设计---在线房屋租赁系统的设计与实现.doc...
  10. 指数函数e^x和对数函数lnx 导数的求导过程
  11. html旋转 缩放 移动,CSS3旋转缩放移动倾斜等效果——transform
  12. 子母钟运用在什么领域,设备如何调试,天穹告诉你子母钟系统授时的意义
  13. 深耕企业组网 H3C企业主网交换机评测
  14. 一个一本正经的科普--5G是什么?
  15. (十进制快速幂+矩阵优化)BZOJ 3240 3240: [Noi2013]矩阵游戏
  16. unity无光照着色器(顶点片元着色器)使用TAA抗锯齿后角色移动时模糊(虚影)解决方案
  17. 如何重新启动Windows的Explorer.exe(以及任务栏和“开始”菜单)
  18. BlackHat2020议题之Web缓存投毒
  19. java汉字转拼音区别多音字_java中文转拼音,支持多音字词组,不支持音标
  20. 计算机gt是什么单位,数据存储计量单位除了BKMGT,还有什么?换算..._注册计量师_帮考网...

热门文章

  1. 2020年节假日JSON,全年日期对应的上班日、周末、节假日
  2. 光伏板怎么申请ASTM E108阻燃测试?
  3. 19行列式公式和代数余子式
  4. 走过30年岁月的WPS,它的复兴之路该怎么走
  5. LiveData 源码解析(2.4.1 版本)
  6. 《肖申克的救赎》- 阅后小记
  7. 路由器刷机解决学校无线上网问题(小米4A千兆版)
  8. 赫兹的单位换算_「频率单位」CPU频率和单位换算 - seo实验室
  9. build.prop文件详细赏析
  10. Java 实现word、excel、ppt、txt等办公文件在线预览功能!