瀏覽代碼

UI以及库中,新增字段 "失败重试次数"

xuxueli 6 年之前
父節點
當前提交
6fd7c943f2

+ 95 - 95
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java 查看文件

@@ -1,95 +1,95 @@
1
-package com.xxl.job.admin.controller;
2
-
3
-import com.xxl.job.admin.core.model.XxlJobGroup;
4
-import com.xxl.job.admin.core.model.XxlJobInfo;
5
-import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
6
-import com.xxl.job.admin.dao.XxlJobGroupDao;
7
-import com.xxl.job.admin.service.XxlJobService;
8
-import com.xxl.job.core.biz.model.ReturnT;
9
-import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
10
-import com.xxl.job.core.glue.GlueTypeEnum;
11
-import org.springframework.stereotype.Controller;
12
-import org.springframework.ui.Model;
13
-import org.springframework.web.bind.annotation.RequestMapping;
14
-import org.springframework.web.bind.annotation.RequestParam;
15
-import org.springframework.web.bind.annotation.ResponseBody;
16
-
17
-import javax.annotation.Resource;
18
-import java.util.List;
19
-import java.util.Map;
20
-
21
-/**
22
- * index controller
23
- * @author xuxueli 2015-12-19 16:13:16
24
- */
25
-@Controller
26
-@RequestMapping("/jobinfo")
27
-public class JobInfoController {
28
-
29
-	@Resource
30
-	private XxlJobGroupDao xxlJobGroupDao;
31
-	@Resource
32
-	private XxlJobService xxlJobService;
33
-	
34
-	@RequestMapping
35
-	public String index(Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
36
-
37
-		// 枚举-字典
38
-		model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values());	// 路由策略-列表
39
-		model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());								// Glue类型-字典
40
-		model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values());	// 阻塞处理策略-字典
41
-
42
-		// 任务组
43
-		List<XxlJobGroup> jobGroupList =  xxlJobGroupDao.findAll();
44
-		model.addAttribute("JobGroupList", jobGroupList);
45
-		model.addAttribute("jobGroup", jobGroup);
46
-
47
-		return "jobinfo/jobinfo.index";
48
-	}
49
-	
50
-	@RequestMapping("/pageList")
51
-	@ResponseBody
52
-	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
53
-			@RequestParam(required = false, defaultValue = "10") int length,
54
-			int jobGroup, String jobDesc, String executorHandler, String filterTime) {
55
-		
56
-		return xxlJobService.pageList(start, length, jobGroup, jobDesc, executorHandler, filterTime);
57
-	}
58
-	
59
-	@RequestMapping("/add")
60
-	@ResponseBody
61
-	public ReturnT<String> add(XxlJobInfo jobInfo) {
62
-		return xxlJobService.add(jobInfo);
63
-	}
64
-	
65
-	@RequestMapping("/update")
66
-	@ResponseBody
67
-	public ReturnT<String> update(XxlJobInfo jobInfo) {
68
-		return xxlJobService.update(jobInfo);
69
-	}
70
-	
71
-	@RequestMapping("/remove")
72
-	@ResponseBody
73
-	public ReturnT<String> remove(int id) {
74
-		return xxlJobService.remove(id);
75
-	}
76
-	
77
-	@RequestMapping("/pause")
78
-	@ResponseBody
79
-	public ReturnT<String> pause(int id) {
80
-		return xxlJobService.pause(id);
81
-	}
82
-	
83
-	@RequestMapping("/resume")
84
-	@ResponseBody
85
-	public ReturnT<String> resume(int id) {
86
-		return xxlJobService.resume(id);
87
-	}
88
-	
89
-	@RequestMapping("/trigger")
90
-	@ResponseBody
91
-	public ReturnT<String> triggerJob(int id) {
92
-		return xxlJobService.triggerJob(id);
93
-	}
94
-	
95
-}
1
+package com.xxl.job.admin.controller;
2
+
3
+import com.xxl.job.admin.core.model.XxlJobGroup;
4
+import com.xxl.job.admin.core.model.XxlJobInfo;
5
+import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
6
+import com.xxl.job.admin.dao.XxlJobGroupDao;
7
+import com.xxl.job.admin.service.XxlJobService;
8
+import com.xxl.job.core.biz.model.ReturnT;
9
+import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
10
+import com.xxl.job.core.glue.GlueTypeEnum;
11
+import org.springframework.stereotype.Controller;
12
+import org.springframework.ui.Model;
13
+import org.springframework.web.bind.annotation.RequestMapping;
14
+import org.springframework.web.bind.annotation.RequestParam;
15
+import org.springframework.web.bind.annotation.ResponseBody;
16
+
17
+import javax.annotation.Resource;
18
+import java.util.List;
19
+import java.util.Map;
20
+
21
+/**
22
+ * index controller
23
+ * @author xuxueli 2015-12-19 16:13:16
24
+ */
25
+@Controller
26
+@RequestMapping("/jobinfo")
27
+public class JobInfoController {
28
+
29
+	@Resource
30
+	private XxlJobGroupDao xxlJobGroupDao;
31
+	@Resource
32
+	private XxlJobService xxlJobService;
33
+	
34
+	@RequestMapping
35
+	public String index(Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
36
+
37
+		// 枚举-字典
38
+		model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values());	// 路由策略-列表
39
+		model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());								// Glue类型-字典
40
+		model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values());	// 阻塞处理策略-字典
41
+
42
+		// 任务组
43
+		List<XxlJobGroup> jobGroupList =  xxlJobGroupDao.findAll();
44
+		model.addAttribute("JobGroupList", jobGroupList);
45
+		model.addAttribute("jobGroup", jobGroup);
46
+
47
+		return "jobinfo/jobinfo.index";
48
+	}
49
+	
50
+	@RequestMapping("/pageList")
51
+	@ResponseBody
52
+	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
53
+			@RequestParam(required = false, defaultValue = "10") int length,
54
+			int jobGroup, String jobDesc, String executorHandler, String filterTime) {
55
+		
56
+		return xxlJobService.pageList(start, length, jobGroup, jobDesc, executorHandler, filterTime);
57
+	}
58
+	
59
+	@RequestMapping("/add")
60
+	@ResponseBody
61
+	public ReturnT<String> add(XxlJobInfo jobInfo) {
62
+		return xxlJobService.add(jobInfo);
63
+	}
64
+	
65
+	@RequestMapping("/update")
66
+	@ResponseBody
67
+	public ReturnT<String> update(XxlJobInfo jobInfo) {
68
+		return xxlJobService.update(jobInfo);
69
+	}
70
+	
71
+	@RequestMapping("/remove")
72
+	@ResponseBody
73
+	public ReturnT<String> remove(int id) {
74
+		return xxlJobService.remove(id);
75
+	}
76
+	
77
+	@RequestMapping("/pause")
78
+	@ResponseBody
79
+	public ReturnT<String> pause(int id) {
80
+		return xxlJobService.pause(id);
81
+	}
82
+	
83
+	@RequestMapping("/resume")
84
+	@ResponseBody
85
+	public ReturnT<String> resume(int id) {
86
+		return xxlJobService.resume(id);
87
+	}
88
+	
89
+	@RequestMapping("/trigger")
90
+	@ResponseBody
91
+	public ReturnT<String> triggerJob(int id) {
92
+		return xxlJobService.triggerJob(id);
93
+	}
94
+	
95
+}

+ 211 - 211
xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java 查看文件

@@ -1,211 +1,211 @@
1
-package com.xxl.job.admin.core.model;
2
-
3
-import java.util.Date;
4
-
5
-/**
6
- * xxl-job info
7
- *
8
- * @author xuxueli  2016-1-12 18:25:49
9
- */
10
-public class XxlJobInfo {
11
-	
12
-	private int id;				// 主键ID	    (JobKey.name)
13
-	
14
-	private int jobGroup;		// 执行器主键ID	(JobKey.group)
15
-	private String jobCron;		// 任务执行CRON表达式 【base on quartz】
16
-	private String jobDesc;
17
-	
18
-	private Date addTime;
19
-	private Date updateTime;
20
-	
21
-	private String author;		// 负责人
22
-	private String alarmEmail;	// 报警邮件
23
-
24
-	private String executorRouteStrategy;	// 执行器路由策略
25
-	private String executorHandler;		    // 执行器,任务Handler名称
26
-	private String executorParam;		    // 执行器,任务参数
27
-	private String executorBlockStrategy;	// 阻塞处理策略
28
-	private String executorFailStrategy;	// 失败处理策略
29
-	private int executorTimeout;     		// 任务执行超时时间,单位秒
30
-	private int executorFailRetryCount;		// 失败重试次数
31
-	
32
-	private String glueType;		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnum
33
-	private String glueSource;		// GLUE源代码
34
-	private String glueRemark;		// GLUE备注
35
-	private Date glueUpdatetime;	// GLUE更新时间
36
-
37
-	private String childJobId;		// 子任务ID,多个逗号分隔
38
-	
39
-	// copy from quartz
40
-	private String jobStatus;		// 任务状态 【base on quartz】
41
-
42
-
43
-	public int getId() {
44
-		return id;
45
-	}
46
-
47
-	public void setId(int id) {
48
-		this.id = id;
49
-	}
50
-
51
-	public int getJobGroup() {
52
-		return jobGroup;
53
-	}
54
-
55
-	public void setJobGroup(int jobGroup) {
56
-		this.jobGroup = jobGroup;
57
-	}
58
-
59
-	public String getJobCron() {
60
-		return jobCron;
61
-	}
62
-
63
-	public void setJobCron(String jobCron) {
64
-		this.jobCron = jobCron;
65
-	}
66
-
67
-	public String getJobDesc() {
68
-		return jobDesc;
69
-	}
70
-
71
-	public void setJobDesc(String jobDesc) {
72
-		this.jobDesc = jobDesc;
73
-	}
74
-
75
-	public Date getAddTime() {
76
-		return addTime;
77
-	}
78
-
79
-	public void setAddTime(Date addTime) {
80
-		this.addTime = addTime;
81
-	}
82
-
83
-	public Date getUpdateTime() {
84
-		return updateTime;
85
-	}
86
-
87
-	public void setUpdateTime(Date updateTime) {
88
-		this.updateTime = updateTime;
89
-	}
90
-
91
-	public String getAuthor() {
92
-		return author;
93
-	}
94
-
95
-	public void setAuthor(String author) {
96
-		this.author = author;
97
-	}
98
-
99
-	public String getAlarmEmail() {
100
-		return alarmEmail;
101
-	}
102
-
103
-	public void setAlarmEmail(String alarmEmail) {
104
-		this.alarmEmail = alarmEmail;
105
-	}
106
-
107
-	public String getExecutorRouteStrategy() {
108
-		return executorRouteStrategy;
109
-	}
110
-
111
-	public void setExecutorRouteStrategy(String executorRouteStrategy) {
112
-		this.executorRouteStrategy = executorRouteStrategy;
113
-	}
114
-
115
-	public String getExecutorHandler() {
116
-		return executorHandler;
117
-	}
118
-
119
-	public void setExecutorHandler(String executorHandler) {
120
-		this.executorHandler = executorHandler;
121
-	}
122
-
123
-	public String getExecutorParam() {
124
-		return executorParam;
125
-	}
126
-
127
-	public void setExecutorParam(String executorParam) {
128
-		this.executorParam = executorParam;
129
-	}
130
-
131
-	public String getExecutorBlockStrategy() {
132
-		return executorBlockStrategy;
133
-	}
134
-
135
-	public void setExecutorBlockStrategy(String executorBlockStrategy) {
136
-		this.executorBlockStrategy = executorBlockStrategy;
137
-	}
138
-
139
-	public String getExecutorFailStrategy() {
140
-		return executorFailStrategy;
141
-	}
142
-
143
-	public void setExecutorFailStrategy(String executorFailStrategy) {
144
-		this.executorFailStrategy = executorFailStrategy;
145
-	}
146
-
147
-	public int getExecutorTimeout() {
148
-		return executorTimeout;
149
-	}
150
-
151
-	public void setExecutorTimeout(int executorTimeout) {
152
-		this.executorTimeout = executorTimeout;
153
-	}
154
-
155
-	public int getExecutorFailRetryCount() {
156
-		return executorFailRetryCount;
157
-	}
158
-
159
-	public void setExecutorFailRetryCount(int executorFailRetryCount) {
160
-		this.executorFailRetryCount = executorFailRetryCount;
161
-	}
162
-
163
-	public String getGlueType() {
164
-		return glueType;
165
-	}
166
-
167
-	public void setGlueType(String glueType) {
168
-		this.glueType = glueType;
169
-	}
170
-
171
-	public String getGlueSource() {
172
-		return glueSource;
173
-	}
174
-
175
-	public void setGlueSource(String glueSource) {
176
-		this.glueSource = glueSource;
177
-	}
178
-
179
-	public String getGlueRemark() {
180
-		return glueRemark;
181
-	}
182
-
183
-	public void setGlueRemark(String glueRemark) {
184
-		this.glueRemark = glueRemark;
185
-	}
186
-
187
-	public Date getGlueUpdatetime() {
188
-		return glueUpdatetime;
189
-	}
190
-
191
-	public void setGlueUpdatetime(Date glueUpdatetime) {
192
-		this.glueUpdatetime = glueUpdatetime;
193
-	}
194
-
195
-	public String getChildJobId() {
196
-		return childJobId;
197
-	}
198
-
199
-	public void setChildJobId(String childJobId) {
200
-		this.childJobId = childJobId;
201
-	}
202
-
203
-	public String getJobStatus() {
204
-		return jobStatus;
205
-	}
206
-
207
-	public void setJobStatus(String jobStatus) {
208
-		this.jobStatus = jobStatus;
209
-	}
210
-
211
-}
1
+package com.xxl.job.admin.core.model;
2
+
3
+import java.util.Date;
4
+
5
+/**
6
+ * xxl-job info
7
+ *
8
+ * @author xuxueli  2016-1-12 18:25:49
9
+ */
10
+public class XxlJobInfo {
11
+	
12
+	private int id;				// 主键ID	    (JobKey.name)
13
+	
14
+	private int jobGroup;		// 执行器主键ID	(JobKey.group)
15
+	private String jobCron;		// 任务执行CRON表达式 【base on quartz】
16
+	private String jobDesc;
17
+	
18
+	private Date addTime;
19
+	private Date updateTime;
20
+	
21
+	private String author;		// 负责人
22
+	private String alarmEmail;	// 报警邮件
23
+
24
+	private String executorRouteStrategy;	// 执行器路由策略
25
+	private String executorHandler;		    // 执行器,任务Handler名称
26
+	private String executorParam;		    // 执行器,任务参数
27
+	private String executorBlockStrategy;	// 阻塞处理策略
28
+	private String executorFailStrategy;	// 失败处理策略
29
+	private int executorTimeout;     		// 任务执行超时时间,单位秒
30
+	private int executorFailRetryCount;		// 失败重试次数
31
+	
32
+	private String glueType;		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnum
33
+	private String glueSource;		// GLUE源代码
34
+	private String glueRemark;		// GLUE备注
35
+	private Date glueUpdatetime;	// GLUE更新时间
36
+
37
+	private String childJobId;		// 子任务ID,多个逗号分隔
38
+	
39
+	// copy from quartz
40
+	private String jobStatus;		// 任务状态 【base on quartz】
41
+
42
+
43
+	public int getId() {
44
+		return id;
45
+	}
46
+
47
+	public void setId(int id) {
48
+		this.id = id;
49
+	}
50
+
51
+	public int getJobGroup() {
52
+		return jobGroup;
53
+	}
54
+
55
+	public void setJobGroup(int jobGroup) {
56
+		this.jobGroup = jobGroup;
57
+	}
58
+
59
+	public String getJobCron() {
60
+		return jobCron;
61
+	}
62
+
63
+	public void setJobCron(String jobCron) {
64
+		this.jobCron = jobCron;
65
+	}
66
+
67
+	public String getJobDesc() {
68
+		return jobDesc;
69
+	}
70
+
71
+	public void setJobDesc(String jobDesc) {
72
+		this.jobDesc = jobDesc;
73
+	}
74
+
75
+	public Date getAddTime() {
76
+		return addTime;
77
+	}
78
+
79
+	public void setAddTime(Date addTime) {
80
+		this.addTime = addTime;
81
+	}
82
+
83
+	public Date getUpdateTime() {
84
+		return updateTime;
85
+	}
86
+
87
+	public void setUpdateTime(Date updateTime) {
88
+		this.updateTime = updateTime;
89
+	}
90
+
91
+	public String getAuthor() {
92
+		return author;
93
+	}
94
+
95
+	public void setAuthor(String author) {
96
+		this.author = author;
97
+	}
98
+
99
+	public String getAlarmEmail() {
100
+		return alarmEmail;
101
+	}
102
+
103
+	public void setAlarmEmail(String alarmEmail) {
104
+		this.alarmEmail = alarmEmail;
105
+	}
106
+
107
+	public String getExecutorRouteStrategy() {
108
+		return executorRouteStrategy;
109
+	}
110
+
111
+	public void setExecutorRouteStrategy(String executorRouteStrategy) {
112
+		this.executorRouteStrategy = executorRouteStrategy;
113
+	}
114
+
115
+	public String getExecutorHandler() {
116
+		return executorHandler;
117
+	}
118
+
119
+	public void setExecutorHandler(String executorHandler) {
120
+		this.executorHandler = executorHandler;
121
+	}
122
+
123
+	public String getExecutorParam() {
124
+		return executorParam;
125
+	}
126
+
127
+	public void setExecutorParam(String executorParam) {
128
+		this.executorParam = executorParam;
129
+	}
130
+
131
+	public String getExecutorBlockStrategy() {
132
+		return executorBlockStrategy;
133
+	}
134
+
135
+	public void setExecutorBlockStrategy(String executorBlockStrategy) {
136
+		this.executorBlockStrategy = executorBlockStrategy;
137
+	}
138
+
139
+	public String getExecutorFailStrategy() {
140
+		return executorFailStrategy;
141
+	}
142
+
143
+	public void setExecutorFailStrategy(String executorFailStrategy) {
144
+		this.executorFailStrategy = executorFailStrategy;
145
+	}
146
+
147
+	public int getExecutorTimeout() {
148
+		return executorTimeout;
149
+	}
150
+
151
+	public void setExecutorTimeout(int executorTimeout) {
152
+		this.executorTimeout = executorTimeout;
153
+	}
154
+
155
+	public int getExecutorFailRetryCount() {
156
+		return executorFailRetryCount;
157
+	}
158
+
159
+	public void setExecutorFailRetryCount(int executorFailRetryCount) {
160
+		this.executorFailRetryCount = executorFailRetryCount;
161
+	}
162
+
163
+	public String getGlueType() {
164
+		return glueType;
165
+	}
166
+
167
+	public void setGlueType(String glueType) {
168
+		this.glueType = glueType;
169
+	}
170
+
171
+	public String getGlueSource() {
172
+		return glueSource;
173
+	}
174
+
175
+	public void setGlueSource(String glueSource) {
176
+		this.glueSource = glueSource;
177
+	}
178
+
179
+	public String getGlueRemark() {
180
+		return glueRemark;
181
+	}
182
+
183
+	public void setGlueRemark(String glueRemark) {
184
+		this.glueRemark = glueRemark;
185
+	}
186
+
187
+	public Date getGlueUpdatetime() {
188
+		return glueUpdatetime;
189
+	}
190
+
191
+	public void setGlueUpdatetime(Date glueUpdatetime) {
192
+		this.glueUpdatetime = glueUpdatetime;
193
+	}
194
+
195
+	public String getChildJobId() {
196
+		return childJobId;
197
+	}
198
+
199
+	public void setChildJobId(String childJobId) {
200
+		this.childJobId = childJobId;
201
+	}
202
+
203
+	public String getJobStatus() {
204
+		return jobStatus;
205
+	}
206
+
207
+	public void setJobStatus(String jobStatus) {
208
+		this.jobStatus = jobStatus;
209
+	}
210
+
211
+}

+ 385 - 385
xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java 查看文件

@@ -1,385 +1,385 @@
1
-package com.xxl.job.admin.service.impl;
2
-
3
-import com.xxl.job.admin.core.model.XxlJobGroup;
4
-import com.xxl.job.admin.core.model.XxlJobInfo;
5
-import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
6
-import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
7
-import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
8
-import com.xxl.job.admin.core.util.I18nUtil;
9
-import com.xxl.job.admin.dao.XxlJobGroupDao;
10
-import com.xxl.job.admin.dao.XxlJobInfoDao;
11
-import com.xxl.job.admin.dao.XxlJobLogDao;
12
-import com.xxl.job.admin.dao.XxlJobLogGlueDao;
13
-import com.xxl.job.admin.service.XxlJobService;
14
-import com.xxl.job.core.biz.model.ReturnT;
15
-import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
16
-import com.xxl.job.core.glue.GlueTypeEnum;
17
-import org.apache.commons.collections4.CollectionUtils;
18
-import org.apache.commons.lang3.StringUtils;
19
-import org.apache.commons.lang3.time.DateUtils;
20
-import org.apache.commons.lang3.time.FastDateFormat;
21
-import org.quartz.CronExpression;
22
-import org.quartz.SchedulerException;
23
-import org.slf4j.Logger;
24
-import org.slf4j.LoggerFactory;
25
-import org.springframework.stereotype.Service;
26
-
27
-import javax.annotation.Resource;
28
-import java.text.MessageFormat;
29
-import java.util.*;
30
-
31
-/**
32
- * core job action for xxl-job
33
- * @author xuxueli 2016-5-28 15:30:33
34
- */
35
-@Service
36
-public class XxlJobServiceImpl implements XxlJobService {
37
-	private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);
38
-
39
-	@Resource
40
-	private XxlJobGroupDao xxlJobGroupDao;
41
-	@Resource
42
-	private XxlJobInfoDao xxlJobInfoDao;
43
-	@Resource
44
-	public XxlJobLogDao xxlJobLogDao;
45
-	@Resource
46
-	private XxlJobLogGlueDao xxlJobLogGlueDao;
47
-	
48
-	@Override
49
-	public Map<String, Object> pageList(int start, int length, int jobGroup, String jobDesc, String executorHandler, String filterTime) {
50
-
51
-		// page list
52
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobDesc, executorHandler);
53
-		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobDesc, executorHandler);
54
-		
55
-		// fill job info
56
-		if (list!=null && list.size()>0) {
57
-			for (XxlJobInfo jobInfo : list) {
58
-				XxlJobDynamicScheduler.fillJobInfo(jobInfo);
59
-			}
60
-		}
61
-		
62
-		// package result
63
-		Map<String, Object> maps = new HashMap<String, Object>();
64
-	    maps.put("recordsTotal", list_count);		// 总记录数
65
-	    maps.put("recordsFiltered", list_count);	// 过滤后的总记录数
66
-	    maps.put("data", list);  					// 分页列表
67
-		return maps;
68
-	}
69
-
70
-	@Override
71
-	public ReturnT<String> add(XxlJobInfo jobInfo) {
72
-		// valid
73
-		XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
74
-		if (group == null) {
75
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")) );
76
-		}
77
-		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
78
-			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
79
-		}
80
-		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
81
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
82
-		}
83
-		if (StringUtils.isBlank(jobInfo.getAuthor())) {
84
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
85
-		}
86
-		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
87
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
88
-		}
89
-		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
90
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
91
-		}
92
-		if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
93
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
94
-		}
95
-		if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringUtils.isBlank(jobInfo.getExecutorHandler())) {
96
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
97
-		}
98
-
99
-		// fix "\r" in shell
100
-		if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource()!=null) {
101
-			jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
102
-		}
103
-
104
-		// ChildJobId valid
105
-		if (StringUtils.isNotBlank(jobInfo.getChildJobId())) {
106
-			String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ",");
107
-			for (String childJobIdItem: childJobIds) {
108
-				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
109
-					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
110
-					if (childJobInfo==null) {
111
-						return new ReturnT<String>(ReturnT.FAIL_CODE,
112
-								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
113
-					}
114
-				} else {
115
-					return new ReturnT<String>(ReturnT.FAIL_CODE,
116
-							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
117
-				}
118
-			}
119
-			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
120
-		}
121
-
122
-		// add in db
123
-		xxlJobInfoDao.save(jobInfo);
124
-		if (jobInfo.getId() < 1) {
125
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
126
-		}
127
-
128
-		// add in quartz
129
-        String qz_group = String.valueOf(jobInfo.getJobGroup());
130
-        String qz_name = String.valueOf(jobInfo.getId());
131
-        try {
132
-            XxlJobDynamicScheduler.addJob(qz_name, qz_group, jobInfo.getJobCron());
133
-            //XxlJobDynamicScheduler.pauseJob(qz_name, qz_group);
134
-            return ReturnT.SUCCESS;
135
-        } catch (SchedulerException e) {
136
-            logger.error(e.getMessage(), e);
137
-            try {
138
-                xxlJobInfoDao.delete(jobInfo.getId());
139
-                XxlJobDynamicScheduler.removeJob(qz_name, qz_group);
140
-            } catch (SchedulerException e1) {
141
-                logger.error(e.getMessage(), e1);
142
-            }
143
-            return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail"))+":" + e.getMessage());
144
-        }
145
-	}
146
-
147
-	@Override
148
-	public ReturnT<String> update(XxlJobInfo jobInfo) {
149
-
150
-		// valid
151
-		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
152
-			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
153
-		}
154
-		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
155
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
156
-		}
157
-		if (StringUtils.isBlank(jobInfo.getAuthor())) {
158
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
159
-		}
160
-		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
161
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
162
-		}
163
-		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
164
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
165
-		}
166
-
167
-		// ChildJobId valid
168
-		if (StringUtils.isNotBlank(jobInfo.getChildJobId())) {
169
-			String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ",");
170
-			for (String childJobIdItem: childJobIds) {
171
-				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
172
-					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
173
-					if (childJobInfo==null) {
174
-						return new ReturnT<String>(ReturnT.FAIL_CODE,
175
-								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
176
-					}
177
-					// avoid cycle relate
178
-					if (childJobInfo.getId() == jobInfo.getId()) {
179
-						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format(I18nUtil.getString("jobinfo_field_childJobId_limit"), childJobIdItem));
180
-					}
181
-				} else {
182
-					return new ReturnT<String>(ReturnT.FAIL_CODE,
183
-							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
184
-				}
185
-			}
186
-			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
187
-		}
188
-
189
-		// stage job info
190
-		XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
191
-		if (exists_jobInfo == null) {
192
-			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_not_found")) );
193
-		}
194
-		//String old_cron = exists_jobInfo.getJobCron();
195
-
196
-		exists_jobInfo.setJobCron(jobInfo.getJobCron());
197
-		exists_jobInfo.setJobDesc(jobInfo.getJobDesc());
198
-		exists_jobInfo.setAuthor(jobInfo.getAuthor());
199
-		exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());
200
-		exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
201
-		exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());
202
-		exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
203
-		exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
204
-		exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy());
205
-		exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
206
-		exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
207
-		exists_jobInfo.setChildJobId(jobInfo.getChildJobId());
208
-        xxlJobInfoDao.update(exists_jobInfo);
209
-
210
-		// fresh quartz
211
-		String qz_group = String.valueOf(exists_jobInfo.getJobGroup());
212
-		String qz_name = String.valueOf(exists_jobInfo.getId());
213
-        try {
214
-            boolean ret = XxlJobDynamicScheduler.rescheduleJob(qz_group, qz_name, exists_jobInfo.getJobCron());
215
-            return ret?ReturnT.SUCCESS:ReturnT.FAIL;
216
-        } catch (SchedulerException e) {
217
-            logger.error(e.getMessage(), e);
218
-        }
219
-
220
-		return ReturnT.FAIL;
221
-	}
222
-
223
-	@Override
224
-	public ReturnT<String> remove(int id) {
225
-		XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
226
-        String group = String.valueOf(xxlJobInfo.getJobGroup());
227
-        String name = String.valueOf(xxlJobInfo.getId());
228
-
229
-		try {
230
-			XxlJobDynamicScheduler.removeJob(name, group);
231
-			xxlJobInfoDao.delete(id);
232
-			xxlJobLogDao.delete(id);
233
-			xxlJobLogGlueDao.deleteByJobId(id);
234
-			return ReturnT.SUCCESS;
235
-		} catch (SchedulerException e) {
236
-			logger.error(e.getMessage(), e);
237
-		}
238
-		return ReturnT.FAIL;
239
-	}
240
-
241
-	@Override
242
-	public ReturnT<String> pause(int id) {
243
-        XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
244
-        String group = String.valueOf(xxlJobInfo.getJobGroup());
245
-        String name = String.valueOf(xxlJobInfo.getId());
246
-
247
-		try {
248
-            boolean ret = XxlJobDynamicScheduler.pauseJob(name, group);	// jobStatus do not store
249
-            return ret?ReturnT.SUCCESS:ReturnT.FAIL;
250
-		} catch (SchedulerException e) {
251
-			logger.error(e.getMessage(), e);
252
-			return ReturnT.FAIL;
253
-		}
254
-	}
255
-
256
-	@Override
257
-	public ReturnT<String> resume(int id) {
258
-        XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
259
-        String group = String.valueOf(xxlJobInfo.getJobGroup());
260
-        String name = String.valueOf(xxlJobInfo.getId());
261
-
262
-		try {
263
-			boolean ret = XxlJobDynamicScheduler.resumeJob(name, group);
264
-			return ret?ReturnT.SUCCESS:ReturnT.FAIL;
265
-		} catch (SchedulerException e) {
266
-			logger.error(e.getMessage(), e);
267
-			return ReturnT.FAIL;
268
-		}
269
-	}
270
-
271
-	@Override
272
-	public ReturnT<String> triggerJob(int id) {
273
-
274
-		JobTriggerPoolHelper.trigger(id);
275
-		return ReturnT.SUCCESS;
276
-
277
-        /*XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
278
-        if (xxlJobInfo == null) {
279
-        	return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_unvalid")) );
280
-		}
281
-
282
-        String group = String.valueOf(xxlJobInfo.getJobGroup());
283
-        String name = String.valueOf(xxlJobInfo.getId());
284
-
285
-		try {
286
-			XxlJobDynamicScheduler.triggerJob(name, group);
287
-			return ReturnT.SUCCESS;
288
-		} catch (SchedulerException e) {
289
-			logger.error(e.getMessage(), e);
290
-			return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
291
-		}*/
292
-
293
-	}
294
-
295
-	@Override
296
-	public Map<String, Object> dashboardInfo() {
297
-
298
-		int jobInfoCount = xxlJobInfoDao.findAllCount();
299
-		int jobLogCount = xxlJobLogDao.triggerCountByHandleCode(-1);
300
-		int jobLogSuccessCount = xxlJobLogDao.triggerCountByHandleCode(ReturnT.SUCCESS_CODE);
301
-
302
-		// executor count
303
-		Set<String> executerAddressSet = new HashSet<String>();
304
-		List<XxlJobGroup> groupList = xxlJobGroupDao.findAll();
305
-
306
-		if (CollectionUtils.isNotEmpty(groupList)) {
307
-			for (XxlJobGroup group: groupList) {
308
-				if (CollectionUtils.isNotEmpty(group.getRegistryList())) {
309
-					executerAddressSet.addAll(group.getRegistryList());
310
-				}
311
-			}
312
-		}
313
-
314
-		int executorCount = executerAddressSet.size();
315
-
316
-		Map<String, Object> dashboardMap = new HashMap<String, Object>();
317
-		dashboardMap.put("jobInfoCount", jobInfoCount);
318
-		dashboardMap.put("jobLogCount", jobLogCount);
319
-		dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount);
320
-		dashboardMap.put("executorCount", executorCount);
321
-		return dashboardMap;
322
-	}
323
-
324
-	private static final String TRIGGER_CHART_DATA_CACHE = "trigger_chart_data_cache";
325
-	@Override
326
-	public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
327
-		/*// get cache
328
-		String cacheKey = TRIGGER_CHART_DATA_CACHE + "_" + startDate.getTime() + "_" + endDate.getTime();
329
-		Map<String, Object> chartInfo = (Map<String, Object>) LocalCacheUtil.get(cacheKey);
330
-		if (chartInfo != null) {
331
-			return new ReturnT<Map<String, Object>>(chartInfo);
332
-		}*/
333
-
334
-		// process
335
-		List<String> triggerDayList = new ArrayList<String>();
336
-		List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
337
-		List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
338
-		List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
339
-		int triggerCountRunningTotal = 0;
340
-		int triggerCountSucTotal = 0;
341
-		int triggerCountFailTotal = 0;
342
-
343
-		List<Map<String, Object>> triggerCountMapAll = xxlJobLogDao.triggerCountByDay(startDate, endDate);
344
-		if (CollectionUtils.isNotEmpty(triggerCountMapAll)) {
345
-			for (Map<String, Object> item: triggerCountMapAll) {
346
-				String day = String.valueOf(item.get("triggerDay"));
347
-				int triggerDayCount = Integer.valueOf(String.valueOf(item.get("triggerDayCount")));
348
-				int triggerDayCountRunning = Integer.valueOf(String.valueOf(item.get("triggerDayCountRunning")));
349
-				int triggerDayCountSuc = Integer.valueOf(String.valueOf(item.get("triggerDayCountSuc")));
350
-				int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;
351
-
352
-				triggerDayList.add(day);
353
-				triggerDayCountRunningList.add(triggerDayCountRunning);
354
-				triggerDayCountSucList.add(triggerDayCountSuc);
355
-				triggerDayCountFailList.add(triggerDayCountFail);
356
-
357
-				triggerCountRunningTotal += triggerDayCountRunning;
358
-				triggerCountSucTotal += triggerDayCountSuc;
359
-				triggerCountFailTotal += triggerDayCountFail;
360
-			}
361
-		} else {
362
-            for (int i = 4; i > -1; i--) {
363
-                triggerDayList.add(FastDateFormat.getInstance("yyyy-MM-dd").format(DateUtils.addDays(new Date(), -i)));
364
-                triggerDayCountSucList.add(0);
365
-                triggerDayCountFailList.add(0);
366
-            }
367
-		}
368
-
369
-		Map<String, Object> result = new HashMap<String, Object>();
370
-		result.put("triggerDayList", triggerDayList);
371
-		result.put("triggerDayCountRunningList", triggerDayCountRunningList);
372
-		result.put("triggerDayCountSucList", triggerDayCountSucList);
373
-		result.put("triggerDayCountFailList", triggerDayCountFailList);
374
-
375
-		result.put("triggerCountRunningTotal", triggerCountRunningTotal);
376
-		result.put("triggerCountSucTotal", triggerCountSucTotal);
377
-		result.put("triggerCountFailTotal", triggerCountFailTotal);
378
-
379
-		/*// set cache
380
-		LocalCacheUtil.set(cacheKey, result, 60*1000);     // cache 60s*/
381
-
382
-		return new ReturnT<Map<String, Object>>(result);
383
-	}
384
-
385
-}
1
+package com.xxl.job.admin.service.impl;
2
+
3
+import com.xxl.job.admin.core.model.XxlJobGroup;
4
+import com.xxl.job.admin.core.model.XxlJobInfo;
5
+import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
6
+import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
7
+import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
8
+import com.xxl.job.admin.core.util.I18nUtil;
9
+import com.xxl.job.admin.dao.XxlJobGroupDao;
10
+import com.xxl.job.admin.dao.XxlJobInfoDao;
11
+import com.xxl.job.admin.dao.XxlJobLogDao;
12
+import com.xxl.job.admin.dao.XxlJobLogGlueDao;
13
+import com.xxl.job.admin.service.XxlJobService;
14
+import com.xxl.job.core.biz.model.ReturnT;
15
+import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
16
+import com.xxl.job.core.glue.GlueTypeEnum;
17
+import org.apache.commons.collections4.CollectionUtils;
18
+import org.apache.commons.lang3.StringUtils;
19
+import org.apache.commons.lang3.time.DateUtils;
20
+import org.apache.commons.lang3.time.FastDateFormat;
21
+import org.quartz.CronExpression;
22
+import org.quartz.SchedulerException;
23
+import org.slf4j.Logger;
24
+import org.slf4j.LoggerFactory;
25
+import org.springframework.stereotype.Service;
26
+
27
+import javax.annotation.Resource;
28
+import java.text.MessageFormat;
29
+import java.util.*;
30
+
31
+/**
32
+ * core job action for xxl-job
33
+ * @author xuxueli 2016-5-28 15:30:33
34
+ */
35
+@Service
36
+public class XxlJobServiceImpl implements XxlJobService {
37
+	private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);
38
+
39
+	@Resource
40
+	private XxlJobGroupDao xxlJobGroupDao;
41
+	@Resource
42
+	private XxlJobInfoDao xxlJobInfoDao;
43
+	@Resource
44
+	public XxlJobLogDao xxlJobLogDao;
45
+	@Resource
46
+	private XxlJobLogGlueDao xxlJobLogGlueDao;
47
+	
48
+	@Override
49
+	public Map<String, Object> pageList(int start, int length, int jobGroup, String jobDesc, String executorHandler, String filterTime) {
50
+
51
+		// page list
52
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobDesc, executorHandler);
53
+		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobDesc, executorHandler);
54
+		
55
+		// fill job info
56
+		if (list!=null && list.size()>0) {
57
+			for (XxlJobInfo jobInfo : list) {
58
+				XxlJobDynamicScheduler.fillJobInfo(jobInfo);
59
+			}
60
+		}
61
+		
62
+		// package result
63
+		Map<String, Object> maps = new HashMap<String, Object>();
64
+	    maps.put("recordsTotal", list_count);		// 总记录数
65
+	    maps.put("recordsFiltered", list_count);	// 过滤后的总记录数
66
+	    maps.put("data", list);  					// 分页列表
67
+		return maps;
68
+	}
69
+
70
+	@Override
71
+	public ReturnT<String> add(XxlJobInfo jobInfo) {
72
+		// valid
73
+		XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
74
+		if (group == null) {
75
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")) );
76
+		}
77
+		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
78
+			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
79
+		}
80
+		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
81
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
82
+		}
83
+		if (StringUtils.isBlank(jobInfo.getAuthor())) {
84
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
85
+		}
86
+		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
87
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
88
+		}
89
+		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
90
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
91
+		}
92
+		if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
93
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
94
+		}
95
+		if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringUtils.isBlank(jobInfo.getExecutorHandler())) {
96
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
97
+		}
98
+
99
+		// fix "\r" in shell
100
+		if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource()!=null) {
101
+			jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
102
+		}
103
+
104
+		// ChildJobId valid
105
+		if (StringUtils.isNotBlank(jobInfo.getChildJobId())) {
106
+			String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ",");
107
+			for (String childJobIdItem: childJobIds) {
108
+				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
109
+					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
110
+					if (childJobInfo==null) {
111
+						return new ReturnT<String>(ReturnT.FAIL_CODE,
112
+								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
113
+					}
114
+				} else {
115
+					return new ReturnT<String>(ReturnT.FAIL_CODE,
116
+							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
117
+				}
118
+			}
119
+			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
120
+		}
121
+
122
+		// add in db
123
+		xxlJobInfoDao.save(jobInfo);
124
+		if (jobInfo.getId() < 1) {
125
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
126
+		}
127
+
128
+		// add in quartz
129
+        String qz_group = String.valueOf(jobInfo.getJobGroup());
130
+        String qz_name = String.valueOf(jobInfo.getId());
131
+        try {
132
+            XxlJobDynamicScheduler.addJob(qz_name, qz_group, jobInfo.getJobCron());
133
+            //XxlJobDynamicScheduler.pauseJob(qz_name, qz_group);
134
+            return ReturnT.SUCCESS;
135
+        } catch (SchedulerException e) {
136
+            logger.error(e.getMessage(), e);
137
+            try {
138
+                xxlJobInfoDao.delete(jobInfo.getId());
139
+                XxlJobDynamicScheduler.removeJob(qz_name, qz_group);
140
+            } catch (SchedulerException e1) {
141
+                logger.error(e.getMessage(), e1);
142
+            }
143
+            return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail"))+":" + e.getMessage());
144
+        }
145
+	}
146
+
147
+	@Override
148
+	public ReturnT<String> update(XxlJobInfo jobInfo) {
149
+
150
+		// valid
151
+		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
152
+			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
153
+		}
154
+		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
155
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
156
+		}
157
+		if (StringUtils.isBlank(jobInfo.getAuthor())) {
158
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
159
+		}
160
+		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
161
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
162
+		}
163
+		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
164
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
165
+		}
166
+
167
+		// ChildJobId valid
168
+		if (StringUtils.isNotBlank(jobInfo.getChildJobId())) {
169
+			String[] childJobIds = StringUtils.split(jobInfo.getChildJobId(), ",");
170
+			for (String childJobIdItem: childJobIds) {
171
+				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
172
+					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
173
+					if (childJobInfo==null) {
174
+						return new ReturnT<String>(ReturnT.FAIL_CODE,
175
+								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
176
+					}
177
+					// avoid cycle relate
178
+					if (childJobInfo.getId() == jobInfo.getId()) {
179
+						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format(I18nUtil.getString("jobinfo_field_childJobId_limit"), childJobIdItem));
180
+					}
181
+				} else {
182
+					return new ReturnT<String>(ReturnT.FAIL_CODE,
183
+							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
184
+				}
185
+			}
186
+			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
187
+		}
188
+
189
+		// stage job info
190
+		XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
191
+		if (exists_jobInfo == null) {
192
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_not_found")) );
193
+		}
194
+		//String old_cron = exists_jobInfo.getJobCron();
195
+
196
+		exists_jobInfo.setJobCron(jobInfo.getJobCron());
197
+		exists_jobInfo.setJobDesc(jobInfo.getJobDesc());
198
+		exists_jobInfo.setAuthor(jobInfo.getAuthor());
199
+		exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());
200
+		exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
201
+		exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());
202
+		exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
203
+		exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
204
+		exists_jobInfo.setExecutorFailStrategy(jobInfo.getExecutorFailStrategy());
205
+		exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
206
+		exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
207
+		exists_jobInfo.setChildJobId(jobInfo.getChildJobId());
208
+        xxlJobInfoDao.update(exists_jobInfo);
209
+
210
+		// fresh quartz
211
+		String qz_group = String.valueOf(exists_jobInfo.getJobGroup());
212
+		String qz_name = String.valueOf(exists_jobInfo.getId());
213
+        try {
214
+            boolean ret = XxlJobDynamicScheduler.rescheduleJob(qz_group, qz_name, exists_jobInfo.getJobCron());
215
+            return ret?ReturnT.SUCCESS:ReturnT.FAIL;
216
+        } catch (SchedulerException e) {
217
+            logger.error(e.getMessage(), e);
218
+        }
219
+
220
+		return ReturnT.FAIL;
221
+	}
222
+
223
+	@Override
224
+	public ReturnT<String> remove(int id) {
225
+		XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
226
+        String group = String.valueOf(xxlJobInfo.getJobGroup());
227
+        String name = String.valueOf(xxlJobInfo.getId());
228
+
229
+		try {
230
+			XxlJobDynamicScheduler.removeJob(name, group);
231
+			xxlJobInfoDao.delete(id);
232
+			xxlJobLogDao.delete(id);
233
+			xxlJobLogGlueDao.deleteByJobId(id);
234
+			return ReturnT.SUCCESS;
235
+		} catch (SchedulerException e) {
236
+			logger.error(e.getMessage(), e);
237
+		}
238
+		return ReturnT.FAIL;
239
+	}
240
+
241
+	@Override
242
+	public ReturnT<String> pause(int id) {
243
+        XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
244
+        String group = String.valueOf(xxlJobInfo.getJobGroup());
245
+        String name = String.valueOf(xxlJobInfo.getId());
246
+
247
+		try {
248
+            boolean ret = XxlJobDynamicScheduler.pauseJob(name, group);	// jobStatus do not store
249
+            return ret?ReturnT.SUCCESS:ReturnT.FAIL;
250
+		} catch (SchedulerException e) {
251
+			logger.error(e.getMessage(), e);
252
+			return ReturnT.FAIL;
253
+		}
254
+	}
255
+
256
+	@Override
257
+	public ReturnT<String> resume(int id) {
258
+        XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
259
+        String group = String.valueOf(xxlJobInfo.getJobGroup());
260
+        String name = String.valueOf(xxlJobInfo.getId());
261
+
262
+		try {
263
+			boolean ret = XxlJobDynamicScheduler.resumeJob(name, group);
264
+			return ret?ReturnT.SUCCESS:ReturnT.FAIL;
265
+		} catch (SchedulerException e) {
266
+			logger.error(e.getMessage(), e);
267
+			return ReturnT.FAIL;
268
+		}
269
+	}
270
+
271
+	@Override
272
+	public ReturnT<String> triggerJob(int id) {
273
+
274
+		JobTriggerPoolHelper.trigger(id);
275
+		return ReturnT.SUCCESS;
276
+
277
+        /*XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
278
+        if (xxlJobInfo == null) {
279
+        	return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_unvalid")) );
280
+		}
281
+
282
+        String group = String.valueOf(xxlJobInfo.getJobGroup());
283
+        String name = String.valueOf(xxlJobInfo.getId());
284
+
285
+		try {
286
+			XxlJobDynamicScheduler.triggerJob(name, group);
287
+			return ReturnT.SUCCESS;
288
+		} catch (SchedulerException e) {
289
+			logger.error(e.getMessage(), e);
290
+			return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());
291
+		}*/
292
+
293
+	}
294
+
295
+	@Override
296
+	public Map<String, Object> dashboardInfo() {
297
+
298
+		int jobInfoCount = xxlJobInfoDao.findAllCount();
299
+		int jobLogCount = xxlJobLogDao.triggerCountByHandleCode(-1);
300
+		int jobLogSuccessCount = xxlJobLogDao.triggerCountByHandleCode(ReturnT.SUCCESS_CODE);
301
+
302
+		// executor count
303
+		Set<String> executerAddressSet = new HashSet<String>();
304
+		List<XxlJobGroup> groupList = xxlJobGroupDao.findAll();
305
+
306
+		if (CollectionUtils.isNotEmpty(groupList)) {
307
+			for (XxlJobGroup group: groupList) {
308
+				if (CollectionUtils.isNotEmpty(group.getRegistryList())) {
309
+					executerAddressSet.addAll(group.getRegistryList());
310
+				}
311
+			}
312
+		}
313
+
314
+		int executorCount = executerAddressSet.size();
315
+
316
+		Map<String, Object> dashboardMap = new HashMap<String, Object>();
317
+		dashboardMap.put("jobInfoCount", jobInfoCount);
318
+		dashboardMap.put("jobLogCount", jobLogCount);
319
+		dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount);
320
+		dashboardMap.put("executorCount", executorCount);
321
+		return dashboardMap;
322
+	}
323
+
324
+	private static final String TRIGGER_CHART_DATA_CACHE = "trigger_chart_data_cache";
325
+	@Override
326
+	public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
327
+		/*// get cache
328
+		String cacheKey = TRIGGER_CHART_DATA_CACHE + "_" + startDate.getTime() + "_" + endDate.getTime();
329
+		Map<String, Object> chartInfo = (Map<String, Object>) LocalCacheUtil.get(cacheKey);
330
+		if (chartInfo != null) {
331
+			return new ReturnT<Map<String, Object>>(chartInfo);
332
+		}*/
333
+
334
+		// process
335
+		List<String> triggerDayList = new ArrayList<String>();
336
+		List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
337
+		List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
338
+		List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
339
+		int triggerCountRunningTotal = 0;
340
+		int triggerCountSucTotal = 0;
341
+		int triggerCountFailTotal = 0;
342
+
343
+		List<Map<String, Object>> triggerCountMapAll = xxlJobLogDao.triggerCountByDay(startDate, endDate);
344
+		if (CollectionUtils.isNotEmpty(triggerCountMapAll)) {
345
+			for (Map<String, Object> item: triggerCountMapAll) {
346
+				String day = String.valueOf(item.get("triggerDay"));
347
+				int triggerDayCount = Integer.valueOf(String.valueOf(item.get("triggerDayCount")));
348
+				int triggerDayCountRunning = Integer.valueOf(String.valueOf(item.get("triggerDayCountRunning")));
349
+				int triggerDayCountSuc = Integer.valueOf(String.valueOf(item.get("triggerDayCountSuc")));
350
+				int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;
351
+
352
+				triggerDayList.add(day);
353
+				triggerDayCountRunningList.add(triggerDayCountRunning);
354
+				triggerDayCountSucList.add(triggerDayCountSuc);
355
+				triggerDayCountFailList.add(triggerDayCountFail);
356
+
357
+				triggerCountRunningTotal += triggerDayCountRunning;
358
+				triggerCountSucTotal += triggerDayCountSuc;
359
+				triggerCountFailTotal += triggerDayCountFail;
360
+			}
361
+		} else {
362
+            for (int i = 4; i > -1; i--) {
363
+                triggerDayList.add(FastDateFormat.getInstance("yyyy-MM-dd").format(DateUtils.addDays(new Date(), -i)));
364
+                triggerDayCountSucList.add(0);
365
+                triggerDayCountFailList.add(0);
366
+            }
367
+		}
368
+
369
+		Map<String, Object> result = new HashMap<String, Object>();
370
+		result.put("triggerDayList", triggerDayList);
371
+		result.put("triggerDayCountRunningList", triggerDayCountRunningList);
372
+		result.put("triggerDayCountSucList", triggerDayCountSucList);
373
+		result.put("triggerDayCountFailList", triggerDayCountFailList);
374
+
375
+		result.put("triggerCountRunningTotal", triggerCountRunningTotal);
376
+		result.put("triggerCountSucTotal", triggerCountSucTotal);
377
+		result.put("triggerCountFailTotal", triggerCountFailTotal);
378
+
379
+		/*// set cache
380
+		LocalCacheUtil.set(cacheKey, result, 60*1000);     // cache 60s*/
381
+
382
+		return new ReturnT<Map<String, Object>>(result);
383
+	}
384
+
385
+}

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

@@ -1,186 +1,186 @@
1
-<?xml version="1.0" encoding="UTF-8"?>
2
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
3
-	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
4
-<mapper namespace="com.xxl.job.admin.dao.XxlJobInfoDao">
5
-
6
-	<resultMap id="XxlJobInfo" type="com.xxl.job.admin.core.model.XxlJobInfo" >
7
-		<result column="id" property="id" />
8
-
9
-		<result column="job_group" property="jobGroup" />
10
-	    <result column="job_cron" property="jobCron" />
11
-	    <result column="job_desc" property="jobDesc" />
12
-
13
-	    <result column="add_time" property="addTime" />
14
-	    <result column="update_time" property="updateTime" />
15
-
16
-	    <result column="author" property="author" />
17
-	    <result column="alarm_email" property="alarmEmail" />
18
-
19
-		<result column="executor_route_strategy" property="executorRouteStrategy" />
20
-		<result column="executor_handler" property="executorHandler" />
21
-	    <result column="executor_param" property="executorParam" />
22
-		<result column="executor_block_strategy" property="executorBlockStrategy" />
23
-		<result column="executor_fail_strategy" property="executorFailStrategy" />
24
-		<result column="executor_timeout" property="executorTimeout" />
25
-		<result column="executor_fail_retry_count" property="executorFailRetryCount" />
26
-
27
-	    <result column="glue_type" property="glueType" />
28
-	    <result column="glue_source" property="glueSource" />
29
-	    <result column="glue_remark" property="glueRemark" />
30
-		<result column="glue_updatetime" property="glueUpdatetime" />
31
-
32
-		<result column="child_jobid" property="childJobId" />
33
-	</resultMap>
34
-
35
-	<sql id="Base_Column_List">
36
-		t.id,
37
-		t.job_group,
38
-		t.job_cron,
39
-		t.job_desc,
40
-		t.add_time,
41
-		t.update_time,
42
-		t.author,
43
-		t.alarm_email,
44
-		t.executor_route_strategy,
45
-		t.executor_handler,
46
-		t.executor_param,
47
-		t.executor_block_strategy,
48
-		t.executor_fail_strategy,
49
-		t.executor_timeout,
50
-		t.executor_fail_retry_count,
51
-		t.glue_type,
52
-		t.glue_source,
53
-		t.glue_remark,
54
-		t.glue_updatetime,
55
-		t.child_jobid
56
-	</sql>
57
-
58
-	<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
59
-		SELECT <include refid="Base_Column_List" />
60
-		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
61
-		<trim prefix="WHERE" prefixOverrides="AND | OR" >
62
-			<if test="jobGroup gt 0">
63
-				AND t.job_group = #{jobGroup}
64
-			</if>
65
-			<if test="jobDesc != null and jobDesc != ''">
66
-				AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
67
-			</if>
68
-			<if test="executorHandler != null and executorHandler != ''">
69
-				AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
70
-			</if>
71
-		</trim>
72
-		ORDER BY id DESC
73
-		LIMIT #{offset}, #{pagesize}
74
-	</select>
75
-
76
-	<select id="pageListCount" parameterType="java.util.HashMap" resultType="int">
77
-		SELECT count(1)
78
-		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
79
-		<trim prefix="WHERE" prefixOverrides="AND | OR" >
80
-			<if test="jobGroup gt 0">
81
-				AND t.job_group = #{jobGroup}
82
-			</if>
83
-			<if test="jobDesc != null and jobDesc != ''">
84
-				AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
85
-			</if>
86
-			<if test="executorHandler != null and executorHandler != ''">
87
-				AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
88
-			</if>
89
-		</trim>
90
-	</select>
91
-
92
-	<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobInfo" useGeneratedKeys="true" keyProperty="id" >
93
-		INSERT INTO XXL_JOB_QRTZ_TRIGGER_INFO (
94
-			job_group,
95
-			job_cron,
96
-			job_desc,
97
-			add_time,
98
-			update_time,
99
-			author,
100
-			alarm_email,
101
-            executor_route_strategy,
102
-			executor_handler,
103
-			executor_param,
104
-			executor_block_strategy,
105
-			executor_fail_strategy,
106
-			executor_timeout,
107
-			executor_fail_retry_count,
108
-			glue_type,
109
-			glue_source,
110
-			glue_remark,
111
-			glue_updatetime,
112
-			child_jobid
113
-		) VALUES (
114
-			#{jobGroup},
115
-			#{jobCron},
116
-			#{jobDesc},
117
-			NOW(),
118
-			NOW(),
119
-			#{author},
120
-			#{alarmEmail},
121
-			#{executorRouteStrategy},
122
-			#{executorHandler},
123
-			#{executorParam},
124
-			#{executorBlockStrategy},
125
-			#{executorFailStrategy},
126
-			#{executorTimeout},
127
-			#{executorFailRetryCount},
128
-			#{glueType},
129
-			#{glueSource},
130
-			#{glueRemark},
131
-			NOW(),
132
-			#{childJobId}
133
-		);
134
-		<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
135
-			SELECT LAST_INSERT_ID()
136
-			/*SELECT @@IDENTITY AS id*/
137
-		</selectKey>-->
138
-	</insert>
139
-
140
-	<select id="loadById" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
141
-		SELECT <include refid="Base_Column_List" />
142
-		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
143
-		WHERE t.id = #{id}
144
-	</select>
145
-
146
-	<update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobInfo" >
147
-		UPDATE XXL_JOB_QRTZ_TRIGGER_INFO
148
-		SET
149
-			job_cron = #{jobCron},
150
-			job_desc = #{jobDesc},
151
-			update_time = NOW(),
152
-			author = #{author},
153
-			alarm_email = #{alarmEmail},
154
-			executor_route_strategy = #{executorRouteStrategy},
155
-			executor_handler = #{executorHandler},
156
-			executor_param = #{executorParam},
157
-			executor_block_strategy = #{executorBlockStrategy},
158
-			executor_fail_strategy = #{executorFailStrategy},
159
-			executor_timeout = ${executorTimeout},
160
-			executor_fail_retry_count = ${executorFailRetryCount},
161
-			glue_type = #{glueType},
162
-			glue_source = #{glueSource},
163
-			glue_remark = #{glueRemark},
164
-			glue_updatetime = #{glueUpdatetime},
165
-			child_jobid = #{childJobId}
166
-		WHERE id = #{id}
167
-	</update>
168
-
169
-	<delete id="delete" parameterType="java.util.HashMap">
170
-		DELETE
171
-		FROM XXL_JOB_QRTZ_TRIGGER_INFO
172
-		WHERE id = #{id}
173
-	</delete>
174
-
175
-	<select id="getJobsByGroup" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
176
-		SELECT <include refid="Base_Column_List" />
177
-		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
178
-		WHERE t.job_group = #{jobGroup}
179
-	</select>
180
-
181
-	<select id="findAllCount" resultType="int">
182
-		SELECT count(1)
183
-		FROM XXL_JOB_QRTZ_TRIGGER_INFO
184
-	</select>
185
-
1
+<?xml version="1.0" encoding="UTF-8"?>
2
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
3
+	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
4
+<mapper namespace="com.xxl.job.admin.dao.XxlJobInfoDao">
5
+
6
+	<resultMap id="XxlJobInfo" type="com.xxl.job.admin.core.model.XxlJobInfo" >
7
+		<result column="id" property="id" />
8
+
9
+		<result column="job_group" property="jobGroup" />
10
+	    <result column="job_cron" property="jobCron" />
11
+	    <result column="job_desc" property="jobDesc" />
12
+
13
+	    <result column="add_time" property="addTime" />
14
+	    <result column="update_time" property="updateTime" />
15
+
16
+	    <result column="author" property="author" />
17
+	    <result column="alarm_email" property="alarmEmail" />
18
+
19
+		<result column="executor_route_strategy" property="executorRouteStrategy" />
20
+		<result column="executor_handler" property="executorHandler" />
21
+	    <result column="executor_param" property="executorParam" />
22
+		<result column="executor_block_strategy" property="executorBlockStrategy" />
23
+		<result column="executor_fail_strategy" property="executorFailStrategy" />
24
+		<result column="executor_timeout" property="executorTimeout" />
25
+		<result column="executor_fail_retry_count" property="executorFailRetryCount" />
26
+
27
+	    <result column="glue_type" property="glueType" />
28
+	    <result column="glue_source" property="glueSource" />
29
+	    <result column="glue_remark" property="glueRemark" />
30
+		<result column="glue_updatetime" property="glueUpdatetime" />
31
+
32
+		<result column="child_jobid" property="childJobId" />
33
+	</resultMap>
34
+
35
+	<sql id="Base_Column_List">
36
+		t.id,
37
+		t.job_group,
38
+		t.job_cron,
39
+		t.job_desc,
40
+		t.add_time,
41
+		t.update_time,
42
+		t.author,
43
+		t.alarm_email,
44
+		t.executor_route_strategy,
45
+		t.executor_handler,
46
+		t.executor_param,
47
+		t.executor_block_strategy,
48
+		t.executor_fail_strategy,
49
+		t.executor_timeout,
50
+		t.executor_fail_retry_count,
51
+		t.glue_type,
52
+		t.glue_source,
53
+		t.glue_remark,
54
+		t.glue_updatetime,
55
+		t.child_jobid
56
+	</sql>
57
+
58
+	<select id="pageList" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
59
+		SELECT <include refid="Base_Column_List" />
60
+		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
61
+		<trim prefix="WHERE" prefixOverrides="AND | OR" >
62
+			<if test="jobGroup gt 0">
63
+				AND t.job_group = #{jobGroup}
64
+			</if>
65
+			<if test="jobDesc != null and jobDesc != ''">
66
+				AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
67
+			</if>
68
+			<if test="executorHandler != null and executorHandler != ''">
69
+				AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
70
+			</if>
71
+		</trim>
72
+		ORDER BY id DESC
73
+		LIMIT #{offset}, #{pagesize}
74
+	</select>
75
+
76
+	<select id="pageListCount" parameterType="java.util.HashMap" resultType="int">
77
+		SELECT count(1)
78
+		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
79
+		<trim prefix="WHERE" prefixOverrides="AND | OR" >
80
+			<if test="jobGroup gt 0">
81
+				AND t.job_group = #{jobGroup}
82
+			</if>
83
+			<if test="jobDesc != null and jobDesc != ''">
84
+				AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
85
+			</if>
86
+			<if test="executorHandler != null and executorHandler != ''">
87
+				AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
88
+			</if>
89
+		</trim>
90
+	</select>
91
+
92
+	<insert id="save" parameterType="com.xxl.job.admin.core.model.XxlJobInfo" useGeneratedKeys="true" keyProperty="id" >
93
+		INSERT INTO XXL_JOB_QRTZ_TRIGGER_INFO (
94
+			job_group,
95
+			job_cron,
96
+			job_desc,
97
+			add_time,
98
+			update_time,
99
+			author,
100
+			alarm_email,
101
+            executor_route_strategy,
102
+			executor_handler,
103
+			executor_param,
104
+			executor_block_strategy,
105
+			executor_fail_strategy,
106
+			executor_timeout,
107
+			executor_fail_retry_count,
108
+			glue_type,
109
+			glue_source,
110
+			glue_remark,
111
+			glue_updatetime,
112
+			child_jobid
113
+		) VALUES (
114
+			#{jobGroup},
115
+			#{jobCron},
116
+			#{jobDesc},
117
+			NOW(),
118
+			NOW(),
119
+			#{author},
120
+			#{alarmEmail},
121
+			#{executorRouteStrategy},
122
+			#{executorHandler},
123
+			#{executorParam},
124
+			#{executorBlockStrategy},
125
+			#{executorFailStrategy},
126
+			#{executorTimeout},
127
+			#{executorFailRetryCount},
128
+			#{glueType},
129
+			#{glueSource},
130
+			#{glueRemark},
131
+			NOW(),
132
+			#{childJobId}
133
+		);
134
+		<!--<selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id">
135
+			SELECT LAST_INSERT_ID()
136
+			/*SELECT @@IDENTITY AS id*/
137
+		</selectKey>-->
138
+	</insert>
139
+
140
+	<select id="loadById" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
141
+		SELECT <include refid="Base_Column_List" />
142
+		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
143
+		WHERE t.id = #{id}
144
+	</select>
145
+
146
+	<update id="update" parameterType="com.xxl.job.admin.core.model.XxlJobInfo" >
147
+		UPDATE XXL_JOB_QRTZ_TRIGGER_INFO
148
+		SET
149
+			job_cron = #{jobCron},
150
+			job_desc = #{jobDesc},
151
+			update_time = NOW(),
152
+			author = #{author},
153
+			alarm_email = #{alarmEmail},
154
+			executor_route_strategy = #{executorRouteStrategy},
155
+			executor_handler = #{executorHandler},
156
+			executor_param = #{executorParam},
157
+			executor_block_strategy = #{executorBlockStrategy},
158
+			executor_fail_strategy = #{executorFailStrategy},
159
+			executor_timeout = ${executorTimeout},
160
+			executor_fail_retry_count = ${executorFailRetryCount},
161
+			glue_type = #{glueType},
162
+			glue_source = #{glueSource},
163
+			glue_remark = #{glueRemark},
164
+			glue_updatetime = #{glueUpdatetime},
165
+			child_jobid = #{childJobId}
166
+		WHERE id = #{id}
167
+	</update>
168
+
169
+	<delete id="delete" parameterType="java.util.HashMap">
170
+		DELETE
171
+		FROM XXL_JOB_QRTZ_TRIGGER_INFO
172
+		WHERE id = #{id}
173
+	</delete>
174
+
175
+	<select id="getJobsByGroup" parameterType="java.util.HashMap" resultMap="XxlJobInfo">
176
+		SELECT <include refid="Base_Column_List" />
177
+		FROM XXL_JOB_QRTZ_TRIGGER_INFO AS t
178
+		WHERE t.job_group = #{jobGroup}
179
+	</select>
180
+
181
+	<select id="findAllCount" resultType="int">
182
+		SELECT count(1)
183
+		FROM XXL_JOB_QRTZ_TRIGGER_INFO
184
+	</select>
185
+
186 186
 </mapper>

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

@@ -1,377 +1,377 @@
1
-<!DOCTYPE html>
2
-<html>
3
-<head>
4
-  	<#import "/common/common.macro.ftl" as netCommon>
5
-	<@netCommon.commonStyle />
6
-	<!-- DataTables -->
7
-  	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
8
-    <title>${I18n.admin_name}</title>
9
-</head>
10
-<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if>">
11
-<div class="wrapper">
12
-	<!-- header -->
13
-	<@netCommon.commonHeader />
14
-	<!-- left -->
15
-	<@netCommon.commonLeft "jobinfo" />
16
-	
17
-	<!-- Content Wrapper. Contains page content -->
18
-	<div class="content-wrapper">
19
-		<!-- Content Header (Page header) -->
20
-		<section class="content-header">
21
-			<h1>${I18n.jobinfo_name}</h1>
22
-		</section>
23
-		
24
-		<!-- Main content -->
25
-	    <section class="content">
26
-	    
27
-	    	<div class="row">
28
-	    		<div class="col-xs-3">
29
-	              	<div class="input-group">
30
-	                	<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
31
-                		<select class="form-control" id="jobGroup" >
32
-                			<#list JobGroupList as group>
33
-                				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
34
-                			</#list>
35
-	                  	</select>
36
-	              	</div>
37
-	            </div>
38
-                <div class="col-xs-3">
39
-                    <div class="input-group">
40
-                        <span class="input-group-addon">${I18n.jobinfo_field_jobdesc}</span>
41
-                        <input type="text" class="form-control" id="jobDesc" autocomplete="on" >
42
-                    </div>
43
-                </div>
44
-                <div class="col-xs-3">
45
-                    <div class="input-group">
46
-                        <span class="input-group-addon">JobHandler</span>
47
-                        <input type="text" class="form-control" id="executorHandler" autocomplete="on" >
48
-                    </div>
49
-                </div>
50
-	            <div class="col-xs-1">
51
-	            	<button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
52
-	            </div>
53
-	            <div class="col-xs-2">
54
-	            	<button class="btn btn-block btn-success add" type="button">${I18n.jobinfo_field_add}</button>
55
-	            </div>
56
-          	</div>
57
-	    	
58
-			<div class="row">
59
-				<div class="col-xs-12">
60
-					<div class="box">
61
-			            <#--<div class="box-header hide">
62
-			            	<h3 class="box-title">调度列表</h3>
63
-			            </div>-->
64
-			            <div class="box-body" >
65
-			              	<table id="job_list" class="table table-bordered table-striped" width="100%" >
66
-				                <thead>
67
-					            	<tr>
68
-					            		<th name="id" >${I18n.jobinfo_field_id}</th>
69
-					                	<th name="jobGroup" >${I18n.jobinfo_field_jobgroup}</th>
70
-					                  	<th name="jobDesc" >${I18n.jobinfo_field_jobdesc}</th>
71
-                                        <th name="glueType" >${I18n.jobinfo_field_gluetype}</th>
72
-					                  	<th name="executorParam" >${I18n.jobinfo_field_executorparam}</th>
73
-                                        <th name="jobCron" >Cron</th>
74
-					                  	<th name="addTime" >addTime</th>
75
-					                  	<th name="updateTime" >updateTime</th>
76
-					                  	<th name="author" >${I18n.jobinfo_field_author}</th>
77
-					                  	<th name="alarmEmail" >${I18n.jobinfo_field_alarmemail}</th>
78
-					                  	<th name="jobStatus" >${I18n.system_status}</th>
79
-					                  	<th>${I18n.system_opt}</th>
80
-					                </tr>
81
-				                </thead>
82
-				                <tbody></tbody>
83
-				                <tfoot></tfoot>
84
-							</table>
85
-						</div>
86
-					</div>
87
-				</div>
88
-			</div>
89
-	    </section>
90
-	</div>
91
-	
92
-	<!-- footer -->
93
-	<@netCommon.commonFooter />
94
-</div>
95
-
96
-<!-- job新增.模态框 -->
97
-<div class="modal fade" id="addModal" tabindex="-1" role="dialog"  aria-hidden="true">
98
-	<div class="modal-dialog modal-lg">
99
-		<div class="modal-content">
100
-			<div class="modal-header">
101
-            	<h4 class="modal-title" >${I18n.jobinfo_field_add}</h4>
102
-         	</div>
103
-         	<div class="modal-body">
104
-				<form class="form-horizontal form" role="form" >
105
-					<div class="form-group">
106
-						<label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
107
-						<div class="col-sm-4">
108
-							<select class="form-control" name="jobGroup" >
109
-		            			<#list JobGroupList as group>
110
-		            				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
111
-		            			</#list>
112
-		                  	</select>
113
-						</div>
114
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
115
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}" maxlength="50" ></div>
116
-					</div>
117
-                    <div class="form-group">
118
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
119
-                        <div class="col-sm-4">
120
-                            <select class="form-control" name="executorRouteStrategy" >
121
-							<#list ExecutorRouteStrategyEnum as item>
122
-                                <option value="${item}" >${item.title}</option>
123
-							</#list>
124
-                            </select>
125
-                        </div>
126
-                        <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
127
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
128
-                    </div>
129
-                    <div class="form-group">
130
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
131
-                        <div class="col-sm-4">
132
-                            <select class="form-control glueType" name="glueType" >
133
-								<#list GlueTypeEnum as item>
134
-									<option value="${item}" >${item.desc}</option>
135
-								</#list>
136
-                            </select>
137
-                        </div>
138
-                        <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="red">*</font></label>
139
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
140
-                    </div>
141
-                    <div class="form-group">
142
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
143
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}" maxlength="512" ></div>
144
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
145
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
146
-                    </div>
147
-                    <div class="form-group">
148
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font color="black">*</font></label>
149
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout" placeholder="${I18n.jobinfo_field_executorTimeout_placeholder}" maxlength="6" ></div>
150
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
151
-                        <div class="col-sm-4">
152
-                            <select class="form-control" name="executorBlockStrategy" >
153
-								<#list ExecutorBlockStrategyEnum as item>
154
-                                    <option value="${item}" >${item.title}</option>
155
-                                </#list>
156
-                            </select>
157
-                        </div>
158
-                    </div>
159
-                    <div class="form-group">
160
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailRetryCount}<font color="black">*</font></label>
161
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorFailRetryCount" placeholder="${I18n.jobinfo_field_executorFailRetryCount_placeholder}" maxlength="4" ></div>
162
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
163
-                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></div>
164
-                    </div>
165
-					<div class="form-group">
166
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
167
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}" maxlength="50" ></div>
168
-					</div>
169
-
170
-                    <hr>
171
-					<div class="form-group">
172
-						<div class="col-sm-offset-3 col-sm-6">
173
-							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
174
-							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
175
-						</div>
176
-					</div>
177
-
178
-<input type="hidden" name="glueRemark" value="GLUE代码初始化" >
179
-<textarea name="glueSource" style="display:none;" ></textarea>
180
-<textarea class="glueSource_java" style="display:none;" >
181
-package com.xxl.job.service.handler;
182
-
183
-import com.xxl.job.core.log.XxlJobLogger;
184
-import com.xxl.job.core.biz.model.ReturnT;
185
-import com.xxl.job.core.handler.IJobHandler;
186
-
187
-public class DemoGlueJobHandler extends IJobHandler {
188
-
189
-	@Override
190
-	public ReturnT<String> execute(String param) throws Exception {
191
-		XxlJobLogger.log("XXL-JOB, Hello World.");
192
-		return ReturnT.SUCCESS;
193
-	}
194
-
195
-}
196
-</textarea>
197
-<textarea class="glueSource_shell" style="display:none;" >
198
-#!/bin/bash
199
-echo "xxl-job: hello shell"
200
-
201
-echo "${I18n.jobinfo_script_location}:$0"
202
-echo "${I18n.jobinfo_field_executorparam}:$1"
203
-echo "${I18n.jobinfo_shard_index} = $2"
204
-echo "${I18n.jobinfo_shard_total} = $3"
205
-<#--echo "参数数量:$#"
206
-for param in $*
207
-do
208
-    echo "参数 : $param"
209
-    sleep 1s
210
-done-->
211
-
212
-echo "Good bye!"
213
-exit 0
214
-</textarea>
215
-<textarea class="glueSource_python" style="display:none;" >
216
-#!/usr/bin/python
217
-# -*- coding: UTF-8 -*-
218
-import time
219
-import sys
220
-
221
-print "xxl-job: hello python"
222
-
223
-print "${I18n.jobinfo_script_location}:", sys.argv[0]
224
-print "${I18n.jobinfo_field_executorparam}:", sys.argv[1]
225
-print "${I18n.jobinfo_shard_index}:", sys.argv[2]
226
-print "${I18n.jobinfo_shard_total}:", sys.argv[3]
227
-<#--for i in range(1, len(sys.argv)):
228
-	time.sleep(1)
229
-	print "参数", i, sys.argv[i]-->
230
-
231
-print "Good bye!"
232
-exit(0)
233
-<#--
234
-import logging
235
-logging.basicConfig(level=logging.DEBUG)
236
-logging.info("脚本文件:" + sys.argv[0])
237
--->
238
-</textarea>
239
-<#--这里有问题,新建一个运行模式为 php 的任务后,GLUE 中没有下边的 php 代码-->
240
-<textarea class="glueSource_php" style="display:none;" >
241
-<?php
242
-
243
-    echo "xxl-job: hello php  \n";
244
-
245
-    echo "${I18n.jobinfo_script_location}:$argv[0]  \n";
246
-    echo "${I18n.jobinfo_field_executorparam}:$argv[1]  \n";
247
-    echo "${I18n.jobinfo_shard_index} = $argv[2]  \n";
248
-    echo "${I18n.jobinfo_shard_total} = $argv[3]  \n";
249
-
250
-    echo "Good bye!  \n";
251
-    exit(0);
252
-
253
-?>
254
-</textarea>
255
-<textarea class="glueSource_nodejs" style="display:none;" >
256
-#!/usr/bin/env node
257
-console.log("xxl-job: hello nodejs")
258
-
259
-var arguments = process.argv
260
-
261
-console.log("${I18n.jobinfo_script_location}: " + arguments[1])
262
-console.log("${I18n.jobinfo_field_executorparam}: " + arguments[2])
263
-console.log("${I18n.jobinfo_shard_index}: " + arguments[3])
264
-console.log("${I18n.jobinfo_shard_total}: " + arguments[4])
265
-<#--for (var i = 2; i < arguments.length; i++){
266
-	console.log("参数 %s = %s", (i-1), arguments[i]);
267
-}-->
268
-
269
-console.log("Good bye!")
270
-process.exit(0)
271
-</textarea>		
272
-				</form>
273
-         	</div>
274
-		</div>
275
-	</div>
276
-</div>
277
-
278
-<!-- 更新.模态框 -->
279
-<div class="modal fade" id="updateModal" tabindex="-1" role="dialog"  aria-hidden="true">
280
-	<div class="modal-dialog modal-lg">
281
-		<div class="modal-content">
282
-			<div class="modal-header">
283
-            	<h4 class="modal-title" >${I18n.jobinfo_field_update}</h4>
284
-         	</div>
285
-         	<div class="modal-body">
286
-				<form class="form-horizontal form" role="form" >
287
-					<div class="form-group">
288
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
289
-                        <div class="col-sm-4">
290
-                            <select class="form-control" name="jobGroup" disabled >
291
-							<#list JobGroupList as group>
292
-                                <option value="${group.id}" >${group.title}</option>
293
-							</#list>
294
-                            </select>
295
-                        </div>
296
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
297
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}" maxlength="50" ></div>
298
-                    </div>
299
-                    <div class="form-group">
300
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
301
-                        <div class="col-sm-4">
302
-                            <select class="form-control" name="executorRouteStrategy" >
303
-							<#list ExecutorRouteStrategyEnum as item>
304
-                                <option value="${item}" >${item.title}</option>
305
-							</#list>
306
-                            </select>
307
-                        </div>
308
-                        <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
309
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
310
-                    </div>
311
-                    <div class="form-group">
312
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
313
-                        <div class="col-sm-4">
314
-                            <select class="form-control glueType" name="glueType" disabled >
315
-							<#list GlueTypeEnum as item>
316
-                                <option value="${item}" >${item.desc}</option>
317
-							</#list>
318
-                            </select>
319
-                        </div>
320
-                        <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="red">*</font></label>
321
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
322
-                    </div>
323
-                    <div class="form-group">
324
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
325
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}" maxlength="512" ></div>
326
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
327
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
328
-                    </div>
329
-                    <div class="form-group">
330
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font color="black">*</font></label>
331
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout" placeholder="${I18n.jobinfo_field_executorTimeout_placeholder}" maxlength="6" ></div>
332
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
333
-                        <div class="col-sm-4">
334
-                            <select class="form-control" name="executorBlockStrategy" >
335
-							<#list ExecutorBlockStrategyEnum as item>
336
-                                <option value="${item}" >${item.title}</option>
337
-                            </#list>
338
-                            </select>
339
-                        </div>
340
-                    </div>
341
-                    <div class="form-group">
342
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailRetryCount}<font color="black">*</font></label>
343
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorFailRetryCount" placeholder="${I18n.jobinfo_field_executorFailRetryCount_placeholder}" maxlength="4" ></div>
344
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
345
-                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></div>
346
-
347
-                    </div>
348
-                    <div class="form-group">
349
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
350
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}" maxlength="50" ></div>
351
-                    </div>
352
-
353
-					<hr>
354
-					<div class="form-group">
355
-                        <div class="col-sm-offset-3 col-sm-6">
356
-							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
357
-							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
358
-                            <input type="hidden" name="id" >
359
-						</div>
360
-					</div>
361
-
362
-				</form>
363
-         	</div>
364
-		</div>
365
-	</div>
366
-</div>
367
-
368
-<@netCommon.commonScript />
369
-<!-- DataTables -->
370
-<script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
371
-<script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
372
-<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
373
-<!-- moment -->
374
-<script src="${request.contextPath}/static/adminlte/plugins/daterangepicker/moment.min.js"></script>
375
-<script src="${request.contextPath}/static/js/jobinfo.index.1.js"></script>
376
-</body>
377
-</html>
1
+<!DOCTYPE html>
2
+<html>
3
+<head>
4
+  	<#import "/common/common.macro.ftl" as netCommon>
5
+	<@netCommon.commonStyle />
6
+	<!-- DataTables -->
7
+  	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
8
+    <title>${I18n.admin_name}</title>
9
+</head>
10
+<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if>">
11
+<div class="wrapper">
12
+	<!-- header -->
13
+	<@netCommon.commonHeader />
14
+	<!-- left -->
15
+	<@netCommon.commonLeft "jobinfo" />
16
+	
17
+	<!-- Content Wrapper. Contains page content -->
18
+	<div class="content-wrapper">
19
+		<!-- Content Header (Page header) -->
20
+		<section class="content-header">
21
+			<h1>${I18n.jobinfo_name}</h1>
22
+		</section>
23
+		
24
+		<!-- Main content -->
25
+	    <section class="content">
26
+	    
27
+	    	<div class="row">
28
+	    		<div class="col-xs-3">
29
+	              	<div class="input-group">
30
+	                	<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
31
+                		<select class="form-control" id="jobGroup" >
32
+                			<#list JobGroupList as group>
33
+                				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
34
+                			</#list>
35
+	                  	</select>
36
+	              	</div>
37
+	            </div>
38
+                <div class="col-xs-3">
39
+                    <div class="input-group">
40
+                        <span class="input-group-addon">${I18n.jobinfo_field_jobdesc}</span>
41
+                        <input type="text" class="form-control" id="jobDesc" autocomplete="on" >
42
+                    </div>
43
+                </div>
44
+                <div class="col-xs-3">
45
+                    <div class="input-group">
46
+                        <span class="input-group-addon">JobHandler</span>
47
+                        <input type="text" class="form-control" id="executorHandler" autocomplete="on" >
48
+                    </div>
49
+                </div>
50
+	            <div class="col-xs-1">
51
+	            	<button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
52
+	            </div>
53
+	            <div class="col-xs-2">
54
+	            	<button class="btn btn-block btn-success add" type="button">${I18n.jobinfo_field_add}</button>
55
+	            </div>
56
+          	</div>
57
+	    	
58
+			<div class="row">
59
+				<div class="col-xs-12">
60
+					<div class="box">
61
+			            <#--<div class="box-header hide">
62
+			            	<h3 class="box-title">调度列表</h3>
63
+			            </div>-->
64
+			            <div class="box-body" >
65
+			              	<table id="job_list" class="table table-bordered table-striped" width="100%" >
66
+				                <thead>
67
+					            	<tr>
68
+					            		<th name="id" >${I18n.jobinfo_field_id}</th>
69
+					                	<th name="jobGroup" >${I18n.jobinfo_field_jobgroup}</th>
70
+					                  	<th name="jobDesc" >${I18n.jobinfo_field_jobdesc}</th>
71
+                                        <th name="glueType" >${I18n.jobinfo_field_gluetype}</th>
72
+					                  	<th name="executorParam" >${I18n.jobinfo_field_executorparam}</th>
73
+                                        <th name="jobCron" >Cron</th>
74
+					                  	<th name="addTime" >addTime</th>
75
+					                  	<th name="updateTime" >updateTime</th>
76
+					                  	<th name="author" >${I18n.jobinfo_field_author}</th>
77
+					                  	<th name="alarmEmail" >${I18n.jobinfo_field_alarmemail}</th>
78
+					                  	<th name="jobStatus" >${I18n.system_status}</th>
79
+					                  	<th>${I18n.system_opt}</th>
80
+					                </tr>
81
+				                </thead>
82
+				                <tbody></tbody>
83
+				                <tfoot></tfoot>
84
+							</table>
85
+						</div>
86
+					</div>
87
+				</div>
88
+			</div>
89
+	    </section>
90
+	</div>
91
+	
92
+	<!-- footer -->
93
+	<@netCommon.commonFooter />
94
+</div>
95
+
96
+<!-- job新增.模态框 -->
97
+<div class="modal fade" id="addModal" tabindex="-1" role="dialog"  aria-hidden="true">
98
+	<div class="modal-dialog modal-lg">
99
+		<div class="modal-content">
100
+			<div class="modal-header">
101
+            	<h4 class="modal-title" >${I18n.jobinfo_field_add}</h4>
102
+         	</div>
103
+         	<div class="modal-body">
104
+				<form class="form-horizontal form" role="form" >
105
+					<div class="form-group">
106
+						<label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
107
+						<div class="col-sm-4">
108
+							<select class="form-control" name="jobGroup" >
109
+		            			<#list JobGroupList as group>
110
+		            				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
111
+		            			</#list>
112
+		                  	</select>
113
+						</div>
114
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
115
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}" maxlength="50" ></div>
116
+					</div>
117
+                    <div class="form-group">
118
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
119
+                        <div class="col-sm-4">
120
+                            <select class="form-control" name="executorRouteStrategy" >
121
+							<#list ExecutorRouteStrategyEnum as item>
122
+                                <option value="${item}" >${item.title}</option>
123
+							</#list>
124
+                            </select>
125
+                        </div>
126
+                        <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
127
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
128
+                    </div>
129
+                    <div class="form-group">
130
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
131
+                        <div class="col-sm-4">
132
+                            <select class="form-control glueType" name="glueType" >
133
+								<#list GlueTypeEnum as item>
134
+									<option value="${item}" >${item.desc}</option>
135
+								</#list>
136
+                            </select>
137
+                        </div>
138
+                        <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="red">*</font></label>
139
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
140
+                    </div>
141
+                    <div class="form-group">
142
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
143
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}" maxlength="512" ></div>
144
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
145
+                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
146
+                    </div>
147
+                    <div class="form-group">
148
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font color="black">*</font></label>
149
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout" placeholder="${I18n.jobinfo_field_executorTimeout_placeholder}" maxlength="6" ></div>
150
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
151
+                        <div class="col-sm-4">
152
+                            <select class="form-control" name="executorBlockStrategy" >
153
+								<#list ExecutorBlockStrategyEnum as item>
154
+                                    <option value="${item}" >${item.title}</option>
155
+                                </#list>
156
+                            </select>
157
+                        </div>
158
+                    </div>
159
+                    <div class="form-group">
160
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailRetryCount}<font color="black">*</font></label>
161
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorFailRetryCount" placeholder="${I18n.jobinfo_field_executorFailRetryCount_placeholder}" maxlength="4" ></div>
162
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
163
+                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></div>
164
+                    </div>
165
+					<div class="form-group">
166
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
167
+                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}" maxlength="50" ></div>
168
+					</div>
169
+
170
+                    <hr>
171
+					<div class="form-group">
172
+						<div class="col-sm-offset-3 col-sm-6">
173
+							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
174
+							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
175
+						</div>
176
+					</div>
177
+
178
+<input type="hidden" name="glueRemark" value="GLUE代码初始化" >
179
+<textarea name="glueSource" style="display:none;" ></textarea>
180
+<textarea class="glueSource_java" style="display:none;" >
181
+package com.xxl.job.service.handler;
182
+
183
+import com.xxl.job.core.log.XxlJobLogger;
184
+import com.xxl.job.core.biz.model.ReturnT;
185
+import com.xxl.job.core.handler.IJobHandler;
186
+
187
+public class DemoGlueJobHandler extends IJobHandler {
188
+
189
+	@Override
190
+	public ReturnT<String> execute(String param) throws Exception {
191
+		XxlJobLogger.log("XXL-JOB, Hello World.");
192
+		return ReturnT.SUCCESS;
193
+	}
194
+
195
+}
196
+</textarea>
197
+<textarea class="glueSource_shell" style="display:none;" >
198
+#!/bin/bash
199
+echo "xxl-job: hello shell"
200
+
201
+echo "${I18n.jobinfo_script_location}:$0"
202
+echo "${I18n.jobinfo_field_executorparam}:$1"
203
+echo "${I18n.jobinfo_shard_index} = $2"
204
+echo "${I18n.jobinfo_shard_total} = $3"
205
+<#--echo "参数数量:$#"
206
+for param in $*
207
+do
208
+    echo "参数 : $param"
209
+    sleep 1s
210
+done-->
211
+
212
+echo "Good bye!"
213
+exit 0
214
+</textarea>
215
+<textarea class="glueSource_python" style="display:none;" >
216
+#!/usr/bin/python
217
+# -*- coding: UTF-8 -*-
218
+import time
219
+import sys
220
+
221
+print "xxl-job: hello python"
222
+
223
+print "${I18n.jobinfo_script_location}:", sys.argv[0]
224
+print "${I18n.jobinfo_field_executorparam}:", sys.argv[1]
225
+print "${I18n.jobinfo_shard_index}:", sys.argv[2]
226
+print "${I18n.jobinfo_shard_total}:", sys.argv[3]
227
+<#--for i in range(1, len(sys.argv)):
228
+	time.sleep(1)
229
+	print "参数", i, sys.argv[i]-->
230
+
231
+print "Good bye!"
232
+exit(0)
233
+<#--
234
+import logging
235
+logging.basicConfig(level=logging.DEBUG)
236
+logging.info("脚本文件:" + sys.argv[0])
237
+-->
238
+</textarea>
239
+<#--这里有问题,新建一个运行模式为 php 的任务后,GLUE 中没有下边的 php 代码-->
240
+<textarea class="glueSource_php" style="display:none;" >
241
+<?php
242
+
243
+    echo "xxl-job: hello php  \n";
244
+
245
+    echo "${I18n.jobinfo_script_location}:$argv[0]  \n";
246
+    echo "${I18n.jobinfo_field_executorparam}:$argv[1]  \n";
247
+    echo "${I18n.jobinfo_shard_index} = $argv[2]  \n";
248
+    echo "${I18n.jobinfo_shard_total} = $argv[3]  \n";
249
+
250
+    echo "Good bye!  \n";
251
+    exit(0);
252
+
253
+?>
254
+</textarea>
255
+<textarea class="glueSource_nodejs" style="display:none;" >
256
+#!/usr/bin/env node
257
+console.log("xxl-job: hello nodejs")
258
+
259
+var arguments = process.argv
260
+
261
+console.log("${I18n.jobinfo_script_location}: " + arguments[1])
262
+console.log("${I18n.jobinfo_field_executorparam}: " + arguments[2])
263
+console.log("${I18n.jobinfo_shard_index}: " + arguments[3])
264
+console.log("${I18n.jobinfo_shard_total}: " + arguments[4])
265
+<#--for (var i = 2; i < arguments.length; i++){
266
+	console.log("参数 %s = %s", (i-1), arguments[i]);
267
+}-->
268
+
269
+console.log("Good bye!")
270
+process.exit(0)
271
+</textarea>		
272
+				</form>
273
+         	</div>
274
+		</div>
275
+	</div>
276
+</div>
277
+
278
+<!-- 更新.模态框 -->
279
+<div class="modal fade" id="updateModal" tabindex="-1" role="dialog"  aria-hidden="true">
280
+	<div class="modal-dialog modal-lg">
281
+		<div class="modal-content">
282
+			<div class="modal-header">
283
+            	<h4 class="modal-title" >${I18n.jobinfo_field_update}</h4>
284
+         	</div>
285
+         	<div class="modal-body">
286
+				<form class="form-horizontal form" role="form" >
287
+					<div class="form-group">
288
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
289
+                        <div class="col-sm-4">
290
+                            <select class="form-control" name="jobGroup" disabled >
291
+							<#list JobGroupList as group>
292
+                                <option value="${group.id}" >${group.title}</option>
293
+							</#list>
294
+                            </select>
295
+                        </div>
296
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
297
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}" maxlength="50" ></div>
298
+                    </div>
299
+                    <div class="form-group">
300
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
301
+                        <div class="col-sm-4">
302
+                            <select class="form-control" name="executorRouteStrategy" >
303
+							<#list ExecutorRouteStrategyEnum as item>
304
+                                <option value="${item}" >${item.title}</option>
305
+							</#list>
306
+                            </select>
307
+                        </div>
308
+                        <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
309
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
310
+                    </div>
311
+                    <div class="form-group">
312
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
313
+                        <div class="col-sm-4">
314
+                            <select class="form-control glueType" name="glueType" disabled >
315
+							<#list GlueTypeEnum as item>
316
+                                <option value="${item}" >${item.desc}</option>
317
+							</#list>
318
+                            </select>
319
+                        </div>
320
+                        <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="red">*</font></label>
321
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
322
+                    </div>
323
+                    <div class="form-group">
324
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
325
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}" maxlength="512" ></div>
326
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
327
+                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
328
+                    </div>
329
+                    <div class="form-group">
330
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font color="black">*</font></label>
331
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout" placeholder="${I18n.jobinfo_field_executorTimeout_placeholder}" maxlength="6" ></div>
332
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
333
+                        <div class="col-sm-4">
334
+                            <select class="form-control" name="executorBlockStrategy" >
335
+							<#list ExecutorBlockStrategyEnum as item>
336
+                                <option value="${item}" >${item.title}</option>
337
+                            </#list>
338
+                            </select>
339
+                        </div>
340
+                    </div>
341
+                    <div class="form-group">
342
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailRetryCount}<font color="black">*</font></label>
343
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorFailRetryCount" placeholder="${I18n.jobinfo_field_executorFailRetryCount_placeholder}" maxlength="4" ></div>
344
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
345
+                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></div>
346
+
347
+                    </div>
348
+                    <div class="form-group">
349
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
350
+                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}" maxlength="50" ></div>
351
+                    </div>
352
+
353
+					<hr>
354
+					<div class="form-group">
355
+                        <div class="col-sm-offset-3 col-sm-6">
356
+							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
357
+							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
358
+                            <input type="hidden" name="id" >
359
+						</div>
360
+					</div>
361
+
362
+				</form>
363
+         	</div>
364
+		</div>
365
+	</div>
366
+</div>
367
+
368
+<@netCommon.commonScript />
369
+<!-- DataTables -->
370
+<script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
371
+<script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
372
+<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
373
+<!-- moment -->
374
+<script src="${request.contextPath}/static/adminlte/plugins/daterangepicker/moment.min.js"></script>
375
+<script src="${request.contextPath}/static/js/jobinfo.index.1.js"></script>
376
+</body>
377
+</html>

文件差異過大導致無法顯示
+ 505 - 505
xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js