浏览代码

重要版本升级:

xueli.xue 9 年前
父节点
当前提交
554429ea59
共有 19 个文件被更改,包括 571 次插入547 次删除
  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 @@
1 1
 package com.xxl.job.controller;
2 2
 
3
-import java.io.UnsupportedEncodingException;
3
+import java.util.ArrayList;
4 4
 import java.util.HashMap;
5 5
 import java.util.List;
6 6
 import java.util.Map;
7
-import java.util.Map.Entry;
8
-import java.util.Set;
9 7
 
10 8
 import javax.annotation.Resource;
11
-import javax.servlet.http.HttpServletRequest;
12 9
 
13 10
 import org.apache.commons.lang.StringUtils;
14 11
 import org.quartz.CronExpression;
@@ -28,6 +25,8 @@ import com.xxl.job.core.model.XxlJobInfo;
28 25
 import com.xxl.job.core.util.DynamicSchedulerUtil;
29 26
 import com.xxl.job.dao.IXxlJobInfoDao;
30 27
 import com.xxl.job.service.job.HttpJobBean;
28
+import com.xxl.job.service.job.LocalJobBean;
29
+import com.xxl.job.service.job.LocalJobBeanB;
31 30
 
32 31
 /**
33 32
  * index controller
@@ -40,9 +39,20 @@ public class JobInfoController {
40 39
 	@Resource
41 40
 	private IXxlJobInfoDao xxlJobInfoDao;
42 41
 	
42
+	// remote job bean
43
+	public static Class <? extends Job> remoteJobBean = HttpJobBean.class;
44
+	// loacal job bean
45
+	public static List<Class <? extends Job>> localJobBeanList = new ArrayList<Class<? extends Job>>();
46
+	static{
47
+		localJobBeanList.add(LocalJobBean.class);
48
+		localJobBeanList.add(LocalJobBeanB.class);
49
+	}
50
+	
43 51
 	@RequestMapping
44 52
 	public String index(Model model) {
45
-		model.addAttribute("JobGroupList", JobGroupEnum.values());
53
+		model.addAttribute("localJobBeanList", localJobBeanList);			// 本地任务-列表
54
+		model.addAttribute("remoteJobBean", remoteJobBean);	// 远程任务-jobBean
55
+		model.addAttribute("JobGroupList", JobGroupEnum.values());			// 任务组列表
46 56
 		return "jobinfo/index";
47 57
 	}
48 58
 	
@@ -50,11 +60,11 @@ public class JobInfoController {
50 60
 	@ResponseBody
51 61
 	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
52 62
 			@RequestParam(required = false, defaultValue = "10") int length,
53
-			String jobName, String filterTime) {
63
+			String jobGroup, String jobName, String filterTime) {
54 64
 		
55 65
 		// page list
56
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobName, null, null);
57
-		int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null);
66
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobName);
67
+		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobName);
58 68
 		
59 69
 		// fill job info
60 70
 		if (list!=null && list.size()>0) {
@@ -71,72 +81,89 @@ public class JobInfoController {
71 81
 		return maps;
72 82
 	}
73 83
 	
84
+	@SuppressWarnings("unchecked")
74 85
 	@RequestMapping("/add")
75 86
 	@ResponseBody
76
-	public ReturnT<String> add(HttpServletRequest request) {
77
-		String triggerKeyName = null;
78
-		String cronExpression = null;
79
-		Map<String, String> jobData = new HashMap<String, String>();
87
+	public ReturnT<String> add(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass,
88
+			String handler_params, String handler_address, String handler_name, 
89
+			String author, String alarm_email, int alarm_threshold) {
80 90
 		
91
+		// valid
92
+		if (JobGroupEnum.match(jobGroup) == null) {
93
+			return new ReturnT<String>(500, "请选择“任务组”");
94
+		}
95
+		if (StringUtils.isBlank(jobName)) {
96
+			return new ReturnT<String>(500, "请输入“任务名”");
97
+		}
98
+		if (!CronExpression.isValidExpression(jobCron)) {
99
+			return new ReturnT<String>(500, "“corn”不合法");
100
+		}
101
+		if (StringUtils.isBlank(jobDesc)) {
102
+			return new ReturnT<String>(500, "请输入“任务描述”");
103
+		}
104
+		Class<? extends Job> jobClass_ = null;
81 105
 		try {
82
-			request.setCharacterEncoding("utf-8");
83
-		} catch (UnsupportedEncodingException e1) {
106
+			Class<?> clazz = Class.forName(jobClass);
107
+			if (clazz!=null) {
108
+				jobClass_ = (Class<? extends Job>) clazz;
109
+			}
110
+		} catch (ClassNotFoundException e1) {
84 111
 			e1.printStackTrace();
85 112
 		}
86
-		@SuppressWarnings("unchecked")
87
-		Set<Map.Entry<String, String[]>> paramSet = request.getParameterMap().entrySet();
88
-		for (Entry<String, String[]> param : paramSet) {
89
-			if (param.getKey().equals("triggerKeyName")) {
90
-				triggerKeyName = param.getValue()[0];
91
-			} else if (param.getKey().equals("cronExpression")) {
92
-				cronExpression = param.getValue()[0];
93
-			} else {
94
-				jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue()));
95
-			}
113
+		if (jobClass_ == null) {
114
+			return new ReturnT<String>(500, "请选择“JobBean”");
96 115
 		}
97
-		
98
-		// triggerKeyName
99
-		if (StringUtils.isBlank(triggerKeyName)) {
100
-			return new ReturnT<String>(500, "请输入“任务key”");
116
+		if (jobClass_.getClass().getName().equals(remoteJobBean.getName())) {
117
+			if (StringUtils.isBlank(handler_address)) {
118
+				return new ReturnT<String>(500, "请输入“远程-机器地址”");
119
+			}
120
+			if (StringUtils.isBlank(handler_name)) {
121
+				return new ReturnT<String>(500, "请输入“远程-执行器”");
122
+			}
101 123
 		}
102
-		
103
-		// cronExpression
104
-		if (StringUtils.isBlank(cronExpression)) {
105
-			return new ReturnT<String>(500, "请输入“任务corn”");
124
+		if (StringUtils.isBlank(author)) {
125
+			return new ReturnT<String>(500, "请输入“负责人”");
106 126
 		}
107
-		if (!CronExpression.isValidExpression(cronExpression)) {
108
-			return new ReturnT<String>(500, "“任务corn”不合法");
127
+		if (StringUtils.isBlank(alarm_email)) {
128
+			return new ReturnT<String>(500, "请输入“报警邮件”");
109 129
 		}
110 130
 		
111
-		// jobData
112
-		if (jobData.get(HandlerRepository.job_desc)==null || jobData.get(HandlerRepository.job_desc).toString().trim().length()==0) {
113
-			return new ReturnT<String>(500, "请输入“任务描述”");
114
-		}
115
-		if (jobData.get(HandlerRepository.job_url)==null || jobData.get(HandlerRepository.job_url).toString().trim().length()==0) {
116
-			return new ReturnT<String>(500, "请输入“任务URL”");
117
-		}
118
-		if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) {
119
-			return new ReturnT<String>(500, "请输入“任务handler”");
131
+		try {
132
+			if (DynamicSchedulerUtil.checkExists(jobName, jobGroup)) {
133
+				return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
134
+			}
135
+		} catch (SchedulerException e1) {
136
+			e1.printStackTrace();
137
+			return new ReturnT<String>(500, "此任务已存在,请更换任务组或任务名");
120 138
 		}
121 139
 		
122
-		// jobClass
123
-		Class<? extends Job> jobClass = HttpJobBean.class;
140
+		HashMap<String, String> jobDataMap = new HashMap<String, String>();
141
+		jobDataMap.put(HandlerRepository.HANDLER_PARAMS, handler_params);
142
+		jobDataMap.put(HandlerRepository.HANDLER_ADDRESS, handler_address);
143
+		jobDataMap.put(HandlerRepository.HANDLER_NAME, handler_name);
144
+		
145
+		// Backup to the database
146
+		XxlJobInfo jobInfo = new XxlJobInfo();
147
+		jobInfo.setJobGroup(jobGroup);
148
+		jobInfo.setJobName(jobName);
149
+		jobInfo.setJobCron(jobCron);
150
+		jobInfo.setJobDesc(jobDesc);
151
+		jobInfo.setJobClass(jobClass);
152
+		jobInfo.setJobData(JacksonUtil.writeValueAsString(jobDataMap));
153
+		jobInfo.setAuthor(author);
154
+		jobInfo.setAlarmEmail(alarm_email);
155
+		jobInfo.setAlarmThreshold(alarm_threshold);
156
+		xxlJobInfoDao.save(jobInfo);
124 157
 		
125 158
 		try {
126 159
 			// add job 2 quartz
127
-			boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null);
128
-			if (!result) {
129
-				return new ReturnT<String>(500, "任务ID重复,请更换确认");
160
+			boolean result = DynamicSchedulerUtil.addJob(jobInfo);
161
+			if (result) {
162
+				return ReturnT.SUCCESS;
163
+			} else {
164
+				xxlJobInfoDao.delete(jobGroup, jobName);
165
+				return new ReturnT<String>(500, "新增任务失败");
130 166
 			}
131
-			// Backup to the database
132
-			XxlJobInfo jobInfo = new XxlJobInfo();
133
-			jobInfo.setJobName(triggerKeyName);
134
-			jobInfo.setJobCron(cronExpression);
135
-			jobInfo.setJobClass(jobClass.getName());
136
-			jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData));
137
-			xxlJobInfoDao.save(jobInfo);
138
-			
139
-			return ReturnT.SUCCESS;
140 167
 		} catch (SchedulerException e) {
141 168
 			e.printStackTrace();
142 169
 		}
@@ -145,27 +172,30 @@ public class JobInfoController {
145 172
 	
146 173
 	@RequestMapping("/reschedule")
147 174
 	@ResponseBody
148
-	public ReturnT<String> reschedule(String triggerKeyName, String cronExpression) {
149
-		// triggerKeyName
150
-		if (StringUtils.isBlank(triggerKeyName)) {
151
-			return new ReturnT<String>(500, "请输入“任务key”");
175
+	public ReturnT<String> reschedule(String jobGroup, String jobName, String jobCron, String jobDesc, String jobClass,
176
+			String handler_params, String handler_address, String handler_name, 
177
+			String author, String alarm_email, int alarm_threshold) {
178
+		
179
+		// valid
180
+		if (JobGroupEnum.match(jobGroup) == null) {
181
+			return new ReturnT<String>(500, "请选择“任务组”");
152 182
 		}
153
-		// cronExpression
154
-		if (StringUtils.isBlank(cronExpression)) {
155
-			return new ReturnT<String>(500, "请输入“任务corn”");
183
+		if (StringUtils.isBlank(jobName)) {
184
+			return new ReturnT<String>(500, "请输入“任务名”");
156 185
 		}
157
-		if (!CronExpression.isValidExpression(cronExpression)) {
158
-			return new ReturnT<String>(500, "“任务corn”不合法");
186
+		if (!CronExpression.isValidExpression(jobCron)) {
187
+			return new ReturnT<String>(500, "“corn”不合法");
159 188
 		}
189
+		
190
+		XxlJobInfo jobInfo = xxlJobInfoDao.load(jobGroup, jobName);
191
+		jobInfo.setJobCron(jobCron);
192
+		
160 193
 		try {
161
-			DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression);
194
+			// fresh quartz
195
+			DynamicSchedulerUtil.rescheduleJob(jobInfo);
162 196
 			
163
-			// update
164
-			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
165
-			if (jobInfo!=null) {
166
-				jobInfo.setJobCron(cronExpression);
167
-				xxlJobInfoDao.update(jobInfo);
168
-			}
197
+			// fresh db
198
+			xxlJobInfoDao.update(jobInfo);
169 199
 			return ReturnT.SUCCESS;
170 200
 		} catch (SchedulerException e) {
171 201
 			e.printStackTrace();
@@ -175,13 +205,11 @@ public class JobInfoController {
175 205
 	
176 206
 	@RequestMapping("/remove")
177 207
 	@ResponseBody
178
-	public ReturnT<String> remove(String triggerKeyName) {
208
+	public ReturnT<String> remove(String jobGroup, String jobName) {
179 209
 		try {
180
-			if (triggerKeyName!=null) {
181
-				DynamicSchedulerUtil.removeJob(triggerKeyName);
182
-				xxlJobInfoDao.delete(triggerKeyName);
183
-				return ReturnT.SUCCESS;
184
-			}
210
+			DynamicSchedulerUtil.removeJob(jobName, jobGroup);
211
+			xxlJobInfoDao.delete(jobGroup, jobName);
212
+			return ReturnT.SUCCESS;
185 213
 		} catch (SchedulerException e) {
186 214
 			e.printStackTrace();
187 215
 		}
@@ -190,15 +218,9 @@ public class JobInfoController {
190 218
 	
191 219
 	@RequestMapping("/pause")
192 220
 	@ResponseBody
193
-	public ReturnT<String> pause(String triggerKeyName) {
221
+	public ReturnT<String> pause(String jobGroup, String jobName) {
194 222
 		try {
195
-			DynamicSchedulerUtil.pauseJob(triggerKeyName);
196
-			// update
197
-			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
198
-			if (jobInfo!=null) {
199
-				jobInfo.setJobStatus("PAUSED");
200
-				xxlJobInfoDao.update(jobInfo);
201
-			}
223
+			DynamicSchedulerUtil.pauseJob(jobName, jobGroup);	// jobStatus do not store
202 224
 			return ReturnT.SUCCESS;
203 225
 		} catch (SchedulerException e) {
204 226
 			e.printStackTrace();
@@ -208,15 +230,9 @@ public class JobInfoController {
208 230
 	
209 231
 	@RequestMapping("/resume")
210 232
 	@ResponseBody
211
-	public ReturnT<String> resume(String triggerKeyName) {
233
+	public ReturnT<String> resume(String jobGroup, String jobName) {
212 234
 		try {
213
-			DynamicSchedulerUtil.resumeJob(triggerKeyName);
214
-			// update
215
-			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
216
-			if (jobInfo!=null) {
217
-				jobInfo.setJobStatus("NORMAL");
218
-				xxlJobInfoDao.update(jobInfo);
219
-			}
235
+			DynamicSchedulerUtil.resumeJob(jobName, jobGroup);
220 236
 			return ReturnT.SUCCESS;
221 237
 		} catch (SchedulerException e) {
222 238
 			e.printStackTrace();
@@ -226,9 +242,9 @@ public class JobInfoController {
226 242
 	
227 243
 	@RequestMapping("/trigger")
228 244
 	@ResponseBody
229
-	public ReturnT<String> triggerJob(String triggerKeyName) {
245
+	public ReturnT<String> triggerJob(String jobGroup, String jobName) {
230 246
 		try {
231
-			DynamicSchedulerUtil.triggerJob(triggerKeyName);
247
+			DynamicSchedulerUtil.triggerJob(jobName, jobGroup);
232 248
 			return ReturnT.SUCCESS;
233 249
 		} catch (SchedulerException e) {
234 250
 			e.printStackTrace();

+ 5 - 3
xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java 查看文件

@@ -33,7 +33,9 @@ public class JobLogController {
33 33
 	public IXxlJobLogDao xxlJobLogDao;
34 34
 	
35 35
 	@RequestMapping
36
-	public String index(Model model) {
36
+	public String index(Model model, String jobGroup, String jobName) {
37
+		model.addAttribute("jobGroup", jobGroup);
38
+		model.addAttribute("jobName", jobName);
37 39
 		model.addAttribute("JobGroupList", JobGroupEnum.values());
38 40
 		return "joblog/index";
39 41
 	}
@@ -71,8 +73,8 @@ public class JobLogController {
71 73
 	
72 74
 	@RequestMapping("/save")
73 75
 	@ResponseBody
74
-	public ReturnT<String> triggerLog(int triggerLogId, String status, String msg) {
75
-		XxlJobLog log = xxlJobLogDao.load(triggerLogId);
76
+	public ReturnT<String> triggerLog(int trigger_log_id, String status, String msg) {
77
+		XxlJobLog log = xxlJobLogDao.load(trigger_log_id);
76 78
 		if (log!=null) {
77 79
 			log.setHandleTime(new Date());
78 80
 			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 {
10 10
 	
11 11
 	private int id;
12 12
 	
13
-	private String jobGroup;	// base on quartz	任务组
14
-	private String jobName;		// base on quartz	任务名
15
-	private String jobCron;		// base on quartz	任务执行CRON表达式
16
-	private String jobClass;	// base on quartz	任务执行JobBean
17
-	private String jobData;		// base on db, Map-JSON-String	任务执行数据
13
+	private String jobGroup;	// 任务组
14
+	private String jobName;		// 任务名
15
+	private String jobCron;		// 任务执行CRON表达式 【base on quartz】
16
+	private String jobDesc;
17
+	private String jobClass;	// 任务执行JobBean 【base on quartz】
18
+	private String jobData;		// 任务执行数据 Map-JSON-String
18 19
 	
19 20
 	private Date addTime;
20 21
 	private Date updateTime;
21 22
 	
22
-	private String author;		// 作者
23
+	private String author;		// 负责人
23 24
 	private String alarmEmail;	// 报警邮件
24 25
 	private int alarmThreshold;	// 报警阀值
25 26
 	
26 27
 	// copy from quartz
27
-	private String jobStatus;	// 任务状态
28
+	private String jobStatus;	// 任务状态 【base on quartz】
28 29
 
29 30
 	public int getId() {
30 31
 		return id;
@@ -58,6 +59,14 @@ public class XxlJobInfo {
58 59
 		this.jobCron = jobCron;
59 60
 	}
60 61
 
62
+	public String getJobDesc() {
63
+		return jobDesc;
64
+	}
65
+
66
+	public void setJobDesc(String jobDesc) {
67
+		this.jobDesc = jobDesc;
68
+	}
69
+
61 70
 	public String getJobClass() {
62 71
 		return jobClass;
63 72
 	}
@@ -125,9 +134,9 @@ public class XxlJobInfo {
125 134
 	@Override
126 135
 	public String toString() {
127 136
 		return "XxlJobInfo [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron
128
-				+ ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime + ", updateTime="
129
-				+ updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail + ", alarmThreshold="
130
-				+ alarmThreshold + ", jobStatus=" + jobStatus + "]";
137
+				+ ", jobDesc=" + jobDesc + ", jobClass=" + jobClass + ", jobData=" + jobData + ", addTime=" + addTime
138
+				+ ", updateTime=" + updateTime + ", author=" + author + ", alarmEmail=" + alarmEmail
139
+				+ ", alarmThreshold=" + alarmThreshold + ", jobStatus=" + jobStatus + "]";
131 140
 	}
132
-	
141
+
133 142
 }

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

@@ -14,6 +14,7 @@ public class XxlJobLog {
14 14
 	private String jobGroup;
15 15
 	private String jobName;
16 16
 	private String jobCron;
17
+	private String jobDesc;
17 18
 	private String jobClass;
18 19
 	private String jobData;
19 20
 	
@@ -26,7 +27,6 @@ public class XxlJobLog {
26 27
 	private Date handleTime;
27 28
 	private String handleStatus;
28 29
 	private String handleMsg;
29
-	
30 30
 	public int getId() {
31 31
 		return id;
32 32
 	}
@@ -51,6 +51,12 @@ public class XxlJobLog {
51 51
 	public void setJobCron(String jobCron) {
52 52
 		this.jobCron = jobCron;
53 53
 	}
54
+	public String getJobDesc() {
55
+		return jobDesc;
56
+	}
57
+	public void setJobDesc(String jobDesc) {
58
+		this.jobDesc = jobDesc;
59
+	}
54 60
 	public String getJobClass() {
55 61
 		return jobClass;
56 62
 	}
@@ -103,9 +109,9 @@ public class XxlJobLog {
103 109
 	@Override
104 110
 	public String toString() {
105 111
 		return "XxlJobLog [id=" + id + ", jobGroup=" + jobGroup + ", jobName=" + jobName + ", jobCron=" + jobCron
106
-				+ ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime=" + triggerTime
107
-				+ ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime=" + handleTime
108
-				+ ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]";
112
+				+ ", jobDesc=" + jobDesc + ", jobClass=" + jobClass + ", jobData=" + jobData + ", triggerTime="
113
+				+ triggerTime + ", triggerStatus=" + triggerStatus + ", triggerMsg=" + triggerMsg + ", handleTime="
114
+				+ handleTime + ", handleStatus=" + handleStatus + ", handleMsg=" + handleMsg + "]";
109 115
 	}
110 116
 	
111 117
 }

+ 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;
3 3
 import java.util.ArrayList;
4 4
 import java.util.Date;
5 5
 import java.util.HashMap;
6
+import java.util.HashSet;
6 7
 import java.util.List;
7 8
 import java.util.Map;
8 9
 import java.util.Set;
@@ -29,6 +30,7 @@ import org.slf4j.LoggerFactory;
29 30
 import org.springframework.beans.factory.InitializingBean;
30 31
 import org.springframework.util.Assert;
31 32
 
33
+import com.xxl.job.client.util.JacksonUtil;
32 34
 import com.xxl.job.core.model.XxlJobInfo;
33 35
 import com.xxl.job.dao.IXxlJobInfoDao;
34 36
 import com.xxl.job.dao.IXxlJobLogDao;
@@ -124,29 +126,42 @@ public final class DynamicSchedulerUtil implements InitializingBean {
124 126
 			e.printStackTrace();
125 127
 		}
126 128
 	}
129
+	
130
+	// check if exists
131
+	public static boolean checkExists(String jobName, String jobGroup) throws SchedulerException{
132
+		TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
133
+		return scheduler.checkExists(triggerKey);
134
+	}
127 135
 
128 136
 	// addJob 新增
129
-    public static boolean addJob(String triggerKeyName, String cronExpression, Class<? extends Job> jobClass, Map<String, Object> jobData) throws SchedulerException {
137
+    @SuppressWarnings("unchecked")
138
+	public static boolean addJob(XxlJobInfo jobInfo) throws SchedulerException {
130 139
     	// TriggerKey : name + group
131
-    	String group = Scheduler.DEFAULT_GROUP;
132
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
140
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(), jobInfo.getJobGroup());
141
+        JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
133 142
         
134 143
         // TriggerKey valid if_exists
135
-        if (scheduler.checkExists(triggerKey)) {
136
-            Trigger trigger = scheduler.getTrigger(triggerKey);
137
-            logger.info(">>>>>>>>> Already exist trigger [" + trigger + "] by key [" + triggerKey + "] in Scheduler");
144
+        if (checkExists(jobInfo.getJobName(), jobInfo.getJobGroup())) {
145
+            logger.info(">>>>>>>>> addJob fail, job already exist, jobInfo:{}", jobInfo);
138 146
             return false;
139 147
         }
140 148
         
141 149
         // CronTrigger : TriggerKey + cronExpression	// withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度
142
-        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
150
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getJobCron()).withMisfireHandlingInstructionDoNothing();
143 151
         CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
144 152
 
145 153
         // JobDetail : jobClass
146
-        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(triggerKeyName, group).build();
147
-        if (jobData!=null && jobData.size() > 0) {
154
+		Class<? extends Job> jobClass_ = null;
155
+		try {
156
+			jobClass_ = (Class<? extends Job>)Class.forName(jobInfo.getJobClass());
157
+		} catch (ClassNotFoundException e) {
158
+			e.printStackTrace();
159
+		}
160
+        
161
+		JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();
162
+        if (jobInfo.getJobData()!=null) {
148 163
         	JobDataMap jobDataMap = jobDetail.getJobDataMap();
149
-        	jobDataMap.putAll(jobData);	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
164
+        	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));	// JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
150 165
 		}
151 166
         
152 167
         // schedule : jobDetail + cronTrigger
@@ -156,49 +171,60 @@ public final class DynamicSchedulerUtil implements InitializingBean {
156 171
         return true;
157 172
     }
158 173
     
159
-    // reschedule 重置cron
160
-    public static boolean rescheduleJob(String triggerKeyName, String cronExpression) throws SchedulerException {
174
+    // reschedule
175
+    @SuppressWarnings("unchecked")
176
+	public static boolean rescheduleJob(XxlJobInfo jobInfo) throws SchedulerException {
177
+    	
178
+    	// TriggerKey valid if_exists
179
+        if (!checkExists(jobInfo.getJobName(), jobInfo.getJobGroup())) {
180
+        	logger.info(">>>>>>>>>>> rescheduleJob fail, job not exists, jobInfo:{}", jobInfo);
181
+            return false;
182
+        }
183
+        
161 184
         // TriggerKey : name + group
162
-    	String group = Scheduler.DEFAULT_GROUP;
163
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
185
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(), jobInfo.getJobGroup());
186
+        JobKey jobKey = new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup());
164 187
         
165
-        boolean result = false;
166
-        if (scheduler.checkExists(triggerKey)) {
167
-            // CronTrigger : TriggerKey + cronExpression
168
-            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
169
-            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
170
-            
171
-            Date date = scheduler.rescheduleJob(triggerKey, cronTrigger);
172
-            result = true;
173
-            logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}, cronExpression:{}, date:{}", triggerKey, cronExpression, date);
174
-        } else {
175
-        	logger.info(">>>>>>>>>>> resumeJob fail, triggerKey:{}, cronExpression:{}", triggerKey, cronExpression);
176
-        }
177
-        return result;
188
+        // CronTrigger : TriggerKey + cronExpression
189
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(jobInfo.getJobCron()).withMisfireHandlingInstructionDoNothing();
190
+        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
191
+        
192
+        //scheduler.rescheduleJob(triggerKey, cronTrigger);
193
+        
194
+        // JobDetail-JobDataMap fresh
195
+        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
196
+    	JobDataMap jobDataMap = jobDetail.getJobDataMap();
197
+    	jobDataMap.clear();
198
+    	jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));
199
+    	
200
+    	// Trigger fresh
201
+    	HashSet<Trigger> triggerSet = new HashSet<Trigger>();
202
+    	triggerSet.add(cronTrigger);
203
+        
204
+        scheduler.scheduleJob(jobDetail, triggerSet, true);
205
+        logger.info(">>>>>>>>>>> resumeJob success, jobInfo:{}", jobInfo);
206
+        return true;
178 207
     }
179 208
     
180
-    // unscheduleJob 删除
181
-    public static boolean removeJob(String triggerKeyName) throws SchedulerException {
209
+    // unscheduleJob
210
+    public static boolean removeJob(String jobName, String jobGroup) throws SchedulerException {
182 211
     	// TriggerKey : name + group
183
-    	String group = Scheduler.DEFAULT_GROUP;
184
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
185
-        
212
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
186 213
         boolean result = false;
187
-        if (scheduler.checkExists(triggerKey)) {
214
+        if (checkExists(jobName, jobGroup)) {
188 215
             result = scheduler.unscheduleJob(triggerKey);
216
+            logger.info(">>>>>>>>>>> removeJob, triggerKey:{}, result [{}]", triggerKey, result);
189 217
         }
190
-        logger.info(">>>>>>>>>>> removeJob, triggerKey:{}, result [{}]", triggerKey, result);
191
-        return result;
218
+        return true;
192 219
     }
193 220
 
194
-    // Pause 暂停
195
-    public static boolean pauseJob(String triggerKeyName) throws SchedulerException {
221
+    // Pause
222
+    public static boolean pauseJob(String jobName, String jobGroup) throws SchedulerException {
196 223
     	// TriggerKey : name + group
197
-    	String group = Scheduler.DEFAULT_GROUP;
198
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
224
+    	TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
199 225
         
200 226
         boolean result = false;
201
-        if (scheduler.checkExists(triggerKey)) {
227
+        if (checkExists(jobName, jobGroup)) {
202 228
             scheduler.pauseTrigger(triggerKey);
203 229
             result = true;
204 230
             logger.info(">>>>>>>>>>> pauseJob success, triggerKey:{}", triggerKey);
@@ -208,14 +234,13 @@ public final class DynamicSchedulerUtil implements InitializingBean {
208 234
         return result;
209 235
     }
210 236
     
211
-    // resume 重启 
212
-    public static boolean resumeJob(String triggerKeyName) throws SchedulerException {
213
-        // TriggerKey : name + group
214
-    	String group = Scheduler.DEFAULT_GROUP;
215
-        TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
237
+    // resume
238
+    public static boolean resumeJob(String jobName, String jobGroup) throws SchedulerException {
239
+    	// TriggerKey : name + group
240
+    	TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
216 241
         
217 242
         boolean result = false;
218
-        if (scheduler.checkExists(triggerKey)) {
243
+        if (checkExists(jobName, jobGroup)) {
219 244
             scheduler.resumeTrigger(triggerKey);
220 245
             result = true;
221 246
             logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}", triggerKey);
@@ -225,14 +250,13 @@ public final class DynamicSchedulerUtil implements InitializingBean {
225 250
         return result;
226 251
     }
227 252
     
228
-    // run 执行一次 
229
-    public static boolean triggerJob(String triggerKeyName) throws SchedulerException {
230
-        // TriggerKey : name + group
231
-    	String group = Scheduler.DEFAULT_GROUP;
232
-        JobKey jobKey = JobKey.jobKey(triggerKeyName, group);
253
+    // run
254
+    public static boolean triggerJob(String jobName, String jobGroup) throws SchedulerException {
255
+    	// TriggerKey : name + group
256
+    	JobKey jobKey = new JobKey(jobName, jobGroup);
233 257
         
234 258
         boolean result = false;
235
-        if (scheduler.checkExists(jobKey)) {
259
+        if (checkExists(jobName, jobGroup)) {
236 260
             scheduler.triggerJob(jobKey);
237 261
             result = true;
238 262
             logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey);

+ 4 - 5
xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobInfoDao.java 查看文件

@@ -1,6 +1,5 @@
1 1
 package com.xxl.job.dao;
2 2
 
3
-import java.util.Date;
4 3
 import java.util.List;
5 4
 
6 5
 import com.xxl.job.core.model.XxlJobInfo;
@@ -11,15 +10,15 @@ import com.xxl.job.core.model.XxlJobInfo;
11 10
  */
12 11
 public interface IXxlJobInfoDao {
13 12
 
14
-	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd);
15
-	public int pageListCount(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd);
13
+	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobGroup, String jobName);
14
+	public int pageListCount(int offset, int pagesize, String jobGroup, String jobName);
16 15
 	
17 16
 	public int save(XxlJobInfo info);
18 17
 	
19
-	public XxlJobInfo load(String jobName);
18
+	public XxlJobInfo load(String jobGroup, String jobName);
20 19
 	
21 20
 	public int update(XxlJobInfo item);
22 21
 	
23
-	public int delete(String jobName);
22
+	public int delete(String jobGroup, String jobName);
24 23
 	
25 24
 }

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

@@ -1,6 +1,5 @@
1 1
 package com.xxl.job.dao.impl;
2 2
 
3
-import java.util.Date;
4 3
 import java.util.HashMap;
5 4
 import java.util.List;
6 5
 
@@ -23,25 +22,23 @@ public class XxlJobInfoDaoImpl implements IXxlJobInfoDao {
23 22
 	public SqlSessionTemplate sqlSessionTemplate;
24 23
 
25 24
 	@Override
26
-	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd) {
25
+	public List<XxlJobInfo> pageList(int offset, int pagesize, String jobGroup, String jobName) {
27 26
 		HashMap<String, Object> params = new HashMap<String, Object>();
28 27
 		params.put("offset", offset);
29 28
 		params.put("pagesize", pagesize);
29
+		params.put("jobGroup", jobGroup);
30 30
 		params.put("jobName", jobName);
31
-		params.put("addTimeStart", addTimeStart);
32
-		params.put("addTimeEnd", addTimeEnd);
33 31
 		
34 32
 		return sqlSessionTemplate.selectList("XxlJobInfoMapper.pageList", params);
35 33
 	}
36 34
 
37 35
 	@Override
38
-	public int pageListCount(int offset, int pagesize, String jobName, Date addTimeStart, Date addTimeEnd) {
36
+	public int pageListCount(int offset, int pagesize, String jobGroup, String jobName) {
39 37
 		HashMap<String, Object> params = new HashMap<String, Object>();
40 38
 		params.put("offset", offset);
41 39
 		params.put("pagesize", pagesize);
40
+		params.put("jobGroup", jobGroup);
42 41
 		params.put("jobName", jobName);
43
-		params.put("addTimeStart", addTimeStart);
44
-		params.put("addTimeEnd", addTimeEnd);
45 42
 		
46 43
 		return sqlSessionTemplate.selectOne("XxlJobInfoMapper.pageListCount", params);
47 44
 	}
@@ -52,8 +49,12 @@ public class XxlJobInfoDaoImpl implements IXxlJobInfoDao {
52 49
 	}
53 50
 
54 51
 	@Override
55
-	public XxlJobInfo load(String jobName) {
56
-		return sqlSessionTemplate.selectOne("XxlJobInfoMapper.load", jobName);
52
+	public XxlJobInfo load(String jobGroup, String jobName) {
53
+		HashMap<String, Object> params = new HashMap<String, Object>();
54
+		params.put("jobGroup", jobGroup);
55
+		params.put("jobName", jobName);
56
+		
57
+		return sqlSessionTemplate.selectOne("XxlJobInfoMapper.load", params);
57 58
 	}
58 59
 
59 60
 	@Override
@@ -62,8 +63,12 @@ public class XxlJobInfoDaoImpl implements IXxlJobInfoDao {
62 63
 	}
63 64
 
64 65
 	@Override
65
-	public int delete(String jobName) {
66
-		return sqlSessionTemplate.update("XxlJobInfoMapper.delete", jobName);
66
+	public int delete(String jobGroup, String jobName) {
67
+		HashMap<String, Object> params = new HashMap<String, Object>();
68
+		params.put("jobGroup", jobGroup);
69
+		params.put("jobName", jobName);
70
+		
71
+		return sqlSessionTemplate.update("XxlJobInfoMapper.delete", params);
67 72
 	}
68 73
 	
69 74
 }

+ 22 - 22
xxl-job-admin/src/main/java/com/xxl/job/service/job/HttpJobBean.java 查看文件

@@ -5,9 +5,10 @@ import java.util.HashMap;
5 5
 import java.util.Map;
6 6
 
7 7
 import org.apache.commons.lang.StringUtils;
8
+import org.quartz.DisallowConcurrentExecution;
8 9
 import org.quartz.JobExecutionContext;
9 10
 import org.quartz.JobExecutionException;
10
-import org.quartz.impl.triggers.CronTriggerImpl;
11
+import org.quartz.JobKey;
11 12
 import org.slf4j.Logger;
12 13
 import org.slf4j.LoggerFactory;
13 14
 import org.springframework.scheduling.quartz.QuartzJobBean;
@@ -22,44 +23,43 @@ import com.xxl.job.core.util.PropertiesUtil;
22 23
 
23 24
 /**
24 25
  * http job bean
26
+ * “@DisallowConcurrentExecution” diable concurrent, thread size can not be only one, better given more
25 27
  * @author xuxueli 2015-12-17 18:20:34
26 28
  */
29
+@DisallowConcurrentExecution
27 30
 public class HttpJobBean extends QuartzJobBean {
28 31
 	private static Logger logger = LoggerFactory.getLogger(HttpJobBean.class);
29
-
32
+	
30 33
 	@SuppressWarnings("unchecked")
31 34
 	@Override
32 35
 	protected void executeInternal(JobExecutionContext context)
33 36
 			throws JobExecutionException {
34
-		String triggerKey = context.getTrigger().getJobKey().getName();
35
-		
36
-		// jobDataMap 2 params
37
-		Map<String, String> params = new HashMap<String, String>();
38
-		XxlJobInfo jobInfo = DynamicSchedulerUtil.xxlJobInfoDao.load(triggerKey);
39
-		if (jobInfo!=null && jobInfo.getJobData()!=null) {
40
-			params = JacksonUtil.readValue(jobInfo.getJobData(), Map.class);
41
-		}
42
-		
43
-		// corn
44
-		String cornExp = null;
45
-		if (context.getTrigger() instanceof CronTriggerImpl) {
46
-			CronTriggerImpl trigger = (CronTriggerImpl) context.getTrigger();
47
-			cornExp = trigger.getCronExpression();
48
-		}
37
+		JobKey jobKey = context.getTrigger().getJobKey();
49 38
 		
39
+		XxlJobInfo jobInfo = DynamicSchedulerUtil.xxlJobInfoDao.load(jobKey.getGroup(), jobKey.getName());
40
+		HashMap<String, String> jobDataMap = (HashMap<String, String>) JacksonUtil.readValueRefer(jobInfo.getJobData(), Map.class);
50 41
 		// save log
51 42
 		XxlJobLog jobLog = new XxlJobLog();
52
-		jobLog.setJobName(triggerKey);
53
-		jobLog.setJobCron(cornExp);
43
+		jobLog.setJobGroup(jobInfo.getJobGroup());
44
+		jobLog.setJobName(jobInfo.getJobName());
45
+		jobLog.setJobCron(jobInfo.getJobCron());
46
+		jobLog.setJobDesc(jobInfo.getJobDesc());
47
+		jobLog.setJobClass(jobInfo.getJobClass());
48
+		jobLog.setJobData(jobInfo.getJobData());
49
+		
54 50
 		jobLog.setJobClass(HttpJobBean.class.getName());
55 51
 		jobLog.setJobData(jobInfo.getJobData());
56 52
 		DynamicSchedulerUtil.xxlJobLogDao.save(jobLog);
57 53
 		logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog);
58 54
 		
59 55
 		// trigger request
60
-		params.put(HandlerRepository.triggerLogId, String.valueOf(jobLog.getId()));
61
-		params.put(HandlerRepository.triggerLogUrl, PropertiesUtil.getString(HandlerRepository.triggerLogUrl));
62
-		String[] postResp = HttpUtil.post(params.get(HandlerRepository.job_url), params);
56
+		HashMap<String, String> params = new HashMap<String, String>();
57
+		params.put(HandlerRepository.TRIGGER_LOG_URL, PropertiesUtil.getString(HandlerRepository.TRIGGER_LOG_URL));
58
+		params.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(jobLog.getId()));
59
+		params.put(HandlerRepository.HANDLER_NAME, jobDataMap.get(HandlerRepository.HANDLER_NAME));
60
+		params.put(HandlerRepository.HANDLER_PARAMS, jobDataMap.get(HandlerRepository.HANDLER_PARAMS));
61
+		
62
+		String[] postResp = HttpUtil.post(jobDataMap.get(HandlerRepository.HANDLER_ADDRESS), params);
63 63
 		logger.info(">>>>>>>>>>> xxl-job trigger http response, jobLog.id:{}, jobLog:{}", jobLog.getId(), jobLog);
64 64
 		
65 65
 		// parse trigger response

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

@@ -6,37 +6,45 @@
6 6
 	<resultMap id="XxlJobInfo" type="com.xxl.job.core.model.XxlJobInfo" >
7 7
 		<result column="id" property="id" />
8 8
 	
9
+		<result column="job_group" property="jobGroup" />
9 10
 	    <result column="job_name" property="jobName" />
10 11
 	    <result column="job_cron" property="jobCron" />
12
+	    <result column="job_desc" property="jobDesc" />
11 13
 	    <result column="job_class" property="jobClass" />
12 14
 	    <result column="job_data" property="jobData" />
13 15
 	    
14 16
 	    <result column="add_time" property="addTime" />
15 17
 	    <result column="update_time" property="updateTime" />
18
+	    
19
+	    <result column="author" property="author" />
20
+	    <result column="alarm_email" property="alarmEmail" />
21
+	    <result column="alarm_threshold" property="alarmThreshold" />
16 22
 	</resultMap>
17 23
 
18 24
 	<sql id="Base_Column_List">
19 25
 		t.id,
26
+		t.job_group,
20 27
 		t.job_name,
21 28
 		t.job_cron,
29
+		t.job_desc,
22 30
 		t.job_class,
23 31
 		t.job_data,
24 32
 		t.add_time,
25
-		t.update_time
33
+		t.update_time,
34
+		t.author,
35
+		t.alarm_email,
36
+		t.alarm_threshold
26 37
 	</sql>
27 38
 	
28 39
 	<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
29 40
 		SELECT <include refid="Base_Column_List" />
30 41
 		FROM xxl_job_qrtz_trigger_info AS t
31 42
 		<trim prefix="WHERE" prefixOverrides="AND | OR" >
32
-			<if test="jobName != null and jobName!=''">
33
-				AND t.job_name = #{jobName}
34
-			</if>
35
-			<if test="addTimeStart != null">
36
-				AND t.add_time <![CDATA[ > ]]> #{addTimeStart}
43
+			<if test="jobGroup != null and jobGroup != ''">
44
+				AND t.job_group = #{jobGroup}
37 45
 			</if>
38
-			<if test="addTimeEnd != null">
39
-				AND t.add_time <![CDATA[ < ]]> #{addTimeEnd}
46
+			<if test="jobName != null and jobName != ''">
47
+				AND t.job_name like CONCAT(CONCAT('%', #{jobName}), '%')
40 48
 			</if>
41 49
 		</trim>
42 50
 		ORDER BY id DESC
@@ -47,56 +55,74 @@
47 55
 		SELECT count(1)
48 56
 		FROM xxl_job_qrtz_trigger_info AS t
49 57
 		<trim prefix="WHERE" prefixOverrides="AND | OR" >
50
-			<if test="jobName != null and jobName!=''">
51
-				AND t.job_name = #{jobName}
58
+			<if test="jobGroup != null and jobGroup != ''">
59
+				AND t.job_group = #{jobGroup}
52 60
 			</if>
53
-			<if test="addTimeStart != null">
54
-				AND t.add_time <![CDATA[ > ]]> #{addTimeStart}
55
-			</if>
56
-			<if test="addTimeEnd != null">
57
-				AND t.add_time <![CDATA[ < ]]> #{addTimeEnd}
61
+			<if test="jobName != null and jobName != ''">
62
+				AND t.job_name like CONCAT(CONCAT('%', #{jobName}), '%')
58 63
 			</if>
59 64
 		</trim>
60 65
 	</select>
61 66
 	
62 67
 	<insert id="save" parameterType="com.xxl.job.core.model.XxlJobInfo" useGeneratedKeys="true" keyProperty="id" >
63 68
 		INSERT INTO `xxl_job_qrtz_trigger_info` (
64
-			`job_name`, 
65
-			`job_cron`, 
66
-			`job_class`, 
67
-			`job_data`,
68
-			`add_time`,
69
-			`update_time`
69
+			job_group,
70
+			job_name,
71
+			job_cron,
72
+			job_desc,
73
+			job_class,
74
+			job_data,
75
+			add_time,
76
+			update_time,
77
+			author,
78
+			alarm_email,
79
+			alarm_threshold
70 80
 		) VALUES (
81
+			#{jobGroup}, 
71 82
 			#{jobName}, 
72 83
 			#{jobCron}, 
84
+			#{jobDesc}, 
73 85
 			#{jobClass}, 
74 86
 			#{jobData},
75 87
 			NOW(),
76
-			NOW()
88
+			NOW(),
89
+			#{author},
90
+			#{alarmEmail},
91
+			#{alarmThreshold}
77 92
 		);
78 93
 		<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> 
79 94
 			SELECT LAST_INSERT_ID() 
80 95
 		</selectKey> 
81 96
 	</insert>
82 97
 	
83
-	<select id="load" parameterType="java.lang.String" resultMap="XxlJobInfo">
98
+	<select id="load" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
84 99
 		SELECT <include refid="Base_Column_List" />
85 100
 		FROM xxl_job_qrtz_trigger_info AS t
86
-		WHERE t.job_name = #{jobName}
101
+		WHERE t.job_group = #{jobGroup}
102
+			AND t.job_name = #{jobName}
87 103
 	</select>
88 104
 	
89
-	<update id="update">
105
+	<update id="update" parameterType="com.xxl.job.core.model.XxlJobInfo" >
90 106
 		UPDATE `xxl_job_qrtz_trigger_info` 
91
-		SET `job_cron`= #{jobCron}, 
92
-			`job_data`= #{jobData},
93
-			`update_time`= NOW()
94
-		WHERE `id`= #{id}
107
+		SET 
108
+			job_cron = #{jobCron},
109
+			job_desc = #{jobDesc},
110
+			job_data = #{jobData},
111
+			update_time = NOW(),
112
+			author = #{author},
113
+			alarm_email = #{alarmEmail},
114
+			alarm_threshold = #{alarmThreshold}
115
+		WHERE job_group = #{jobGroup}
116
+			AND job_name = #{jobName}
95 117
 	</update>
96 118
 	
97 119
 	<delete id="delete" parameterType="java.lang.String">
98
-		delete from xxl_job_qrtz_trigger_info
99
-		where job_name = #{jobName}
120
+		DELETE
121
+		FROM
122
+			xxl_job_qrtz_trigger_info
123
+		WHERE
124
+			job_group = #{jobGroup}
125
+		AND job_name = #{jobName}
100 126
 	</delete>
101 127
 	
102 128
 </mapper>

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

@@ -9,6 +9,7 @@
9 9
 	    <result column="job_group" property="jobGroup" />
10 10
 	    <result column="job_name" property="jobName" />
11 11
 	    <result column="job_cron" property="jobCron" />
12
+	    <result column="job_desc" property="jobDesc" />
12 13
 	    <result column="job_class" property="jobClass" />
13 14
 	    <result column="job_data" property="jobData" />
14 15
 	    
@@ -26,8 +27,9 @@
26 27
 		t.job_group,
27 28
 		t.job_name,
28 29
 		t.job_cron,
30
+		t.job_desc,
29 31
 		t.job_class,
30
-		t.job_data,
32
+		t.job_desc,
31 33
 		t.trigger_time,
32 34
 		t.trigger_status,
33 35
 		t.trigger_msg,
@@ -94,12 +96,14 @@
94 96
 			`job_group`,
95 97
 			`job_name`,
96 98
 			`job_cron`, 
99
+			`job_desc`,
97 100
 			`job_class`, 
98 101
 			`job_data`
99 102
 		) VALUES (
100 103
 			#{jobGroup}, 
101 104
 			#{jobName},
102 105
 			#{jobCron},
106
+			#{jobDesc},
103 107
 			#{jobClass},
104 108
 			#{jobData}
105 109
 		);

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

@@ -42,9 +42,7 @@
42 42
 	            </div>
43 43
 	            <div class="col-xs-4">
44 44
 	              	<div class="input-group">
45
-	                	<span class="input-group-addon">
46
-	                  		jobName
47
-	                	</span>
45
+	                	<span class="input-group-addon">任务名</span>
48 46
 	                	<input type="text" class="form-control" id="jobName" value="${jobName}" autocomplete="on" >
49 47
 	              	</div>
50 48
 	            </div>
@@ -66,63 +64,23 @@
66 64
 			              	<table id="job_list" class="table table-bordered table-striped">
67 65
 				                <thead>
68 66
 					            	<tr>
69
-					            		<th>id</th>
70
-					                	<th>任务Key</th>
71
-					                  	<th>任务Cron</th>
72
-					                  	<th>任务Class</th>
73
-					                  	<th>状态Status</th>
74
-					                  	<th>参数</th>
75
-					                  	<th>addTime</th>
76
-					                  	<th>updateTime</th>
67
+					            		<th name="id" >id</th>
68
+					                	<th name="jobGroup" >任务组</th>
69
+					                  	<th name="jobName" >任务名</th>
70
+					                  	<th name="jobCron" >Cron</th>
71
+					                  	<th name="jobDesc" >描述</th>
72
+					                  	<th name="jobClass" >JobBean</th>
73
+					                  	<th name="jobData" >任务数据</th>
74
+					                  	<th name="addTime" >新增时间</th>
75
+					                  	<th name="updateTime" >更新时间</th>
76
+					                  	<th name="author" >负责人</th>
77
+					                  	<th name="alarmEmail" >报警邮件</th>
78
+					                  	<th name="alarmThreshold" >报警阀值</th>
79
+					                  	<th name="jobStatus" >状态</th>
77 80
 					                  	<th>操作</th>
78 81
 					                </tr>
79 82
 				                </thead>
80
-				                <tbody>
81
-				                	<#--
82
-			                		<#if jobList?exists && jobList?size gt 0>
83
-									<#list jobList as item>
84
-									<tr>
85
-					            		<td>${item['TriggerKey'].name}</td>
86
-					                  	<td>${item['Trigger'].cronExpression}</td>
87
-					                  	<td>${item['JobDetail'].jobClass}</td>
88
-					                  	<td>
89
-					                  		<#assign jobDataMap = item['JobDetail'].jobDataMap />
90
-					                  		<#if jobDataMap?exists && jobDataMap?keys?size gt 0>
91
-					                  			<#list jobDataMap?keys as key>
92
-					                  				${key}	=	${jobDataMap[key]}	<br>
93
-					                  			</#list>
94
-					                  		</#if>
95
-					                  	</td>
96
-					                  	<td state="${item['TriggerState']}" >
97
-					                  		<#if item['TriggerState'] == 'NORMAL'>
98
-					                  			<button class="btn btn-block btn-success" type="button">运行ing</button>
99
-					                  		<#elseif item['TriggerState'] == 'PAUSED'>
100
-					                  			<button class="btn btn-block btn-warning" type="button">暂停ing</button>
101
-					                  		<#else>
102
-					                  			<button class="btn btn-block" type="button">${item['TriggerState']}</button>
103
-					                  		</#if>
104
-					                  	</td>
105
-					                  	<td>
106
-											<p name="${item['TriggerKey'].name}" group="${item['TriggerKey'].group}" 
107
-												cronExpression="${item['Trigger'].cronExpression}" jobClassName="${item['JobDetail'].jobClass}" jobDesc="${job_desc?if_exists}" >
108
-												<#if item['TriggerState'] == 'NORMAL'>
109
-													<button class="btn btn-info btn-xs job_operate" type="job_pause" type="button">暂停</button>
110
-												<#elseif item['TriggerState'] == 'PAUSED'>
111
-													<button class="btn btn-info btn-xs job_operate" type="job_resume" type="button">恢复</button>
112
-												</#if>
113
-												<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行一次</button>
114
-												<button class="btn btn-info btn-xs update" type="button">更新corn</button>
115
-											  	<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>
116
-											  	<button class="btn btn-warning btn-xs" type="job_del" type="button" 
117
-											  		onclick="javascript:window.open('${request.contextPath}/joblog?jobName=${item['TriggerKey'].name}')" >查看日志</button>
118
-											</p>
119
-					                  	</td>
120
-					                </tr>
121
-									</#list>
122
-									</#if>
123
-									
124
-									-->
125
-				                </tbody>
83
+				                <tbody></tbody>
126 84
 				                <tfoot></tfoot>
127 85
 							</table>
128 86
 						</div>
@@ -155,29 +113,51 @@
155 113
 		                  	</select>
156 114
 						</div>
157 115
 						<label for="firstname" class="col-sm-2 control-label">任务名</label>
158
-						<div class="col-sm-4"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" ></div>
116
+						<div class="col-sm-4"><input type="text" class="form-control" name="jobName" placeholder="请输入“任务名”" minlength="4" maxlength="100" ></div>
159 117
 					</div>
160 118
 					<div class="form-group">
161
-						<label for="lastname" class="col-sm-3 control-label">任务Corn</label>
162
-						<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div>
119
+						<label for="lastname" class="col-sm-2 control-label">Corn</label>
120
+						<div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="请输入“Corn”" maxlength="100" ></div>
121
+						<label for="lastname" class="col-sm-2 control-label">描述</label>
122
+						<div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="请输入“描述”" maxlength="200" ></div>
163 123
 					</div>
164 124
 					<div class="form-group">
165
-						<label for="lastname" class="col-sm-3 control-label">任务描述</label>
166
-						<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述" maxlength="200" ></div>
125
+						<label for="firstname" class="col-sm-2 control-label">JobBean</label>
126
+						<div class="col-sm-4">
127
+							<select class="form-control" name="jobClass" >
128
+								<#if remoteJobBean?exists >
129
+								<option value="${remoteJobBean.name}" jobClassType="remote" >【远程任务】</option>
130
+								</#if>
131
+								<#if localJobBeanList?exists && localJobBeanList?size gt 0 >
132
+								<#list localJobBeanList as localJobBean>
133
+									<option value="${localJobBean.name}" jobClassType="local" >${localJobBean.name}</option>
134
+								</#list>
135
+								</#if>
136
+		                  	</select>
137
+						</div>
138
+						<label for="firstname" class="col-sm-2 control-label">执行参数</label>
139
+						<div class="col-sm-4"><input type="text" class="form-control" name="handler_params" placeholder="请输入“执行参数”" maxlength="100" ></div>
140
+					</div>
141
+					<div class="form-group remote_panel">
142
+						<label for="lastname" class="col-sm-2 control-label">远程-机器地址</label>
143
+						<div class="col-sm-4"><input type="text" class="form-control" name="handler_address" placeholder="请输入“远程-机器地址”" maxlength="200" ></div>
144
+						<label for="lastname" class="col-sm-2 control-label">远程-执行器</label>
145
+						<div class="col-sm-4"><input type="text" class="form-control" name="handler_name" placeholder="请输入“远程-执行器”" maxlength="200" ></div>
167 146
 					</div>
168 147
 					<div class="form-group">
169
-						<label for="lastname" class="col-sm-3 control-label">任务URL</label>
170
-						<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL" maxlength="200" ></div>
148
+						<label for="lastname" class="col-sm-2 control-label">负责人</label>
149
+						<div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="200" ></div>
150
+						<label for="lastname" class="col-sm-2 control-label">报警邮件</label>
151
+						<div class="col-sm-4"><input type="text" class="form-control" name="alarm_email" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="200" ></div>
171 152
 					</div>
172 153
 					<div class="form-group">
173
-						<label for="lastname" class="col-sm-3 control-label">任务handler</label>
174
-						<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler" maxlength="200" ></div>
154
+						<label for="lastname" class="col-sm-2 control-label">报警阈值</label>
155
+						<div class="col-sm-4"><input type="text" class="form-control" name="alarm_threshold" placeholder="请输入“报警阈值”" maxlength="200" ></div>
175 156
 					</div>
176 157
 					<div class="form-group">
177 158
 						<div class="col-sm-offset-3 col-sm-9">
178 159
 							<button type="submit" class="btn btn-primary"  >保存</button>
179 160
 							<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
180
-							<button type="button" class="btn btn-info pull-right addParam">+ arg</button>
181 161
 						</div>
182 162
 					</div>
183 163
 				</form>

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

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

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

@@ -7,32 +7,68 @@ $(function() {
7 7
 		"ajax": {
8 8
 			url: base_url + "/jobinfo/pageList",
9 9
 	        data : function ( d ) {
10
-                d.jobName = $('#jobName').val()
10
+	        	d.jobGroup = $('#jobGroup').val();
11
+                d.jobName = $('#jobName').val();
11 12
             }
12 13
 	    },
14
+	    "searching": false,
15
+	    "ordering": false,
13 16
 	    //"scrollX": true,	// X轴滚动条,取消自适应
14 17
 	    "columns": [
15 18
 	                { "data": 'id', "bSortable": false, "visible" : false},
16
-	                { "data": 'jobName', "bSortable": false},
17
-	                { "data": 'jobCron', "bSortable": false, "visible" : true},
18
-	                { "data": 'jobClass', "bSortable": false, "visible" : false},
19
-	                { "data": 'jobStatus', "bSortable": false, "visible" : true},
20
-	                { "data": 'jobData', "bSortable": false, "visible" : true},
19
+	                { 
20
+	                	"data": 'jobGroup', 
21
+	                	"render": function ( data, type, row ) {
22
+	            			var groupMenu = $("#jobGroup").find("option");
23
+	            			for ( var index in $("#jobGroup").find("option")) {
24
+	            				if ($(groupMenu[index]).attr('value') == data) {
25
+									return $(groupMenu[index]).html();
26
+								}
27
+							}
28
+	            			return data;
29
+	            		}
30
+            		},
31
+	                { "data": 'jobName'},
32
+	                { "data": 'jobCron', "visible" : true},
33
+	                { "data": 'jobDesc', "visible" : false},
34
+	                { "data": 'jobClass', "visible" : true},
35
+	                { 
36
+	                	"data": 'jobData',
37
+	                	"visible" : true,
38
+	                	"render": function ( data, type, row ) {
39
+	                		return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
40
+	                	}
41
+	                },
21 42
 	                { 
22 43
 	                	"data": 'addTime', 
23
-	                	"bSortable": false, 
44
+	                	"visible" : false, 
24 45
 	                	"render": function ( data, type, row ) {
25 46
 	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
26 47
 	                	}
27 48
 	                },
28 49
 	                { 
29 50
 	                	"data": 'updateTime', 
30
-	                	"bSortable": false, 
51
+	                	"visible" : false, 
31 52
 	                	"render": function ( data, type, row ) {
32 53
 	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
33 54
 	                	}
34 55
 	                },
35
-	                { "data": '操作' , "bSortable": false,
56
+	                { "data": 'author', "visible" : true},
57
+	                { "data": 'alarmEmail', "visible" : false},
58
+	                { "data": 'alarmThreshold', "visible" : false},
59
+	                { 
60
+	                	"data": 'jobStatus', 
61
+	                	"visible" : true,
62
+	                	"render": function ( data, type, row ) {
63
+	                		if ('NORMAL' == data) {
64
+	                			return '<small class="label label-success" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
65
+							} else if ('PAUSED' == data){
66
+								return '<small class="label label-default"><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
67
+							}
68
+	                		return data;
69
+	                	}
70
+	                },
71
+	                { "data": '操作' ,
36 72
 	                	"render": function ( data, type, row ) {
37 73
 	                		return function(){
38 74
 	                			// status
@@ -43,23 +79,31 @@ $(function() {
43 79
 									pause_resume = '<button class="btn btn-info btn-xs job_operate" type="job_resume" type="button">恢复</button>  ';
44 80
 								}
45 81
 	                			// log url
46
-	                			var logUrl = base_url +'/joblog?jobName='+ row.jobName;
82
+	                			var logUrl = base_url +'/joblog?jobGroup='+ row.jobGroup +'&jobName='+ row.jobName;
47 83
 	                			
48 84
 	                			// job data
49 85
 	                			var jobDataMap = eval('(' + row.jobData + ')');
50 86
 	                			
51
-	                			var html = '<p jobName="'+ row.jobName +'" '+
52
-	                							' cronExpression="'+ row.jobCron +'" '+
53
-	                							' job_desc="'+jobDataMap.job_desc +'" '+
54
-	                							' job_url="'+ jobDataMap.job_url +'" '+
55
-	                							' handleName="'+ jobDataMap.handleName +'" '+
87
+	                			var html = '<p id="'+ row.id +'" '+
88
+	                							' jobGroup="'+ row.jobGroup +'" '+
89
+	                							' jobName="'+ row.jobName +'" '+
90
+	                							' jobCron="'+ row.jobCron +'" '+
91
+	                							' jobDesc="'+ row.jobDesc +'" '+
92
+	                							' jobClass="'+ row.jobClass +'" '+
93
+	                							' jobData="'+ row.jobData +'" '+
94
+	                							' author="'+ row.author +'" '+
95
+	                							' alarmEmail="'+ row.alarmEmail +'" '+
96
+	                							' alarmThreshold="'+ row.alarmThreshold +'" '+
97
+	                							' handler_params="'+jobDataMap.handler_params +'" '+
98
+	                							' handler_address="'+ jobDataMap.handler_address +'" '+
99
+	                							' handler_name="'+ jobDataMap.handler_name +'" '+
56 100
 	                							'>'+
57 101
 	                					pause_resume +
58 102
 										'<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行</button>  '+
59
-										'<button class="btn btn-info btn-xs update" type="button">更新corn</button>  '+
60
-									  	'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>  '+
103
+										'<button class="btn btn-warning btn-xs update" type="button">编辑</button><br> '+
61 104
 									  	'<button class="btn btn-warning btn-xs" type="job_del" type="button" '+
62
-									  		'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button>'+
105
+									  		'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button> '+
106
+								  		'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>  '+
63 107
 									'</p>';
64 108
 									
65 109
 	                			
@@ -68,8 +112,6 @@ $(function() {
68 112
 	                	}
69 113
 	                }
70 114
 	            ],
71
-	    "searching": false,
72
-	    "ordering": true,
73 115
 		"language" : {
74 116
 			"sProcessing" : "处理中...",
75 117
 			"sLengthMenu" : "每页 _MENU_ 条记录",
@@ -96,6 +138,12 @@ $(function() {
96 138
 		}
97 139
 	});
98 140
 	
141
+	// 日志弹框提示
142
+	$('#job_list').on('click', '.logTips', function(){
143
+		var msg = $(this).find('span').html();
144
+		ComAlertTec.show(msg);
145
+	});
146
+	
99 147
 	// 搜索按钮
100 148
 	$('#searchBtn').on('click', function(){
101 149
 		jobTable.fnDraw();
@@ -108,28 +156,30 @@ $(function() {
108 156
 		var type = $(this).attr("type");
109 157
 		if ("job_pause" == type) {
110 158
 			typeName = "暂停";
111
-			url = base_url + "/job/pause";
159
+			url = base_url + "/jobinfo/pause";
112 160
 		} else if ("job_resume" == type) {
113 161
 			typeName = "恢复";
114
-			url = base_url + "/job/resume";
162
+			url = base_url + "/jobinfo/resume";
115 163
 		} else if ("job_del" == type) {
116 164
 			typeName = "删除";
117
-			url = base_url + "/job/remove";
165
+			url = base_url + "/jobinfo/remove";
118 166
 		} else if ("job_trigger" == type) {
119
-			typeName = "执行一次";
120
-			url = base_url + "/job/trigger";
167
+			typeName = "执行";
168
+			url = base_url + "/jobinfo/trigger";
121 169
 		} else {
122 170
 			return;
123 171
 		}
124 172
 		
125
-		var name = $(this).parent('p').attr("jobName");
173
+		var jobGroup = $(this).parent('p').attr("jobGroup");
174
+		var jobName = $(this).parent('p').attr("jobName");
126 175
 		
127 176
 		ComConfirm.show("确认" + typeName + "?", function(){
128 177
 			$.ajax({
129 178
 				type : 'POST',
130 179
 				url : url,
131 180
 				data : {
132
-					"triggerKeyName" :	name
181
+					"jobGroup" : jobGroup,
182
+					"jobName"  : jobName
133 183
 				},
134 184
 				dataType : "json",
135 185
 				success : function(data){
@@ -162,50 +212,74 @@ $(function() {
162 212
         errorClass : 'help-block',
163 213
         focusInvalid : true,  
164 214
         rules : {  
165
-        	triggerKeyName : {  
215
+        	jobName : {  
166 216
         		required : true ,
167 217
                 minlength: 4,
168 218
                 maxlength: 100,
169 219
                 myValid01:true
170 220
             },  
171
-            cronExpression : {  
221
+            jobCron : {  
172 222
             	required : true ,
173 223
                 maxlength: 100
174 224
             },  
175
-            job_desc : {  
225
+            jobDesc : {  
176 226
             	required : true ,
177 227
                 maxlength: 200
178 228
             },
179
-            job_url : {
229
+            handler_address : {
180 230
             	required : true ,
181 231
                 maxlength: 200
182 232
             },
183
-            handleName : {
233
+            handler_name : {
184 234
             	required : true ,
185 235
                 maxlength: 200
236
+            },
237
+            author : {
238
+            	required : true ,
239
+                maxlength: 200
240
+            },
241
+            alarm_email : {
242
+            	required : true ,
243
+                maxlength: 200
244
+            },
245
+            alarm_threshold : {
246
+            	required : true ,
247
+            	digits:true
186 248
             }
187 249
         }, 
188 250
         messages : {  
189
-        	triggerKeyName : {  
190
-        		required :"请输入“任务Key”."  ,
191
-                minlength:"“任务Key”长度不应低于4位",
192
-                maxlength:"“任务Key”长度不应超过100位"
251
+        	jobName : {  
252
+        		required :"请输入“任务名”"  ,
253
+                minlength:"“任务”长度不应低于4位",
254
+                maxlength:"“任务”长度不应超过100位"
193 255
             },  
194
-            cronExpression : {
195
-            	required :"请输入“任务Corn”."  ,
196
-                maxlength:"“任务Corn”长度不应超过100位"
256
+            jobCron : {
257
+            	required :"请输入“Corn”."  ,
258
+                maxlength:"“Corn”长度不应超过100位"
197 259
             },  
198
-            job_desc : {
260
+            jobDesc : {
199 261
             	required :"请输入“任务描述”."  ,
200 262
                 maxlength:"“任务描述”长度不应超过200位"
201 263
             },  
202
-            job_url : {
203
-            	required :"请输入“任务URL”."  ,
204
-                maxlength:"“任务URL”长度不应超过200位"
264
+            handler_address : {
265
+            	required :"请输入“远程-机器地址”."  ,
266
+                maxlength:"“远程-机器地址”长度不应超过200位"
205 267
             },
206
-            handleName : {
207
-            	required : "请输入“任务handler”."  ,
208
-                maxlength: "“任务handler”长度不应超过200位"
268
+            handler_name : {
269
+            	required : "请输入“远程-执行器”."  ,
270
+                maxlength: "“远程-执行器”长度不应超过200位"
271
+            },
272
+            author : {
273
+            	required : "请输入“负责人”."  ,
274
+                maxlength: "“负责人”长度不应超过50位"
275
+            },
276
+            alarm_email : {
277
+            	required : "请输入“报警邮件”."  ,
278
+                maxlength: "“报警邮件”长度不应超过200位"
279
+            },
280
+            alarm_threshold : {
281
+            	required : "请输入“报警阈值”."  ,
282
+            	digits:"阀值应该为整数."
209 283
             }
210 284
         }, 
211 285
 		highlight : function(element) {  
@@ -219,52 +293,20 @@ $(function() {
219 293
             element.parent('div').append(error);  
220 294
         },
221 295
         submitHandler : function(form) {
222
-        	
223
-        	var triggerKeyName = $('#addModal input[name="triggerKeyName"]').val();
224
-        	var cronExpression = $('#addModal input[name="cronExpression"]').val();
225
-        	var job_desc = $('#addModal input[name="job_desc"]').val();
226
-        	var job_url = $('#addModal input[name="job_url"]').val();
227
-        	var handleName = $('#addModal input[name="handleName"]').val();
228
-        	
229
-        	var paramStr = 'triggerKeyName=' + triggerKeyName + 
230
-        		'&cronExpression=' + cronExpression + 
231
-        		'&job_desc=' + job_desc +
232
-        		'&job_url=' + job_url +
233
-        		'&handleName=' + handleName;
234
-        	
235
-        	var ifFin = true;
236
-        	$('#addModal .newParam').each(function(){
237
-        		ifFin = false;
238
-        		var key = $(this).find('input[name="key"]').val();
239
-        		var value = $(this).find('input[name="value"]').val();
240
-        		if (!key) {
241
-        			ComAlert.show(2, "新增参数key不可为空");
242
-        			return;
243
-				} else {
244
-					if(!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)){
245
-						ComAlert.show(2, "新增参数key不合法, 只支持英文字母开头,只含有英文字母、数字和下划线");
246
-	        			return;
247
-					}
248
-				}
249
-        		paramStr += "&" + key + "=" + value;
250
-        		ifFin = true;
251
-        	});
252
-        	
253
-        	if(ifFin){
254
-        		$.post(base_url + "/job/add", paramStr, function(data, status) {
255
-        			if (data.code == "200") {
256
-        				ComAlert.show(1, "新增调度任务成功", function(){
257
-        					window.location.reload();
258
-        				});
259
-        			} else {
260
-        				if (data.msg) {
261
-        					ComAlert.show(2, data.msg);
262
-        				} else {
263
-        					ComAlert.show(2, "新增失败");
264
-        				}
265
-        			}
266
-        		});
267
-        	}
296
+        	$.post(base_url + "/jobinfo/add",  $("#addModal .form").serialize(), function(data, status) {
297
+    			if (data.code == "200") {
298
+    				ComAlert.show(1, "新增调度任务成功", function(){
299
+    					ComAlert.show(1, "新增任务成功");
300
+    					jobTable.fnDraw();
301
+    				});
302
+    			} else {
303
+    				if (data.msg) {
304
+    					ComAlert.show(2, data.msg);
305
+    				} else {
306
+    					ComAlert.show(2, "新增失败");
307
+    				}
308
+    			}
309
+    		});
268 310
 		}
269 311
 	});
270 312
 	$("#addModal").on('hide.bs.modal', function () {
@@ -273,19 +315,16 @@ $(function() {
273 315
 		$("#addModal .form .form-group").removeClass("has-error");
274 316
 	});
275 317
 	
276
-	// 新增-添加参数
277
-	$("#addModal .addParam").on('click', function () {
278
-		var html = '<div class="form-group newParam">'+
279
-				'<label for="lastname" class="col-sm-2 control-label">参数&nbsp;<button class="btn btn-danger btn-xs removeParam" type="button">移除</button></label>'+
280
-				'<div class="col-sm-4"><input type="text" class="form-control" name="key" placeholder="请输入参数key[将会强转为String]" maxlength="200" /></div>'+
281
-				'<div class="col-sm-6"><input type="text" class="form-control" name="value" placeholder="请输入参数value[将会强转为String]" maxlength="200" /></div>'+
282
-			'</div>';
283
-		$(this).parents('.form-group').parent().append(html);
284
-		
285
-		$("#addModal .removeParam").on('click', function () {
286
-			$(this).parents('.form-group').remove();
287
-		});
288
-	});
318
+	// 远程任务/本地任务,切换
319
+	$("#addModal select[name='jobClass']").change(function() {
320
+		//console.log($(this).val());
321
+		console.log( $(this).val().indexOf('HttpJobBean') );
322
+		if($(this).val().indexOf('HttpJobBean') > -1){
323
+			$(".remote_panel").show();	// remote
324
+		} else if($(this).val().indexOf('HttpJobBean') == -1){
325
+			$(".remote_panel").hide();	// local
326
+		}
327
+    });
289 328
 	
290 329
 	// 更新
291 330
 	$("#job_list").on('click', '.update',function() {
@@ -376,4 +415,20 @@ $(function() {
376 415
 		$("#updateModal .form")[0].reset()
377 416
 	});
378 417
 	
418
+	
419
+	/*
420
+	// 新增-添加参数
421
+	$("#addModal .addParam").on('click', function () {
422
+		var html = '<div class="form-group newParam">'+
423
+				'<label for="lastname" class="col-sm-2 control-label">参数&nbsp;<button class="btn btn-danger btn-xs removeParam" type="button">移除</button></label>'+
424
+				'<div class="col-sm-4"><input type="text" class="form-control" name="key" placeholder="请输入参数key[将会强转为String]" maxlength="200" /></div>'+
425
+				'<div class="col-sm-6"><input type="text" class="form-control" name="value" placeholder="请输入参数value[将会强转为String]" maxlength="200" /></div>'+
426
+			'</div>';
427
+		$(this).parents('.form-group').parent().append(html);
428
+		
429
+		$("#addModal .removeParam").on('click', function () {
430
+			$(this).parents('.form-group').remove();
431
+		});
432
+	});
433
+	*/
379 434
 });

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

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

+ 4 - 4
xxl-job-admin/src/test/java/com/xxl/job/dao/impl/XxlJobInfoTest.java 查看文件

@@ -21,8 +21,8 @@ public class XxlJobInfoTest {
21 21
 	
22 22
 	@Test
23 23
 	public void pageList(){
24
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, null, null, null);
25
-		int list_count = xxlJobInfoDao.pageListCount(0, 20, null, null, null);
24
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, null, null);
25
+		int list_count = xxlJobInfoDao.pageListCount(0, 20, null, null);
26 26
 		
27 27
 		System.out.println(list);
28 28
 		System.out.println(list_count);
@@ -39,13 +39,13 @@ public class XxlJobInfoTest {
39 39
 		System.out.println(count);
40 40
 		System.out.println(info.getId());
41 41
 		
42
-		XxlJobInfo item = xxlJobInfoDao.load("job_name");
42
+		XxlJobInfo item = xxlJobInfoDao.load(null ,"job_name");
43 43
 		System.out.println(item);
44 44
 	}
45 45
 	
46 46
 	@Test
47 47
 	public void update(){
48
-		XxlJobInfo item = xxlJobInfoDao.load("job_name");
48
+		XxlJobInfo item = xxlJobInfoDao.load(null ,"job_name");
49 49
 		
50 50
 		item.setJobCron("jobCron2");
51 51
 		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 {
57 57
 	
58 58
 	@Test
59 59
 	public void pageList(){
60
-		List<XxlJobLog> list = xxlJobLogDao.pageList(0, 20, null, null, null);
61
-		int list_count = xxlJobLogDao.pageListCount(0, 20, null, null, null);
60
+		List<XxlJobLog> list = xxlJobLogDao.pageList(0, 20, null, null, null, null);
61
+		int list_count = xxlJobLogDao.pageListCount(0, 20, null, null, null, null);
62 62
 		
63 63
 		System.out.println(list);
64 64
 		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 @@
1 1
 package com.xxl.job.service.handler;
2 2
 
3
-import java.util.Map;
4 3
 import java.util.Random;
5 4
 import java.util.concurrent.TimeUnit;
6 5
 
@@ -20,12 +19,12 @@ public class DemoJobHandler extends IJobHandler {
20 19
 	private static transient Logger logger = LoggerFactory.getLogger(DemoJobHandler.class);
21 20
 	
22 21
 	public DemoJobHandler() {
23
-		HandlerRepository.regist(DemoJobHandler.class.getName(), this);
22
+		HandlerRepository.regist("demoJobHandler", this);
24 23
 	}
25 24
 	
26 25
 	@Override
27
-	public JobHandleStatus handle(Map<String, String> param) throws Exception {
28
-		logger.info(" ... param:{}", param);
26
+	public JobHandleStatus handle(String... params) throws Exception {
27
+		logger.info(" ... params:" + params);
29 28
 		TimeUnit.SECONDS.sleep(new Random().nextInt(5));
30 29
 		return JobHandleStatus.SUCCESS;
31 30
 	}

+ 23 - 124
xxl-job-client/src/main/java/com/xxl/job/client/handler/HandlerRepository.java 查看文件

@@ -1,21 +1,15 @@
1 1
 package com.xxl.job.client.handler;
2 2
 
3
-import java.io.PrintWriter;
4
-import java.io.StringWriter;
5 3
 import java.util.HashMap;
6 4
 import java.util.Map;
7 5
 import java.util.concurrent.ConcurrentHashMap;
8
-import java.util.concurrent.LinkedBlockingQueue;
9
-import java.util.concurrent.TimeUnit;
10 6
 
11 7
 import org.slf4j.Logger;
12 8
 import org.slf4j.LoggerFactory;
13 9
 
14
-import com.xxl.job.client.handler.IJobHandler.JobHandleStatus;
15 10
 import com.xxl.job.client.util.HttpUtil;
16 11
 import com.xxl.job.client.util.JacksonUtil;
17 12
 
18
-
19 13
 /**
20 14
  * handler repository
21 15
  * @author xuxueli 2015-12-19 19:28:44
@@ -23,142 +17,47 @@ import com.xxl.job.client.util.JacksonUtil;
23 17
 public class HandlerRepository {
24 18
 	private static Logger logger = LoggerFactory.getLogger(HandlerRepository.class);
25 19
 	
26
-	public static final String job_desc = "job_desc";
27
-	public static final String job_url = "job_url";
28
-	public static final String handleName = "handleName";
29
-	public static final String triggerLogId = "triggerLogId";
30
-	public static final String triggerLogUrl = "triggerLogUrl";
31
-
32
-	// handler class map
33
-	private static ConcurrentHashMap<String, IJobHandler> handlerClassMap = new ConcurrentHashMap<String, IJobHandler>();
34
-	// handler thread map
35
-	private static ConcurrentHashMap<String, HandlerThread> handlerTreadMap = new ConcurrentHashMap<String, HandlerThread>();
36
-	// handler date queue map
37
-	private static ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>> handlerDataQueueMap = new ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>>();
20
+	public static final String HANDLER_ADDRESS = "handler_address";
21
+	public static final String HANDLER_NAME = "handler_name";
22
+	public static final String HANDLER_PARAMS = "handler_params";
23
+	
24
+	public static final String TRIGGER_LOG_ID = "trigger_log_id";
25
+	public static final String TRIGGER_LOG_URL = "trigger_log_url";
26
+	
27
+	public static ConcurrentHashMap<String, HandlerThread> handlerTreadMap = new ConcurrentHashMap<String, HandlerThread>();
38 28
 	
39 29
 	// regist handler
40 30
 	public static void regist(String handleName, IJobHandler handler){
41
-		handlerClassMap.put(handleName, handler);
42
-		LinkedBlockingQueue<Map<String, String>> handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
43
-		handlerDataQueueMap.put(handleName, handlerDateQueue);
44
-		HandlerThread handlerThread = new HandlerThread(handleName);
31
+		HandlerThread handlerThread = new HandlerThread(handler);
45 32
 		handlerThread.start();
46
-		handlerTreadMap.put(handleName, handlerThread);
47
-		logger.info(">>>>>>>>>>> xxl-job regist handler success, handleName:{}, handler:{}, handlerDateQueue:{}, handlerThread:{}", 
48
-				new Object[]{handleName, handler, handlerDateQueue, handlerThread});
49
-	}
50
-	
51
-	// create handler thread
52
-	static class HandlerThread extends Thread{
53
-		private String _handleName;
54
-		public HandlerThread(String _handleName) {
55
-			this._handleName = _handleName;
56
-		}
57
-		public boolean isValid = true;
58
-		public void stopThread(){
59
-			isValid = false;
60
-		}
61
-		@Override
62
-		public void run() {
63
-			while (isValid) {
64
-				LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(_handleName);
65
-				Map<String, String> handlerData = handlerDateQueue.poll();
66
-				if (handlerData!=null) {
67
-					// handle job
68
-					JobHandleStatus _status = JobHandleStatus.FAIL;
69
-					String _msg = null;
70
-					try {
71
-						IJobHandler handler = handlerClassMap.get(_handleName);
72
-						_status = handler.handle(handlerData);
73
-					} catch (Exception e) {
74
-						e.printStackTrace();
75
-						_status = JobHandleStatus.FAIL;
76
-						StringWriter out = new StringWriter();
77
-						e.printStackTrace(new PrintWriter(out));
78
-						_msg = out.toString();
79
-					}
80
-
81
-					// callback handler info
82
-					String callback_response[] = null;
83
-					try {
84
-						String _triggerLogUrl = handlerData.get(HandlerRepository.triggerLogUrl);
85
-						HashMap<String, String> params = new HashMap<String, String>();
86
-						params.put(HandlerRepository.triggerLogId, handlerData.get(HandlerRepository.triggerLogId));
87
-						params.put(HttpUtil.status, _status.name());
88
-						params.put(HttpUtil.msg, _msg);
89
-						callback_response = HttpUtil.post(_triggerLogUrl, params);
90
-					} catch (Exception e) {
91
-						e.printStackTrace();
92
-					}
93
-					logger.info("<<<<<<<<<<< xxl-job thread handle, handlerData:{}, callback_status:{}, callback_msg:{}, callback_response:{}, thread:{}", 
94
-							new Object[]{handlerData, _status, _msg, callback_response, this});
95
-				} else {
96
-					try {
97
-						TimeUnit.MILLISECONDS.sleep(200);
98
-					} catch (InterruptedException e) {
99
-						e.printStackTrace();
100
-					}
101
-				}
102
-			}
103
-		}
33
+		handlerTreadMap.put(handleName, handlerThread);	// putIfAbsent
34
+		logger.info(">>>>>>>>>>> xxl-job regist handler success, handleName:{}, handler:{}", new Object[]{handleName, handler});
104 35
 	}
105 36
 	
106 37
 	// handler push to queue
107 38
 	public static String pushHandleQueue(Map<String, String> _param) {
39
+		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue start, _param:{}", new Object[]{_param});
108 40
 		
109
-		// resuolt
41
+		// result
110 42
 		String _status = HttpUtil.FAIL;
111 43
 		String _msg = "";
44
+		
112 45
 		// push data to queue
113
-		String _handleName = _param.get(HandlerRepository.handleName);
114
-		int _triggerLogId = Integer.valueOf(_param.get(HandlerRepository.triggerLogId));	 // 次数应校验,停止队列功能为开发
115
-		try {
116
-			if (_handleName!=null && _handleName.trim().length()>0) {
117
-				IJobHandler handler = handlerClassMap.get(_handleName);
118
-				if (handler != null) {
119
-					// push data to handler queue
120
-					LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(_handleName);
121
-					if (handlerDateQueue == null) {
122
-						handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
123
-						handlerDataQueueMap.put(_handleName, handlerDateQueue);
124
-						logger.info(">>>>>>>>>>> xxl-job handler lazy fresh handlerDateQueue, _handleName:{}, handler:{}, handlerDateQueue:{}", 
125
-								new Object[]{_handleName, handler, handlerDateQueue});
126
-					}
127
-					// check handler thread
128
-					HandlerThread handlerThreadOld = handlerTreadMap.get(_handleName);
129
-					if (!handlerThreadOld.isAlive()) {
130
-						handlerThreadOld.stopThread();
131
-						HandlerThread handlerThread = new HandlerThread(_handleName);
132
-						handlerThread.start();
133
-						handlerTreadMap.put(_handleName, handlerThread);
134
-						logger.info(">>>>>>>>>>> xxl-job handler lazy fresh thread, _handleName:{}, handler:{}, handlerThread:{}", 
135
-								new Object[]{_handleName, handler, handlerThread});
136
-					}
137
-					// push to queue
138
-					handlerDateQueue.offer(_param);
139
-					_status = HttpUtil.SUCCESS;
140
-				}
141
-			}
142
-		} catch (Exception e) {
143
-			e.printStackTrace();
144
-			StringWriter out = new StringWriter();
145
-			e.printStackTrace(new PrintWriter(out));
146
-			_status = HttpUtil.FAIL;
147
-			_msg = out.toString();
46
+		HandlerThread handlerThread = handlerTreadMap.get(_param.get(HandlerRepository.HANDLER_NAME));
47
+		if (handlerThread != null) {
48
+			handlerThread.pushData(_param);
49
+			_status = HttpUtil.SUCCESS;
50
+		} else {
51
+			_msg = "handler not found.";
148 52
 		}
149
-		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue, _handleName:{}, _triggerLogId:{}, _param:{}, _status:{}, _msg:{}", 
150
-				new Object[]{_handleName, _triggerLogId, _param, _status, _msg});
151 53
 		
152 54
 		HashMap<String, String> triggerData = new HashMap<String, String>();
55
+		triggerData.put(HandlerRepository.TRIGGER_LOG_ID, _param.get(HandlerRepository.TRIGGER_LOG_ID));
153 56
 		triggerData.put(HttpUtil.status, _status);
154 57
 		triggerData.put(HttpUtil.msg, _msg);
155
-		return JacksonUtil.writeValueAsString(triggerData);
156 58
 		
157
-		/**
158
-		 * trigger-log : 
159
-		 * 		trigger side : store trigger-info >> trigger request >> update trigger-response-status
160
-		 * 		job side : handler trigger >> update trigger-result
161
-		 */
59
+		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue end, triggerData:{}", new Object[]{triggerData});
60
+		return JacksonUtil.writeValueAsString(triggerData);
162 61
 	}
163 62
 	
164 63
 }

+ 1 - 3
xxl-job-client/src/main/java/com/xxl/job/client/handler/IJobHandler.java 查看文件

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