JFinal+Quartz动态任务调度控制台

来源:互联网 发布:pla 算法初始化 编辑:程序博客网 时间:2024/03/28 18:07

前言】因为项目需要后台动态调度远程服务的任务,其中动态调度选用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 DynamicJob3 implements Job {    @Override    public void execute(JobExecutionContext context) throws JobExecutionException {        System.out.println("任务3:"+DateUtil.dateFormat(new Date(), "yyyyMMddHHmmss"));    }}

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

任务表

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模式了。

原创粉丝点击