diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@ + + diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@ + + diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@ + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl deleted file mode 100644 index 6aaf3b3..0000000 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl +++ /dev/null @@ -1,224 +0,0 @@ - - - - 调度中心 - <#import "/common/common.macro.ftl" as netCommon> - <@netCommon.commonStyle /> - - - - - -
- - <@netCommon.commonHeader /> - - <@netCommon.commonLeft /> - - -
- -
-

调度管理调度中心

- -
- - -
- -
-
-
- - jobName - - -
-
-
- -
-
- -
-
- -
-
-
-
-

调度列表

-
-
- - - - - - - - - - - - - - - - <#-- - <#if jobList?exists && jobList?size gt 0> - <#list jobList as item> - - - - - - - - - - - - --> - - -
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} - <#assign jobDataMap = item['JobDetail'].jobDataMap /> - <#if jobDataMap?exists && jobDataMap?keys?size gt 0> - <#list jobDataMap?keys as key> - ${key} = ${jobDataMap[key]}
- - -
- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - <#else> - - - -

- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - - - - - -

-
-
-
-
-
-
-
- - - <@netCommon.commonFooter /> -
- - - - - - - -<@netCommon.commonScript /> -<@netCommon.comAlert /> - - - - - - - - - - - diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@
+ + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl deleted file mode 100644 index 6aaf3b3..0000000 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl +++ /dev/null @@ -1,224 +0,0 @@ - - - - 调度中心 - <#import "/common/common.macro.ftl" as netCommon> - <@netCommon.commonStyle /> - - - - - -
- - <@netCommon.commonHeader /> - - <@netCommon.commonLeft /> - - -
- -
-

调度管理调度中心

- -
- - -
- -
-
-
- - jobName - - -
-
-
- -
-
- -
-
- -
-
-
-
-

调度列表

-
-
- - - - - - - - - - - - - - - - <#-- - <#if jobList?exists && jobList?size gt 0> - <#list jobList as item> - - - - - - - - - - - - --> - - -
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} - <#assign jobDataMap = item['JobDetail'].jobDataMap /> - <#if jobDataMap?exists && jobDataMap?keys?size gt 0> - <#list jobDataMap?keys as key> - ${key} = ${jobDataMap[key]}
- - -
- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - <#else> - - - -

- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - - - - - -

-
-
-
-
-
-
-
- - - <@netCommon.commonFooter /> -
- - - - - - - -<@netCommon.commonScript /> -<@netCommon.comAlert /> - - - - - - - - - - - diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl new file mode 100644 index 0000000..0f0b385 --- /dev/null +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl @@ -0,0 +1,242 @@ + + + + 调度中心 + <#import "/common/common.macro.ftl" as netCommon> + <@netCommon.commonStyle /> + + + + + +
+ + <@netCommon.commonHeader /> + + <@netCommon.commonLeft /> + + +
+ +
+

调度管理调度中心

+ +
+ + +
+ +
+
+
+ 任务组 + +
+
+
+
+ + jobName + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
+

调度列表

+
+
+ + + + + + + + + + + + + + + + <#-- + <#if jobList?exists && jobList?size gt 0> + <#list jobList as item> + + + + + + + + + + + + --> + + +
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} + <#assign jobDataMap = item['JobDetail'].jobDataMap /> + <#if jobDataMap?exists && jobDataMap?keys?size gt 0> + <#list jobDataMap?keys as key> + ${key} = ${jobDataMap[key]}
+ + +
+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + <#else> + + + +

+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + + + + + +

+
+
+
+
+
+
+
+ + + <@netCommon.commonFooter /> +
+ + + + + + + +<@netCommon.commonScript /> +<@netCommon.comAlert /> + + + + + + + + + + + diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@
+ + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl deleted file mode 100644 index 6aaf3b3..0000000 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl +++ /dev/null @@ -1,224 +0,0 @@ - - - - 调度中心 - <#import "/common/common.macro.ftl" as netCommon> - <@netCommon.commonStyle /> - - - - - -
- - <@netCommon.commonHeader /> - - <@netCommon.commonLeft /> - - -
- -
-

调度管理调度中心

- -
- - -
- -
-
-
- - jobName - - -
-
-
- -
-
- -
-
- -
-
-
-
-

调度列表

-
-
- - - - - - - - - - - - - - - - <#-- - <#if jobList?exists && jobList?size gt 0> - <#list jobList as item> - - - - - - - - - - - - --> - - -
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} - <#assign jobDataMap = item['JobDetail'].jobDataMap /> - <#if jobDataMap?exists && jobDataMap?keys?size gt 0> - <#list jobDataMap?keys as key> - ${key} = ${jobDataMap[key]}
- - -
- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - <#else> - - - -

- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - - - - - -

-
-
-
-
-
-
-
- - - <@netCommon.commonFooter /> -
- - - - - - - -<@netCommon.commonScript /> -<@netCommon.comAlert /> - - - - - - - - - - - diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl new file mode 100644 index 0000000..0f0b385 --- /dev/null +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl @@ -0,0 +1,242 @@ + + + + 调度中心 + <#import "/common/common.macro.ftl" as netCommon> + <@netCommon.commonStyle /> + + + + + +
+ + <@netCommon.commonHeader /> + + <@netCommon.commonLeft /> + + +
+ +
+

调度管理调度中心

+ +
+ + +
+ +
+
+
+ 任务组 + +
+
+
+
+ + jobName + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
+

调度列表

+
+
+ + + + + + + + + + + + + + + + <#-- + <#if jobList?exists && jobList?size gt 0> + <#list jobList as item> + + + + + + + + + + + + --> + + +
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} + <#assign jobDataMap = item['JobDetail'].jobDataMap /> + <#if jobDataMap?exists && jobDataMap?keys?size gt 0> + <#list jobDataMap?keys as key> + ${key} = ${jobDataMap[key]}
+ + +
+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + <#else> + + + +

+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + + + + + +

+
+
+
+
+
+
+
+ + + <@netCommon.commonFooter /> +
+ + + + + + + +<@netCommon.commonScript /> +<@netCommon.comAlert /> + + + + + + + + + + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl index ce141da..b5ba01d 100644 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl @@ -30,23 +30,33 @@
-
+
+
+ 任务组 + +
+
+
+
+ 任务名 + +
+
+
调度时间 + value2="<#if triggerTimeStart?exists && triggerTimeEnd?exists >${triggerTimeStart?if_exists?string('yyyy-MM-dd HH:mm:ss')} - ${triggerTimeEnd?if_exists?string('yyyy-MM-dd HH:mm:ss')}" >
-
-
- - jobName - - -
-
+ +
@@ -60,17 +70,18 @@ - - - - - - - - - - - + + + + + + + + + + + + diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@ + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl deleted file mode 100644 index 6aaf3b3..0000000 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl +++ /dev/null @@ -1,224 +0,0 @@ - - - - 调度中心 - <#import "/common/common.macro.ftl" as netCommon> - <@netCommon.commonStyle /> - - - - - -
- - <@netCommon.commonHeader /> - - <@netCommon.commonLeft /> - - -
- -
-

调度管理调度中心

- -
- - -
- -
-
-
- - jobName - - -
-
-
- -
-
- -
-
- -
-
-
-
-

调度列表

-
-
-
idjobNamejobCronjobClassjobDatatriggerTimetriggerStatustriggerMsghandleTimehandleStatushandleMsgid任务组任务名CronJobBean任务数据调度时间调度结果调度日志执行时间执行结果执行日志
- - - - - - - - - - - - - - - <#-- - <#if jobList?exists && jobList?size gt 0> - <#list jobList as item> - - - - - - - - - - - - --> - - -
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} - <#assign jobDataMap = item['JobDetail'].jobDataMap /> - <#if jobDataMap?exists && jobDataMap?keys?size gt 0> - <#list jobDataMap?keys as key> - ${key} = ${jobDataMap[key]}
- - -
- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - <#else> - - - -

- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - - - - - -

-
-
-
- - -
- - - - <@netCommon.commonFooter /> - - - - - - - - -<@netCommon.commonScript /> -<@netCommon.comAlert /> - - - - - - - - - - - diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl new file mode 100644 index 0000000..0f0b385 --- /dev/null +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl @@ -0,0 +1,242 @@ + + + + 调度中心 + <#import "/common/common.macro.ftl" as netCommon> + <@netCommon.commonStyle /> + + + + + +
+ + <@netCommon.commonHeader /> + + <@netCommon.commonLeft /> + + +
+ +
+

调度管理调度中心

+ +
+ + +
+ +
+
+
+ 任务组 + +
+
+
+
+ + jobName + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
+

调度列表

+
+
+ + + + + + + + + + + + + + + + <#-- + <#if jobList?exists && jobList?size gt 0> + <#list jobList as item> + + + + + + + + + + + + --> + + +
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} + <#assign jobDataMap = item['JobDetail'].jobDataMap /> + <#if jobDataMap?exists && jobDataMap?keys?size gt 0> + <#list jobDataMap?keys as key> + ${key} = ${jobDataMap[key]}
+ + +
+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + <#else> + + + +

+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + + + + + +

+
+
+
+
+
+
+
+ + + <@netCommon.commonFooter /> +
+ + + + + + + +<@netCommon.commonScript /> +<@netCommon.comAlert /> + + + + + + + + + + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl index ce141da..b5ba01d 100644 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl @@ -30,23 +30,33 @@
-
+
+
+ 任务组 + +
+
+
+
+ 任务名 + +
+
+
调度时间 + value2="<#if triggerTimeStart?exists && triggerTimeEnd?exists >${triggerTimeStart?if_exists?string('yyyy-MM-dd HH:mm:ss')} - ${triggerTimeEnd?if_exists?string('yyyy-MM-dd HH:mm:ss')}" >
-
-
- - jobName - - -
-
+ +
@@ -60,17 +70,18 @@ - - - - - - - - - - - + + + + + + + + + + + + diff --git a/xxl-job-admin/src/main/webapp/static/js/job.index.1.js b/xxl-job-admin/src/main/webapp/static/js/job.index.1.js deleted file mode 100644 index 256ba22..0000000 --- a/xxl-job-admin/src/main/webapp/static/js/job.index.1.js +++ /dev/null @@ -1,379 +0,0 @@ -$(function() { - // init date tables - var jobTable = $("#job_list").dataTable({ - "deferRender": true, - "processing" : true, - "serverSide": true, - "ajax": { - url: base_url + "/job/pageList", - data : function ( d ) { - d.jobName = $('#jobName').val() - } - }, - //"scrollX": true, // X轴滚动条,取消自适应 - "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, - { "data": 'jobName', "bSortable": false}, - { "data": 'jobCron', "bSortable": false, "visible" : true}, - { "data": 'jobClass', "bSortable": false, "visible" : false}, - { "data": 'jobStatus', "bSortable": false, "visible" : true}, - { "data": 'jobData', "bSortable": false, "visible" : true}, - { - "data": 'addTime', - "bSortable": false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { - "data": 'updateTime', - "bSortable": false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { "data": '操作' , "bSortable": false, - "render": function ( data, type, row ) { - return function(){ - // status - var pause_resume = ""; - if ('NORMAL' == row.jobStatus) { - pause_resume = ' '; - } else if ('PAUSED' == row.jobStatus){ - pause_resume = ' '; - } - // log url - var logUrl = base_url +'/joblog?jobName='+ row.jobName; - - // job data - var jobDataMap = eval('(' + row.jobData + ')'); - - var html = '

'+ - pause_resume + - ' '+ - ' '+ - ' '+ - ''+ - '

'; - - - return html; - }; - } - } - ], - "searching": false, - "ordering": true, - "language" : { - "sProcessing" : "处理中...", - "sLengthMenu" : "每页 _MENU_ 条记录", - "sZeroRecords" : "没有匹配结果", - "sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页 )", - "sInfoEmpty" : "无记录", - "sInfoFiltered" : "(由 _MAX_ 项结果过滤)", - "sInfoPostFix" : "", - "sSearch" : "搜索:", - "sUrl" : "", - "sEmptyTable" : "表中数据为空", - "sLoadingRecords" : "载入中...", - "sInfoThousands" : ",", - "oPaginate" : { - "sFirst" : "首页", - "sPrevious" : "上页", - "sNext" : "下页", - "sLast" : "末页" - }, - "oAria" : { - "sSortAscending" : ": 以升序排列此列", - "sSortDescending" : ": 以降序排列此列" - } - } - }); - - // 搜索按钮 - $('#searchBtn').on('click', function(){ - jobTable.fnDraw(); - }); - - // job operate - $("#job_list").on('click', '.job_operate',function() { - var typeName; - var url; - var type = $(this).attr("type"); - if ("job_pause" == type) { - typeName = "暂停"; - url = base_url + "/job/pause"; - } else if ("job_resume" == type) { - typeName = "恢复"; - url = base_url + "/job/resume"; - } else if ("job_del" == type) { - typeName = "删除"; - url = base_url + "/job/remove"; - } else if ("job_trigger" == type) { - typeName = "执行一次"; - url = base_url + "/job/trigger"; - } else { - return; - } - - var name = $(this).parent('p').attr("jobName"); - - ComConfirm.show("确认" + typeName + "?", function(){ - $.ajax({ - type : 'POST', - url : url, - data : { - "triggerKeyName" : name - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - ComAlert.show(1, typeName + "成功", function(){ - //window.location.reload(); - jobTable.fnDraw(); - }); - } else { - ComAlert.show(1, typeName + "失败"); - } - }, - }); - }); - }); - - // jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线” - jQuery.validator.addMethod("myValid01", function(value, element) { - var length = value.length; - var valid = /^[a-zA-Z][a-zA-Z0-9_]*$/; - return this.optional(element) || valid.test(value); - }, "只支持英文字母开头,只含有英文字母、数字和下划线"); - - // 新增 - $(".add").click(function(){ - $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var addModalValidate = $("#addModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - triggerKeyName : { - required : true , - minlength: 4, - maxlength: 100, - myValid01:true - }, - cronExpression : { - required : true , - maxlength: 100 - }, - job_desc : { - required : true , - maxlength: 200 - }, - job_url : { - required : true , - maxlength: 200 - }, - handleName : { - required : true , - maxlength: 200 - } - }, - messages : { - triggerKeyName : { - required :"请输入“任务Key”." , - minlength:"“任务Key”长度不应低于4位", - maxlength:"“任务Key”长度不应超过100位" - }, - cronExpression : { - required :"请输入“任务Corn”." , - maxlength:"“任务Corn”长度不应超过100位" - }, - job_desc : { - required :"请输入“任务描述”." , - maxlength:"“任务描述”长度不应超过200位" - }, - job_url : { - required :"请输入“任务URL”." , - maxlength:"“任务URL”长度不应超过200位" - }, - handleName : { - required : "请输入“任务handler”." , - maxlength: "“任务handler”长度不应超过200位" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - - var triggerKeyName = $('#addModal input[name="triggerKeyName"]').val(); - var cronExpression = $('#addModal input[name="cronExpression"]').val(); - var job_desc = $('#addModal input[name="job_desc"]').val(); - var job_url = $('#addModal input[name="job_url"]').val(); - var handleName = $('#addModal input[name="handleName"]').val(); - - var paramStr = 'triggerKeyName=' + triggerKeyName + - '&cronExpression=' + cronExpression + - '&job_desc=' + job_desc + - '&job_url=' + job_url + - '&handleName=' + handleName; - - var ifFin = true; - $('#addModal .newParam').each(function(){ - ifFin = false; - var key = $(this).find('input[name="key"]').val(); - var value = $(this).find('input[name="value"]').val(); - if (!key) { - ComAlert.show(2, "新增参数key不可为空"); - return; - } else { - if(!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)){ - ComAlert.show(2, "新增参数key不合法, 只支持英文字母开头,只含有英文字母、数字和下划线"); - return; - } - } - paramStr += "&" + key + "=" + value; - ifFin = true; - }); - - if(ifFin){ - $.post(base_url + "/job/add", paramStr, function(data, status) { - if (data.code == "200") { - ComAlert.show(1, "新增调度任务成功", function(){ - window.location.reload(); - }); - } else { - if (data.msg) { - ComAlert.show(2, data.msg); - } else { - ComAlert.show(2, "新增失败"); - } - } - }); - } - } - }); - $("#addModal").on('hide.bs.modal', function () { - //$("#addModal .form")[0].reset(); - addModalValidate.resetForm(); - $("#addModal .form .form-group").removeClass("has-error"); - }); - - // 新增-添加参数 - $("#addModal .addParam").on('click', function () { - var html = '
'+ - ''+ - '
'+ - '
'+ - '
'; - $(this).parents('.form-group').parent().append(html); - - $("#addModal .removeParam").on('click', function () { - $(this).parents('.form-group').remove(); - }); - }); - - // 更新 - $("#job_list").on('click', '.update',function() { - $("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("jobName")); - $("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression")); - $("#updateModal .form input[name='job_desc']").val($(this).parent('p').attr("job_desc")); - $("#updateModal .form input[name='job_url']").val($(this).parent('p').attr("job_url")); - $("#updateModal .form input[name='handleName']").val($(this).parent('p').attr("handleName")); - $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var updateModalValidate = $("#updateModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - triggerKeyName : { - required : true , - minlength: 4, - maxlength: 100 - }, - cronExpression : { - required : true , - maxlength: 100 - }, - job_desc : { - required : true , - maxlength: 200 - }, - job_url : { - required : true , - maxlength: 200 - }, - handleName : { - required : true , - maxlength: 200 - } - }, - messages : { - triggerKeyName : { - required :"请输入“任务Key”." , - minlength:"“任务Key”不应低于4位", - maxlength:"“任务Key”不应超过100位" - }, - cronExpression : { - required :"请输入“任务Corn”." , - maxlength:"“任务Corn”不应超过100位" - }, - job_desc : { - required :"请输入“任务描述”." , - maxlength:"“任务描述”长度不应超过200位" - }, - job_url : { - required :"请输入“任务URL”." , - maxlength:"“任务URL”长度不应超过200位" - }, - handleName : { - required : "请输入“任务handler”." , - maxlength: "“任务handler”长度不应超过200位" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - $.post(base_url + "/job/reschedule", $("#updateModal .form").serialize(), function(data, status) { - if (data.code == "200") { - ComAlert.show(1, "更新成功", function(){ - window.location.reload(); - }); - } else { - if (data.msg) { - ComAlert.show(2, data.msg); - } else { - ComAlert.show(2, "更新失败"); - } - } - }); - } - }); - $("#updateModal").on('hide.bs.modal', function () { - $("#updateModal .form")[0].reset() - }); - -}); diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@ + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl deleted file mode 100644 index 6aaf3b3..0000000 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl +++ /dev/null @@ -1,224 +0,0 @@ - - - - 调度中心 - <#import "/common/common.macro.ftl" as netCommon> - <@netCommon.commonStyle /> - - - - - -
- - <@netCommon.commonHeader /> - - <@netCommon.commonLeft /> - - -
- -
-

调度管理调度中心

- -
- - -
- -
-
-
- - jobName - - -
-
-
- -
-
- -
-
- -
-
-
-
-

调度列表

-
-
-
idjobNamejobCronjobClassjobDatatriggerTimetriggerStatustriggerMsghandleTimehandleStatushandleMsgid任务组任务名CronJobBean任务数据调度时间调度结果调度日志执行时间执行结果执行日志
- - - - - - - - - - - - - - - <#-- - <#if jobList?exists && jobList?size gt 0> - <#list jobList as item> - - - - - - - - - - - - --> - - -
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} - <#assign jobDataMap = item['JobDetail'].jobDataMap /> - <#if jobDataMap?exists && jobDataMap?keys?size gt 0> - <#list jobDataMap?keys as key> - ${key} = ${jobDataMap[key]}
- - -
- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - <#else> - - - -

- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - - - - - -

-
-
-
- - -
- - - - <@netCommon.commonFooter /> - - - - - - - - -<@netCommon.commonScript /> -<@netCommon.comAlert /> - - - - - - - - - - - diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl new file mode 100644 index 0000000..0f0b385 --- /dev/null +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl @@ -0,0 +1,242 @@ + + + + 调度中心 + <#import "/common/common.macro.ftl" as netCommon> + <@netCommon.commonStyle /> + + + + + +
+ + <@netCommon.commonHeader /> + + <@netCommon.commonLeft /> + + +
+ +
+

调度管理调度中心

+ +
+ + +
+ +
+
+
+ 任务组 + +
+
+
+
+ + jobName + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
+

调度列表

+
+
+ + + + + + + + + + + + + + + + <#-- + <#if jobList?exists && jobList?size gt 0> + <#list jobList as item> + + + + + + + + + + + + --> + + +
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} + <#assign jobDataMap = item['JobDetail'].jobDataMap /> + <#if jobDataMap?exists && jobDataMap?keys?size gt 0> + <#list jobDataMap?keys as key> + ${key} = ${jobDataMap[key]}
+ + +
+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + <#else> + + + +

+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + + + + + +

+
+
+
+
+
+
+
+ + + <@netCommon.commonFooter /> +
+ + + + + + + +<@netCommon.commonScript /> +<@netCommon.comAlert /> + + + + + + + + + + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl index ce141da..b5ba01d 100644 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl @@ -30,23 +30,33 @@
-
+
+
+ 任务组 + +
+
+
+
+ 任务名 + +
+
+
调度时间 + value2="<#if triggerTimeStart?exists && triggerTimeEnd?exists >${triggerTimeStart?if_exists?string('yyyy-MM-dd HH:mm:ss')} - ${triggerTimeEnd?if_exists?string('yyyy-MM-dd HH:mm:ss')}" >
-
-
- - jobName - - -
-
+ +
@@ -60,17 +70,18 @@ - - - - - - - - - - - + + + + + + + + + + + + diff --git a/xxl-job-admin/src/main/webapp/static/js/job.index.1.js b/xxl-job-admin/src/main/webapp/static/js/job.index.1.js deleted file mode 100644 index 256ba22..0000000 --- a/xxl-job-admin/src/main/webapp/static/js/job.index.1.js +++ /dev/null @@ -1,379 +0,0 @@ -$(function() { - // init date tables - var jobTable = $("#job_list").dataTable({ - "deferRender": true, - "processing" : true, - "serverSide": true, - "ajax": { - url: base_url + "/job/pageList", - data : function ( d ) { - d.jobName = $('#jobName').val() - } - }, - //"scrollX": true, // X轴滚动条,取消自适应 - "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, - { "data": 'jobName', "bSortable": false}, - { "data": 'jobCron', "bSortable": false, "visible" : true}, - { "data": 'jobClass', "bSortable": false, "visible" : false}, - { "data": 'jobStatus', "bSortable": false, "visible" : true}, - { "data": 'jobData', "bSortable": false, "visible" : true}, - { - "data": 'addTime', - "bSortable": false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { - "data": 'updateTime', - "bSortable": false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { "data": '操作' , "bSortable": false, - "render": function ( data, type, row ) { - return function(){ - // status - var pause_resume = ""; - if ('NORMAL' == row.jobStatus) { - pause_resume = ' '; - } else if ('PAUSED' == row.jobStatus){ - pause_resume = ' '; - } - // log url - var logUrl = base_url +'/joblog?jobName='+ row.jobName; - - // job data - var jobDataMap = eval('(' + row.jobData + ')'); - - var html = '

'+ - pause_resume + - ' '+ - ' '+ - ' '+ - ''+ - '

'; - - - return html; - }; - } - } - ], - "searching": false, - "ordering": true, - "language" : { - "sProcessing" : "处理中...", - "sLengthMenu" : "每页 _MENU_ 条记录", - "sZeroRecords" : "没有匹配结果", - "sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页 )", - "sInfoEmpty" : "无记录", - "sInfoFiltered" : "(由 _MAX_ 项结果过滤)", - "sInfoPostFix" : "", - "sSearch" : "搜索:", - "sUrl" : "", - "sEmptyTable" : "表中数据为空", - "sLoadingRecords" : "载入中...", - "sInfoThousands" : ",", - "oPaginate" : { - "sFirst" : "首页", - "sPrevious" : "上页", - "sNext" : "下页", - "sLast" : "末页" - }, - "oAria" : { - "sSortAscending" : ": 以升序排列此列", - "sSortDescending" : ": 以降序排列此列" - } - } - }); - - // 搜索按钮 - $('#searchBtn').on('click', function(){ - jobTable.fnDraw(); - }); - - // job operate - $("#job_list").on('click', '.job_operate',function() { - var typeName; - var url; - var type = $(this).attr("type"); - if ("job_pause" == type) { - typeName = "暂停"; - url = base_url + "/job/pause"; - } else if ("job_resume" == type) { - typeName = "恢复"; - url = base_url + "/job/resume"; - } else if ("job_del" == type) { - typeName = "删除"; - url = base_url + "/job/remove"; - } else if ("job_trigger" == type) { - typeName = "执行一次"; - url = base_url + "/job/trigger"; - } else { - return; - } - - var name = $(this).parent('p').attr("jobName"); - - ComConfirm.show("确认" + typeName + "?", function(){ - $.ajax({ - type : 'POST', - url : url, - data : { - "triggerKeyName" : name - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - ComAlert.show(1, typeName + "成功", function(){ - //window.location.reload(); - jobTable.fnDraw(); - }); - } else { - ComAlert.show(1, typeName + "失败"); - } - }, - }); - }); - }); - - // jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线” - jQuery.validator.addMethod("myValid01", function(value, element) { - var length = value.length; - var valid = /^[a-zA-Z][a-zA-Z0-9_]*$/; - return this.optional(element) || valid.test(value); - }, "只支持英文字母开头,只含有英文字母、数字和下划线"); - - // 新增 - $(".add").click(function(){ - $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var addModalValidate = $("#addModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - triggerKeyName : { - required : true , - minlength: 4, - maxlength: 100, - myValid01:true - }, - cronExpression : { - required : true , - maxlength: 100 - }, - job_desc : { - required : true , - maxlength: 200 - }, - job_url : { - required : true , - maxlength: 200 - }, - handleName : { - required : true , - maxlength: 200 - } - }, - messages : { - triggerKeyName : { - required :"请输入“任务Key”." , - minlength:"“任务Key”长度不应低于4位", - maxlength:"“任务Key”长度不应超过100位" - }, - cronExpression : { - required :"请输入“任务Corn”." , - maxlength:"“任务Corn”长度不应超过100位" - }, - job_desc : { - required :"请输入“任务描述”." , - maxlength:"“任务描述”长度不应超过200位" - }, - job_url : { - required :"请输入“任务URL”." , - maxlength:"“任务URL”长度不应超过200位" - }, - handleName : { - required : "请输入“任务handler”." , - maxlength: "“任务handler”长度不应超过200位" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - - var triggerKeyName = $('#addModal input[name="triggerKeyName"]').val(); - var cronExpression = $('#addModal input[name="cronExpression"]').val(); - var job_desc = $('#addModal input[name="job_desc"]').val(); - var job_url = $('#addModal input[name="job_url"]').val(); - var handleName = $('#addModal input[name="handleName"]').val(); - - var paramStr = 'triggerKeyName=' + triggerKeyName + - '&cronExpression=' + cronExpression + - '&job_desc=' + job_desc + - '&job_url=' + job_url + - '&handleName=' + handleName; - - var ifFin = true; - $('#addModal .newParam').each(function(){ - ifFin = false; - var key = $(this).find('input[name="key"]').val(); - var value = $(this).find('input[name="value"]').val(); - if (!key) { - ComAlert.show(2, "新增参数key不可为空"); - return; - } else { - if(!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)){ - ComAlert.show(2, "新增参数key不合法, 只支持英文字母开头,只含有英文字母、数字和下划线"); - return; - } - } - paramStr += "&" + key + "=" + value; - ifFin = true; - }); - - if(ifFin){ - $.post(base_url + "/job/add", paramStr, function(data, status) { - if (data.code == "200") { - ComAlert.show(1, "新增调度任务成功", function(){ - window.location.reload(); - }); - } else { - if (data.msg) { - ComAlert.show(2, data.msg); - } else { - ComAlert.show(2, "新增失败"); - } - } - }); - } - } - }); - $("#addModal").on('hide.bs.modal', function () { - //$("#addModal .form")[0].reset(); - addModalValidate.resetForm(); - $("#addModal .form .form-group").removeClass("has-error"); - }); - - // 新增-添加参数 - $("#addModal .addParam").on('click', function () { - var html = '
'+ - ''+ - '
'+ - '
'+ - '
'; - $(this).parents('.form-group').parent().append(html); - - $("#addModal .removeParam").on('click', function () { - $(this).parents('.form-group').remove(); - }); - }); - - // 更新 - $("#job_list").on('click', '.update',function() { - $("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("jobName")); - $("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression")); - $("#updateModal .form input[name='job_desc']").val($(this).parent('p').attr("job_desc")); - $("#updateModal .form input[name='job_url']").val($(this).parent('p').attr("job_url")); - $("#updateModal .form input[name='handleName']").val($(this).parent('p').attr("handleName")); - $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var updateModalValidate = $("#updateModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - triggerKeyName : { - required : true , - minlength: 4, - maxlength: 100 - }, - cronExpression : { - required : true , - maxlength: 100 - }, - job_desc : { - required : true , - maxlength: 200 - }, - job_url : { - required : true , - maxlength: 200 - }, - handleName : { - required : true , - maxlength: 200 - } - }, - messages : { - triggerKeyName : { - required :"请输入“任务Key”." , - minlength:"“任务Key”不应低于4位", - maxlength:"“任务Key”不应超过100位" - }, - cronExpression : { - required :"请输入“任务Corn”." , - maxlength:"“任务Corn”不应超过100位" - }, - job_desc : { - required :"请输入“任务描述”." , - maxlength:"“任务描述”长度不应超过200位" - }, - job_url : { - required :"请输入“任务URL”." , - maxlength:"“任务URL”长度不应超过200位" - }, - handleName : { - required : "请输入“任务handler”." , - maxlength: "“任务handler”长度不应超过200位" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - $.post(base_url + "/job/reschedule", $("#updateModal .form").serialize(), function(data, status) { - if (data.code == "200") { - ComAlert.show(1, "更新成功", function(){ - window.location.reload(); - }); - } else { - if (data.msg) { - ComAlert.show(2, data.msg); - } else { - ComAlert.show(2, "更新失败"); - } - } - }); - } - }); - $("#updateModal").on('hide.bs.modal', function () { - $("#updateModal .form")[0].reset() - }); - -}); diff --git a/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js new file mode 100644 index 0000000..58f13ae --- /dev/null +++ b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js @@ -0,0 +1,379 @@ +$(function() { + // init date tables + var jobTable = $("#job_list").dataTable({ + "deferRender": true, + "processing" : true, + "serverSide": true, + "ajax": { + url: base_url + "/jobinfo/pageList", + data : function ( d ) { + d.jobName = $('#jobName').val() + } + }, + //"scrollX": true, // X轴滚动条,取消自适应 + "columns": [ + { "data": 'id', "bSortable": false, "visible" : false}, + { "data": 'jobName', "bSortable": false}, + { "data": 'jobCron', "bSortable": false, "visible" : true}, + { "data": 'jobClass', "bSortable": false, "visible" : false}, + { "data": 'jobStatus', "bSortable": false, "visible" : true}, + { "data": 'jobData', "bSortable": false, "visible" : true}, + { + "data": 'addTime', + "bSortable": false, + "render": function ( data, type, row ) { + return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; + } + }, + { + "data": 'updateTime', + "bSortable": false, + "render": function ( data, type, row ) { + return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; + } + }, + { "data": '操作' , "bSortable": false, + "render": function ( data, type, row ) { + return function(){ + // status + var pause_resume = ""; + if ('NORMAL' == row.jobStatus) { + pause_resume = ' '; + } else if ('PAUSED' == row.jobStatus){ + pause_resume = ' '; + } + // log url + var logUrl = base_url +'/joblog?jobName='+ row.jobName; + + // job data + var jobDataMap = eval('(' + row.jobData + ')'); + + var html = '

'+ + pause_resume + + ' '+ + ' '+ + ' '+ + ''+ + '

'; + + + return html; + }; + } + } + ], + "searching": false, + "ordering": true, + "language" : { + "sProcessing" : "处理中...", + "sLengthMenu" : "每页 _MENU_ 条记录", + "sZeroRecords" : "没有匹配结果", + "sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页 )", + "sInfoEmpty" : "无记录", + "sInfoFiltered" : "(由 _MAX_ 项结果过滤)", + "sInfoPostFix" : "", + "sSearch" : "搜索:", + "sUrl" : "", + "sEmptyTable" : "表中数据为空", + "sLoadingRecords" : "载入中...", + "sInfoThousands" : ",", + "oPaginate" : { + "sFirst" : "首页", + "sPrevious" : "上页", + "sNext" : "下页", + "sLast" : "末页" + }, + "oAria" : { + "sSortAscending" : ": 以升序排列此列", + "sSortDescending" : ": 以降序排列此列" + } + } + }); + + // 搜索按钮 + $('#searchBtn').on('click', function(){ + jobTable.fnDraw(); + }); + + // job operate + $("#job_list").on('click', '.job_operate',function() { + var typeName; + var url; + var type = $(this).attr("type"); + if ("job_pause" == type) { + typeName = "暂停"; + url = base_url + "/job/pause"; + } else if ("job_resume" == type) { + typeName = "恢复"; + url = base_url + "/job/resume"; + } else if ("job_del" == type) { + typeName = "删除"; + url = base_url + "/job/remove"; + } else if ("job_trigger" == type) { + typeName = "执行一次"; + url = base_url + "/job/trigger"; + } else { + return; + } + + var name = $(this).parent('p').attr("jobName"); + + ComConfirm.show("确认" + typeName + "?", function(){ + $.ajax({ + type : 'POST', + url : url, + data : { + "triggerKeyName" : name + }, + dataType : "json", + success : function(data){ + if (data.code == 200) { + ComAlert.show(1, typeName + "成功", function(){ + //window.location.reload(); + jobTable.fnDraw(); + }); + } else { + ComAlert.show(1, typeName + "失败"); + } + }, + }); + }); + }); + + // jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线” + jQuery.validator.addMethod("myValid01", function(value, element) { + var length = value.length; + var valid = /^[a-zA-Z][a-zA-Z0-9_]*$/; + return this.optional(element) || valid.test(value); + }, "只支持英文字母开头,只含有英文字母、数字和下划线"); + + // 新增 + $(".add").click(function(){ + $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); + }); + var addModalValidate = $("#addModal .form").validate({ + errorElement : 'span', + errorClass : 'help-block', + focusInvalid : true, + rules : { + triggerKeyName : { + required : true , + minlength: 4, + maxlength: 100, + myValid01:true + }, + cronExpression : { + required : true , + maxlength: 100 + }, + job_desc : { + required : true , + maxlength: 200 + }, + job_url : { + required : true , + maxlength: 200 + }, + handleName : { + required : true , + maxlength: 200 + } + }, + messages : { + triggerKeyName : { + required :"请输入“任务Key”." , + minlength:"“任务Key”长度不应低于4位", + maxlength:"“任务Key”长度不应超过100位" + }, + cronExpression : { + required :"请输入“任务Corn”." , + maxlength:"“任务Corn”长度不应超过100位" + }, + job_desc : { + required :"请输入“任务描述”." , + maxlength:"“任务描述”长度不应超过200位" + }, + job_url : { + required :"请输入“任务URL”." , + maxlength:"“任务URL”长度不应超过200位" + }, + handleName : { + required : "请输入“任务handler”." , + maxlength: "“任务handler”长度不应超过200位" + } + }, + highlight : function(element) { + $(element).closest('.form-group').addClass('has-error'); + }, + success : function(label) { + label.closest('.form-group').removeClass('has-error'); + label.remove(); + }, + errorPlacement : function(error, element) { + element.parent('div').append(error); + }, + submitHandler : function(form) { + + var triggerKeyName = $('#addModal input[name="triggerKeyName"]').val(); + var cronExpression = $('#addModal input[name="cronExpression"]').val(); + var job_desc = $('#addModal input[name="job_desc"]').val(); + var job_url = $('#addModal input[name="job_url"]').val(); + var handleName = $('#addModal input[name="handleName"]').val(); + + var paramStr = 'triggerKeyName=' + triggerKeyName + + '&cronExpression=' + cronExpression + + '&job_desc=' + job_desc + + '&job_url=' + job_url + + '&handleName=' + handleName; + + var ifFin = true; + $('#addModal .newParam').each(function(){ + ifFin = false; + var key = $(this).find('input[name="key"]').val(); + var value = $(this).find('input[name="value"]').val(); + if (!key) { + ComAlert.show(2, "新增参数key不可为空"); + return; + } else { + if(!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)){ + ComAlert.show(2, "新增参数key不合法, 只支持英文字母开头,只含有英文字母、数字和下划线"); + return; + } + } + paramStr += "&" + key + "=" + value; + ifFin = true; + }); + + if(ifFin){ + $.post(base_url + "/job/add", paramStr, function(data, status) { + if (data.code == "200") { + ComAlert.show(1, "新增调度任务成功", function(){ + window.location.reload(); + }); + } else { + if (data.msg) { + ComAlert.show(2, data.msg); + } else { + ComAlert.show(2, "新增失败"); + } + } + }); + } + } + }); + $("#addModal").on('hide.bs.modal', function () { + //$("#addModal .form")[0].reset(); + addModalValidate.resetForm(); + $("#addModal .form .form-group").removeClass("has-error"); + }); + + // 新增-添加参数 + $("#addModal .addParam").on('click', function () { + var html = '
'+ + ''+ + '
'+ + '
'+ + '
'; + $(this).parents('.form-group').parent().append(html); + + $("#addModal .removeParam").on('click', function () { + $(this).parents('.form-group').remove(); + }); + }); + + // 更新 + $("#job_list").on('click', '.update',function() { + $("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("jobName")); + $("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression")); + $("#updateModal .form input[name='job_desc']").val($(this).parent('p').attr("job_desc")); + $("#updateModal .form input[name='job_url']").val($(this).parent('p').attr("job_url")); + $("#updateModal .form input[name='handleName']").val($(this).parent('p').attr("handleName")); + $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); + }); + var updateModalValidate = $("#updateModal .form").validate({ + errorElement : 'span', + errorClass : 'help-block', + focusInvalid : true, + rules : { + triggerKeyName : { + required : true , + minlength: 4, + maxlength: 100 + }, + cronExpression : { + required : true , + maxlength: 100 + }, + job_desc : { + required : true , + maxlength: 200 + }, + job_url : { + required : true , + maxlength: 200 + }, + handleName : { + required : true , + maxlength: 200 + } + }, + messages : { + triggerKeyName : { + required :"请输入“任务Key”." , + minlength:"“任务Key”不应低于4位", + maxlength:"“任务Key”不应超过100位" + }, + cronExpression : { + required :"请输入“任务Corn”." , + maxlength:"“任务Corn”不应超过100位" + }, + job_desc : { + required :"请输入“任务描述”." , + maxlength:"“任务描述”长度不应超过200位" + }, + job_url : { + required :"请输入“任务URL”." , + maxlength:"“任务URL”长度不应超过200位" + }, + handleName : { + required : "请输入“任务handler”." , + maxlength: "“任务handler”长度不应超过200位" + } + }, + highlight : function(element) { + $(element).closest('.form-group').addClass('has-error'); + }, + success : function(label) { + label.closest('.form-group').removeClass('has-error'); + label.remove(); + }, + errorPlacement : function(error, element) { + element.parent('div').append(error); + }, + submitHandler : function(form) { + $.post(base_url + "/job/reschedule", $("#updateModal .form").serialize(), function(data, status) { + if (data.code == "200") { + ComAlert.show(1, "更新成功", function(){ + window.location.reload(); + }); + } else { + if (data.msg) { + ComAlert.show(2, data.msg); + } else { + ComAlert.show(2, "更新失败"); + } + } + }); + } + }); + $("#updateModal").on('hide.bs.modal', function () { + $("#updateModal .form")[0].reset() + }); + +}); diff --git a/README.md b/README.md index b10ef4f..0b45a70 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job 博客地址(内附使用教程):http://www.cnblogs.com/xuxueli/p/5021979.html + +技术交流群(仅作技术交流):367260654 # 特点:基于quartz封装实现的的集群任务调度管理平台 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手; diff --git a/doc/db/tables_xxl_log.sql b/doc/db/tables_xxl_log.sql index 6af3e0a..867b328 100644 --- a/doc/db/tables_xxl_log.sql +++ b/doc/db/tables_xxl_log.sql @@ -10,6 +10,7 @@ # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`; +# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`; CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS ( @@ -158,18 +159,35 @@ CREATE TABLE `xxl_job_qrtz_trigger_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `job_name` varchar(255) NOT NULL, - `job_cron` varchar(128) DEFAULT NULL, - `job_class` varchar(255) DEFAULT NULL, - `job_data` varchar(2048) DEFAULT NULL, - `trigger_time` datetime DEFAULT NULL, - `trigger_status` varchar(255) DEFAULT NULL, - `trigger_msg` varchar(2048) DEFAULT NULL, - `handle_time` datetime DEFAULT NULL, - `handle_status` varchar(255) DEFAULT NULL, - `handle_msg` varchar(2048) DEFAULT NULL, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8; +); + +CREATE TABLE `xxl_job_qrtz_trigger_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_group` varchar(255) NOT NULL COMMENT '任务组', + `job_name` varchar(255) NOT NULL COMMENT '任务名', + `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', + `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', + `job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', + `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', + `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', + `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', + `handle_time` datetime DEFAULT NULL COMMENT '执行-时间', + `handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', + `handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志', + PRIMARY KEY (`id`) +); commit; diff --git a/xxl-job-admin/pom.xml b/xxl-job-admin/pom.xml index 4fd7a6d..b621579 100644 --- a/xxl-job-admin/pom.xml +++ b/xxl-job-admin/pom.xml @@ -127,7 +127,7 @@ org.quartz-scheduler quartz - 2.2.1 + 2.2.2 diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java index caffe29..d73c4ca 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/IndexController.java @@ -13,7 +13,7 @@ @RequestMapping("/") public String index(Model model) { - return "redirect:job"; + return "redirect:jobinfo"; } @RequestMapping("/help") diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java deleted file mode 100644 index 2a3b941..0000000 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java +++ /dev/null @@ -1,239 +0,0 @@ -package com.xxl.job.controller; - -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang.StringUtils; -import org.quartz.CronExpression; -import org.quartz.Job; -import org.quartz.SchedulerException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; - -import com.xxl.job.client.handler.HandlerRepository; -import com.xxl.job.client.util.JacksonUtil; -import com.xxl.job.core.model.ReturnT; -import com.xxl.job.core.model.XxlJobInfo; -import com.xxl.job.core.util.DynamicSchedulerUtil; -import com.xxl.job.dao.IXxlJobInfoDao; -import com.xxl.job.service.job.HttpJobBean; - -/** - * index controller - * @author xuxueli 2015-12-19 16:13:16 - */ -@Controller -@RequestMapping("/job") -public class JobController { - - @Resource - private IXxlJobInfoDao xxlJobInfoDao; - - @RequestMapping - public String index(Model model) { - //List> jobList = DynamicSchedulerUtil.getJobList(); - //model.addAttribute("jobList", jobList); - return "job/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - - // page list - List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); - int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); - - // fill job info - if (list!=null && list.size()>0) { - for (XxlJobInfo jobInfo : list) { - DynamicSchedulerUtil.fillJobInfo(jobInfo); - } - } - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count); // 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - - @RequestMapping("/add") - @ResponseBody - public ReturnT add(HttpServletRequest request) { - String triggerKeyName = null; - String cronExpression = null; - Map jobData = new HashMap(); - - try { - request.setCharacterEncoding("utf-8"); - } catch (UnsupportedEncodingException e1) { - e1.printStackTrace(); - } - @SuppressWarnings("unchecked") - Set> paramSet = request.getParameterMap().entrySet(); - for (Entry param : paramSet) { - if (param.getKey().equals("triggerKeyName")) { - triggerKeyName = param.getValue()[0]; - } else if (param.getKey().equals("cronExpression")) { - cronExpression = param.getValue()[0]; - } else { - jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); - } - } - - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - - // jobData - if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务描述”"); - } - if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务URL”"); - } - if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { - return new ReturnT(500, "请输入“任务handler”"); - } - - // jobClass - Class jobClass = HttpJobBean.class; - - try { - // add job 2 quartz - boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); - if (!result) { - return new ReturnT(500, "任务ID重复,请更换确认"); - } - // Backup to the database - XxlJobInfo jobInfo = new XxlJobInfo(); - jobInfo.setJobName(triggerKeyName); - jobInfo.setJobCron(cronExpression); - jobInfo.setJobClass(jobClass.getName()); - jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); - xxlJobInfoDao.save(jobInfo); - - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/reschedule") - @ResponseBody - public ReturnT reschedule(String triggerKeyName, String cronExpression) { - // triggerKeyName - if (StringUtils.isBlank(triggerKeyName)) { - return new ReturnT(500, "请输入“任务key”"); - } - // cronExpression - if (StringUtils.isBlank(cronExpression)) { - return new ReturnT(500, "请输入“任务corn”"); - } - if (!CronExpression.isValidExpression(cronExpression)) { - return new ReturnT(500, "“任务corn”不合法"); - } - try { - DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); - - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobCron(cronExpression); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/remove") - @ResponseBody - public ReturnT remove(String triggerKeyName) { - try { - if (triggerKeyName!=null) { - DynamicSchedulerUtil.removeJob(triggerKeyName); - xxlJobInfoDao.delete(triggerKeyName); - return ReturnT.SUCCESS; - } - } catch (SchedulerException e) { - e.printStackTrace(); - } - return ReturnT.FAIL; - } - - @RequestMapping("/pause") - @ResponseBody - public ReturnT pause(String triggerKeyName) { - try { - DynamicSchedulerUtil.pauseJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("PAUSED"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/resume") - @ResponseBody - public ReturnT resume(String triggerKeyName) { - try { - DynamicSchedulerUtil.resumeJob(triggerKeyName); - // update - XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); - if (jobInfo!=null) { - jobInfo.setJobStatus("NORMAL"); - xxlJobInfoDao.update(jobInfo); - } - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - - @RequestMapping("/trigger") - @ResponseBody - public ReturnT triggerJob(String triggerKeyName) { - try { - DynamicSchedulerUtil.triggerJob(triggerKeyName); - return ReturnT.SUCCESS; - } catch (SchedulerException e) { - e.printStackTrace(); - return ReturnT.FAIL; - } - } - -} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java new file mode 100644 index 0000000..128916a --- /dev/null +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java @@ -0,0 +1,239 @@ +package com.xxl.job.controller; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.lang.StringUtils; +import org.quartz.CronExpression; +import org.quartz.Job; +import org.quartz.SchedulerException; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.xxl.job.client.handler.HandlerRepository; +import com.xxl.job.client.util.JacksonUtil; +import com.xxl.job.core.constant.Constants.JobGroupEnum; +import com.xxl.job.core.model.ReturnT; +import com.xxl.job.core.model.XxlJobInfo; +import com.xxl.job.core.util.DynamicSchedulerUtil; +import com.xxl.job.dao.IXxlJobInfoDao; +import com.xxl.job.service.job.HttpJobBean; + +/** + * index controller + * @author xuxueli 2015-12-19 16:13:16 + */ +@Controller +@RequestMapping("/jobinfo") +public class JobInfoController { + + @Resource + private IXxlJobInfoDao xxlJobInfoDao; + + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "jobinfo/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobName, String filterTime) { + + // page list + List list = xxlJobInfoDao.pageList(start, length, jobName, null, null); + int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null); + + // fill job info + if (list!=null && list.size()>0) { + for (XxlJobInfo jobInfo : list) { + DynamicSchedulerUtil.fillJobInfo(jobInfo); + } + } + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + + @RequestMapping("/add") + @ResponseBody + public ReturnT add(HttpServletRequest request) { + String triggerKeyName = null; + String cronExpression = null; + Map jobData = new HashMap(); + + try { + request.setCharacterEncoding("utf-8"); + } catch (UnsupportedEncodingException e1) { + e1.printStackTrace(); + } + @SuppressWarnings("unchecked") + Set> paramSet = request.getParameterMap().entrySet(); + for (Entry param : paramSet) { + if (param.getKey().equals("triggerKeyName")) { + triggerKeyName = param.getValue()[0]; + } else if (param.getKey().equals("cronExpression")) { + cronExpression = param.getValue()[0]; + } else { + jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue())); + } + } + + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + + // jobData + if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务描述”"); + } + if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务URL”"); + } + if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) { + return new ReturnT(500, "请输入“任务handler”"); + } + + // jobClass + Class jobClass = HttpJobBean.class; + + try { + // add job 2 quartz + boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null); + if (!result) { + return new ReturnT(500, "任务ID重复,请更换确认"); + } + // Backup to the database + XxlJobInfo jobInfo = new XxlJobInfo(); + jobInfo.setJobName(triggerKeyName); + jobInfo.setJobCron(cronExpression); + jobInfo.setJobClass(jobClass.getName()); + jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData)); + xxlJobInfoDao.save(jobInfo); + + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/reschedule") + @ResponseBody + public ReturnT reschedule(String triggerKeyName, String cronExpression) { + // triggerKeyName + if (StringUtils.isBlank(triggerKeyName)) { + return new ReturnT(500, "请输入“任务key”"); + } + // cronExpression + if (StringUtils.isBlank(cronExpression)) { + return new ReturnT(500, "请输入“任务corn”"); + } + if (!CronExpression.isValidExpression(cronExpression)) { + return new ReturnT(500, "“任务corn”不合法"); + } + try { + DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression); + + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobCron(cronExpression); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/remove") + @ResponseBody + public ReturnT remove(String triggerKeyName) { + try { + if (triggerKeyName!=null) { + DynamicSchedulerUtil.removeJob(triggerKeyName); + xxlJobInfoDao.delete(triggerKeyName); + return ReturnT.SUCCESS; + } + } catch (SchedulerException e) { + e.printStackTrace(); + } + return ReturnT.FAIL; + } + + @RequestMapping("/pause") + @ResponseBody + public ReturnT pause(String triggerKeyName) { + try { + DynamicSchedulerUtil.pauseJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("PAUSED"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/resume") + @ResponseBody + public ReturnT resume(String triggerKeyName) { + try { + DynamicSchedulerUtil.resumeJob(triggerKeyName); + // update + XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName); + if (jobInfo!=null) { + jobInfo.setJobStatus("NORMAL"); + xxlJobInfoDao.update(jobInfo); + } + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + + @RequestMapping("/trigger") + @ResponseBody + public ReturnT triggerJob(String triggerKeyName) { + try { + DynamicSchedulerUtil.triggerJob(triggerKeyName); + return ReturnT.SUCCESS; + } catch (SchedulerException e) { + e.printStackTrace(); + return ReturnT.FAIL; + } + } + +} diff --git a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java index 3122a42..a0c79f2 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java @@ -1,7 +1,6 @@ package com.xxl.job.controller; import java.text.ParseException; -import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -17,6 +16,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; +import com.xxl.job.core.constant.Constants.JobGroupEnum; import com.xxl.job.core.model.ReturnT; import com.xxl.job.core.model.XxlJobLog; import com.xxl.job.dao.IXxlJobLogDao; @@ -32,6 +32,43 @@ @Resource public IXxlJobLogDao xxlJobLogDao; + @RequestMapping + public String index(Model model) { + model.addAttribute("JobGroupList", JobGroupEnum.values()); + return "joblog/index"; + } + + @RequestMapping("/pageList") + @ResponseBody + public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, + @RequestParam(required = false, defaultValue = "10") int length, + String jobGroup, String jobName, String filterTime) { + + // parse param + Date triggerTimeStart = null; + Date triggerTimeEnd = null; + if (StringUtils.isNotBlank(filterTime)) { + String[] temp = filterTime.split(" - "); + if (temp!=null && temp.length == 2) { + try { + triggerTimeStart = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); + triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); + } catch (ParseException e) { } + } + } + + // page query + List list = xxlJobLogDao.pageList(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobName, triggerTimeStart, triggerTimeEnd); + + // package result + Map maps = new HashMap(); + maps.put("recordsTotal", list_count); // 总记录数 + maps.put("recordsFiltered", list_count); // 过滤后的总记录数 + maps.put("data", list); // 分页列表 + return maps; + } + @RequestMapping("/save") @ResponseBody public ReturnT triggerLog(int triggerLogId, String status, String msg) { @@ -46,52 +83,4 @@ return ReturnT.FAIL; } - @RequestMapping - public String index(Model model, String jobName, String filterTime) { - - // 默认filterTime - Calendar todayz = Calendar.getInstance(); - todayz.set(Calendar.HOUR_OF_DAY, 0); - todayz.set(Calendar.MINUTE, 0); - todayz.set(Calendar.SECOND, 0); - model.addAttribute("triggerTimeStart", todayz.getTime()); - model.addAttribute("triggerTimeEnd", Calendar.getInstance().getTime()); - - model.addAttribute("jobName", jobName); - model.addAttribute("filterTime", filterTime); - return "joblog/index"; - } - - @RequestMapping("/pageList") - @ResponseBody - public Map pageList(@RequestParam(required = false, defaultValue = "0") int start, - @RequestParam(required = false, defaultValue = "10") int length, - String jobName, String filterTime) { - // parse param - Date triggerTimeStart = null; - Date triggerTimeEnd = null; - if (StringUtils.isNotBlank(filterTime)) { - String[] temp = filterTime.split(" - "); - if (temp!=null && temp.length == 2) { - try { - triggerTimeEnd = DateUtils.parseDate(temp[0], new String[]{"yyyy-MM-dd HH:mm:ss"}); - triggerTimeEnd = DateUtils.parseDate(temp[1], new String[]{"yyyy-MM-dd HH:mm:ss"}); - } catch (ParseException e) { - e.printStackTrace(); - } - } - } - - // page query - List list = xxlJobLogDao.pageList(start, length, jobName, triggerTimeStart, triggerTimeEnd); - int list_count = xxlJobLogDao.pageListCount(start, length, jobName, triggerTimeStart, triggerTimeEnd); - - // package result - Map maps = new HashMap(); - maps.put("recordsTotal", list_count); // 总记录数 - maps.put("recordsFiltered", list_count);// 过滤后的总记录数 - maps.put("data", list); // 分页列表 - return maps; - } - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java index e539af0..749b104 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java @@ -9,69 +9,125 @@ public class XxlJobInfo { private int id; - // job info - private String jobName; - private String jobCron; // base on quartz - private String jobClass; // base on quartz - private String jobStatus; // base on quartz - private String jobData; // base on db, Map-JSON-String + + private String jobGroup; // base on quartz 任务组 + private String jobName; // base on quartz 任务名 + private String jobCron; // base on quartz 任务执行CRON表达式 + private String jobClass; // base on quartz 任务执行JobBean + private String jobData; // base on db, Map-JSON-String 任务执行数据 + private Date addTime; private Date updateTime; + private String author; // 作者 + private String alarmEmail; // 报警邮件 + private int alarmThreshold; // 报警阀值 + + // copy from quartz + private String jobStatus; // 任务状态 + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getJobGroup() { + return jobGroup; + } + + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } + public String getJobName() { return jobName; } + public void setJobName(String jobName) { this.jobName = jobName; } + public String getJobCron() { return jobCron; } + public void setJobCron(String jobCron) { this.jobCron = jobCron; } + public String getJobClass() { return jobClass; } + public void setJobClass(String jobClass) { this.jobClass = jobClass; } - public String getJobStatus() { - return jobStatus; - } - public void setJobStatus(String jobStatus) { - this.jobStatus = jobStatus; - } + public String getJobData() { return jobData; } + public void setJobData(String jobData) { this.jobData = jobData; } + public Date getAddTime() { return addTime; } + public void setAddTime(Date addTime) { this.addTime = addTime; } + public Date getUpdateTime() { return updateTime; } + public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } - + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getAlarmEmail() { + return alarmEmail; + } + + public void setAlarmEmail(String alarmEmail) { + this.alarmEmail = alarmEmail; + } + + public int getAlarmThreshold() { + return alarmThreshold; + } + + public void setAlarmThreshold(int alarmThreshold) { + this.alarmThreshold = alarmThreshold; + } + + public String getJobStatus() { + return jobStatus; + } + + public void setJobStatus(String jobStatus) { + this.jobStatus = jobStatus; + } + @Override public String toString() { - return "XxlJobInfo [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobStatus=" + jobStatus + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" - + updateTime + "]"; + return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime=" + + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold=" + + alarmThreshold + ", jobStatus=" + jobStatus + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java index 4aaf7c3..c4b8a2e 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java @@ -9,7 +9,9 @@ public class XxlJobLog { private int id; + // job info + private String jobGroup; private String jobName; private String jobCron; private String jobClass; @@ -31,6 +33,12 @@ public void setId(int id) { this.id = id; } + public String getJobGroup() { + return jobGroup; + } + public void setJobGroup(String jobGroup) { + this.jobGroup = jobGroup; + } public String getJobName() { return jobName; } @@ -94,10 +102,10 @@ @Override public String toString() { - return "XxlJobLog [id=" + id + ", jobName=" + jobName + ", jobCron=" + jobCron + ", jobClass=" + jobClass - + ", jobData=" + jobData + ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus - + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus - + ", handleMsg=" + handleMsg + "]"; + return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron + + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime + + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime + + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]"; } } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java index 40394dc..5f6b206 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java @@ -1,6 +1,5 @@ package com.xxl.job.dao; - import java.util.Date; import java.util.List; @@ -12,16 +11,14 @@ */ public interface IXxlJobLogDao { - public int save(XxlJobLog xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd); public XxlJobLog load(int id); + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName); + public int save(XxlJobLog xxlJobLog); public int updateTriggerInfo(XxlJobLog xxlJobLog); - public int updateHandleInfo(XxlJobLog xxlJobLog); - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd); - } diff --git a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java index a3185a3..ef62845 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java @@ -23,19 +23,53 @@ public SqlSessionTemplate sqlSessionTemplate; @Override - public int save(XxlJobLog xxlJobLog) { - if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { - xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); - } - return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + public List pageList(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); + } + + @Override + public int pageListCount(int offset, int pagesize, String jobGroup, String jobName, Date triggerTimeStart, Date triggerTimeEnd) { + HashMap params = new HashMap(); + params.put("offset", offset); + params.put("pagesize", pagesize); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + params.put("triggerTimeStart", triggerTimeStart); + params.put("triggerTimeEnd", triggerTimeEnd); + + return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); } @Override public XxlJobLog load(int id) { return sqlSessionTemplate.selectOne("XxlJobLogMapper.load", id); } + + @Override + public XxlJobLog loadByGroupAndName(String jobGroup, String jobName) { + HashMap params = new HashMap(); + params.put("jobGroup", jobGroup); + params.put("jobName", jobName); + return sqlSessionTemplate.selectOne("XxlJobLogMapper.loadByGroupAndName", params); + } @Override + public int save(XxlJobLog xxlJobLog) { + if (xxlJobLog!=null && xxlJobLog.getJobData().length()>2000) { + xxlJobLog.setJobData(xxlJobLog.getJobData().substring(0, 2000)); + } + return sqlSessionTemplate.insert("XxlJobLogMapper.save", xxlJobLog); + } + + @Override public int updateTriggerInfo(XxlJobLog xxlJobLog) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); @@ -50,27 +84,5 @@ } return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); } - - @Override - public List pageList(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectList("XxlJobLogMapper.pageList", params); - } - - @Override - public int pageListCount(int offset, int pagesize,String jobName, Date triggerTimeStart, Date triggerTimeEnd) { - HashMap params = new HashMap(); - params.put("offset", offset); - params.put("pagesize", pagesize); - params.put("jobName", jobName); - params.put("triggerTimeStart", triggerTimeStart); - params.put("triggerTimeEnd", triggerTimeEnd); - return sqlSessionTemplate.selectOne("XxlJobLogMapper.pageListCount", params); - } } diff --git a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml index 24f1179..0fa5af7 100644 --- a/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml +++ b/xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ t.id, + t.job_group, t.job_name, t.job_cron, t.job_class, @@ -34,22 +36,45 @@ t.handle_msg - - INSERT INTO `xxl_job_qrtz_trigger_log` ( - `job_name`, - `job_cron`, - `job_class`, - `job_data` - ) VALUES ( - #{jobName}, - #{jobCron}, - #{jobClass}, - #{jobData} - ); - - SELECT LAST_INSERT_ID() - - + + + + + + + INSERT INTO `xxl_job_qrtz_trigger_log` ( + `job_group`, + `job_name`, + `job_cron`, + `job_class`, + `job_data` + ) VALUES ( + #{jobGroup}, + #{jobName}, + #{jobCron}, + #{jobClass}, + #{jobData} + ); + + SELECT LAST_INSERT_ID() + + + UPDATE `xxl_job_qrtz_trigger_log` SET @@ -75,38 +126,4 @@ WHERE `id`= #{id} - - - - \ No newline at end of file diff --git a/xxl-job-admin/src/main/resources/springmvc-context.xml b/xxl-job-admin/src/main/resources/springmvc-context.xml index 6d7548c..4f16544 100644 --- a/xxl-job-admin/src/main/resources/springmvc-context.xml +++ b/xxl-job-admin/src/main/resources/springmvc-context.xml @@ -38,6 +38,8 @@ + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl deleted file mode 100644 index 6aaf3b3..0000000 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl +++ /dev/null @@ -1,224 +0,0 @@ - - - - 调度中心 - <#import "/common/common.macro.ftl" as netCommon> - <@netCommon.commonStyle /> - - - - - -
- - <@netCommon.commonHeader /> - - <@netCommon.commonLeft /> - - -
- -
-

调度管理调度中心

- -
- - -
- -
-
-
- - jobName - - -
-
-
- -
-
- -
-
- -
-
-
-
-

调度列表

-
-
-
idjobNamejobCronjobClassjobDatatriggerTimetriggerStatustriggerMsghandleTimehandleStatushandleMsgid任务组任务名CronJobBean任务数据调度时间调度结果调度日志执行时间执行结果执行日志
- - - - - - - - - - - - - - - <#-- - <#if jobList?exists && jobList?size gt 0> - <#list jobList as item> - - - - - - - - - - - - --> - - -
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} - <#assign jobDataMap = item['JobDetail'].jobDataMap /> - <#if jobDataMap?exists && jobDataMap?keys?size gt 0> - <#list jobDataMap?keys as key> - ${key} = ${jobDataMap[key]}
- - -
- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - <#else> - - - -

- <#if item['TriggerState'] == 'NORMAL'> - - <#elseif item['TriggerState'] == 'PAUSED'> - - - - - - -

-
-
-
- - -
- - - - <@netCommon.commonFooter /> - - - - - - - - -<@netCommon.commonScript /> -<@netCommon.comAlert /> - - - - - - - - - - - diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl new file mode 100644 index 0000000..0f0b385 --- /dev/null +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl @@ -0,0 +1,242 @@ + + + + 调度中心 + <#import "/common/common.macro.ftl" as netCommon> + <@netCommon.commonStyle /> + + + + + +
+ + <@netCommon.commonHeader /> + + <@netCommon.commonLeft /> + + +
+ +
+

调度管理调度中心

+ +
+ + +
+ +
+
+
+ 任务组 + +
+
+
+
+ + jobName + + +
+
+
+ +
+
+ +
+
+ +
+
+
+
+

调度列表

+
+
+ + + + + + + + + + + + + + + + <#-- + <#if jobList?exists && jobList?size gt 0> + <#list jobList as item> + + + + + + + + + + + + --> + + +
id任务Key任务Cron任务Class状态Status参数addTimeupdateTime操作
${item['TriggerKey'].name}${item['Trigger'].cronExpression}${item['JobDetail'].jobClass} + <#assign jobDataMap = item['JobDetail'].jobDataMap /> + <#if jobDataMap?exists && jobDataMap?keys?size gt 0> + <#list jobDataMap?keys as key> + ${key} = ${jobDataMap[key]}
+ + +
+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + <#else> + + + +

+ <#if item['TriggerState'] == 'NORMAL'> + + <#elseif item['TriggerState'] == 'PAUSED'> + + + + + + +

+
+
+
+
+
+
+
+ + + <@netCommon.commonFooter /> +
+ + + + + + + +<@netCommon.commonScript /> +<@netCommon.comAlert /> + + + + + + + + + + + diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl index ce141da..b5ba01d 100644 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl @@ -30,23 +30,33 @@
-
+
+
+ 任务组 + +
+
+
+
+ 任务名 + +
+
+
调度时间 + value2="<#if triggerTimeStart?exists && triggerTimeEnd?exists >${triggerTimeStart?if_exists?string('yyyy-MM-dd HH:mm:ss')} - ${triggerTimeEnd?if_exists?string('yyyy-MM-dd HH:mm:ss')}" >
-
-
- - jobName - - -
-
+ +
@@ -60,17 +70,18 @@ - - - - - - - - - - - + + + + + + + + + + + + diff --git a/xxl-job-admin/src/main/webapp/static/js/job.index.1.js b/xxl-job-admin/src/main/webapp/static/js/job.index.1.js deleted file mode 100644 index 256ba22..0000000 --- a/xxl-job-admin/src/main/webapp/static/js/job.index.1.js +++ /dev/null @@ -1,379 +0,0 @@ -$(function() { - // init date tables - var jobTable = $("#job_list").dataTable({ - "deferRender": true, - "processing" : true, - "serverSide": true, - "ajax": { - url: base_url + "/job/pageList", - data : function ( d ) { - d.jobName = $('#jobName').val() - } - }, - //"scrollX": true, // X轴滚动条,取消自适应 - "columns": [ - { "data": 'id', "bSortable": false, "visible" : false}, - { "data": 'jobName', "bSortable": false}, - { "data": 'jobCron', "bSortable": false, "visible" : true}, - { "data": 'jobClass', "bSortable": false, "visible" : false}, - { "data": 'jobStatus', "bSortable": false, "visible" : true}, - { "data": 'jobData', "bSortable": false, "visible" : true}, - { - "data": 'addTime', - "bSortable": false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { - "data": 'updateTime', - "bSortable": false, - "render": function ( data, type, row ) { - return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; - } - }, - { "data": '操作' , "bSortable": false, - "render": function ( data, type, row ) { - return function(){ - // status - var pause_resume = ""; - if ('NORMAL' == row.jobStatus) { - pause_resume = ' '; - } else if ('PAUSED' == row.jobStatus){ - pause_resume = ' '; - } - // log url - var logUrl = base_url +'/joblog?jobName='+ row.jobName; - - // job data - var jobDataMap = eval('(' + row.jobData + ')'); - - var html = '

'+ - pause_resume + - ' '+ - ' '+ - ' '+ - ''+ - '

'; - - - return html; - }; - } - } - ], - "searching": false, - "ordering": true, - "language" : { - "sProcessing" : "处理中...", - "sLengthMenu" : "每页 _MENU_ 条记录", - "sZeroRecords" : "没有匹配结果", - "sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页 )", - "sInfoEmpty" : "无记录", - "sInfoFiltered" : "(由 _MAX_ 项结果过滤)", - "sInfoPostFix" : "", - "sSearch" : "搜索:", - "sUrl" : "", - "sEmptyTable" : "表中数据为空", - "sLoadingRecords" : "载入中...", - "sInfoThousands" : ",", - "oPaginate" : { - "sFirst" : "首页", - "sPrevious" : "上页", - "sNext" : "下页", - "sLast" : "末页" - }, - "oAria" : { - "sSortAscending" : ": 以升序排列此列", - "sSortDescending" : ": 以降序排列此列" - } - } - }); - - // 搜索按钮 - $('#searchBtn').on('click', function(){ - jobTable.fnDraw(); - }); - - // job operate - $("#job_list").on('click', '.job_operate',function() { - var typeName; - var url; - var type = $(this).attr("type"); - if ("job_pause" == type) { - typeName = "暂停"; - url = base_url + "/job/pause"; - } else if ("job_resume" == type) { - typeName = "恢复"; - url = base_url + "/job/resume"; - } else if ("job_del" == type) { - typeName = "删除"; - url = base_url + "/job/remove"; - } else if ("job_trigger" == type) { - typeName = "执行一次"; - url = base_url + "/job/trigger"; - } else { - return; - } - - var name = $(this).parent('p').attr("jobName"); - - ComConfirm.show("确认" + typeName + "?", function(){ - $.ajax({ - type : 'POST', - url : url, - data : { - "triggerKeyName" : name - }, - dataType : "json", - success : function(data){ - if (data.code == 200) { - ComAlert.show(1, typeName + "成功", function(){ - //window.location.reload(); - jobTable.fnDraw(); - }); - } else { - ComAlert.show(1, typeName + "失败"); - } - }, - }); - }); - }); - - // jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线” - jQuery.validator.addMethod("myValid01", function(value, element) { - var length = value.length; - var valid = /^[a-zA-Z][a-zA-Z0-9_]*$/; - return this.optional(element) || valid.test(value); - }, "只支持英文字母开头,只含有英文字母、数字和下划线"); - - // 新增 - $(".add").click(function(){ - $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var addModalValidate = $("#addModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - triggerKeyName : { - required : true , - minlength: 4, - maxlength: 100, - myValid01:true - }, - cronExpression : { - required : true , - maxlength: 100 - }, - job_desc : { - required : true , - maxlength: 200 - }, - job_url : { - required : true , - maxlength: 200 - }, - handleName : { - required : true , - maxlength: 200 - } - }, - messages : { - triggerKeyName : { - required :"请输入“任务Key”." , - minlength:"“任务Key”长度不应低于4位", - maxlength:"“任务Key”长度不应超过100位" - }, - cronExpression : { - required :"请输入“任务Corn”." , - maxlength:"“任务Corn”长度不应超过100位" - }, - job_desc : { - required :"请输入“任务描述”." , - maxlength:"“任务描述”长度不应超过200位" - }, - job_url : { - required :"请输入“任务URL”." , - maxlength:"“任务URL”长度不应超过200位" - }, - handleName : { - required : "请输入“任务handler”." , - maxlength: "“任务handler”长度不应超过200位" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - - var triggerKeyName = $('#addModal input[name="triggerKeyName"]').val(); - var cronExpression = $('#addModal input[name="cronExpression"]').val(); - var job_desc = $('#addModal input[name="job_desc"]').val(); - var job_url = $('#addModal input[name="job_url"]').val(); - var handleName = $('#addModal input[name="handleName"]').val(); - - var paramStr = 'triggerKeyName=' + triggerKeyName + - '&cronExpression=' + cronExpression + - '&job_desc=' + job_desc + - '&job_url=' + job_url + - '&handleName=' + handleName; - - var ifFin = true; - $('#addModal .newParam').each(function(){ - ifFin = false; - var key = $(this).find('input[name="key"]').val(); - var value = $(this).find('input[name="value"]').val(); - if (!key) { - ComAlert.show(2, "新增参数key不可为空"); - return; - } else { - if(!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)){ - ComAlert.show(2, "新增参数key不合法, 只支持英文字母开头,只含有英文字母、数字和下划线"); - return; - } - } - paramStr += "&" + key + "=" + value; - ifFin = true; - }); - - if(ifFin){ - $.post(base_url + "/job/add", paramStr, function(data, status) { - if (data.code == "200") { - ComAlert.show(1, "新增调度任务成功", function(){ - window.location.reload(); - }); - } else { - if (data.msg) { - ComAlert.show(2, data.msg); - } else { - ComAlert.show(2, "新增失败"); - } - } - }); - } - } - }); - $("#addModal").on('hide.bs.modal', function () { - //$("#addModal .form")[0].reset(); - addModalValidate.resetForm(); - $("#addModal .form .form-group").removeClass("has-error"); - }); - - // 新增-添加参数 - $("#addModal .addParam").on('click', function () { - var html = '
'+ - ''+ - '
'+ - '
'+ - '
'; - $(this).parents('.form-group').parent().append(html); - - $("#addModal .removeParam").on('click', function () { - $(this).parents('.form-group').remove(); - }); - }); - - // 更新 - $("#job_list").on('click', '.update',function() { - $("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("jobName")); - $("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression")); - $("#updateModal .form input[name='job_desc']").val($(this).parent('p').attr("job_desc")); - $("#updateModal .form input[name='job_url']").val($(this).parent('p').attr("job_url")); - $("#updateModal .form input[name='handleName']").val($(this).parent('p').attr("handleName")); - $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); - }); - var updateModalValidate = $("#updateModal .form").validate({ - errorElement : 'span', - errorClass : 'help-block', - focusInvalid : true, - rules : { - triggerKeyName : { - required : true , - minlength: 4, - maxlength: 100 - }, - cronExpression : { - required : true , - maxlength: 100 - }, - job_desc : { - required : true , - maxlength: 200 - }, - job_url : { - required : true , - maxlength: 200 - }, - handleName : { - required : true , - maxlength: 200 - } - }, - messages : { - triggerKeyName : { - required :"请输入“任务Key”." , - minlength:"“任务Key”不应低于4位", - maxlength:"“任务Key”不应超过100位" - }, - cronExpression : { - required :"请输入“任务Corn”." , - maxlength:"“任务Corn”不应超过100位" - }, - job_desc : { - required :"请输入“任务描述”." , - maxlength:"“任务描述”长度不应超过200位" - }, - job_url : { - required :"请输入“任务URL”." , - maxlength:"“任务URL”长度不应超过200位" - }, - handleName : { - required : "请输入“任务handler”." , - maxlength: "“任务handler”长度不应超过200位" - } - }, - highlight : function(element) { - $(element).closest('.form-group').addClass('has-error'); - }, - success : function(label) { - label.closest('.form-group').removeClass('has-error'); - label.remove(); - }, - errorPlacement : function(error, element) { - element.parent('div').append(error); - }, - submitHandler : function(form) { - $.post(base_url + "/job/reschedule", $("#updateModal .form").serialize(), function(data, status) { - if (data.code == "200") { - ComAlert.show(1, "更新成功", function(){ - window.location.reload(); - }); - } else { - if (data.msg) { - ComAlert.show(2, data.msg); - } else { - ComAlert.show(2, "更新失败"); - } - } - }); - } - }); - $("#updateModal").on('hide.bs.modal', function () { - $("#updateModal .form")[0].reset() - }); - -}); diff --git a/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js new file mode 100644 index 0000000..58f13ae --- /dev/null +++ b/xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js @@ -0,0 +1,379 @@ +$(function() { + // init date tables + var jobTable = $("#job_list").dataTable({ + "deferRender": true, + "processing" : true, + "serverSide": true, + "ajax": { + url: base_url + "/jobinfo/pageList", + data : function ( d ) { + d.jobName = $('#jobName').val() + } + }, + //"scrollX": true, // X轴滚动条,取消自适应 + "columns": [ + { "data": 'id', "bSortable": false, "visible" : false}, + { "data": 'jobName', "bSortable": false}, + { "data": 'jobCron', "bSortable": false, "visible" : true}, + { "data": 'jobClass', "bSortable": false, "visible" : false}, + { "data": 'jobStatus', "bSortable": false, "visible" : true}, + { "data": 'jobData', "bSortable": false, "visible" : true}, + { + "data": 'addTime', + "bSortable": false, + "render": function ( data, type, row ) { + return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; + } + }, + { + "data": 'updateTime', + "bSortable": false, + "render": function ( data, type, row ) { + return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; + } + }, + { "data": '操作' , "bSortable": false, + "render": function ( data, type, row ) { + return function(){ + // status + var pause_resume = ""; + if ('NORMAL' == row.jobStatus) { + pause_resume = ' '; + } else if ('PAUSED' == row.jobStatus){ + pause_resume = ' '; + } + // log url + var logUrl = base_url +'/joblog?jobName='+ row.jobName; + + // job data + var jobDataMap = eval('(' + row.jobData + ')'); + + var html = '

'+ + pause_resume + + ' '+ + ' '+ + ' '+ + ''+ + '

'; + + + return html; + }; + } + } + ], + "searching": false, + "ordering": true, + "language" : { + "sProcessing" : "处理中...", + "sLengthMenu" : "每页 _MENU_ 条记录", + "sZeroRecords" : "没有匹配结果", + "sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页 )", + "sInfoEmpty" : "无记录", + "sInfoFiltered" : "(由 _MAX_ 项结果过滤)", + "sInfoPostFix" : "", + "sSearch" : "搜索:", + "sUrl" : "", + "sEmptyTable" : "表中数据为空", + "sLoadingRecords" : "载入中...", + "sInfoThousands" : ",", + "oPaginate" : { + "sFirst" : "首页", + "sPrevious" : "上页", + "sNext" : "下页", + "sLast" : "末页" + }, + "oAria" : { + "sSortAscending" : ": 以升序排列此列", + "sSortDescending" : ": 以降序排列此列" + } + } + }); + + // 搜索按钮 + $('#searchBtn').on('click', function(){ + jobTable.fnDraw(); + }); + + // job operate + $("#job_list").on('click', '.job_operate',function() { + var typeName; + var url; + var type = $(this).attr("type"); + if ("job_pause" == type) { + typeName = "暂停"; + url = base_url + "/job/pause"; + } else if ("job_resume" == type) { + typeName = "恢复"; + url = base_url + "/job/resume"; + } else if ("job_del" == type) { + typeName = "删除"; + url = base_url + "/job/remove"; + } else if ("job_trigger" == type) { + typeName = "执行一次"; + url = base_url + "/job/trigger"; + } else { + return; + } + + var name = $(this).parent('p').attr("jobName"); + + ComConfirm.show("确认" + typeName + "?", function(){ + $.ajax({ + type : 'POST', + url : url, + data : { + "triggerKeyName" : name + }, + dataType : "json", + success : function(data){ + if (data.code == 200) { + ComAlert.show(1, typeName + "成功", function(){ + //window.location.reload(); + jobTable.fnDraw(); + }); + } else { + ComAlert.show(1, typeName + "失败"); + } + }, + }); + }); + }); + + // jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线” + jQuery.validator.addMethod("myValid01", function(value, element) { + var length = value.length; + var valid = /^[a-zA-Z][a-zA-Z0-9_]*$/; + return this.optional(element) || valid.test(value); + }, "只支持英文字母开头,只含有英文字母、数字和下划线"); + + // 新增 + $(".add").click(function(){ + $('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); + }); + var addModalValidate = $("#addModal .form").validate({ + errorElement : 'span', + errorClass : 'help-block', + focusInvalid : true, + rules : { + triggerKeyName : { + required : true , + minlength: 4, + maxlength: 100, + myValid01:true + }, + cronExpression : { + required : true , + maxlength: 100 + }, + job_desc : { + required : true , + maxlength: 200 + }, + job_url : { + required : true , + maxlength: 200 + }, + handleName : { + required : true , + maxlength: 200 + } + }, + messages : { + triggerKeyName : { + required :"请输入“任务Key”." , + minlength:"“任务Key”长度不应低于4位", + maxlength:"“任务Key”长度不应超过100位" + }, + cronExpression : { + required :"请输入“任务Corn”." , + maxlength:"“任务Corn”长度不应超过100位" + }, + job_desc : { + required :"请输入“任务描述”." , + maxlength:"“任务描述”长度不应超过200位" + }, + job_url : { + required :"请输入“任务URL”." , + maxlength:"“任务URL”长度不应超过200位" + }, + handleName : { + required : "请输入“任务handler”." , + maxlength: "“任务handler”长度不应超过200位" + } + }, + highlight : function(element) { + $(element).closest('.form-group').addClass('has-error'); + }, + success : function(label) { + label.closest('.form-group').removeClass('has-error'); + label.remove(); + }, + errorPlacement : function(error, element) { + element.parent('div').append(error); + }, + submitHandler : function(form) { + + var triggerKeyName = $('#addModal input[name="triggerKeyName"]').val(); + var cronExpression = $('#addModal input[name="cronExpression"]').val(); + var job_desc = $('#addModal input[name="job_desc"]').val(); + var job_url = $('#addModal input[name="job_url"]').val(); + var handleName = $('#addModal input[name="handleName"]').val(); + + var paramStr = 'triggerKeyName=' + triggerKeyName + + '&cronExpression=' + cronExpression + + '&job_desc=' + job_desc + + '&job_url=' + job_url + + '&handleName=' + handleName; + + var ifFin = true; + $('#addModal .newParam').each(function(){ + ifFin = false; + var key = $(this).find('input[name="key"]').val(); + var value = $(this).find('input[name="value"]').val(); + if (!key) { + ComAlert.show(2, "新增参数key不可为空"); + return; + } else { + if(!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)){ + ComAlert.show(2, "新增参数key不合法, 只支持英文字母开头,只含有英文字母、数字和下划线"); + return; + } + } + paramStr += "&" + key + "=" + value; + ifFin = true; + }); + + if(ifFin){ + $.post(base_url + "/job/add", paramStr, function(data, status) { + if (data.code == "200") { + ComAlert.show(1, "新增调度任务成功", function(){ + window.location.reload(); + }); + } else { + if (data.msg) { + ComAlert.show(2, data.msg); + } else { + ComAlert.show(2, "新增失败"); + } + } + }); + } + } + }); + $("#addModal").on('hide.bs.modal', function () { + //$("#addModal .form")[0].reset(); + addModalValidate.resetForm(); + $("#addModal .form .form-group").removeClass("has-error"); + }); + + // 新增-添加参数 + $("#addModal .addParam").on('click', function () { + var html = '
'+ + ''+ + '
'+ + '
'+ + '
'; + $(this).parents('.form-group').parent().append(html); + + $("#addModal .removeParam").on('click', function () { + $(this).parents('.form-group').remove(); + }); + }); + + // 更新 + $("#job_list").on('click', '.update',function() { + $("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("jobName")); + $("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression")); + $("#updateModal .form input[name='job_desc']").val($(this).parent('p').attr("job_desc")); + $("#updateModal .form input[name='job_url']").val($(this).parent('p').attr("job_url")); + $("#updateModal .form input[name='handleName']").val($(this).parent('p').attr("handleName")); + $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); + }); + var updateModalValidate = $("#updateModal .form").validate({ + errorElement : 'span', + errorClass : 'help-block', + focusInvalid : true, + rules : { + triggerKeyName : { + required : true , + minlength: 4, + maxlength: 100 + }, + cronExpression : { + required : true , + maxlength: 100 + }, + job_desc : { + required : true , + maxlength: 200 + }, + job_url : { + required : true , + maxlength: 200 + }, + handleName : { + required : true , + maxlength: 200 + } + }, + messages : { + triggerKeyName : { + required :"请输入“任务Key”." , + minlength:"“任务Key”不应低于4位", + maxlength:"“任务Key”不应超过100位" + }, + cronExpression : { + required :"请输入“任务Corn”." , + maxlength:"“任务Corn”不应超过100位" + }, + job_desc : { + required :"请输入“任务描述”." , + maxlength:"“任务描述”长度不应超过200位" + }, + job_url : { + required :"请输入“任务URL”." , + maxlength:"“任务URL”长度不应超过200位" + }, + handleName : { + required : "请输入“任务handler”." , + maxlength: "“任务handler”长度不应超过200位" + } + }, + highlight : function(element) { + $(element).closest('.form-group').addClass('has-error'); + }, + success : function(label) { + label.closest('.form-group').removeClass('has-error'); + label.remove(); + }, + errorPlacement : function(error, element) { + element.parent('div').append(error); + }, + submitHandler : function(form) { + $.post(base_url + "/job/reschedule", $("#updateModal .form").serialize(), function(data, status) { + if (data.code == "200") { + ComAlert.show(1, "更新成功", function(){ + window.location.reload(); + }); + } else { + if (data.msg) { + ComAlert.show(2, data.msg); + } else { + ComAlert.show(2, "更新失败"); + } + } + }); + } + }); + $("#updateModal").on('hide.bs.modal', function () { + $("#updateModal .form")[0].reset() + }); + +}); diff --git a/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js b/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js index 154a487..82c4a00 100644 --- a/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js +++ b/xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js @@ -8,46 +8,66 @@ "ajax": { url: base_url + "/joblog/pageList" , data : function ( d ) { + d.jobGroup = $('#jobGroup').val(); + d.jobName = $('#jobName').val(); d.filterTime = $('#filterTime').val(); - d.jobName = $('#jobName').val() } }, - //"scrollX": true, // X轴滚动条,取消自适应 + "searching": false, + "ordering": false, + //"scrollX": false, "columns": [ { "data": 'id', "bSortable": false, "visible" : false}, - { "data": 'jobName', "bSortable": false}, - { "data": 'jobCron', "bSortable": false, "visible" : false}, - { "data": 'jobClass', "bSortable": false, "visible" : false}, - { "data": 'jobData', "bSortable": false, "visible" : false}, + { + "data": 'jobGroup', + "bSortable": false, + "render": function ( data, type, row ) { + var groupMenu = $("#jobGroup").find("option"); + for ( var index in $("#jobGroup").find("option")) { + if ($(groupMenu[index]).attr('value') == data) { + return $(groupMenu[index]).html(); + } + } + return data; + } + }, + { "data": 'jobName'}, + { "data": 'jobCron', "visible" : false}, + { "data": 'jobClass', "visible" : false}, + { + "data": 'jobData', + "visible" : false, + "render": function ( data, type, row ) { + return data?'查看'+ data +'':"无"; + } + }, { "data": 'triggerTime', - "bSortable": false, "render": function ( data, type, row ) { return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; } }, - { "data": 'triggerStatus', "bSortable": false}, - { "data": 'triggerMsg',"bSortable": false, + { "data": 'triggerStatus'}, + { + "data": 'triggerMsg', "render": function ( data, type, row ) { - return data?'调度日志'+ data +'':"无"; + return data?'查看'+ data +'':"无"; } }, { "data": 'handleTime', - "bSortable": false, "render": function ( data, type, row ) { return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):""; } }, { "data": 'handleStatus',"bSortable": false}, - { "data": 'handleMsg' , "bSortable": false, + { + "data": 'handleMsg', "render": function ( data, type, row ) { - return data?'执行日志'+ data +'':"无"; + return data?'查看'+ data +'':"无"; } } ], - "searching": false, - "ordering": true, "language" : { "sProcessing" : "处理中...", "sLengthMenu" : "每页 _MENU_ 条记录", @@ -94,7 +114,7 @@ '最近7日': [moment().subtract('days', 6), moment()], '最近30日': [moment().subtract('days', 29), moment()] }, - opens : 'right', //日期选择框的弹出位置 + opens : 'left', //日期选择框的弹出位置 locale : { customRangeLabel : '自定义', applyLabel : '确定', @@ -106,6 +126,7 @@ firstDay : 1 } }); + $('#filterTime').val( moment(new Date()).format("YYYY-MM-DD 00:00:00") + ' - ' + moment(new Date()).format("YYYY-MM-DD HH:mm:ss") ); // 搜索按钮 $('#searchBtn').on('click', function(){
idjobNamejobCronjobClassjobDatatriggerTimetriggerStatustriggerMsghandleTimehandleStatushandleMsgid任务组任务名CronJobBean任务数据调度时间调度结果调度日志执行时间执行结果执行日志