提交 aeee9f11 authored 作者: xueli.xue's avatar xueli.xue

版本大升级v1.2.0,关键字如下:1、任务组;2、“远程任务”、“本地任务”;3、“任务日志”;4、“串行执行”,并行执行;

上级 dc0011c1
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
# DROP TABLE IF EXISTS XXL_JOB_QRTZ_TRIGGERS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_TRIGGERS;
# DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS; # DROP TABLE IF EXISTS XXL_JOB_QRTZ_JOB_DETAILS;
# DROP TABLE IF EXISTS XXL_JOB_QRTZ_CALENDARS; # 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`; # DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`;
# DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`;
CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS CREATE TABLE XXL_JOB_QRTZ_JOB_DETAILS
( (
...@@ -157,29 +157,32 @@ CREATE TABLE XXL_JOB_QRTZ_LOCKS ...@@ -157,29 +157,32 @@ CREATE TABLE XXL_JOB_QRTZ_LOCKS
); );
CREATE TABLE `xxl_job_qrtz_trigger_log` ( DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_info`;
CREATE TABLE `xxl_job_qrtz_trigger_info` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`job_group` varchar(255) NOT NULL COMMENT '任务组', `job_group` varchar(255) NOT NULL COMMENT '任务组',
`job_name` varchar(255) NOT NULL COMMENT '任务名', `job_name` varchar(255) NOT NULL COMMENT '任务名',
`job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN',
`job_desc` varchar(255) NOT NULL,
`job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean',
`job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', `job_data` varchar(512) DEFAULT NULL COMMENT '任务执行数据',
`trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', `add_time` datetime DEFAULT NULL,
`trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', `update_time` datetime DEFAULT NULL,
`trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', `author` varchar(64) DEFAULT NULL COMMENT '作者',
`handle_time` datetime DEFAULT NULL COMMENT '执行-时间', `alarm_email` varchar(255) DEFAULT NULL COMMENT '报警邮件',
`handle_status` varchar(255) DEFAULT NULL COMMENT '执行-状态', `alarm_threshold` int(11) DEFAULT NULL COMMENT '报警阀值(连续失败次数)',
`handle_msg` varchar(2048) DEFAULT NULL COMMENT '执行-日志',
PRIMARY KEY (`id`) PRIMARY KEY (`id`)
); );
DROP TABLE IF EXISTS `xxl_job_qrtz_trigger_log`;
CREATE TABLE `xxl_job_qrtz_trigger_log` ( CREATE TABLE `xxl_job_qrtz_trigger_log` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`job_group` varchar(255) NOT NULL COMMENT '任务组', `job_group` varchar(255) NOT NULL COMMENT '任务组',
`job_name` varchar(255) NOT NULL COMMENT '任务名', `job_name` varchar(255) NOT NULL COMMENT '任务名',
`job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式', `job_cron` varchar(128) NOT NULL COMMENT '任务执行CORN表达式',
`job_desc` varchar(255) NOT NULL,
`job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean', `job_class` varchar(255) NOT NULL COMMENT '任务执行JobBean',
`job_data` varchar(2048) DEFAULT NULL COMMENT '任务执行数据', `job_data` varchar(512) DEFAULT NULL COMMENT '任务执行数据',
`trigger_time` datetime DEFAULT NULL COMMENT '调度-时间', `trigger_time` datetime DEFAULT NULL COMMENT '调度-时间',
`trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果', `trigger_status` varchar(255) DEFAULT NULL COMMENT '调度-结果',
`trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志', `trigger_msg` varchar(2048) DEFAULT NULL COMMENT '调度-日志',
......
...@@ -3,13 +3,12 @@ ...@@ -3,13 +3,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.xxl</groupId> <groupId>com.xxl</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.1.1-SNAPSHOT</version> <version>1.2.0-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<modules> <modules>
<module>xxl-job-admin</module> <module>xxl-job-admin</module>
<module>xxl-job-client</module> <module>xxl-job-client</module>
<module>xxl-job-client-demo</module> <module>xxl-job-client-demo</module>
<module>xxl-job-simple</module>
</modules> </modules>
<build> <build>
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
<parent> <parent>
<groupId>com.xxl</groupId> <groupId>com.xxl</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.1.1-SNAPSHOT</version> <version>1.2.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-admin</artifactId> <artifactId>xxl-job-admin</artifactId>
<version>1.1.2-SNAPSHOT</version> <version>1.2.1-SNAPSHOT</version>
<packaging>war</packaging> <packaging>war</packaging>
<properties> <properties>
...@@ -123,13 +123,6 @@ ...@@ -123,13 +123,6 @@
<version>5.1.29</version> <version>5.1.29</version>
</dependency> </dependency>
<!-- quartz :quartz-2.2.1/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.2</version>
</dependency>
<!-- httpclient --> <!-- httpclient -->
<dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId> <groupId>org.apache.httpcomponents</groupId>
...@@ -137,11 +130,18 @@ ...@@ -137,11 +130,18 @@
<version>4.3.6</version> <version>4.3.6</version>
</dependency> </dependency>
<!-- quartz :quartz-2.2.1/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.2</version>
</dependency>
<!-- xxl-job-client --> <!-- xxl-job-client -->
<dependency> <dependency>
<groupId>com.xxl</groupId> <groupId>com.xxl</groupId>
<artifactId>xxl-job-client</artifactId> <artifactId>xxl-job-client</artifactId>
<version>1.1.2-SNAPSHOT</version> <version>1.2.1-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>
......
...@@ -24,14 +24,15 @@ import com.xxl.job.core.model.ReturnT; ...@@ -24,14 +24,15 @@ import com.xxl.job.core.model.ReturnT;
import com.xxl.job.core.model.XxlJobInfo; import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.util.DynamicSchedulerUtil; import com.xxl.job.core.util.DynamicSchedulerUtil;
import com.xxl.job.dao.IXxlJobInfoDao; import com.xxl.job.dao.IXxlJobInfoDao;
import com.xxl.job.service.job.HttpJobBean; import com.xxl.job.service.job.RemoteHttpJobBean;
import com.xxl.job.service.job.LocalJobBean; import com.xxl.job.service.job.impl.DemoConcurrentJobBean;
import com.xxl.job.service.job.LocalJobBeanB; import com.xxl.job.service.job.impl.DemoNomalJobBean;
/** /**
* index controller * index controller
* @author xuxueli 2015-12-19 16:13:16 * @author xuxueli 2015-12-19 16:13:16
*/ */
@SuppressWarnings("unchecked")
@Controller @Controller
@RequestMapping("/jobinfo") @RequestMapping("/jobinfo")
public class JobInfoController { public class JobInfoController {
...@@ -40,12 +41,12 @@ public class JobInfoController { ...@@ -40,12 +41,12 @@ public class JobInfoController {
private IXxlJobInfoDao xxlJobInfoDao; private IXxlJobInfoDao xxlJobInfoDao;
// remote job bean // remote job bean
public static Class <? extends Job> remoteJobBean = HttpJobBean.class; public static Class <? extends Job> remoteJobBean = RemoteHttpJobBean.class;
// loacal job bean // loacal job bean
public static List<Class <? extends Job>> localJobBeanList = new ArrayList<Class<? extends Job>>(); public static List<Class <? extends Job>> localJobBeanList = new ArrayList<Class<? extends Job>>();
static{ static{
localJobBeanList.add(LocalJobBean.class); localJobBeanList.add((Class<? extends Job>) DemoNomalJobBean.class);
localJobBeanList.add(LocalJobBeanB.class); localJobBeanList.add((Class<? extends Job>) DemoConcurrentJobBean.class);
} }
@RequestMapping @RequestMapping
...@@ -81,12 +82,11 @@ public class JobInfoController { ...@@ -81,12 +82,11 @@ public class JobInfoController {
return maps; return maps;
} }
@SuppressWarnings("unchecked")
@RequestMapping("/add") @RequestMapping("/add")
@ResponseBody @ResponseBody
public ReturnT<String> add(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass, public ReturnT<String> add(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass,
String handler_params, String handler_address, String handler_name, String handler_params, String handler_address, String handler_name,
String author, String alarm_email, int alarm_threshold) { String author, String alarmEmail, int alarmThreshold) {
// valid // valid
if (JobGroupEnum.match(jobGroup) == null) { if (JobGroupEnum.match(jobGroup) == null) {
...@@ -124,7 +124,7 @@ public class JobInfoController { ...@@ -124,7 +124,7 @@ public class JobInfoController {
if (StringUtils.isBlank(author)) { if (StringUtils.isBlank(author)) {
return new ReturnT<String>(500, "请输入“负责人”"); return new ReturnT<String>(500, "请输入“负责人”");
} }
if (StringUtils.isBlank(alarm_email)) { if (StringUtils.isBlank(alarmEmail)) {
return new ReturnT<String>(500, "请输入“报警邮件”"); return new ReturnT<String>(500, "请输入“报警邮件”");
} }
...@@ -137,6 +137,7 @@ public class JobInfoController { ...@@ -137,6 +137,7 @@ public class JobInfoController {
return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名"); return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
} }
// parse jobDataMap
HashMap<String, String> jobDataMap = new HashMap<String, String>(); HashMap<String, String> jobDataMap = new HashMap<String, String>();
jobDataMap.put(HandlerRepository.HANDLER_PARAMS, handler_params); jobDataMap.put(HandlerRepository.HANDLER_PARAMS, handler_params);
jobDataMap.put(HandlerRepository.HANDLER_ADDRESS, handler_address); jobDataMap.put(HandlerRepository.HANDLER_ADDRESS, handler_address);
...@@ -151,8 +152,8 @@ public class JobInfoController { ...@@ -151,8 +152,8 @@ public class JobInfoController {
jobInfo.setJobClass(jobClass); jobInfo.setJobClass(jobClass);
jobInfo.setJobData(JacksonUtil.writeValueAsString(jobDataMap)); jobInfo.setJobData(JacksonUtil.writeValueAsString(jobDataMap));
jobInfo.setAuthor(author); jobInfo.setAuthor(author);
jobInfo.setAlarmEmail(alarm_email); jobInfo.setAlarmEmail(alarmEmail);
jobInfo.setAlarmThreshold(alarm_threshold); jobInfo.setAlarmThreshold(alarmThreshold);
xxlJobInfoDao.save(jobInfo); xxlJobInfoDao.save(jobInfo);
try { try {
...@@ -174,7 +175,7 @@ public class JobInfoController { ...@@ -174,7 +175,7 @@ public class JobInfoController {
@ResponseBody @ResponseBody
public ReturnT<String> reschedule(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass, public ReturnT<String> reschedule(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass,
String handler_params, String handler_address, String handler_name, String handler_params, String handler_address, String handler_name,
String author, String alarm_email, int alarm_threshold) { String author, String alarmEmail, int alarmThreshold) {
// valid // valid
if (JobGroupEnum.match(jobGroup) == null) { if (JobGroupEnum.match(jobGroup) == null) {
...@@ -187,8 +188,19 @@ public class JobInfoController { ...@@ -187,8 +188,19 @@ public class JobInfoController {
return new ReturnT<String>(500, "“corn”不合法"); return new ReturnT<String>(500, "“corn”不合法");
} }
// parse jobDataMap
HashMap<String, String> jobDataMap = new HashMap<String, String>();
jobDataMap.put(HandlerRepository.HANDLER_PARAMS, handler_params);
jobDataMap.put(HandlerRepository.HANDLER_ADDRESS, handler_address);
jobDataMap.put(HandlerRepository.HANDLER_NAME, handler_name);
XxlJobInfo jobInfo = xxlJobInfoDao.load(jobGroup, jobName); XxlJobInfo jobInfo = xxlJobInfoDao.load(jobGroup, jobName);
jobInfo.setJobCron(jobCron); jobInfo.setJobCron(jobCron);
jobInfo.setJobDesc(jobDesc);
jobInfo.setJobData(JacksonUtil.writeValueAsString(jobDataMap));
jobInfo.setAuthor(author);
jobInfo.setAlarmEmail(alarmEmail);
jobInfo.setAlarmThreshold(alarmThreshold);
try { try {
// fresh quartz // fresh quartz
......
...@@ -71,7 +71,7 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao { ...@@ -71,7 +71,7 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao {
@Override @Override
public int updateTriggerInfo(XxlJobLog xxlJobLog) { public int updateTriggerInfo(XxlJobLog xxlJobLog) {
if (xxlJobLog!=null && xxlJobLog.getTriggerMsg().length()>2000) { if (xxlJobLog!=null && xxlJobLog.getTriggerMsg()!=null && xxlJobLog.getTriggerMsg().length()>2000) {
xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000)); xxlJobLog.setTriggerMsg(xxlJobLog.getTriggerMsg().substring(0, 2000));
} }
return sqlSessionTemplate.update("XxlJobLogMapper.updateTriggerInfo", xxlJobLog); return sqlSessionTemplate.update("XxlJobLogMapper.updateTriggerInfo", xxlJobLog);
...@@ -79,7 +79,7 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao { ...@@ -79,7 +79,7 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao {
@Override @Override
public int updateHandleInfo(XxlJobLog xxlJobLog) { public int updateHandleInfo(XxlJobLog xxlJobLog) {
if (xxlJobLog!=null && xxlJobLog.getHandleMsg().length()>2000) { if (xxlJobLog!=null && xxlJobLog.getHandleMsg()!=null && xxlJobLog.getHandleMsg().length()>2000) {
xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 2000)); xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 2000));
} }
return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog); return sqlSessionTemplate.update("XxlJobLogMapper.updateHandleInfo", xxlJobLog);
......
package com.xxl.job.service.job;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* http job bean
* @author xuxueli 2015-12-17 18:20:34
*/
@DisallowConcurrentExecution // 串行;线程数要多配置几个,否则不生效;
public class LocalJobBean extends QuartzJobBean {
private static Logger logger = LoggerFactory.getLogger(LocalJobBean.class);
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
String triggerKey = context.getTrigger().getKey().getName();
String triggerGroup = context.getTrigger().getKey().getGroup();
Map<String, Object> jobDataMap = context.getMergedJobDataMap().getWrappedMap();
// jobDataMap 2 params
Map<String, String> params = new HashMap<String, String>();
if (jobDataMap!=null && jobDataMap.size()>0) {
for (Entry<String, Object> item : jobDataMap.entrySet()) {
params.put(item.getKey(), String.valueOf(item.getValue()));
}
}
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info(">>>>>>>>>>> xxl-job run :jobId:{}, group:{}, jobDataMap:{}",
new Object[]{triggerKey, triggerGroup, jobDataMap});
}
}
\ No newline at end of file
package com.xxl.job.service.job;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* http job bean
* @author xuxueli 2015-12-17 18:20:34
*/
public class LocalJobBeanB extends QuartzJobBean {
private static Logger logger = LoggerFactory.getLogger(LocalJobBeanB.class);
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
String triggerKey = context.getTrigger().getKey().getName();
String triggerGroup = context.getTrigger().getKey().getGroup();
Map<String, Object> jobDataMap = context.getMergedJobDataMap().getWrappedMap();
// jobDataMap 2 params
Map<String, String> params = new HashMap<String, String>();
if (jobDataMap!=null && jobDataMap.size()>0) {
for (Entry<String, Object> item : jobDataMap.entrySet()) {
params.put(item.getKey(), String.valueOf(item.getValue()));
}
}
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info(">>>>>>>>>>> xxl-job run :jobId:{}, group:{}, jobDataMap:{}",
new Object[]{triggerKey, triggerGroup, jobDataMap});
}
}
\ No newline at end of file
package com.xxl.job.service.job;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import com.xxl.job.client.handler.HandlerRepository;
import com.xxl.job.client.util.HttpUtil;
import com.xxl.job.client.util.JacksonUtil;
import com.xxl.job.core.model.XxlJobInfo;
import com.xxl.job.core.model.XxlJobLog;
import com.xxl.job.core.util.DynamicSchedulerUtil;
/**
* http job bean
* @author xuxueli 2015-12-17 18:20:34
*/
public abstract class LocalNomalJobBean extends QuartzJobBean {
private static Logger logger = LoggerFactory.getLogger(LocalNomalJobBean.class);
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
JobKey jobKey = context.getTrigger().getJobKey();
XxlJobInfo jobInfo = DynamicSchedulerUtil.xxlJobInfoDao.load(jobKey.getGroup(), jobKey.getName());
@SuppressWarnings("unchecked")
HashMap<String, String> jobDataMap = (HashMap<String, String>) JacksonUtil.readValueRefer(jobInfo.getJobData(), Map.class);
// save log
XxlJobLog jobLog = new XxlJobLog();
jobLog.setJobGroup(jobInfo.getJobGroup());
jobLog.setJobName(jobInfo.getJobName());
jobLog.setJobCron(jobInfo.getJobCron());
jobLog.setJobDesc(jobInfo.getJobDesc());
jobLog.setJobClass(jobInfo.getJobClass());
jobLog.setJobData(jobInfo.getJobData());
jobLog.setJobClass(RemoteHttpJobBean.class.getName());
jobLog.setJobData(jobInfo.getJobData());
DynamicSchedulerUtil.xxlJobLogDao.save(jobLog);
logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog);
// trigger request
String handler_params = jobDataMap.get(HandlerRepository.HANDLER_PARAMS);
String[] handlerParams = null;
if (StringUtils.isNotBlank(handler_params)) {
handlerParams = handler_params.split(",");
}
jobLog.setTriggerTime(new Date());
jobLog.setTriggerStatus(HttpUtil.SUCCESS);
jobLog.setTriggerMsg(null);
try {
Object responseMsg = this.handle(handlerParams);
jobLog.setHandleTime(new Date());
jobLog.setHandleStatus(HttpUtil.SUCCESS);
jobLog.setHandleMsg(JacksonUtil.writeValueAsString(responseMsg));
} catch (Exception e) {
logger.info("HandlerThread Exception:", e);
StringWriter out = new StringWriter();
e.printStackTrace(new PrintWriter(out));
jobLog.setHandleTime(new Date());
jobLog.setHandleStatus(HttpUtil.FAIL);
jobLog.setHandleMsg(out.toString());
}
// update trigger info
DynamicSchedulerUtil.xxlJobLogDao.updateTriggerInfo(jobLog);
DynamicSchedulerUtil.xxlJobLogDao.updateHandleInfo(jobLog);
logger.info(">>>>>>>>>>> xxl-job trigger end, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
}
public abstract Object handle(String... param);
}
\ No newline at end of file
...@@ -27,8 +27,8 @@ import com.xxl.job.core.util.PropertiesUtil; ...@@ -27,8 +27,8 @@ import com.xxl.job.core.util.PropertiesUtil;
* @author xuxueli 2015-12-17 18:20:34 * @author xuxueli 2015-12-17 18:20:34
*/ */
@DisallowConcurrentExecution @DisallowConcurrentExecution
public class HttpJobBean extends QuartzJobBean { public class RemoteHttpJobBean extends QuartzJobBean {
private static Logger logger = LoggerFactory.getLogger(HttpJobBean.class); private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
...@@ -47,7 +47,7 @@ public class HttpJobBean extends QuartzJobBean { ...@@ -47,7 +47,7 @@ public class HttpJobBean extends QuartzJobBean {
jobLog.setJobClass(jobInfo.getJobClass()); jobLog.setJobClass(jobInfo.getJobClass());
jobLog.setJobData(jobInfo.getJobData()); jobLog.setJobData(jobInfo.getJobData());
jobLog.setJobClass(HttpJobBean.class.getName()); jobLog.setJobClass(RemoteHttpJobBean.class.getName());
jobLog.setJobData(jobInfo.getJobData()); jobLog.setJobData(jobInfo.getJobData());
DynamicSchedulerUtil.xxlJobLogDao.save(jobLog); DynamicSchedulerUtil.xxlJobLogDao.save(jobLog);
logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog); logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog);
......
triggerLogUrl=http://localhost:8080/xxl-job-admin/joblog/save trigger_log_url=http://localhost:8080/xxl-job-admin/joblog/save
\ No newline at end of file \ No newline at end of file
...@@ -148,11 +148,11 @@ ...@@ -148,11 +148,11 @@
<label for="lastname" class="col-sm-2 control-label">负责人</label> <label for="lastname" class="col-sm-2 control-label">负责人</label>
<div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="200" ></div> <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="200" ></div>
<label for="lastname" class="col-sm-2 control-label">报警邮件</label> <label for="lastname" class="col-sm-2 control-label">报警邮件</label>
<div class="col-sm-4"><input type="text" class="form-control" name="alarm_email" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="200" ></div> <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="200" ></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="lastname" class="col-sm-2 control-label">报警阈值</label> <label for="lastname" class="col-sm-2 control-label">报警阈值</label>
<div class="col-sm-4"><input type="text" class="form-control" name="alarm_threshold" placeholder="请输入“报警阈值”" maxlength="200" ></div> <div class="col-sm-4"><input type="text" class="form-control" name="alarmThreshold" placeholder="请输入“报警阈值”" maxlength="200" ></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-9"> <div class="col-sm-offset-3 col-sm-9">
...@@ -168,35 +168,49 @@ ...@@ -168,35 +168,49 @@
<!-- 更新.模态框 --> <!-- 更新.模态框 -->
<div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-hidden="true"> <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog"> <div class="modal-dialog modal-lg">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title" >更新corn</h4> <h4 class="modal-title" >新增任务调度信息</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form class="form-horizontal form" role="form" > <form class="form-horizontal form" role="form" >
<div class="form-group"> <div class="form-group">
<label for="firstname" class="col-sm-3 control-label">任务Key</label> <label for="firstname" class="col-sm-2 control-label">任务组</label>
<div class="col-sm-9"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" readonly ></div> <div class="col-sm-4"><input type="text" class="form-control" name="jobGroup" placeholder="请输入“任务组”" minlength="4" maxlength="100" readonly ></div>
<label for="firstname" class="col-sm-2 control-label">任务名</label>
<div class="col-sm-4"><input type="text" class="form-control" name="jobName" placeholder="请输入“任务名”" minlength="4" maxlength="100" readonly ></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务Corn</label> <label for="lastname" class="col-sm-2 control-label">Corn</label>
<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div> <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="请输入“Corn”" maxlength="100" ></div>
<label for="lastname" class="col-sm-2 control-label">描述</label>
<div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="请输入“描述”" maxlength="200" ></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务描述</label> <label for="firstname" class="col-sm-2 control-label">JobBean</label>
<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述" maxlength="200" ></div> <div class="col-sm-4"><input type="text" class="form-control" name="jobClass" placeholder="请输入“执行参数”" maxlength="100" readonly ></div>
<label for="firstname" class="col-sm-2 control-label">执行参数</label>
<div class="col-sm-4"><input type="text" class="form-control" name="handler_params" placeholder="请输入“执行参数”" maxlength="100" ></div>
</div>
<div class="form-group remote_panel">
<label for="lastname" class="col-sm-2 control-label">远程-机器地址</label>
<div class="col-sm-4"><input type="text" class="form-control" name="handler_address" placeholder="请输入“远程-机器地址”" maxlength="200" ></div>
<label for="lastname" class="col-sm-2 control-label">远程-执行器</label>
<div class="col-sm-4"><input type="text" class="form-control" name="handler_name" placeholder="请输入“远程-执行器”" maxlength="200" ></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务URL</label> <label for="lastname" class="col-sm-2 control-label">负责人</label>
<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL" maxlength="200" ></div> <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="200" ></div>
<label for="lastname" class="col-sm-2 control-label">报警邮件</label>
<div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="200" ></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务handler</label> <label for="lastname" class="col-sm-2 control-label">报警阈值</label>
<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler" maxlength="200" ></div> <div class="col-sm-4"><input type="text" class="form-control" name="alarmThreshold" placeholder="请输入“报警阈值”" maxlength="200" ></div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-primary" >保存</button> <button type="submit" class="btn btn-primary" >保存</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</div> </div>
......
...@@ -63,7 +63,9 @@ $(function() { ...@@ -63,7 +63,9 @@ $(function() {
if ('NORMAL' == data) { if ('NORMAL' == data) {
return '<small class="label label-success" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; return '<small class="label label-success" ><i class="fa fa-clock-o"></i>'+ data +'</small>';
} else if ('PAUSED' == data){ } else if ('PAUSED' == data){
return '<small class="label label-default"><i class="fa fa-clock-o"></i>'+ data +'</small>'; return '<small class="label label-default" title="暂停" ><i class="fa fa-clock-o"></i>'+ data +'</small>';
} else if ('BLOCKED' == data){
return '<small class="label label-default" title="阻塞[串行]" ><i class="fa fa-clock-o"></i>'+ data +'</small>';
} }
return data; return data;
} }
...@@ -238,11 +240,11 @@ $(function() { ...@@ -238,11 +240,11 @@ $(function() {
required : true , required : true ,
maxlength: 200 maxlength: 200
}, },
alarm_email : { alarmEmail : {
required : true , required : true ,
maxlength: 200 maxlength: 200
}, },
alarm_threshold : { alarmThreshold : {
required : true , required : true ,
digits:true digits:true
} }
...@@ -273,11 +275,11 @@ $(function() { ...@@ -273,11 +275,11 @@ $(function() {
required : "请输入“负责人”." , required : "请输入“负责人”." ,
maxlength: "“负责人”长度不应超过50位" maxlength: "“负责人”长度不应超过50位"
}, },
alarm_email : { alarmEmail : {
required : "请输入“报警邮件”." , required : "请输入“报警邮件”." ,
maxlength: "“报警邮件”长度不应超过200位" maxlength: "“报警邮件”长度不应超过200位"
}, },
alarm_threshold : { alarmThreshold : {
required : "请输入“报警阈值”." , required : "请输入“报警阈值”." ,
digits:"阀值应该为整数." digits:"阀值应该为整数."
} }
...@@ -295,9 +297,8 @@ $(function() { ...@@ -295,9 +297,8 @@ $(function() {
submitHandler : function(form) { submitHandler : function(form) {
$.post(base_url + "/jobinfo/add", $("#addModal .form").serialize(), function(data, status) { $.post(base_url + "/jobinfo/add", $("#addModal .form").serialize(), function(data, status) {
if (data.code == "200") { if (data.code == "200") {
ComAlert.show(1, "新增调度任务成功", function(){ ComAlert.show(1, "新增任务成功", function(){
ComAlert.show(1, "新增任务成功"); window.location.reload();
jobTable.fnDraw();
}); });
} else { } else {
if (data.msg) { if (data.msg) {
...@@ -310,29 +311,44 @@ $(function() { ...@@ -310,29 +311,44 @@ $(function() {
} }
}); });
$("#addModal").on('hide.bs.modal', function () { $("#addModal").on('hide.bs.modal', function () {
//$("#addModal .form")[0].reset(); $("#addModal .form")[0].reset();
addModalValidate.resetForm(); addModalValidate.resetForm();
$("#addModal .form .form-group").removeClass("has-error"); $("#addModal .form .form-group").removeClass("has-error");
$(".remote_panel").show(); // remote
}); });
// 远程任务/本地任务,切换 // 远程任务/本地任务,切换
$("#addModal select[name='jobClass']").change(function() { $("#addModal select[name='jobClass']").change(function() {
//console.log($(this).val()); //console.log( $(this).val().indexOf('RemoteHttpJobBean') );
console.log( $(this).val().indexOf('HttpJobBean') );
if($(this).val().indexOf('HttpJobBean') > -1){ if($(this).val().indexOf('RemoteHttpJobBean') > -1){
$(".remote_panel").show(); // remote $(".remote_panel").show(); // remote
} else if($(this).val().indexOf('HttpJobBean') == -1){ } else if($(this).val().indexOf('RemoteHttpJobBean') == -1){
$(".remote_panel").hide(); // local $(".remote_panel").hide(); // local
} }
}); });
// 更新 // 更新
$("#job_list").on('click', '.update',function() { $("#job_list").on('click', '.update',function() {
$("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("jobName")); $("#updateModal .form input[name='jobGroup']").val($(this).parent('p').attr("jobGroup"));
$("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression")); $("#updateModal .form input[name='jobName']").val($(this).parent('p').attr("jobName"));
$("#updateModal .form input[name='job_desc']").val($(this).parent('p').attr("job_desc")); $("#updateModal .form input[name='jobCron']").val($(this).parent('p').attr("jobCron"));
$("#updateModal .form input[name='job_url']").val($(this).parent('p').attr("job_url")); $("#updateModal .form input[name='jobDesc']").val($(this).parent('p').attr("jobDesc"));
$("#updateModal .form input[name='handleName']").val($(this).parent('p').attr("handleName")); $("#updateModal .form input[name='jobClass']").val($(this).parent('p').attr("jobClass"));
$("#updateModal .form input[name='handler_params']").val($(this).parent('p').attr("handler_params"));
$("#updateModal .form input[name='handler_address']").val($(this).parent('p').attr("handler_address"));
$("#updateModal .form input[name='handler_name']").val($(this).parent('p').attr("handler_name"));
$("#updateModal .form input[name='author']").val($(this).parent('p').attr("author"));
$("#updateModal .form input[name='alarmEmail']").val($(this).parent('p').attr("alarmEmail"));
$("#updateModal .form input[name='alarmThreshold']").val($(this).parent('p').attr("alarmThreshold"));
var _jobClass = $(this).parent('p').attr("jobClass");
if(_jobClass.indexOf('RemoteHttpJobBean') > -1){
$(".remote_panel").show(); // remote
} else if($(this).val().indexOf('RemoteHttpJobBean') == -1){
$(".remote_panel").hide(); // local
}
$('#updateModal').modal({backdrop: false, keyboard: false}).modal('show'); $('#updateModal').modal({backdrop: false, keyboard: false}).modal('show');
}); });
var updateModalValidate = $("#updateModal .form").validate({ var updateModalValidate = $("#updateModal .form").validate({
...@@ -340,49 +356,63 @@ $(function() { ...@@ -340,49 +356,63 @@ $(function() {
errorClass : 'help-block', errorClass : 'help-block',
focusInvalid : true, focusInvalid : true,
rules : { rules : {
triggerKeyName : { jobCron : {
required : true ,
minlength: 4,
maxlength: 100
},
cronExpression : {
required : true , required : true ,
maxlength: 100 maxlength: 100
}, },
job_desc : { jobDesc : {
required : true , required : true ,
maxlength: 200 maxlength: 200
}, },
job_url : { handler_address : {
required : true , required : true ,
maxlength: 200 maxlength: 200
}, },
handleName : { handler_name : {
required : true , required : true ,
maxlength: 200 maxlength: 200
},
author : {
required : true ,
maxlength: 200
},
alarmEmail : {
required : true ,
maxlength: 200
},
alarmThreshold : {
required : true ,
digits:true
} }
}, },
messages : { messages : {
triggerKeyName : { jobCron : {
required :"请输入“任务Key”." , required :"请输入“Corn”." ,
minlength:"“任务Key”不应低于4位", maxlength:"“Corn”长度不应超过100位"
maxlength:"“任务Key”不应超过100位"
},
cronExpression : {
required :"请输入“任务Corn”." ,
maxlength:"“任务Corn”不应超过100位"
}, },
job_desc : { jobDesc : {
required :"请输入“任务描述”." , required :"请输入“任务描述”." ,
maxlength:"“任务描述”长度不应超过200位" maxlength:"“任务描述”长度不应超过200位"
}, },
job_url : { handler_address : {
required :"请输入“任务URL”." , required :"请输入“远程-机器地址”." ,
maxlength:"“任务URL”长度不应超过200位" maxlength:"“远程-机器地址”长度不应超过200位"
}, },
handleName : { handler_name : {
required : "请输入“任务handler”." , required : "请输入“远程-执行器”." ,
maxlength: "“任务handler”长度不应超过200位" maxlength: "“远程-执行器”长度不应超过200位"
},
author : {
required : "请输入“负责人”." ,
maxlength: "“负责人”长度不应超过50位"
},
alarmEmail : {
required : "请输入“报警邮件”." ,
maxlength: "“报警邮件”长度不应超过200位"
},
alarmThreshold : {
required : "请输入“报警阈值”." ,
digits:"阀值应该为整数."
} }
}, },
highlight : function(element) { highlight : function(element) {
...@@ -396,7 +426,7 @@ $(function() { ...@@ -396,7 +426,7 @@ $(function() {
element.parent('div').append(error); element.parent('div').append(error);
}, },
submitHandler : function(form) { submitHandler : function(form) {
$.post(base_url + "/job/reschedule", $("#updateModal .form").serialize(), function(data, status) { $.post(base_url + "/jobinfo/reschedule", $("#updateModal .form").serialize(), function(data, status) {
if (data.code == "200") { if (data.code == "200") {
ComAlert.show(1, "更新成功", function(){ ComAlert.show(1, "更新成功", function(){
window.location.reload(); window.location.reload();
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/> <wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/> <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/> <wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<dependent-module archiveName="xxl-job-client-1.1.2-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/xxl-job-client/xxl-job-client"> <dependent-module archiveName="xxl-job-client-1.2.1-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/xxl-job-client/xxl-job-client">
<dependency-type>uses</dependency-type> <dependency-type>uses</dependency-type>
</dependent-module> </dependent-module>
<property name="context-root" value="xxl-job-client-demo"/> <property name="context-root" value="xxl-job-client-demo"/>
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
<parent> <parent>
<groupId>com.xxl</groupId> <groupId>com.xxl</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.1.1-SNAPSHOT</version> <version>1.2.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-client-demo</artifactId> <artifactId>xxl-job-client-demo</artifactId>
<version>1.1.2-SNAPSHOT</version> <version>1.2.1-SNAPSHOT</version>
<packaging>war</packaging> <packaging>war</packaging>
<properties> <properties>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
<dependency> <dependency>
<groupId>com.xxl</groupId> <groupId>com.xxl</groupId>
<artifactId>xxl-job-client</artifactId> <artifactId>xxl-job-client</artifactId>
<version>1.1.2-SNAPSHOT</version> <version>1.2.1-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
<parent> <parent>
<groupId>com.xxl</groupId> <groupId>com.xxl</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.1.1-SNAPSHOT</version> <version>1.2.0-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-client</artifactId> <artifactId>xxl-job-client</artifactId>
<version>1.1.2-SNAPSHOT</version> <version>1.2.1-SNAPSHOT</version>
<dependencies> <dependencies>
......
...@@ -43,14 +43,20 @@ public class HandlerRepository { ...@@ -43,14 +43,20 @@ public class HandlerRepository {
String _msg = ""; String _msg = "";
// push data to queue // push data to queue
HandlerThread handlerThread = handlerTreadMap.get(_param.get(HandlerRepository.HANDLER_NAME)); String handler_name = _param.get(HandlerRepository.HANDLER_NAME);
if (handlerThread != null) { if (handler_name!=null && handler_name.trim().length()>0) {
handlerThread.pushData(_param); HandlerThread handlerThread = handlerTreadMap.get(handler_name);
_status = HttpUtil.SUCCESS; if (handlerThread != null) {
} else { handlerThread.pushData(_param);
_msg = "handler not found."; _status = HttpUtil.SUCCESS;
} else {
_msg = "handler not found.";
}
}else{
_msg = "param[HANDLER_NAME] not exists.";
} }
HashMap<String, String> triggerData = new HashMap<String, String>(); HashMap<String, String> triggerData = new HashMap<String, String>();
triggerData.put(HandlerRepository.TRIGGER_LOG_ID, _param.get(HandlerRepository.TRIGGER_LOG_ID)); triggerData.put(HandlerRepository.TRIGGER_LOG_ID, _param.get(HandlerRepository.TRIGGER_LOG_ID));
triggerData.put(HttpUtil.status, _status); triggerData.put(HttpUtil.status, _status);
......
...@@ -35,60 +35,62 @@ public class HandlerThread extends Thread{ ...@@ -35,60 +35,62 @@ public class HandlerThread extends Thread{
int i = 1; int i = 1;
@Override @Override
public void run() { public void run() {
try { while(true){
i++; try {
Map<String, String> handlerData = handlerDataQueue.poll(); i++;
if (handlerData!=null) { Map<String, String> handlerData = handlerDataQueue.poll();
String trigger_log_url = handlerData.get(HandlerRepository.TRIGGER_LOG_URL); if (handlerData!=null) {
String trigger_log_id = handlerData.get(HandlerRepository.TRIGGER_LOG_ID); String trigger_log_url = handlerData.get(HandlerRepository.TRIGGER_LOG_URL);
String handler_params = handlerData.get(HandlerRepository.HANDLER_PARAMS); String trigger_log_id = handlerData.get(HandlerRepository.TRIGGER_LOG_ID);
String handler_params = handlerData.get(HandlerRepository.HANDLER_PARAMS);
// parse param
String[] handlerParams = null;
if (handler_params!=null && handler_params.trim().length()>0) {
handlerParams = handler_params.split(",");
} else {
handlerParams = new String[0];
}
// handle job
JobHandleStatus _status = JobHandleStatus.FAIL;
String _msg = null;
try {
_status = handler.handle(handlerParams);
} catch (Exception e) {
logger.info("HandlerThread Exception:", e);
StringWriter out = new StringWriter();
e.printStackTrace(new PrintWriter(out));
_msg = out.toString();
}
// callback handler info
String callback_response[] = null;
try {
HashMap<String, String> params = new HashMap<String, String>(); // parse param
params.put(HandlerRepository.TRIGGER_LOG_ID, trigger_log_id); String[] handlerParams = null;
params.put(HttpUtil.status, _status.name()); if (handler_params!=null && handler_params.trim().length()>0) {
params.put(HttpUtil.msg, _msg); handlerParams = handler_params.split(",");
callback_response = HttpUtil.post(trigger_log_url, params); } else {
} catch (Exception e) { handlerParams = new String[0];
logger.info("HandlerThread Exception:", e); }
}
logger.info("<<<<<<<<<<< xxl-job thread handle, handlerData:{}, callback_status:{}, callback_msg:{}, callback_response:{}, thread:{}", // handle job
new Object[]{handlerData, _status, _msg, callback_response, this}); JobHandleStatus _status = JobHandleStatus.FAIL;
} else { String _msg = null;
try { try {
TimeUnit.MILLISECONDS.sleep(i * 100); _status = handler.handle(handlerParams);
} catch (InterruptedException e) { } catch (Exception e) {
e.printStackTrace(); logger.info("HandlerThread Exception:", e);
} StringWriter out = new StringWriter();
if (i>5) { e.printStackTrace(new PrintWriter(out));
i= 0; _msg = out.toString();
}
// callback handler info
String callback_response[] = null;
try {
HashMap<String, String> params = new HashMap<String, String>();
params.put(HandlerRepository.TRIGGER_LOG_ID, trigger_log_id);
params.put(HttpUtil.status, _status.name());
params.put(HttpUtil.msg, _msg);
callback_response = HttpUtil.post(trigger_log_url, params);
} catch (Exception e) {
logger.info("HandlerThread Exception:", e);
}
logger.info("<<<<<<<<<<< xxl-job thread handle, handlerData:{}, callback_status:{}, callback_msg:{}, callback_response:{}, thread:{}",
new Object[]{handlerData, _status, _msg, callback_response, this});
} else {
try {
TimeUnit.MILLISECONDS.sleep(i * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i>5) {
i= 0;
}
} }
} catch (Exception e) {
logger.info("HandlerThread Exception:", e);
} }
} catch (Exception e) {
logger.info("HandlerThread Exception:", e);
} }
} }
} }
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
/target/
/.settings/
/bin/
/.gitignore
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>xxl-job-simple</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.common.project.facet.core.builder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
encoding//src/main/java=UTF8
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="xxl-job-simple">
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<property name="context-root" value="xxl-job-simple"/>
<property name="java-output-path" value="/xxl-job-simple/target/classes"/>
</wb-module>
</project-modules>
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<fixed facet="wst.jsdt.web"/>
<installed facet="java" version="1.6"/>
<installed facet="jst.web" version="2.5"/>
<installed facet="wst.jsdt.web" version="1.0"/>
</faceted-project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.xxl</groupId>
<artifactId>xxl-job</artifactId>
<version>1.1.1-SNAPSHOT</version>
</parent>
<artifactId>xxl-job-simple</artifactId>
<version>1.1.2-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<spring.version>3.2.14.RELEASE</spring.version>
</properties>
<dependencies>
<!-- springframe start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- springframe end -->
<!-- aspectjweaver (support spring aop) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<!-- jackson (support spring json) -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency>
<!-- commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<!-- commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<!-- quartz :quartz-2.2.1/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
</plugins>
</build>
</project>
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.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.ResponseBody;
import com.xxl.job.core.model.ReturnT;
import com.xxl.job.core.util.DynamicSchedulerUtil;
import com.xxl.job.service.job.DemoJobBean;
import com.xxl.job.service.job.DemoJobBeanB;
/**
* index controller
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
public class IndexController {
// local job bean list
public static Map<String, String> jobBeanMap = new HashMap<String, String>();
@RequestMapping("")
public String index(Model model) {
jobBeanMap.put(DemoJobBean.class.getName(), "测试任务");
jobBeanMap.put(DemoJobBeanB.class.getName(), "测试任务B");
model.addAttribute("jobBeanMap", jobBeanMap);
// job list
List<Map<String, Object>> jobList = DynamicSchedulerUtil.getJobList();
model.addAttribute("jobList", jobList);
return "job/index";
}
@RequestMapping("/help")
public String help(Model model) {
return "job/help";
}
@SuppressWarnings("unchecked")
@RequestMapping("/job/add")
@ResponseBody
public ReturnT<String> add(HttpServletRequest request) {
String triggerKeyName = null;
String cronExpression = null;
Map<String, Object> jobData = new HashMap<String, Object>();
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
Set<Map.Entry<String, String[]>> paramSet = request.getParameterMap().entrySet();
for (Entry<String, String[]> 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(), param.getValue().length>0?param.getValue()[0]:param.getValue());
}
}
// triggerKeyName
if (StringUtils.isBlank(triggerKeyName)) {
return new ReturnT<String>(500, "请输入“任务key”");
}
// cronExpression
if (StringUtils.isBlank(cronExpression)) {
return new ReturnT<String>(500, "请输入“任务corn”");
}
if (!CronExpression.isValidExpression(cronExpression)) {
return new ReturnT<String>(500, "“任务corn”不合法");
}
// jobData
if (jobData.get(DynamicSchedulerUtil.job_desc)==null || jobData.get(DynamicSchedulerUtil.job_desc).toString().trim().length()==0) {
return new ReturnT<String>(500, "请输入“任务描述”");
}
// job_bean
String job_bean = (String) jobData.get(DynamicSchedulerUtil.job_bean);
if (StringUtils.isBlank(job_bean)) {
return new ReturnT<String>(500, "JobBean不可为空");
}
// jobClass
Class<? extends Job> jobClass = null;
try {
Class<?> clazz = Class.forName(job_bean);
if (clazz!=null) {
jobClass = (Class<? extends Job>) clazz;
}
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
if (jobClass == null) {
return new ReturnT<String>(500, "JobBean未知");
}
try {
boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, jobData);
if (!result) {
return new ReturnT<String>(500, "任务ID重复,请更换确认");
}
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
}
return ReturnT.FAIL;
}
@RequestMapping("/job/reschedule")
@ResponseBody
public ReturnT<String> reschedule(String triggerKeyName, String cronExpression) {
// triggerKeyName
if (StringUtils.isBlank(triggerKeyName)) {
return new ReturnT<String>(500, "请输入“任务key”");
}
// cronExpression
if (StringUtils.isBlank(cronExpression)) {
return new ReturnT<String>(500, "请输入“任务corn”");
}
if (!CronExpression.isValidExpression(cronExpression)) {
return new ReturnT<String>(500, "“任务corn”不合法");
}
try {
DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
}
return ReturnT.FAIL;
}
@RequestMapping("/job/remove")
@ResponseBody
public ReturnT<String> remove(String triggerKeyName) {
try {
DynamicSchedulerUtil.removeJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
@RequestMapping("/job/pause")
@ResponseBody
public ReturnT<String> pause(String triggerKeyName) {
try {
DynamicSchedulerUtil.pauseJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
@RequestMapping("/job/resume")
@ResponseBody
public ReturnT<String> resume(String triggerKeyName) {
try {
DynamicSchedulerUtil.resumeJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
@RequestMapping("/job/trigger")
@ResponseBody
public ReturnT<String> triggerJob(String triggerKeyName) {
try {
DynamicSchedulerUtil.triggerJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
}
package com.xxl.job.core.model;
/**
* common return
* @author xuxueli 2015-12-4 16:32:31
* @param <T>
*/
public class ReturnT<T> {
public static final ReturnT<String> SUCCESS = new ReturnT<String>(null);
public static final ReturnT<String> FAIL = new ReturnT<String>(500, null);
private int code;
private String msg;
private T content;
public ReturnT(int code, String msg) {
this.code = code;
this.msg = msg;
}
public ReturnT(T content) {
this.code = 200;
this.content = content;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
@Override
public String toString() {
return "ReturnT [code=" + code + ", msg=" + msg + ", content="
+ content + "]";
}
}
package com.xxl.job.core.model;
import java.util.Date;
/**
* xxl-job log, used to track trigger process
* @author xuxueli 2015-12-19 23:19:09
*/
public class XxlJobLog {
private String jobTriggerUuid;
private String jobHandleName;
// trigger info
private Date triggerTime;
private String triggerStatus;
private String triggerDetailLog;
// handle info
private Date handleTime;
private String handleStatus;
private String handleDetailLog;
public String getJobTriggerUuid() {
return jobTriggerUuid;
}
public void setJobTriggerUuid(String jobTriggerUuid) {
this.jobTriggerUuid = jobTriggerUuid;
}
public String getJobHandleName() {
return jobHandleName;
}
public void setJobHandleName(String jobHandleName) {
this.jobHandleName = jobHandleName;
}
public Date getTriggerTime() {
return triggerTime;
}
public void setTriggerTime(Date triggerTime) {
this.triggerTime = triggerTime;
}
public String getTriggerStatus() {
return triggerStatus;
}
public void setTriggerStatus(String triggerStatus) {
this.triggerStatus = triggerStatus;
}
public String getTriggerDetailLog() {
return triggerDetailLog;
}
public void setTriggerDetailLog(String triggerDetailLog) {
this.triggerDetailLog = triggerDetailLog;
}
public Date getHandleTime() {
return handleTime;
}
public void setHandleTime(Date handleTime) {
this.handleTime = handleTime;
}
public String getHandleStatus() {
return handleStatus;
}
public void setHandleStatus(String handleStatus) {
this.handleStatus = handleStatus;
}
public String getHandleDetailLog() {
return handleDetailLog;
}
public void setHandleDetailLog(String handleDetailLog) {
this.handleDetailLog = handleDetailLog;
}
@Override
public String toString() {
return "XxlJobLog [jobTriggerUuid=" + jobTriggerUuid + ", jobHandleName=" + jobHandleName
+ ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus + ", triggerDetailLog="
+ triggerDetailLog + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus
+ ", handleDetailLog=" + handleDetailLog + "]";
}
}
package com.xxl.job.core.util;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* base quartz scheduler util
* @author xuxueli 2015-12-19 16:13:53
*/
public final class DynamicSchedulerUtil implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(DynamicSchedulerUtil.class);
// Scheduler
private static Scheduler scheduler;
public static void setScheduler(Scheduler scheduler) {
DynamicSchedulerUtil.scheduler = scheduler;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(scheduler, "quartz scheduler is null");
logger.info(">>>>>>>>> init quartz scheduler success.[{}]", scheduler);
}
// getJobKeys
public static List<Map<String, Object>> getJobList(){
List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
try {
if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
return null;
}
String groupName = scheduler.getJobGroupNames().get(0);
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
if (jobKeys!=null && jobKeys.size()>0) {
for (JobKey jobKey : jobKeys) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
Trigger trigger = scheduler.getTrigger(triggerKey);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
TriggerState triggerState = scheduler.getTriggerState(triggerKey);
Map<String, Object> jobMap = new HashMap<String, Object>();
jobMap.put("TriggerKey", triggerKey);
jobMap.put("Trigger", trigger);
jobMap.put("JobDetail", jobDetail);
jobMap.put("TriggerState", triggerState);
jobList.add(jobMap);
}
}
} catch (SchedulerException e) {
e.printStackTrace();
return null;
}
return jobList;
}
public static final String job_desc = "job_desc";
public static final String job_bean = "job_bean";
// addJob 新增
public static boolean addJob(String triggerKeyName, String cronExpression, Class<? extends Job> jobClass, Map<String, Object> jobData) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
// TriggerKey valid if_exists
if (scheduler.checkExists(triggerKey)) {
Trigger trigger = scheduler.getTrigger(triggerKey);
logger.info(">>>>>>>>> Already exist trigger [" + trigger + "] by key [" + triggerKey + "] in Scheduler");
return false;
}
// CronTrigger : TriggerKey + cronExpression
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
// JobDetail : jobClass
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(triggerKeyName, group).build();
if (jobData!=null && jobData.size() > 0) {
JobDataMap jobDataMap = jobDetail.getJobDataMap();
jobDataMap.putAll(jobData); // JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
}
// schedule : jobDetail + cronTrigger
Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
logger.info(">>>>>>>>>>> addJob success, jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date);
return true;
}
// reschedule 重置cron
public static boolean rescheduleJob(String triggerKeyName, String cronExpression) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
// CronTrigger : TriggerKey + cronExpression
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
Date date = scheduler.rescheduleJob(triggerKey, cronTrigger);
result = true;
logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}, cronExpression:{}, date:{}", triggerKey, cronExpression, date);
} else {
logger.info(">>>>>>>>>>> resumeJob fail, triggerKey:{}, cronExpression:{}", triggerKey, cronExpression);
}
return result;
}
// unscheduleJob 删除
public static boolean removeJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
result = scheduler.unscheduleJob(triggerKey);
}
logger.info(">>>>>>>>>>> removeJob, triggerKey:{}, result [{}]", triggerKey, result);
return result;
}
// Pause 暂停
public static boolean pauseJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
scheduler.pauseTrigger(triggerKey);
result = true;
logger.info(">>>>>>>>>>> pauseJob success, triggerKey:{}", triggerKey);
} else {
logger.info(">>>>>>>>>>> pauseJob fail, triggerKey:{}", triggerKey);
}
return result;
}
// resume 重启
public static boolean resumeJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
scheduler.resumeTrigger(triggerKey);
result = true;
logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}", triggerKey);
} else {
logger.info(">>>>>>>>>>> resumeJob fail, triggerKey:{}", triggerKey);
}
return result;
}
// run 执行一次
public static boolean triggerJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
JobKey jobKey = JobKey.jobKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(jobKey)) {
scheduler.triggerJob(jobKey);
result = true;
logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey);
} else {
logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey);
}
return result;
}
}
\ No newline at end of file
package com.xxl.job.service;
/**
* local trigger, only exists in local jvm
* @author xuxueli 2015-12-17 17:29:23
*/
public interface ITriggerService {
public void beat();
}
package com.xxl.job.service.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.xxl.job.service.ITriggerService;
/**
* local trigger, only exists in local jvm
* @author xuxueli 2015-12-17 17:31:24
*/
@Service("triggerService")
public class TriggerServiceImpl implements ITriggerService {
private static transient Logger logger = LoggerFactory.getLogger(TriggerServiceImpl.class);
public void beat() {
logger.info(">>>>>>>>>>> xxl-job beat success.");
}
}
package com.xxl.job.service.job;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* http job bean
* @author xuxueli 2015-12-17 18:20:34
*/
@DisallowConcurrentExecution // 取消并发执行;线程数要多配置几个,否则不生效;
public class DemoJobBean extends QuartzJobBean {
private static Logger logger = LoggerFactory.getLogger(DemoJobBean.class);
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
String triggerKey = context.getTrigger().getKey().getName();
String triggerGroup = context.getTrigger().getKey().getGroup();
Map<String, Object> jobDataMap = context.getMergedJobDataMap().getWrappedMap();
// jobDataMap 2 params
Map<String, String> params = new HashMap<String, String>();
if (jobDataMap!=null && jobDataMap.size()>0) {
for (Entry<String, Object> item : jobDataMap.entrySet()) {
params.put(item.getKey(), String.valueOf(item.getValue()));
}
}
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info(">>>>>>>>>>> xxl-job run :jobId:{}, group:{}, jobDataMap:{}",
new Object[]{triggerKey, triggerGroup, jobDataMap});
}
}
\ No newline at end of file
package com.xxl.job.service.job;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* http job bean
* @author xuxueli 2015-12-17 18:20:34
*/
public class DemoJobBeanB extends QuartzJobBean {
private static Logger logger = LoggerFactory.getLogger(DemoJobBeanB.class);
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
String triggerKey = context.getTrigger().getKey().getName();
String triggerGroup = context.getTrigger().getKey().getGroup();
Map<String, Object> jobDataMap = context.getMergedJobDataMap().getWrappedMap();
// jobDataMap 2 params
Map<String, String> params = new HashMap<String, String>();
if (jobDataMap!=null && jobDataMap.size()>0) {
for (Entry<String, Object> item : jobDataMap.entrySet()) {
params.put(item.getKey(), String.valueOf(item.getValue()));
}
}
logger.info(">>>>>>>>>>> xxl-job run :jobId:{}, group:{}, jobDataMap:{}",
new Object[]{triggerKey, triggerGroup, jobDataMap});
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config />
<context:component-scan base-package="com.xxl.job.service" />
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/template/" />
<property name="freemarkerSettings">
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:freemarker.properties" />
</bean>
</property>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="fileEncoding" value="utf-8" />
<property name="locations">
<list>
<value>classpath*:jdbc.properties</value>
</list>
</property>
</bean>
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.xxl.service.impl, com.xxl.dao.impl" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${c3p0.driverClass}" />
<property name="jdbcUrl" value="${c3p0.url}" />
<property name="user" value="${c3p0.user}" />
<property name="password" value="${c3p0.password}" />
<property name="initialPoolSize" value="3" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="10" />
<property name="maxIdleTime" value="60" />
<property name="acquireRetryDelay" value="1000" />
<property name="acquireRetryAttempts" value="10" />
<property name="preferredTestQuery" value="SELECT 1" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath*:com/xxl/core/model/mapper/*.xml"/>
</bean>
<!-- scope must be "prototype" when junit -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="quartzScheduler" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="autoStartup" value="true" />
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties"/>
</bean>
<!-- 协同-调度器 -->
<bean id="dynamicSchedulerUtil" class="com.xxl.job.core.util.DynamicSchedulerUtil">
<!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) -->
<property name="scheduler" ref="quartzScheduler"/>
</bean>
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="beatJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="triggerService" />
<property name="targetMethod" value="beat" />
<property name="concurrent" value="false" />
</bean>
<bean id="beatTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="beatJobDetail" />
<property name="cronExpression" value="0/10 * * * * ? *" />
</bean>
<!-- 进程-调度器 -->
<bean name="jvmQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<!-- <ref bean="beatTrigger" /> -->
</list>
</property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="detail*" propagation="SUPPORTS" />
<tx:method name="visit*" propagation="SUPPORTS" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="find*" propagation="SUPPORTS" />
<tx:method name="check*" propagation="SUPPORTS" />
<tx:method name="list*" propagation="SUPPORTS" />
<tx:method name="*" propagation="REQUIRED" rollback-for="exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txoperation" expression="execution(* com.xxl.service.imp.*.*(..))" />
<aop:advisor pointcut-ref="txoperation" advice-ref="txAdvice" />
</aop:config>
</beans>
\ No newline at end of file
template_update_delay=0
default_encoding=UTF-8
output_encoding=UTF-8
locale=zh_CN
number_format=0.##########
date_format=yyyy-MM-dd
time_format=HH:mm:ss
datetime_format=yyyy-MM-dd HH:mm:s
classic_compatible=true
template_exception_handler=ignore
\ No newline at end of file
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.url=jdbc:mysql://localhost:3306/test?Unicode=true&amp;characterEncoding=UTF-8
c3p0.user=root
c3p0.password=root_pwd
\ No newline at end of file
log4j.rootLogger=info,console,logFile
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d - xxl-job-admin - %p [%c] - <%m>%n
log4j.appender.logFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logFile.File=${catalina.base}/logs/xxl-job-admin.log
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=%d - xxl-job-admin - %p [%c] - <%m>%n
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# for cluster
org.quartz.jobStore.tablePrefix = XXL_JOB_QRTZ_
org.quartz.scheduler.instanceId: AUTO
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.isClustered: true
org.quartz.jobStore.clusterCheckinInterval: 1000
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.xxl.job.controller" />
<mvc:resources mapping="/favicon.ico" location="/favicon.ico" />
<mvc:resources mapping="/static/**" location="/static/" />
<mvc:resources mapping="/**/*.html" location="/" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="requestContextAttribute" value="request" />
<property name="cache" value="true" />
<property name="order" value="0" />
</bean>
<!--
// 自定义拦截器,支持SSO登陆拦截
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.xxl.controller.interceptor.PermissionInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<bean id="exceptionResolver" class="com.xxl.controller.resolver.WebExceptionResolver" />
-->
</beans>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>应用程序异常 (500)</title>
<style type="text/css">
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog {
width: 80%;
padding: 1em 4em;
margin: 4em auto 0 auto;
border: 1px solid #ccc;
border-right-color: #999;
border-bottom-color: #999;
}
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
</style>
</head>
</head>
<body>
<div class="dialog">
<h1>应用程序异常</h1>
<p>抱歉!您访问的页面出现异常,请稍后重试或联系管理员。</p>
<p><a href="javascript:showErr();">详 情</a>
<a href="javascript:window.location.href='${request.contextPath}'">返 回</a>
</p>
<div style="display:none;text-align: left;" id="err">${exceptionMsg}</div>
</div>
<script type="text/javascript">
function showErr(){
document.getElementById("err").style.display = "";
}
</script>
</body>
</html>
\ No newline at end of file
<#macro commonStyle>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.5 -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/bootstrap/css/bootstrap.min.css">
<!-- Font Awesome -->
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> -->
<link rel="stylesheet" href="${request.contextPath}/static/plugins/font-awesome-4.3.0/css/font-awesome.min.css">
<!-- Ionicons -->
<!-- <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"> -->
<link rel="stylesheet" href="${request.contextPath}/static/plugins/ionicons-2.0.1/css/ionicons.min.css">
<!-- Theme style -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/AdminLTE.min.css">
<!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/skins/_all-skins.min.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- scrollup -->
<link rel="stylesheet" href="${request.contextPath}/static/plugins/scrollup/image.css">
</#macro>
<#macro commonScript>
<!-- jQuery 2.1.4 -->
<script src="${request.contextPath}/static/adminlte/plugins/jQuery/jQuery-2.1.4.min.js"></script>
<!-- Bootstrap 3.3.5 -->
<script src="${request.contextPath}/static/adminlte/bootstrap/js/bootstrap.min.js"></script>
<!-- FastClick -->
<script src="${request.contextPath}/static/adminlte/plugins/fastclick/fastclick.js"></script>
<!-- AdminLTE App -->
<script src="${request.contextPath}/static/adminlte/dist/js/app.min.js"></script>
<!-- scrollup -->
<script src="${request.contextPath}/static/plugins/scrollup/jquery.scrollUp.min.js"></script>
<script src="${request.contextPath}/static/js/common.1.js"></script>
</#macro>
<#macro commonHeader>
<header class="main-header">
<a href="${request.contextPath}/" class="logo">
<span class="logo-mini"><b>X</b>XL</span>
<span class="logo-lg"><b>任务调度</b>中心</span>
</a>
<nav class="navbar navbar-static-top" role="navigation">
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"><span class="sr-only">切换导航</span></a>
<div class="navbar-custom-menu"></div>
</nav>
</header>
</#macro>
<#macro commonLeft>
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu">
<li class="header">常用模块</li>
<li class="nav-click" ><a href="${request.contextPath}//"><i class="fa fa-circle-o text-red"></i> <span>调度中心</span></a></li>
<li class="nav-click" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-yellow"></i><span>使用教程</span></a></li>
</ul>
</section>
<!-- /.sidebar -->
</aside>
</#macro>
<#macro commonControl >
<!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark">
<!-- Create the tabs -->
<ul class="nav nav-tabs nav-justified control-sidebar-tabs">
<li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
<li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<!-- Home tab content -->
<div class="tab-pane active" id="control-sidebar-home-tab">
<h3 class="control-sidebar-heading">近期活动</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-birthday-cake bg-red"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">张三今天过生日</h4>
<p>2015-09-10</p>
</div>
</a>
</li>
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-user bg-yellow"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Frodo 更新了资料</h4>
<p>更新手机号码 +1(800)555-1234</p>
</div>
</a>
</li>
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-envelope-o bg-light-blue"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Nora 加入邮件列表</h4>
<p>nora@example.com</p>
</div>
</a>
</li>
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-file-code-o bg-green"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">001号定时作业调度</h4>
<p>5秒前执行</p>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
</div>
<!-- /.tab-pane -->
<!-- Settings tab content -->
<div class="tab-pane" id="control-sidebar-settings-tab">
<form method="post">
<h3 class="control-sidebar-heading">个人设置</h3>
<div class="form-group">
<label class="control-sidebar-subheading"> 左侧菜单自适应
<input type="checkbox" class="pull-right" checked>
</label>
<p>左侧菜单栏样式自适应</p>
</div>
<!-- /.form-group -->
</form>
</div>
<!-- /.tab-pane -->
</div>
</aside>
<!-- /.control-sidebar -->
<!-- Add the sidebar's background. This div must be placed immediately after the control sidebar -->
<div class="control-sidebar-bg"></div>
</#macro>
<#macro commonFooter >
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>Version</b> 1.0
</div>
<strong>Copyright &copy; 2015-2015 &nbsp;
<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>&nbsp;
<a href="http://www.cnblogs.com/xuxueli/p/5021979.html" target="_blank" >cnblog</a>.
</strong> All rights reserved.
</footer>
</#macro>
<#macro comAlert >
<!-- ComAlert.模态框Modal -->
<div class="modal fade" id="ComAlert" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<!-- <div class="modal-header"><h4 class="modal-title"><strong>提示:</strong></h4></div> -->
<div class="modal-body"><div class="alert alert-success"></div></div>
<div class="modal-footer">
<div class="text-center" >
<button type="button" class="btn btn-default ok" data-dismiss="modal" >确认</button>
</div>
</div>
</div>
</div>
</div>
<!-- ComConfirm.模态框Modal -->
<div class="modal fade" id="ComConfirm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body"><div class="alert alert-success"></div></div>
<div class="modal-footer">
<div class="text-center" >
<button type="button" class="btn btn-primary ok" data-dismiss="modal" >确认</button>
<button type="button" class="btn btn-default cancel" data-dismiss="modal" >取消</button>
</div>
</div>
</div>
</div>
</div>
<script>
// 通用提示
var ComAlert = {
show:function(type, msg, callback){
// 弹框初始
if (type == 1) {
$('#ComAlert .alert').attr('class', 'alert alert-success');
} else {
$('#ComAlert .alert').attr('class', 'alert alert-warning');
}
$('#ComAlert .alert').html(msg);
$('#ComAlert').modal('show');
$('#ComAlert .ok').click(function(){
$('#ComAlert').modal('hide');
if(typeof callback == 'function') {
callback();
}
});
// $("#ComAlert").on('hide.bs.modal', function () { }); // 监听关闭
}
};
// 通用确认弹框
var ComConfirm = {
show:function(msg, callback){
// 弹框初始
$('#ComConfirm .alert').attr('class', 'alert alert-warning');
$('#ComConfirm .alert').html(msg);
$('#ComConfirm').modal('show');
$('#ComConfirm .ok').unbind("click"); // 解绑陈旧事件
$('#ComConfirm .ok').click(function(){
$('#ComConfirm').modal('hide');
if(typeof callback == 'function') {
callback();
return;
}
});
$('#ComConfirm .cancel').click(function(){
$('#ComConfirm').modal('hide');
return;
});
}
};
</script>
</#macro>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>调度中心</title>
<#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle />
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- header -->
<@netCommon.commonHeader />
<!-- left -->
<@netCommon.commonLeft />
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>使用教程<small>调度管理平台</small></h1>
<ol class="breadcrumb">
<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
<li class="active">使用教程</li>
</ol>
</section>
<!-- Main content -->
<section class="content">
<div class="callout callout-info">
<h4>简介:XXL_JOB</h4>
<p>基于quartz封装实现的的集群任务调度管理平台.</p>
<p></p>
</div>
<div class="callout callout-default">
<h4>特点:</h4>
<p>1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手.</p>
<p>2、动态:支持动态修改任务状态,动态暂停/恢复任务,即时生效.</p>
<p>3、集群:任务信息持久化到mysql中,支持Job服务器集群(高可用),一个任务只会在其中一台服务器上执行.</p>
</div>
<div class="callout callout-default">
<h4>分层模型:</h4>
<p>1、基础:基于quartz封装底层调度层,通过CORN自定义任务执行周期,最终执行自定义JobBean的execute方法,如需多个任务,需要开发多个JobBean实现.</p>
<p>2、分层:上述基础调度模型存在一定局限,调度层和任务层耦合,当新任务上线势必影响任务的正常调度,因此规划将调度系统分层为:调度层 + 任务层 + 通讯层.</p>
<p>
<div class="row">
<div class="col-xs-offset-1 col-xs-11">
<p>》调度模块:维护任务的调度信息,负责定时/周期性的发出调度请求.</p>
<p>》任务模块:具体的任务逻辑,负责接收调度模块的调度请求,执行任务逻辑.</p>
<p>》通讯模块:负责调度模块和任务模块之间的通讯.</p>
<p>(总而言之,一条完整任务由 “调度信息” 和 “任务信息” 组成.)</p>
</div>
</div>
</p>
</div>
<div class="callout callout-default">
<h4>调度属性解析 : 发出HTTP调度请求</h4>
<p>1、调度Key【必填】:调度信息的全局唯一标识.</p>
<p>2、调度Corn【必填】:调度执行的时间表达式.</p>
<p>3、调度描述【必填】:调度的简述.</p>
<p>4、调度URL【必填】:调度执行时发出HTTP请求的目标URL地址.</p>
<p>5、+args【选填】:调度执行时发出HTTP请求的附带的POST参数.</p>
</div>
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<!-- footer -->
<@netCommon.commonFooter />
<!-- control -->
<@netCommon.commonControl />
</div>
<@netCommon.commonScript />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>调度中心</title>
<#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle />
<!-- DataTables -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- header -->
<@netCommon.commonHeader />
<!-- left -->
<@netCommon.commonLeft />
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>调度中心<small>调度管理</small></h1>
<ol class="breadcrumb">
<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
<li class="active">调度管理</li>
</ol>
</section>
<!-- Main content -->
<section class="content">
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">调度列表</h3>
<button class="btn btn-info btn-xs add" type="button">+新增任务</button>
</div>
<div class="box-body">
<table id="job_list" class="table table-bordered table-striped">
<thead>
<tr>
<th>调度key</th>
<th>cron</th>
<!--<th>类路径</th>-->
<th>参数</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<#if jobList?exists && jobList?size gt 0>
<#list jobList as item>
<tr>
<td>${item['TriggerKey'].name}</td>
<td>${item['Trigger'].cronExpression}</td>
<!--<td>${item['JobDetail'].jobClass}</td>-->
<td>
<#assign jobDataMap = item['JobDetail'].jobDataMap />
<#if jobDataMap?exists && jobDataMap?keys?size gt 0>
<#list jobDataMap?keys as key>
${key} = ${jobDataMap[key]} <br>
</#list>
</#if>
</td>
<td state="${item['TriggerState']}" >
<#if item['TriggerState'] == 'NORMAL'>
<button class="btn btn-block btn-success" type="button">运行ing</button>
<#elseif item['TriggerState'] == 'PAUSED'>
<button class="btn btn-block btn-warning" type="button">暂停ing</button>
<#else>
<button class="btn btn-block" type="button">${item['TriggerState']}</button>
</#if>
</td>
<td>
<p name="${item['TriggerKey'].name}" group="${item['TriggerKey'].group}"
cronExpression="${item['Trigger'].cronExpression}" jobClassName="${item['JobDetail'].jobClass}" jobDesc="${job_desc?if_exists}" >
<#if item['TriggerState'] == 'NORMAL'>
<button class="btn btn-info btn-xs job_operate" type="job_pause" type="button">暂停</button>
<#elseif item['TriggerState'] == 'PAUSED'>
<button class="btn btn-info btn-xs job_operate" type="job_resume" type="button">恢复</button>
</#if>
<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行一次</button>
<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>
<button class="btn btn-info btn-xs update" type="button">更新corn</button>
</p>
</td>
</tr>
</#list>
</#if>
</tbody>
<tfoot>
<tr>
<th>调度key</th>
<th>cron</th>
<!--<th>类路径</th>-->
<th>参数</th>
<th>状态</th>
<th>操作</th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</section>
</div>
<!-- footer -->
<@netCommon.commonFooter />
<!-- control -->
<@netCommon.commonControl />
</div>
<!-- job新增.模态框 -->
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" >新增调度信息</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label for="firstname" class="col-sm-3 control-label">任务Key</label>
<div class="col-sm-9"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务Corn</label>
<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn[允许修改]" maxlength="100" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务描述</label>
<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述[不支持修改]" maxlength="200" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务JobBean</label>
<div class="col-sm-9">
<select name="job_bean" >
<#if jobBeanMap?exists && jobBeanMap?size gt 0>
<#list jobBeanMap?keys as key>
<option value ="${key}" <#if key_index == 0>selected="selected"</#if> >${jobBeanMap[key]}[${key}]</option>
</#list>
</#if>
</select>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-primary" >保存</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-info pull-right addParam">+ arg</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 更新.模态框 -->
<div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" >更新corn</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label for="firstname" class="col-sm-2 control-label">任务Key</label>
<div class="col-sm-10"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" readonly ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">任务Corn</label>
<div class="col-sm-10"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" >保存</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<@netCommon.commonScript />
<@netCommon.comAlert />
<!-- DataTables -->
<script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
<script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
<script>var base_url = '${request.contextPath}';</script>
<script src="${request.contextPath}/static/js/job.index.1.js"></script>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>xxl-job-admin</display-name>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>xxl-job-admin</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationcontext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/500.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
</web-app>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论