Ver código fonte

重要版本升级:
1、新增“任务组”;
2、整合“远程调度”和“本地调度”;

xueli.xue 9 anos atrás
pai
commit
554429ea59
19 arquivos alterados com 571 adições e 547 exclusões
  1. 113 97
      xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java
  2. 5 3
      xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java
  3. 20 11
      xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java
  4. 10 4
      xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java
  5. 76 52
      xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java
  6. 4 5
      xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobInfoDao.java
  7. 16 11
      xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobInfoDaoImpl.java
  8. 22 22
      xxl-job-admin/src/main/java/com/xxl/job/service/job/HttpJobBean.java
  9. 57 31
      xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml
  10. 5 1
      xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml
  11. 47 67
      xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl
  12. 2 1
      xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl
  13. 160 105
      xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js
  14. 1 0
      xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js
  15. 4 4
      xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java
  16. 2 2
      xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogTest.java
  17. 3 4
      xxl-job-client-demo/src/main/java/com/xxl/job/service/handler/DemoJobHandler.java
  18. 23 124
      xxl-job-client/src/main/java/com/xxl/job/client/handler/HandlerRepository.java
  19. 1 3
      xxl-job-client/src/main/java/com/xxl/job/client/handler/IJobHandler.java

+ 113 - 97
xxl-job-admin/src/main/java/com/xxl/job/controller/JobInfoController.java

@@ -1,14 +1,11 @@
 package com.xxl.job.controller;
 
-import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
 
 import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.lang.StringUtils;
 import org.quartz.CronExpression;
@@ -28,6 +25,8 @@ import com.xxl.job.core.model.XxlJobInfo;
 import com.xxl.job.core.util.DynamicSchedulerUtil;
 import com.xxl.job.dao.IXxlJobInfoDao;
 import com.xxl.job.service.job.HttpJobBean;
+import com.xxl.job.service.job.LocalJobBean;
+import com.xxl.job.service.job.LocalJobBeanB;
 
 /**
  * index controller
@@ -40,9 +39,20 @@ public class JobInfoController {
 	@Resource
 	private IXxlJobInfoDao xxlJobInfoDao;
 	
+	// remote job bean
+	public static Class <? extends Job> remoteJobBean = HttpJobBean.class;
+	// loacal job bean
+	public static List<Class <? extends Job>> localJobBeanList = new ArrayList<Class<? extends Job>>();
+	static{
+		localJobBeanList.add(LocalJobBean.class);
+		localJobBeanList.add(LocalJobBeanB.class);
+	}
+	
 	@RequestMapping
 	public String index(Model model) {
-		model.addAttribute("JobGroupList", JobGroupEnum.values());
+		model.addAttribute("localJobBeanList", localJobBeanList);			// 本地任务-列表
+		model.addAttribute("remoteJobBean", remoteJobBean);	// 远程任务-jobBean
+		model.addAttribute("JobGroupList", JobGroupEnum.values());			// 任务组列表
 		return "jobinfo/index";
 	}
 	
@@ -50,11 +60,11 @@ public class JobInfoController {
 	@ResponseBody
 	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
 			@RequestParam(required = false, defaultValue = "10") int length,
-			String jobName, String filterTime) {
+			String jobGroup, String jobName, String filterTime) {
 		
 		// page list
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobName, null, null);
-		int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null);
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobName);
+		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobName);
 		
 		// fill job info
 		if (list!=null && list.size()>0) {
@@ -71,72 +81,89 @@ public class JobInfoController {
 		return maps;
 	}
 	
+	@SuppressWarnings("unchecked")
 	@RequestMapping("/add")
 	@ResponseBody
-	public ReturnT<String> add(HttpServletRequest request) {
-		String triggerKeyName = null;
-		String cronExpression = null;
-		Map<String, String> jobData = new HashMap<String, String>();
+	public ReturnT<String> add(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass,
+			String handler_params, String handler_address, String handler_name, 
+			String author, String alarm_email, int alarm_threshold) {
 		
+		// valid
+		if (JobGroupEnum.match(jobGroup) == null) {
+			return new ReturnT<String>(500, "请选择“任务组”");
+		}
+		if (StringUtils.isBlank(jobName)) {
+			return new ReturnT<String>(500, "请输入“任务名”");
+		}
+		if (!CronExpression.isValidExpression(jobCron)) {
+			return new ReturnT<String>(500, "“corn”不合法");
+		}
+		if (StringUtils.isBlank(jobDesc)) {
+			return new ReturnT<String>(500, "请输入“任务描述”");
+		}
+		Class<? extends Job> jobClass_ = null;
 		try {
-			request.setCharacterEncoding("utf-8");
-		} catch (UnsupportedEncodingException e1) {
+			Class<?> clazz = Class.forName(jobClass);
+			if (clazz!=null) {
+				jobClass_ = (Class<? extends Job>) clazz;
+			}
+		} catch (ClassNotFoundException e1) {
 			e1.printStackTrace();
 		}
-		@SuppressWarnings("unchecked")
-		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(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue()));
-			}
+		if (jobClass_ == null) {
+			return new ReturnT<String>(500, "请选择“JobBean”");
 		}
-		
-		// triggerKeyName
-		if (StringUtils.isBlank(triggerKeyName)) {
-			return new ReturnT<String>(500, "请输入“任务key”");
+		if (jobClass_.getClass().getName().equals(remoteJobBean.getName())) {
+			if (StringUtils.isBlank(handler_address)) {
+				return new ReturnT<String>(500, "请输入“远程-机器地址”");
+			}
+			if (StringUtils.isBlank(handler_name)) {
+				return new ReturnT<String>(500, "请输入“远程-执行器”");
+			}
 		}
-		
-		// cronExpression
-		if (StringUtils.isBlank(cronExpression)) {
-			return new ReturnT<String>(500, "请输入“任务corn”");
+		if (StringUtils.isBlank(author)) {
+			return new ReturnT<String>(500, "请输入“负责人”");
 		}
-		if (!CronExpression.isValidExpression(cronExpression)) {
-			return new ReturnT<String>(500, "“任务corn”不合法");
+		if (StringUtils.isBlank(alarm_email)) {
+			return new ReturnT<String>(500, "请输入“报警邮件”");
 		}
 		
-		// jobData
-		if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) {
-			return new ReturnT<String>(500, "请输入“任务描述”");
-		}
-		if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) {
-			return new ReturnT<String>(500, "请输入“任务URL”");
-		}
-		if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) {
-			return new ReturnT<String>(500, "请输入“任务handler”");
+		try {
+			if (DynamicSchedulerUtil.checkExists(jobName, jobGroup)) {
+				return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
+			}
+		} catch (SchedulerException e1) {
+			e1.printStackTrace();
+			return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
 		}
 		
-		// jobClass
-		Class<? extends Job> jobClass = HttpJobBean.class;
+		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);
+		
+		// Backup to the database
+		XxlJobInfo jobInfo = new XxlJobInfo();
+		jobInfo.setJobGroup(jobGroup);
+		jobInfo.setJobName(jobName);
+		jobInfo.setJobCron(jobCron);
+		jobInfo.setJobDesc(jobDesc);
+		jobInfo.setJobClass(jobClass);
+		jobInfo.setJobData(JacksonUtil.writeValueAsString(jobDataMap));
+		jobInfo.setAuthor(author);
+		jobInfo.setAlarmEmail(alarm_email);
+		jobInfo.setAlarmThreshold(alarm_threshold);
+		xxlJobInfoDao.save(jobInfo);
 		
 		try {
 			// add job 2 quartz
-			boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null);
-			if (!result) {
-				return new ReturnT<String>(500, "任务ID重复,请更换确认");
+			boolean result = DynamicSchedulerUtil.addJob(jobInfo);
+			if (result) {
+				return ReturnT.SUCCESS;
+			} else {
+				xxlJobInfoDao.delete(jobGroup, jobName);
+				return new ReturnT<String>(500, "新增任务失败");
 			}
-			// Backup to the database
-			XxlJobInfo jobInfo = new XxlJobInfo();
-			jobInfo.setJobName(triggerKeyName);
-			jobInfo.setJobCron(cronExpression);
-			jobInfo.setJobClass(jobClass.getName());
-			jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData));
-			xxlJobInfoDao.save(jobInfo);
-			
-			return ReturnT.SUCCESS;
 		} catch (SchedulerException e) {
 			e.printStackTrace();
 		}
@@ -145,27 +172,30 @@ public class JobInfoController {
 	
 	@RequestMapping("/reschedule")
 	@ResponseBody
-	public ReturnT<String> reschedule(String triggerKeyName, String cronExpression) {
-		// triggerKeyName
-		if (StringUtils.isBlank(triggerKeyName)) {
-			return new ReturnT<String>(500, "请输入“任务key”");
+	public ReturnT<String> reschedule(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass,
+			String handler_params, String handler_address, String handler_name, 
+			String author, String alarm_email, int alarm_threshold) {
+		
+		// valid
+		if (JobGroupEnum.match(jobGroup) == null) {
+			return new ReturnT<String>(500, "请选择“任务组”");
 		}
-		// cronExpression
-		if (StringUtils.isBlank(cronExpression)) {
-			return new ReturnT<String>(500, "请输入“任务corn”");
+		if (StringUtils.isBlank(jobName)) {
+			return new ReturnT<String>(500, "请输入“任务名”");
 		}
-		if (!CronExpression.isValidExpression(cronExpression)) {
-			return new ReturnT<String>(500, "“任务corn”不合法");
+		if (!CronExpression.isValidExpression(jobCron)) {
+			return new ReturnT<String>(500, "“corn”不合法");
 		}
+		
+		XxlJobInfo jobInfo = xxlJobInfoDao.load(jobGroup, jobName);
+		jobInfo.setJobCron(jobCron);
+		
 		try {
-			DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression);
+			// fresh quartz
+			DynamicSchedulerUtil.rescheduleJob(jobInfo);
 			
-			// update
-			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
-			if (jobInfo!=null) {
-				jobInfo.setJobCron(cronExpression);
-				xxlJobInfoDao.update(jobInfo);
-			}
+			// fresh db
+			xxlJobInfoDao.update(jobInfo);
 			return ReturnT.SUCCESS;
 		} catch (SchedulerException e) {
 			e.printStackTrace();
@@ -175,13 +205,11 @@ public class JobInfoController {
 	
 	@RequestMapping("/remove")
 	@ResponseBody
-	public ReturnT<String> remove(String triggerKeyName) {
+	public ReturnT<String> remove(String jobGroup, String jobName) {
 		try {
-			if (triggerKeyName!=null) {
-				DynamicSchedulerUtil.removeJob(triggerKeyName);
-				xxlJobInfoDao.delete(triggerKeyName);
-				return ReturnT.SUCCESS;
-			}
+			DynamicSchedulerUtil.removeJob(jobName, jobGroup);
+			xxlJobInfoDao.delete(jobGroup, jobName);
+			return ReturnT.SUCCESS;
 		} catch (SchedulerException e) {
 			e.printStackTrace();
 		}
@@ -190,15 +218,9 @@ public class JobInfoController {
 	
 	@RequestMapping("/pause")
 	@ResponseBody
-	public ReturnT<String> pause(String triggerKeyName) {
+	public ReturnT<String> pause(String jobGroup, String jobName) {
 		try {
-			DynamicSchedulerUtil.pauseJob(triggerKeyName);
-			// update
-			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
-			if (jobInfo!=null) {
-				jobInfo.setJobStatus("PAUSED");
-				xxlJobInfoDao.update(jobInfo);
-			}
+			DynamicSchedulerUtil.pauseJob(jobName, jobGroup);	// jobStatus do not store
 			return ReturnT.SUCCESS;
 		} catch (SchedulerException e) {
 			e.printStackTrace();
@@ -208,15 +230,9 @@ public class JobInfoController {
 	
 	@RequestMapping("/resume")
 	@ResponseBody
-	public ReturnT<String> resume(String triggerKeyName) {
+	public ReturnT<String> resume(String jobGroup, String jobName) {
 		try {
-			DynamicSchedulerUtil.resumeJob(triggerKeyName);
-			// update
-			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
-			if (jobInfo!=null) {
-				jobInfo.setJobStatus("NORMAL");
-				xxlJobInfoDao.update(jobInfo);
-			}
+			DynamicSchedulerUtil.resumeJob(jobName, jobGroup);
 			return ReturnT.SUCCESS;
 		} catch (SchedulerException e) {
 			e.printStackTrace();
@@ -226,9 +242,9 @@ public class JobInfoController {
 	
 	@RequestMapping("/trigger")
 	@ResponseBody
-	public ReturnT<String> triggerJob(String triggerKeyName) {
+	public ReturnT<String> triggerJob(String jobGroup, String jobName) {
 		try {
-			DynamicSchedulerUtil.triggerJob(triggerKeyName);
+			DynamicSchedulerUtil.triggerJob(jobName, jobGroup);
 			return ReturnT.SUCCESS;
 		} catch (SchedulerException e) {
 			e.printStackTrace();

+ 5 - 3
xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java

@@ -33,7 +33,9 @@ public class JobLogController {
 	public IXxlJobLogDao xxlJobLogDao;
 	
 	@RequestMapping
-	public String index(Model model) {
+	public String index(Model model, String jobGroup, String jobName) {
+		model.addAttribute("jobGroup", jobGroup);
+		model.addAttribute("jobName", jobName);
 		model.addAttribute("JobGroupList", JobGroupEnum.values());
 		return "joblog/index";
 	}
@@ -71,8 +73,8 @@ public class JobLogController {
 	
 	@RequestMapping("/save")
 	@ResponseBody
-	public ReturnT<String> triggerLog(int triggerLogId, String status, String msg) {
-		XxlJobLog log = xxlJobLogDao.load(triggerLogId);
+	public ReturnT<String> triggerLog(int trigger_log_id, String status, String msg) {
+		XxlJobLog log = xxlJobLogDao.load(trigger_log_id);
 		if (log!=null) {
 			log.setHandleTime(new Date());
 			log.setHandleStatus(status);

+ 20 - 11
xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobInfo.java

@@ -10,21 +10,22 @@ public class XxlJobInfo {
 	
 	private int id;
 	
-	private String jobGroup;	// base on quartz	任务组
-	private String jobName;		// base on quartz	任务名
-	private String jobCron;		// base on quartz	任务执行CRON表达式
-	private String jobClass;	// base on quartz	任务执行JobBean
-	private String jobData;		// base on db, Map-JSON-String	任务执行数据
+	private String jobGroup;	// 任务组
+	private String jobName;		// 任务名
+	private String jobCron;		// 任务执行CRON表达式 【base on quartz】
+	private String jobDesc;
+	private String jobClass;	// 任务执行JobBean 【base on quartz】
+	private String jobData;		// 任务执行数据 Map-JSON-String
 	
 	private Date addTime;
 	private Date updateTime;
 	
-	private String author;		// 作者
+	private String author;		// 负责人
 	private String alarmEmail;	// 报警邮件
 	private int alarmThreshold;	// 报警阀值
 	
 	// copy from quartz
-	private String jobStatus;	// 任务状态
+	private String jobStatus;	// 任务状态 【base on quartz】
 
 	public int getId() {
 		return id;
@@ -58,6 +59,14 @@ public class XxlJobInfo {
 		this.jobCron = jobCron;
 	}
 
+	public String getJobDesc() {
+		return jobDesc;
+	}
+
+	public void setJobDesc(String jobDesc) {
+		this.jobDesc = jobDesc;
+	}
+
 	public String getJobClass() {
 		return jobClass;
 	}
@@ -125,9 +134,9 @@ public class XxlJobInfo {
 	@Override
 	public String toString() {
 		return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron
-				+ ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime="
-				+ updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold="
-				+ alarmThreshold + ", jobStatus=" + jobStatus + "]";
+				+ ", jobDesc=" + jobDesc + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime
+				+ ", updateTime=" + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail
+				+ ", alarmThreshold=" + alarmThreshold + ", jobStatus=" + jobStatus + "]";
 	}
-	
+
 }

+ 10 - 4
xxl-job-admin/src/main/java/com/xxl/job/core/model/XxlJobLog.java

@@ -14,6 +14,7 @@ public class XxlJobLog {
 	private String jobGroup;
 	private String jobName;
 	private String jobCron;
+	private String jobDesc;
 	private String jobClass;
 	private String jobData;
 	
@@ -26,7 +27,6 @@ public class XxlJobLog {
 	private Date handleTime;
 	private String handleStatus;
 	private String handleMsg;
-	
 	public int getId() {
 		return id;
 	}
@@ -51,6 +51,12 @@ public class XxlJobLog {
 	public void setJobCron(String jobCron) {
 		this.jobCron = jobCron;
 	}
+	public String getJobDesc() {
+		return jobDesc;
+	}
+	public void setJobDesc(String jobDesc) {
+		this.jobDesc = jobDesc;
+	}
 	public String getJobClass() {
 		return jobClass;
 	}
@@ -103,9 +109,9 @@ public class XxlJobLog {
 	@Override
 	public String toString() {
 		return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron
-				+ ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime
-				+ ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime
-				+ ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]";
+				+ ", jobDesc=" + jobDesc + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime="
+				+ triggerTime + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime="
+				+ handleTime + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]";
 	}
 	
 }

+ 76 - 52
xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java

@@ -3,6 +3,7 @@ package com.xxl.job.core.util;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -29,6 +30,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.util.Assert;
 
+import com.xxl.job.client.util.JacksonUtil;
 import com.xxl.job.core.model.XxlJobInfo;
 import com.xxl.job.dao.IXxlJobInfoDao;
 import com.xxl.job.dao.IXxlJobLogDao;
@@ -124,29 +126,42 @@ public final class DynamicSchedulerUtil implements InitializingBean {
 			e.printStackTrace();
 		}
 	}
+	
+	// check if exists
+	public static boolean checkExists(String jobName, String jobGroup) throws SchedulerException{
+		TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
+		return scheduler.checkExists(triggerKey);
+	}
 
 	// addJob 新增
-    public static boolean addJob(String triggerKeyName, String cronExpression, Class<? extends Job> jobClass, Map<String, Object> jobData) throws SchedulerException {
+    @SuppressWarnings("unchecked")
+	public static boolean addJob(XxlJobInfo jobInfo) throws SchedulerException {
     	// TriggerKey : name + group
-    	String group = Scheduler.DEFAULT_GROUP;
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(), jobInfo.getJobGroup());
+        JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
         
         // TriggerKey valid if_exists
-        if (scheduler.checkExists(triggerKey)) {
-            Trigger trigger = scheduler.getTrigger(triggerKey);
-            logger.info(">>>>>>>>> Already exist trigger [" + trigger + "] by key [" + triggerKey + "] in Scheduler");
+        if (checkExists(jobInfo.getJobName(), jobInfo.getJobGroup())) {
+            logger.info(">>>>>>>>> addJob fail, job already exist, jobInfo:{}", jobInfo);
             return false;
         }
         
         // CronTrigger : TriggerKey + cronExpression	// withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度
-        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getJobCron()).withMisfireHandlingInstructionDoNothing();
         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) {
+		Class<? extends Job> jobClass_ = null;
+		try {
+			jobClass_ = (Class<? extends Job>)Class.forName(jobInfo.getJobClass());
+		} catch (ClassNotFoundException e) {
+			e.printStackTrace();
+		}
+        
+		JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();
+        if (jobInfo.getJobData()!=null) {
         	JobDataMap jobDataMap = jobDetail.getJobDataMap();
-        	jobDataMap.putAll(jobData);	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
+        	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
 		}
         
         // schedule : jobDetail + cronTrigger
@@ -156,49 +171,60 @@ public final class DynamicSchedulerUtil implements InitializingBean {
         return true;
     }
     
-    // reschedule 重置cron
-    public static boolean rescheduleJob(String triggerKeyName, String cronExpression) throws SchedulerException {
+    // reschedule
+    @SuppressWarnings("unchecked")
+	public static boolean rescheduleJob(XxlJobInfo jobInfo) throws SchedulerException {
+    	
+    	// TriggerKey valid if_exists
+        if (!checkExists(jobInfo.getJobName(), jobInfo.getJobGroup())) {
+        	logger.info(">>>>>>>>>>> rescheduleJob fail, job not exists, jobInfo:{}", jobInfo);
+            return false;
+        }
+        
         // TriggerKey : name + group
-    	String group = Scheduler.DEFAULT_GROUP;
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(), jobInfo.getJobGroup());
+        JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
         
-        boolean result = false;
-        if (scheduler.checkExists(triggerKey)) {
-            // CronTrigger : TriggerKey + cronExpression
-            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
-            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;
+        // CronTrigger : TriggerKey + cronExpression
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getJobCron()).withMisfireHandlingInstructionDoNothing();
+        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
+        
+        //scheduler.rescheduleJob(triggerKey, cronTrigger);
+        
+        // JobDetail-JobDataMap fresh
+        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
+    	JobDataMap jobDataMap = jobDetail.getJobDataMap();
+    	jobDataMap.clear();
+    	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));
+    	
+    	// Trigger fresh
+    	HashSet<Trigger> triggerSet = new HashSet<Trigger>();
+    	triggerSet.add(cronTrigger);
+        
+        scheduler.scheduleJob(jobDetail, triggerSet, true);
+        logger.info(">>>>>>>>>>> resumeJob success, jobInfo:{}", jobInfo);
+        return true;
     }
     
-    // unscheduleJob 删除
-    public static boolean removeJob(String triggerKeyName) throws SchedulerException {
+    // unscheduleJob
+    public static boolean removeJob(String jobName, String jobGroup) throws SchedulerException {
     	// TriggerKey : name + group
-    	String group = Scheduler.DEFAULT_GROUP;
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
-        
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
         boolean result = false;
-        if (scheduler.checkExists(triggerKey)) {
+        if (checkExists(jobName, jobGroup)) {
             result = scheduler.unscheduleJob(triggerKey);
+            logger.info(">>>>>>>>>>> removeJob, triggerKey:{}, result [{}]", triggerKey, result);
         }
-        logger.info(">>>>>>>>>>> removeJob, triggerKey:{}, result [{}]", triggerKey, result);
-        return result;
+        return true;
     }
 
-    // Pause 暂停
-    public static boolean pauseJob(String triggerKeyName) throws SchedulerException {
+    // Pause
+    public static boolean pauseJob(String jobName, String jobGroup) throws SchedulerException {
     	// TriggerKey : name + group
-    	String group = Scheduler.DEFAULT_GROUP;
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
+    	TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
         
         boolean result = false;
-        if (scheduler.checkExists(triggerKey)) {
+        if (checkExists(jobName, jobGroup)) {
             scheduler.pauseTrigger(triggerKey);
             result = true;
             logger.info(">>>>>>>>>>> pauseJob success, triggerKey:{}", triggerKey);
@@ -208,14 +234,13 @@ public final class DynamicSchedulerUtil implements InitializingBean {
         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);
+    // resume
+    public static boolean resumeJob(String jobName, String jobGroup) throws SchedulerException {
+    	// TriggerKey : name + group
+    	TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
         
         boolean result = false;
-        if (scheduler.checkExists(triggerKey)) {
+        if (checkExists(jobName, jobGroup)) {
             scheduler.resumeTrigger(triggerKey);
             result = true;
             logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}", triggerKey);
@@ -225,14 +250,13 @@ public final class DynamicSchedulerUtil implements InitializingBean {
         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);
+    // run
+    public static boolean triggerJob(String jobName, String jobGroup) throws SchedulerException {
+    	// TriggerKey : name + group
+    	JobKey jobKey = new JobKey(jobName, jobGroup);
         
         boolean result = false;
-        if (scheduler.checkExists(jobKey)) {
+        if (checkExists(jobName, jobGroup)) {
             scheduler.triggerJob(jobKey);
             result = true;
             logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey);

+ 4 - 5
xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobInfoDao.java

@@ -1,6 +1,5 @@
 package com.xxl.job.dao;
 
-import java.util.Date;
 import java.util.List;
 
 import com.xxl.job.core.model.XxlJobInfo;
@@ -11,15 +10,15 @@ import com.xxl.job.core.model.XxlJobInfo;
  */
 public interface IXxlJobInfoDao {
 
-	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd);
-	public int pageListCount(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd);
+	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobGroup, String jobName);
+	public int pageListCount(int offset, int pagesize, String jobGroup, String jobName);
 	
 	public int save(XxlJobInfo info);
 	
-	public XxlJobInfo load(String jobName);
+	public XxlJobInfo load(String jobGroup, String jobName);
 	
 	public int update(XxlJobInfo item);
 	
-	public int delete(String jobName);
+	public int delete(String jobGroup, String jobName);
 	
 }

+ 16 - 11
xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobInfoDaoImpl.java

@@ -1,6 +1,5 @@
 package com.xxl.job.dao.impl;
 
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 
@@ -23,25 +22,23 @@ public class XxlJobInfoDaoImpl implements IXxlJobInfoDao {
 	public SqlSessionTemplate sqlSessionTemplate;
 
 	@Override
-	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd) {
+	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobGroup, String jobName) {
 		HashMap<String, Object> params = new HashMap<String, Object>();
 		params.put("offset", offset);
 		params.put("pagesize", pagesize);
+		params.put("jobGroup", jobGroup);
 		params.put("jobName", jobName);
-		params.put("addTimeStart", addTimeStart);
-		params.put("addTimeEnd", addTimeEnd);
 		
 		return sqlSessionTemplate.selectList("XxlJobInfoMapper.pageList", params);
 	}
 
 	@Override
-	public int pageListCount(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd) {
+	public int pageListCount(int offset, int pagesize, String jobGroup, String jobName) {
 		HashMap<String, Object> params = new HashMap<String, Object>();
 		params.put("offset", offset);
 		params.put("pagesize", pagesize);
+		params.put("jobGroup", jobGroup);
 		params.put("jobName", jobName);
-		params.put("addTimeStart", addTimeStart);
-		params.put("addTimeEnd", addTimeEnd);
 		
 		return sqlSessionTemplate.selectOne("XxlJobInfoMapper.pageListCount", params);
 	}
@@ -52,8 +49,12 @@ public class XxlJobInfoDaoImpl implements IXxlJobInfoDao {
 	}
 
 	@Override
-	public XxlJobInfo load(String jobName) {
-		return sqlSessionTemplate.selectOne("XxlJobInfoMapper.load", jobName);
+	public XxlJobInfo load(String jobGroup, String jobName) {
+		HashMap<String, Object> params = new HashMap<String, Object>();
+		params.put("jobGroup", jobGroup);
+		params.put("jobName", jobName);
+		
+		return sqlSessionTemplate.selectOne("XxlJobInfoMapper.load", params);
 	}
 
 	@Override
@@ -62,8 +63,12 @@ public class XxlJobInfoDaoImpl implements IXxlJobInfoDao {
 	}
 
 	@Override
-	public int delete(String jobName) {
-		return sqlSessionTemplate.update("XxlJobInfoMapper.delete", jobName);
+	public int delete(String jobGroup, String jobName) {
+		HashMap<String, Object> params = new HashMap<String, Object>();
+		params.put("jobGroup", jobGroup);
+		params.put("jobName", jobName);
+		
+		return sqlSessionTemplate.update("XxlJobInfoMapper.delete", params);
 	}
 	
 }

+ 22 - 22
xxl-job-admin/src/main/java/com/xxl/job/service/job/HttpJobBean.java

@@ -5,9 +5,10 @@ import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.commons.lang.StringUtils;
+import org.quartz.DisallowConcurrentExecution;
 import org.quartz.JobExecutionContext;
 import org.quartz.JobExecutionException;
-import org.quartz.impl.triggers.CronTriggerImpl;
+import org.quartz.JobKey;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.scheduling.quartz.QuartzJobBean;
@@ -22,44 +23,43 @@ import com.xxl.job.core.util.PropertiesUtil;
 
 /**
  * http job bean
+ * “@DisallowConcurrentExecution” diable concurrent, thread size can not be only one, better given more
  * @author xuxueli 2015-12-17 18:20:34
  */
+@DisallowConcurrentExecution
 public class HttpJobBean extends QuartzJobBean {
 	private static Logger logger = LoggerFactory.getLogger(HttpJobBean.class);
-
+	
 	@SuppressWarnings("unchecked")
 	@Override
 	protected void executeInternal(JobExecutionContext context)
 			throws JobExecutionException {
-		String triggerKey = context.getTrigger().getJobKey().getName();
-		
-		// jobDataMap 2 params
-		Map<String, String> params = new HashMap<String, String>();
-		XxlJobInfo jobInfo = DynamicSchedulerUtil.xxlJobInfoDao.load(triggerKey);
-		if (jobInfo!=null && jobInfo.getJobData()!=null) {
-			params = JacksonUtil.readValue(jobInfo.getJobData(), Map.class);
-		}
-		
-		// corn
-		String cornExp = null;
-		if (context.getTrigger() instanceof CronTriggerImpl) {
-			CronTriggerImpl trigger = (CronTriggerImpl) context.getTrigger();
-			cornExp = trigger.getCronExpression();
-		}
+		JobKey jobKey = context.getTrigger().getJobKey();
 		
+		XxlJobInfo jobInfo = DynamicSchedulerUtil.xxlJobInfoDao.load(jobKey.getGroup(), jobKey.getName());
+		HashMap<String, String> jobDataMap = (HashMap<String, String>) JacksonUtil.readValueRefer(jobInfo.getJobData(), Map.class);
 		// save log
 		XxlJobLog jobLog = new XxlJobLog();
-		jobLog.setJobName(triggerKey);
-		jobLog.setJobCron(cornExp);
+		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(HttpJobBean.class.getName());
 		jobLog.setJobData(jobInfo.getJobData());
 		DynamicSchedulerUtil.xxlJobLogDao.save(jobLog);
 		logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog);
 		
 		// trigger request
-		params.put(HandlerRepository.triggerLogId, String.valueOf(jobLog.getId()));
-		params.put(HandlerRepository.triggerLogUrl, PropertiesUtil.getString(HandlerRepository.triggerLogUrl));
-		String[] postResp = HttpUtil.post(params.get(HandlerRepository.job_url), params);
+		HashMap<String, String> params = new HashMap<String, String>();
+		params.put(HandlerRepository.TRIGGER_LOG_URL, PropertiesUtil.getString(HandlerRepository.TRIGGER_LOG_URL));
+		params.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(jobLog.getId()));
+		params.put(HandlerRepository.HANDLER_NAME, jobDataMap.get(HandlerRepository.HANDLER_NAME));
+		params.put(HandlerRepository.HANDLER_PARAMS, jobDataMap.get(HandlerRepository.HANDLER_PARAMS));
+		
+		String[] postResp = HttpUtil.post(jobDataMap.get(HandlerRepository.HANDLER_ADDRESS), params);
 		logger.info(">>>>>>>>>>> xxl-job trigger http response, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
 		
 		// parse trigger response

+ 57 - 31
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml

@@ -6,37 +6,45 @@
 	<resultMap id="XxlJobInfo" type="com.xxl.job.core.model.XxlJobInfo" >
 		<result column="id" property="id" />
 	
+		<result column="job_group" property="jobGroup" />
 	    <result column="job_name" property="jobName" />
 	    <result column="job_cron" property="jobCron" />
+	    <result column="job_desc" property="jobDesc" />
 	    <result column="job_class" property="jobClass" />
 	    <result column="job_data" property="jobData" />
 	    
 	    <result column="add_time" property="addTime" />
 	    <result column="update_time" property="updateTime" />
+	    
+	    <result column="author" property="author" />
+	    <result column="alarm_email" property="alarmEmail" />
+	    <result column="alarm_threshold" property="alarmThreshold" />
 	</resultMap>
 
 	<sql id="Base_Column_List">
 		t.id,
+		t.job_group,
 		t.job_name,
 		t.job_cron,
+		t.job_desc,
 		t.job_class,
 		t.job_data,
 		t.add_time,
-		t.update_time
+		t.update_time,
+		t.author,
+		t.alarm_email,
+		t.alarm_threshold
 	</sql>
 	
 	<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
 		SELECT <include refid="Base_Column_List" />
 		FROM xxl_job_qrtz_trigger_info AS t
 		<trim prefix="WHERE" prefixOverrides="AND | OR" >
-			<if test="jobName != null and jobName!=''">
-				AND t.job_name = #{jobName}
-			</if>
-			<if test="addTimeStart != null">
-				AND t.add_time <![CDATA[ > ]]> #{addTimeStart}
+			<if test="jobGroup != null and jobGroup != ''">
+				AND t.job_group = #{jobGroup}
 			</if>
-			<if test="addTimeEnd != null">
-				AND t.add_time <![CDATA[ < ]]> #{addTimeEnd}
+			<if test="jobName != null and jobName != ''">
+				AND t.job_name like CONCAT(CONCAT('%', #{jobName}), '%')
 			</if>
 		</trim>
 		ORDER BY id DESC
@@ -47,56 +55,74 @@
 		SELECT count(1)
 		FROM xxl_job_qrtz_trigger_info AS t
 		<trim prefix="WHERE" prefixOverrides="AND | OR" >
-			<if test="jobName != null and jobName!=''">
-				AND t.job_name = #{jobName}
+			<if test="jobGroup != null and jobGroup != ''">
+				AND t.job_group = #{jobGroup}
 			</if>
-			<if test="addTimeStart != null">
-				AND t.add_time <![CDATA[ > ]]> #{addTimeStart}
-			</if>
-			<if test="addTimeEnd != null">
-				AND t.add_time <![CDATA[ < ]]> #{addTimeEnd}
+			<if test="jobName != null and jobName != ''">
+				AND t.job_name like CONCAT(CONCAT('%', #{jobName}), '%')
 			</if>
 		</trim>
 	</select>
 	
 	<insert id="save" parameterType="com.xxl.job.core.model.XxlJobInfo" useGeneratedKeys="true" keyProperty="id" >
 		INSERT INTO `xxl_job_qrtz_trigger_info` (
-			`job_name`, 
-			`job_cron`, 
-			`job_class`, 
-			`job_data`,
-			`add_time`,
-			`update_time`
+			job_group,
+			job_name,
+			job_cron,
+			job_desc,
+			job_class,
+			job_data,
+			add_time,
+			update_time,
+			author,
+			alarm_email,
+			alarm_threshold
 		) VALUES (
+			#{jobGroup}, 
 			#{jobName}, 
 			#{jobCron}, 
+			#{jobDesc}, 
 			#{jobClass}, 
 			#{jobData},
 			NOW(),
-			NOW()
+			NOW(),
+			#{author},
+			#{alarmEmail},
+			#{alarmThreshold}
 		);
 		<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> 
 			SELECT LAST_INSERT_ID() 
 		</selectKey> 
 	</insert>
 	
-	<select id="load" parameterType="java.lang.String" resultMap="XxlJobInfo">
+	<select id="load" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
 		SELECT <include refid="Base_Column_List" />
 		FROM xxl_job_qrtz_trigger_info AS t
-		WHERE t.job_name = #{jobName}
+		WHERE t.job_group = #{jobGroup}
+			AND t.job_name = #{jobName}
 	</select>
 	
-	<update id="update">
+	<update id="update" parameterType="com.xxl.job.core.model.XxlJobInfo" >
 		UPDATE `xxl_job_qrtz_trigger_info` 
-		SET `job_cron`= #{jobCron}, 
-			`job_data`= #{jobData},
-			`update_time`= NOW()
-		WHERE `id`= #{id}
+		SET 
+			job_cron = #{jobCron},
+			job_desc = #{jobDesc},
+			job_data = #{jobData},
+			update_time = NOW(),
+			author = #{author},
+			alarm_email = #{alarmEmail},
+			alarm_threshold = #{alarmThreshold}
+		WHERE job_group = #{jobGroup}
+			AND job_name = #{jobName}
 	</update>
 	
 	<delete id="delete" parameterType="java.lang.String">
-		delete from xxl_job_qrtz_trigger_info
-		where job_name = #{jobName}
+		DELETE
+		FROM
+			xxl_job_qrtz_trigger_info
+		WHERE
+			job_group = #{jobGroup}
+		AND job_name = #{jobName}
 	</delete>
 	
 </mapper>

+ 5 - 1
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml

@@ -9,6 +9,7 @@
 	    <result column="job_group" property="jobGroup" />
 	    <result column="job_name" property="jobName" />
 	    <result column="job_cron" property="jobCron" />
+	    <result column="job_desc" property="jobDesc" />
 	    <result column="job_class" property="jobClass" />
 	    <result column="job_data" property="jobData" />
 	    
@@ -26,8 +27,9 @@
 		t.job_group,
 		t.job_name,
 		t.job_cron,
+		t.job_desc,
 		t.job_class,
-		t.job_data,
+		t.job_desc,
 		t.trigger_time,
 		t.trigger_status,
 		t.trigger_msg,
@@ -94,12 +96,14 @@
 			`job_group`,
 			`job_name`,
 			`job_cron`, 
+			`job_desc`,
 			`job_class`, 
 			`job_data`
 		) VALUES (
 			#{jobGroup}, 
 			#{jobName},
 			#{jobCron},
+			#{jobDesc},
 			#{jobClass},
 			#{jobData}
 		);

+ 47 - 67
xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl

@@ -42,9 +42,7 @@
 	            </div>
 	            <div class="col-xs-4">
 	              	<div class="input-group">
-	                	<span class="input-group-addon">
-	                  		jobName
-	                	</span>
+	                	<span class="input-group-addon">任务名</span>
 	                	<input type="text" class="form-control" id="jobName" value="${jobName}" autocomplete="on" >
 	              	</div>
 	            </div>
@@ -66,63 +64,23 @@
 			              	<table id="job_list" class="table table-bordered table-striped">
 				                <thead>
 					            	<tr>
-					            		<th>id</th>
-					                	<th>任务Key</th>
-					                  	<th>任务Cron</th>
-					                  	<th>任务Class</th>
-					                  	<th>状态Status</th>
-					                  	<th>参数</th>
-					                  	<th>addTime</th>
-					                  	<th>updateTime</th>
+					            		<th name="id" >id</th>
+					                	<th name="jobGroup" >任务组</th>
+					                  	<th name="jobName" >任务名</th>
+					                  	<th name="jobCron" >Cron</th>
+					                  	<th name="jobDesc" >描述</th>
+					                  	<th name="jobClass" >JobBean</th>
+					                  	<th name="jobData" >任务数据</th>
+					                  	<th name="addTime" >新增时间</th>
+					                  	<th name="updateTime" >更新时间</th>
+					                  	<th name="author" >负责人</th>
+					                  	<th name="alarmEmail" >报警邮件</th>
+					                  	<th name="alarmThreshold" >报警阀值</th>
+					                  	<th name="jobStatus" >状态</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-info btn-xs update" type="button">更新corn</button>
-											  	<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>
-											  	<button class="btn btn-warning btn-xs" type="job_del" type="button" 
-											  		onclick="javascript:window.open('${request.contextPath}/joblog?jobName=${item['TriggerKey'].name}')" >查看日志</button>
-											</p>
-					                  	</td>
-					                </tr>
-									</#list>
-									</#if>
-									
-									-->
-				                </tbody>
+				                <tbody></tbody>
 				                <tfoot></tfoot>
 							</table>
 						</div>
@@ -155,29 +113,51 @@
 		                  	</select>
 						</div>
 						<label for="firstname" class="col-sm-2 control-label">任务名</label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" ></div>
+						<div class="col-sm-4"><input type="text" class="form-control" name="jobName" placeholder="请输入“任务名”" 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>
+						<label for="lastname" class="col-sm-2 control-label">Corn</label>
+						<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 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>
+						<label for="firstname" class="col-sm-2 control-label">JobBean</label>
+						<div class="col-sm-4">
+							<select class="form-control" name="jobClass" >
+								<#if remoteJobBean?exists >
+								<option value="${remoteJobBean.name}" jobClassType="remote" >【远程任务】</option>
+								</#if>
+								<#if localJobBeanList?exists && localJobBeanList?size gt 0 >
+								<#list localJobBeanList as localJobBean>
+									<option value="${localJobBean.name}" jobClassType="local" >${localJobBean.name}</option>
+								</#list>
+								</#if>
+		                  	</select>
+						</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 class="form-group">
-						<label for="lastname" class="col-sm-3 control-label">任务URL</label>
-						<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL" 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="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="alarm_email" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="200" ></div>
 					</div>
 					<div class="form-group">
-						<label for="lastname" class="col-sm-3 control-label">任务handler</label>
-						<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler" 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="alarm_threshold" placeholder="请输入“报警阈值”" maxlength="200" ></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>

+ 2 - 1
xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl

@@ -35,7 +35,7 @@
 	                	<span class="input-group-addon">任务组</span>
                 		<select class="form-control" id="jobGroup" >
                 			<#list JobGroupList as group>
-                				<option value="${group}" <#if jobInfo?exists && group == jobInfo.jobGroup>selected</#if> >${group.desc}</option>
+                				<option value="${group}" <#if jobGroup == group>selected</#if> >${group.desc}</option>
                 			</#list>
 	                  	</select>
 	              	</div>
@@ -74,6 +74,7 @@
 					                	<th name="jobGroup" >任务组</th>
 					                  	<th name="jobName" >任务名</th>
 					                  	<th name="jobCron" >Cron</th>
+					                  	<th name="jobDesc" >描述</th>
 					                  	<th name="jobClass" >JobBean</th>
 					                  	<th name="jobData" >任务数据</th>
 					                  	<th name="triggerTime" >调度时间</th>

+ 160 - 105
xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js

@@ -7,32 +7,68 @@ $(function() {
 		"ajax": {
 			url: base_url + "/jobinfo/pageList",
 	        data : function ( d ) {
-                d.jobName = $('#jobName').val()
+	        	d.jobGroup = $('#jobGroup').val();
+                d.jobName = $('#jobName').val();
             }
 	    },
+	    "searching": false,
+	    "ordering": false,
 	    //"scrollX": true,	// X轴滚动条,取消自适应
 	    "columns": [
 	                { "data": 'id', "bSortable": false, "visible" : false},
-	                { "data": 'jobName', "bSortable": false},
-	                { "data": 'jobCron', "bSortable": false, "visible" : true},
-	                { "data": 'jobClass', "bSortable": false, "visible" : false},
-	                { "data": 'jobStatus', "bSortable": false, "visible" : true},
-	                { "data": 'jobData', "bSortable": false, "visible" : true},
+	                { 
+	                	"data": 'jobGroup', 
+	                	"render": function ( data, type, row ) {
+	            			var groupMenu = $("#jobGroup").find("option");
+	            			for ( var index in $("#jobGroup").find("option")) {
+	            				if ($(groupMenu[index]).attr('value') == data) {
+									return $(groupMenu[index]).html();
+								}
+							}
+	            			return data;
+	            		}
+            		},
+	                { "data": 'jobName'},
+	                { "data": 'jobCron', "visible" : true},
+	                { "data": 'jobDesc', "visible" : false},
+	                { "data": 'jobClass', "visible" : true},
+	                { 
+	                	"data": 'jobData',
+	                	"visible" : true,
+	                	"render": function ( data, type, row ) {
+	                		return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
+	                	}
+	                },
 	                { 
 	                	"data": 'addTime', 
-	                	"bSortable": false, 
+	                	"visible" : false, 
 	                	"render": function ( data, type, row ) {
 	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
 	                	}
 	                },
 	                { 
 	                	"data": 'updateTime', 
-	                	"bSortable": false, 
+	                	"visible" : false, 
 	                	"render": function ( data, type, row ) {
 	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
 	                	}
 	                },
-	                { "data": '操作' , "bSortable": false,
+	                { "data": 'author', "visible" : true},
+	                { "data": 'alarmEmail', "visible" : false},
+	                { "data": 'alarmThreshold', "visible" : false},
+	                { 
+	                	"data": 'jobStatus', 
+	                	"visible" : true,
+	                	"render": function ( data, type, row ) {
+	                		if ('NORMAL' == data) {
+	                			return '<small class="label label-success" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
+							} else if ('PAUSED' == data){
+								return '<small class="label label-default"><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
+							}
+	                		return data;
+	                	}
+	                },
+	                { "data": '操作' ,
 	                	"render": function ( data, type, row ) {
 	                		return function(){
 	                			// status
@@ -43,23 +79,31 @@ $(function() {
 									pause_resume = '<button class="btn btn-info btn-xs job_operate" type="job_resume" type="button">恢复</button>  ';
 								}
 	                			// log url
-	                			var logUrl = base_url +'/joblog?jobName='+ row.jobName;
+	                			var logUrl = base_url +'/joblog?jobGroup='+ row.jobGroup +'&jobName='+ row.jobName;
 	                			
 	                			// job data
 	                			var jobDataMap = eval('(' + row.jobData + ')');
 	                			
-	                			var html = '<p jobName="'+ row.jobName +'" '+
-	                							' cronExpression="'+ row.jobCron +'" '+
-	                							' job_desc="'+jobDataMap.job_desc +'" '+
-	                							' job_url="'+ jobDataMap.job_url +'" '+
-	                							' handleName="'+ jobDataMap.handleName +'" '+
+	                			var html = '<p id="'+ row.id +'" '+
+	                							' jobGroup="'+ row.jobGroup +'" '+
+	                							' jobName="'+ row.jobName +'" '+
+	                							' jobCron="'+ row.jobCron +'" '+
+	                							' jobDesc="'+ row.jobDesc +'" '+
+	                							' jobClass="'+ row.jobClass +'" '+
+	                							' jobData="'+ row.jobData +'" '+
+	                							' author="'+ row.author +'" '+
+	                							' alarmEmail="'+ row.alarmEmail +'" '+
+	                							' alarmThreshold="'+ row.alarmThreshold +'" '+
+	                							' handler_params="'+jobDataMap.handler_params +'" '+
+	                							' handler_address="'+ jobDataMap.handler_address +'" '+
+	                							' handler_name="'+ jobDataMap.handler_name +'" '+
 	                							'>'+
 	                					pause_resume +
 										'<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行</button>  '+
-										'<button class="btn btn-info btn-xs update" type="button">更新corn</button>  '+
-									  	'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>  '+
+										'<button class="btn btn-warning btn-xs update" type="button">编辑</button><br> '+
 									  	'<button class="btn btn-warning btn-xs" type="job_del" type="button" '+
-									  		'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button>'+
+									  		'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button> '+
+								  		'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>  '+
 									'</p>';
 									
 	                			
@@ -68,8 +112,6 @@ $(function() {
 	                	}
 	                }
 	            ],
-	    "searching": false,
-	    "ordering": true,
 		"language" : {
 			"sProcessing" : "处理中...",
 			"sLengthMenu" : "每页 _MENU_ 条记录",
@@ -96,6 +138,12 @@ $(function() {
 		}
 	});
 	
+	// 日志弹框提示
+	$('#job_list').on('click', '.logTips', function(){
+		var msg = $(this).find('span').html();
+		ComAlertTec.show(msg);
+	});
+	
 	// 搜索按钮
 	$('#searchBtn').on('click', function(){
 		jobTable.fnDraw();
@@ -108,28 +156,30 @@ $(function() {
 		var type = $(this).attr("type");
 		if ("job_pause" == type) {
 			typeName = "暂停";
-			url = base_url + "/job/pause";
+			url = base_url + "/jobinfo/pause";
 		} else if ("job_resume" == type) {
 			typeName = "恢复";
-			url = base_url + "/job/resume";
+			url = base_url + "/jobinfo/resume";
 		} else if ("job_del" == type) {
 			typeName = "删除";
-			url = base_url + "/job/remove";
+			url = base_url + "/jobinfo/remove";
 		} else if ("job_trigger" == type) {
-			typeName = "执行一次";
-			url = base_url + "/job/trigger";
+			typeName = "执行";
+			url = base_url + "/jobinfo/trigger";
 		} else {
 			return;
 		}
 		
-		var name = $(this).parent('p').attr("jobName");
+		var jobGroup = $(this).parent('p').attr("jobGroup");
+		var jobName = $(this).parent('p').attr("jobName");
 		
 		ComConfirm.show("确认" + typeName + "?", function(){
 			$.ajax({
 				type : 'POST',
 				url : url,
 				data : {
-					"triggerKeyName" :	name
+					"jobGroup" : jobGroup,
+					"jobName"  : jobName
 				},
 				dataType : "json",
 				success : function(data){
@@ -162,50 +212,74 @@ $(function() {
         errorClass : 'help-block',
         focusInvalid : true,  
         rules : {  
-        	triggerKeyName : {  
+        	jobName : {  
         		required : true ,
                 minlength: 4,
                 maxlength: 100,
                 myValid01:true
             },  
-            cronExpression : {  
+            jobCron : {  
             	required : true ,
                 maxlength: 100
             },  
-            job_desc : {  
+            jobDesc : {  
             	required : true ,
                 maxlength: 200
             },
-            job_url : {
+            handler_address : {
             	required : true ,
                 maxlength: 200
             },
-            handleName : {
+            handler_name : {
             	required : true ,
                 maxlength: 200
+            },
+            author : {
+            	required : true ,
+                maxlength: 200
+            },
+            alarm_email : {
+            	required : true ,
+                maxlength: 200
+            },
+            alarm_threshold : {
+            	required : true ,
+            	digits:true
             }
         }, 
         messages : {  
-        	triggerKeyName : {  
-        		required :"请输入“任务Key”."  ,
-                minlength:"“任务Key”长度不应低于4位",
-                maxlength:"“任务Key”长度不应超过100位"
+        	jobName : {  
+        		required :"请输入“任务名”"  ,
+                minlength:"“任务”长度不应低于4位",
+                maxlength:"“任务”长度不应超过100位"
             },  
-            cronExpression : {
-            	required :"请输入“任务Corn”."  ,
-                maxlength:"“任务Corn”长度不应超过100位"
+            jobCron : {
+            	required :"请输入“Corn”."  ,
+                maxlength:"“Corn”长度不应超过100位"
             },  
-            job_desc : {
+            jobDesc : {
             	required :"请输入“任务描述”."  ,
                 maxlength:"“任务描述”长度不应超过200位"
             },  
-            job_url : {
-            	required :"请输入“任务URL”."  ,
-                maxlength:"“任务URL”长度不应超过200位"
+            handler_address : {
+            	required :"请输入“远程-机器地址”."  ,
+                maxlength:"“远程-机器地址”长度不应超过200位"
             },
-            handleName : {
-            	required : "请输入“任务handler”."  ,
-                maxlength: "“任务handler”长度不应超过200位"
+            handler_name : {
+            	required : "请输入“远程-执行器”."  ,
+                maxlength: "“远程-执行器”长度不应超过200位"
+            },
+            author : {
+            	required : "请输入“负责人”."  ,
+                maxlength: "“负责人”长度不应超过50位"
+            },
+            alarm_email : {
+            	required : "请输入“报警邮件”."  ,
+                maxlength: "“报警邮件”长度不应超过200位"
+            },
+            alarm_threshold : {
+            	required : "请输入“报警阈值”."  ,
+            	digits:"阀值应该为整数."
             }
         }, 
 		highlight : function(element) {  
@@ -219,52 +293,20 @@ $(function() {
             element.parent('div').append(error);  
         },
         submitHandler : function(form) {
-        	
-        	var triggerKeyName = $('#addModal input[name="triggerKeyName"]').val();
-        	var cronExpression = $('#addModal input[name="cronExpression"]').val();
-        	var job_desc = $('#addModal input[name="job_desc"]').val();
-        	var job_url = $('#addModal input[name="job_url"]').val();
-        	var handleName = $('#addModal input[name="handleName"]').val();
-        	
-        	var paramStr = 'triggerKeyName=' + triggerKeyName + 
-        		'&cronExpression=' + cronExpression + 
-        		'&job_desc=' + job_desc +
-        		'&job_url=' + job_url +
-        		'&handleName=' + handleName;
-        	
-        	var ifFin = true;
-        	$('#addModal .newParam').each(function(){
-        		ifFin = false;
-        		var key = $(this).find('input[name="key"]').val();
-        		var value = $(this).find('input[name="value"]').val();
-        		if (!key) {
-        			ComAlert.show(2, "新增参数key不可为空");
-        			return;
-				} else {
-					if(!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)){
-						ComAlert.show(2, "新增参数key不合法, 只支持英文字母开头,只含有英文字母、数字和下划线");
-	        			return;
-					}
-				}
-        		paramStr += "&" + key + "=" + value;
-        		ifFin = true;
-        	});
-        	
-        	if(ifFin){
-        		$.post(base_url + "/job/add", paramStr, function(data, status) {
-        			if (data.code == "200") {
-        				ComAlert.show(1, "新增调度任务成功", function(){
-        					window.location.reload();
-        				});
-        			} else {
-        				if (data.msg) {
-        					ComAlert.show(2, data.msg);
-        				} else {
-        					ComAlert.show(2, "新增失败");
-        				}
-        			}
-        		});
-        	}
+        	$.post(base_url + "/jobinfo/add",  $("#addModal .form").serialize(), function(data, status) {
+    			if (data.code == "200") {
+    				ComAlert.show(1, "新增调度任务成功", function(){
+    					ComAlert.show(1, "新增任务成功");
+    					jobTable.fnDraw();
+    				});
+    			} else {
+    				if (data.msg) {
+    					ComAlert.show(2, data.msg);
+    				} else {
+    					ComAlert.show(2, "新增失败");
+    				}
+    			}
+    		});
 		}
 	});
 	$("#addModal").on('hide.bs.modal', function () {
@@ -273,19 +315,16 @@ $(function() {
 		$("#addModal .form .form-group").removeClass("has-error");
 	});
 	
-	// 新增-添加参数
-	$("#addModal .addParam").on('click', function () {
-		var html = '<div class="form-group newParam">'+
-				'<label for="lastname" class="col-sm-2 control-label">参数&nbsp;<button class="btn btn-danger btn-xs removeParam" type="button">移除</button></label>'+
-				'<div class="col-sm-4"><input type="text" class="form-control" name="key" placeholder="请输入参数key[将会强转为String]" maxlength="200" /></div>'+
-				'<div class="col-sm-6"><input type="text" class="form-control" name="value" placeholder="请输入参数value[将会强转为String]" maxlength="200" /></div>'+
-			'</div>';
-		$(this).parents('.form-group').parent().append(html);
-		
-		$("#addModal .removeParam").on('click', function () {
-			$(this).parents('.form-group').remove();
-		});
-	});
+	// 远程任务/本地任务,切换
+	$("#addModal select[name='jobClass']").change(function() {
+		//console.log($(this).val());
+		console.log( $(this).val().indexOf('HttpJobBean') );
+		if($(this).val().indexOf('HttpJobBean') > -1){
+			$(".remote_panel").show();	// remote
+		} else if($(this).val().indexOf('HttpJobBean') == -1){
+			$(".remote_panel").hide();	// local
+		}
+    });
 	
 	// 更新
 	$("#job_list").on('click', '.update',function() {
@@ -376,4 +415,20 @@ $(function() {
 		$("#updateModal .form")[0].reset()
 	});
 	
+	
+	/*
+	// 新增-添加参数
+	$("#addModal .addParam").on('click', function () {
+		var html = '<div class="form-group newParam">'+
+				'<label for="lastname" class="col-sm-2 control-label">参数&nbsp;<button class="btn btn-danger btn-xs removeParam" type="button">移除</button></label>'+
+				'<div class="col-sm-4"><input type="text" class="form-control" name="key" placeholder="请输入参数key[将会强转为String]" maxlength="200" /></div>'+
+				'<div class="col-sm-6"><input type="text" class="form-control" name="value" placeholder="请输入参数value[将会强转为String]" maxlength="200" /></div>'+
+			'</div>';
+		$(this).parents('.form-group').parent().append(html);
+		
+		$("#addModal .removeParam").on('click', function () {
+			$(this).parents('.form-group').remove();
+		});
+	});
+	*/
 });

+ 1 - 0
xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js

@@ -33,6 +33,7 @@ $(function() {
             		},
 	                { "data": 'jobName'},
 	                { "data": 'jobCron', "visible" : false},
+	                { "data": 'jobDesc', "visible" : false},
 	                { "data": 'jobClass', "visible" : false},
 	                { 
 	                	"data": 'jobData',

+ 4 - 4
xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java

@@ -21,8 +21,8 @@ public class XxlJobInfoTest {
 	
 	@Test
 	public void pageList(){
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, null, null, null);
-		int list_count = xxlJobInfoDao.pageListCount(0, 20, null, null, null);
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, null, null);
+		int list_count = xxlJobInfoDao.pageListCount(0, 20, null, null);
 		
 		System.out.println(list);
 		System.out.println(list_count);
@@ -39,13 +39,13 @@ public class XxlJobInfoTest {
 		System.out.println(count);
 		System.out.println(info.getId());
 		
-		XxlJobInfo item = xxlJobInfoDao.load("job_name");
+		XxlJobInfo item = xxlJobInfoDao.load(null ,"job_name");
 		System.out.println(item);
 	}
 	
 	@Test
 	public void update(){
-		XxlJobInfo item = xxlJobInfoDao.load("job_name");
+		XxlJobInfo item = xxlJobInfoDao.load(null ,"job_name");
 		
 		item.setJobCron("jobCron2");
 		item.setJobData("jobData2");

+ 2 - 2
xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobLogTest.java

@@ -57,8 +57,8 @@ public class XxlJobLogTest {
 	
 	@Test
 	public void pageList(){
-		List<XxlJobLog> list = xxlJobLogDao.pageList(0, 20, null, null, null);
-		int list_count = xxlJobLogDao.pageListCount(0, 20, null, null, null);
+		List<XxlJobLog> list = xxlJobLogDao.pageList(0, 20, null, null, null, null);
+		int list_count = xxlJobLogDao.pageListCount(0, 20, null, null, null, null);
 		
 		System.out.println(list);
 		System.out.println(list_count);

+ 3 - 4
xxl-job-client-demo/src/main/java/com/xxl/job/service/handler/DemoJobHandler.java

@@ -1,6 +1,5 @@
 package com.xxl.job.service.handler;
 
-import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
@@ -20,12 +19,12 @@ public class DemoJobHandler extends IJobHandler {
 	private static transient Logger logger = LoggerFactory.getLogger(DemoJobHandler.class);
 	
 	public DemoJobHandler() {
-		HandlerRepository.regist(DemoJobHandler.class.getName(), this);
+		HandlerRepository.regist("demoJobHandler", this);
 	}
 	
 	@Override
-	public JobHandleStatus handle(Map<String, String> param) throws Exception {
-		logger.info(" ... param:{}", param);
+	public JobHandleStatus handle(String... params) throws Exception {
+		logger.info(" ... params:" + params);
 		TimeUnit.SECONDS.sleep(new Random().nextInt(5));
 		return JobHandleStatus.SUCCESS;
 	}

+ 23 - 124
xxl-job-client/src/main/java/com/xxl/job/client/handler/HandlerRepository.java

@@ -1,21 +1,15 @@
 package com.xxl.job.client.handler;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.xxl.job.client.handler.IJobHandler.JobHandleStatus;
 import com.xxl.job.client.util.HttpUtil;
 import com.xxl.job.client.util.JacksonUtil;
 
-
 /**
  * handler repository
  * @author xuxueli 2015-12-19 19:28:44
@@ -23,142 +17,47 @@ import com.xxl.job.client.util.JacksonUtil;
 public class HandlerRepository {
 	private static Logger logger = LoggerFactory.getLogger(HandlerRepository.class);
 	
-	public static final String job_desc = "job_desc";
-	public static final String job_url = "job_url";
-	public static final String handleName = "handleName";
-	public static final String triggerLogId = "triggerLogId";
-	public static final String triggerLogUrl = "triggerLogUrl";
-
-	// handler class map
-	private static ConcurrentHashMap<String, IJobHandler> handlerClassMap = new ConcurrentHashMap<String, IJobHandler>();
-	// handler thread map
-	private static ConcurrentHashMap<String, HandlerThread> handlerTreadMap = new ConcurrentHashMap<String, HandlerThread>();
-	// handler date queue map
-	private static ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>> handlerDataQueueMap = new ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>>();
+	public static final String HANDLER_ADDRESS = "handler_address";
+	public static final String HANDLER_NAME = "handler_name";
+	public static final String HANDLER_PARAMS = "handler_params";
+	
+	public static final String TRIGGER_LOG_ID = "trigger_log_id";
+	public static final String TRIGGER_LOG_URL = "trigger_log_url";
+	
+	public static ConcurrentHashMap<String, HandlerThread> handlerTreadMap = new ConcurrentHashMap<String, HandlerThread>();
 	
 	// regist handler
 	public static void regist(String handleName, IJobHandler handler){
-		handlerClassMap.put(handleName, handler);
-		LinkedBlockingQueue<Map<String, String>> handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
-		handlerDataQueueMap.put(handleName, handlerDateQueue);
-		HandlerThread handlerThread = new HandlerThread(handleName);
+		HandlerThread handlerThread = new HandlerThread(handler);
 		handlerThread.start();
-		handlerTreadMap.put(handleName, handlerThread);
-		logger.info(">>>>>>>>>>> xxl-job regist handler success, handleName:{}, handler:{}, handlerDateQueue:{}, handlerThread:{}", 
-				new Object[]{handleName, handler, handlerDateQueue, handlerThread});
-	}
-	
-	// create handler thread
-	static class HandlerThread extends Thread{
-		private String _handleName;
-		public HandlerThread(String _handleName) {
-			this._handleName = _handleName;
-		}
-		public boolean isValid = true;
-		public void stopThread(){
-			isValid = false;
-		}
-		@Override
-		public void run() {
-			while (isValid) {
-				LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(_handleName);
-				Map<String, String> handlerData = handlerDateQueue.poll();
-				if (handlerData!=null) {
-					// handle job
-					JobHandleStatus _status = JobHandleStatus.FAIL;
-					String _msg = null;
-					try {
-						IJobHandler handler = handlerClassMap.get(_handleName);
-						_status = handler.handle(handlerData);
-					} catch (Exception e) {
-						e.printStackTrace();
-						_status = JobHandleStatus.FAIL;
-						StringWriter out = new StringWriter();
-						e.printStackTrace(new PrintWriter(out));
-						_msg = out.toString();
-					}
-
-					// callback handler info
-					String callback_response[] = null;
-					try {
-						String _triggerLogUrl = handlerData.get(HandlerRepository.triggerLogUrl);
-						HashMap<String, String> params = new HashMap<String, String>();
-						params.put(HandlerRepository.triggerLogId, handlerData.get(HandlerRepository.triggerLogId));
-						params.put(HttpUtil.status, _status.name());
-						params.put(HttpUtil.msg, _msg);
-						callback_response = HttpUtil.post(_triggerLogUrl, params);
-					} catch (Exception e) {
-						e.printStackTrace();
-					}
-					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(200);
-					} catch (InterruptedException e) {
-						e.printStackTrace();
-					}
-				}
-			}
-		}
+		handlerTreadMap.put(handleName, handlerThread);	// putIfAbsent
+		logger.info(">>>>>>>>>>> xxl-job regist handler success, handleName:{}, handler:{}", new Object[]{handleName, handler});
 	}
 	
 	// handler push to queue
 	public static String pushHandleQueue(Map<String, String> _param) {
+		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue start, _param:{}", new Object[]{_param});
 		
-		// resuolt
+		// result
 		String _status = HttpUtil.FAIL;
 		String _msg = "";
+		
 		// push data to queue
-		String _handleName = _param.get(HandlerRepository.handleName);
-		int _triggerLogId = Integer.valueOf(_param.get(HandlerRepository.triggerLogId));	 // 次数应校验,停止队列功能为开发
-		try {
-			if (_handleName!=null && _handleName.trim().length()>0) {
-				IJobHandler handler = handlerClassMap.get(_handleName);
-				if (handler != null) {
-					// push data to handler queue
-					LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(_handleName);
-					if (handlerDateQueue == null) {
-						handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
-						handlerDataQueueMap.put(_handleName, handlerDateQueue);
-						logger.info(">>>>>>>>>>> xxl-job handler lazy fresh handlerDateQueue, _handleName:{}, handler:{}, handlerDateQueue:{}", 
-								new Object[]{_handleName, handler, handlerDateQueue});
-					}
-					// check handler thread
-					HandlerThread handlerThreadOld = handlerTreadMap.get(_handleName);
-					if (!handlerThreadOld.isAlive()) {
-						handlerThreadOld.stopThread();
-						HandlerThread handlerThread = new HandlerThread(_handleName);
-						handlerThread.start();
-						handlerTreadMap.put(_handleName, handlerThread);
-						logger.info(">>>>>>>>>>> xxl-job handler lazy fresh thread, _handleName:{}, handler:{}, handlerThread:{}", 
-								new Object[]{_handleName, handler, handlerThread});
-					}
-					// push to queue
-					handlerDateQueue.offer(_param);
-					_status = HttpUtil.SUCCESS;
-				}
-			}
-		} catch (Exception e) {
-			e.printStackTrace();
-			StringWriter out = new StringWriter();
-			e.printStackTrace(new PrintWriter(out));
-			_status = HttpUtil.FAIL;
-			_msg = out.toString();
+		HandlerThread handlerThread = handlerTreadMap.get(_param.get(HandlerRepository.HANDLER_NAME));
+		if (handlerThread != null) {
+			handlerThread.pushData(_param);
+			_status = HttpUtil.SUCCESS;
+		} else {
+			_msg = "handler not found.";
 		}
-		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue, _handleName:{}, _triggerLogId:{}, _param:{}, _status:{}, _msg:{}", 
-				new Object[]{_handleName, _triggerLogId, _param, _status, _msg});
 		
 		HashMap<String, String> triggerData = new HashMap<String, String>();
+		triggerData.put(HandlerRepository.TRIGGER_LOG_ID, _param.get(HandlerRepository.TRIGGER_LOG_ID));
 		triggerData.put(HttpUtil.status, _status);
 		triggerData.put(HttpUtil.msg, _msg);
-		return JacksonUtil.writeValueAsString(triggerData);
 		
-		/**
-		 * trigger-log : 
-		 * 		trigger side : store trigger-info >> trigger request >> update trigger-response-status
-		 * 		job side : handler trigger >> update trigger-result
-		 */
+		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue end, triggerData:{}", new Object[]{triggerData});
+		return JacksonUtil.writeValueAsString(triggerData);
 	}
 	
 }

+ 1 - 3
xxl-job-client/src/main/java/com/xxl/job/client/handler/IJobHandler.java

@@ -1,7 +1,5 @@
 package com.xxl.job.client.handler;
 
-import java.util.Map;
-
 /**
  * remote job handler
  * @author xuxueli 2015-12-19 19:06:38
@@ -15,7 +13,7 @@ public abstract class IJobHandler extends HandlerRepository{
 	 * @return 
 	 * @throws Exception
 	 */
-	public abstract JobHandleStatus handle(Map<String, String> param) throws Exception;
+	public abstract JobHandleStatus handle(String... params) throws Exception;
 	
 	public enum JobHandleStatus{
 		/**