Browse Source

调度信息迁移至DB中

xueli.xue 9 years ago
parent
commit
2bc58f34ed

+ 72 - 8
xxl-job-admin/src/main/java/com/xxl/job/controller/JobController.java View File

7
 import java.util.Map.Entry;
7
 import java.util.Map.Entry;
8
 import java.util.Set;
8
 import java.util.Set;
9
 
9
 
10
+import javax.annotation.Resource;
10
 import javax.servlet.http.HttpServletRequest;
11
 import javax.servlet.http.HttpServletRequest;
11
 
12
 
12
 import org.apache.commons.lang.StringUtils;
13
 import org.apache.commons.lang.StringUtils;
16
 import org.springframework.stereotype.Controller;
17
 import org.springframework.stereotype.Controller;
17
 import org.springframework.ui.Model;
18
 import org.springframework.ui.Model;
18
 import org.springframework.web.bind.annotation.RequestMapping;
19
 import org.springframework.web.bind.annotation.RequestMapping;
20
+import org.springframework.web.bind.annotation.RequestParam;
19
 import org.springframework.web.bind.annotation.ResponseBody;
21
 import org.springframework.web.bind.annotation.ResponseBody;
20
 
22
 
21
 import com.xxl.job.client.handler.HandlerRepository;
23
 import com.xxl.job.client.handler.HandlerRepository;
24
+import com.xxl.job.client.util.JacksonUtil;
22
 import com.xxl.job.core.model.ReturnT;
25
 import com.xxl.job.core.model.ReturnT;
26
+import com.xxl.job.core.model.XxlJobInfo;
23
 import com.xxl.job.core.util.DynamicSchedulerUtil;
27
 import com.xxl.job.core.util.DynamicSchedulerUtil;
28
+import com.xxl.job.dao.IXxlJobInfoDao;
24
 import com.xxl.job.service.job.HttpJobBean;
29
 import com.xxl.job.service.job.HttpJobBean;
25
 
30
 
26
 /**
31
 /**
31
 @RequestMapping("/job")
36
 @RequestMapping("/job")
32
 public class JobController {
37
 public class JobController {
33
 	
38
 	
39
+	@Resource
40
+	private IXxlJobInfoDao xxlJobInfoDao;
41
+	
34
 	@RequestMapping
42
 	@RequestMapping
35
 	public String index(Model model) {
43
 	public String index(Model model) {
36
-		List<Map<String, Object>> jobList = DynamicSchedulerUtil.getJobList();
37
-		model.addAttribute("jobList", jobList);
44
+		//List<Map<String, Object>> jobList = DynamicSchedulerUtil.getJobList();
45
+		//model.addAttribute("jobList", jobList);
38
 		return "job/index";
46
 		return "job/index";
39
 	}
47
 	}
40
 	
48
 	
49
+	@RequestMapping("/pageList")
50
+	@ResponseBody
51
+	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
52
+			@RequestParam(required = false, defaultValue = "10") int length,
53
+			String jobName, String filterTime) {
54
+		
55
+		// page list
56
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobName, null, null);
57
+		int list_count = xxlJobInfoDao.pageListCount(start, length, jobName, null, null);
58
+		
59
+		// fill job info
60
+		if (list!=null && list.size()>0) {
61
+			for (XxlJobInfo jobInfo : list) {
62
+				DynamicSchedulerUtil.fillJobInfo(jobInfo);
63
+			}
64
+		}
65
+		
66
+		// package result
67
+		Map<String, Object> maps = new HashMap<String, Object>();
68
+	    maps.put("recordsTotal", list_count);		// 总记录数
69
+	    maps.put("recordsFiltered", list_count);	// 过滤后的总记录数
70
+	    maps.put("data", list);  					// 分页列表
71
+		return maps;
72
+	}
73
+	
41
 	@RequestMapping("/add")
74
 	@RequestMapping("/add")
42
 	@ResponseBody
75
 	@ResponseBody
43
 	public ReturnT<String> add(HttpServletRequest request) {
76
 	public ReturnT<String> add(HttpServletRequest request) {
44
 		String triggerKeyName = null;
77
 		String triggerKeyName = null;
45
 		String cronExpression = null;
78
 		String cronExpression = null;
46
-		Map<String, Object> jobData = new HashMap<String, Object>();
79
+		Map<String, String> jobData = new HashMap<String, String>();
47
 		
80
 		
48
 		try {
81
 		try {
49
 			request.setCharacterEncoding("utf-8");
82
 			request.setCharacterEncoding("utf-8");
58
 			} else if (param.getKey().equals("cronExpression")) {
91
 			} else if (param.getKey().equals("cronExpression")) {
59
 				cronExpression = param.getValue()[0];
92
 				cronExpression = param.getValue()[0];
60
 			} else {
93
 			} else {
61
-				jobData.put(param.getKey(), param.getValue().length>0?param.getValue()[0]:param.getValue());
94
+				jobData.put(param.getKey(), (String) (param.getValue().length>0?param.getValue()[0]:param.getValue()));
62
 			}
95
 			}
63
 		}
96
 		}
64
 		
97
 		
90
 		Class<? extends Job> jobClass = HttpJobBean.class;
123
 		Class<? extends Job> jobClass = HttpJobBean.class;
91
 		
124
 		
92
 		try {
125
 		try {
93
-			boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, jobData);
126
+			// add job 2 quartz
127
+			boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, null);
94
 			if (!result) {
128
 			if (!result) {
95
 				return new ReturnT<String>(500, "任务ID重复,请更换确认");
129
 				return new ReturnT<String>(500, "任务ID重复,请更换确认");
96
 			}
130
 			}
131
+			// Backup to the database
132
+			XxlJobInfo jobInfo = new XxlJobInfo();
133
+			jobInfo.setJobName(triggerKeyName);
134
+			jobInfo.setJobCron(cronExpression);
135
+			jobInfo.setJobClass(jobClass.getName());
136
+			jobInfo.setJobData(JacksonUtil.writeValueAsString(jobData));
137
+			xxlJobInfoDao.save(jobInfo);
138
+			
97
 			return ReturnT.SUCCESS;
139
 			return ReturnT.SUCCESS;
98
 		} catch (SchedulerException e) {
140
 		} catch (SchedulerException e) {
99
 			e.printStackTrace();
141
 			e.printStackTrace();
117
 		}
159
 		}
118
 		try {
160
 		try {
119
 			DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression);
161
 			DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression);
162
+			
163
+			// update
164
+			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
165
+			if (jobInfo!=null) {
166
+				jobInfo.setJobCron(cronExpression);
167
+				xxlJobInfoDao.update(jobInfo);
168
+			}
120
 			return ReturnT.SUCCESS;
169
 			return ReturnT.SUCCESS;
121
 		} catch (SchedulerException e) {
170
 		} catch (SchedulerException e) {
122
 			e.printStackTrace();
171
 			e.printStackTrace();
128
 	@ResponseBody
177
 	@ResponseBody
129
 	public ReturnT<String> remove(String triggerKeyName) {
178
 	public ReturnT<String> remove(String triggerKeyName) {
130
 		try {
179
 		try {
131
-			DynamicSchedulerUtil.removeJob(triggerKeyName);
132
-			return ReturnT.SUCCESS;
180
+			if (triggerKeyName!=null) {
181
+				DynamicSchedulerUtil.removeJob(triggerKeyName);
182
+				xxlJobInfoDao.delete(triggerKeyName);
183
+				return ReturnT.SUCCESS;
184
+			}
133
 		} catch (SchedulerException e) {
185
 		} catch (SchedulerException e) {
134
 			e.printStackTrace();
186
 			e.printStackTrace();
135
-			return ReturnT.FAIL;
136
 		}
187
 		}
188
+		return ReturnT.FAIL;
137
 	}
189
 	}
138
 	
190
 	
139
 	@RequestMapping("/pause")
191
 	@RequestMapping("/pause")
141
 	public ReturnT<String> pause(String triggerKeyName) {
193
 	public ReturnT<String> pause(String triggerKeyName) {
142
 		try {
194
 		try {
143
 			DynamicSchedulerUtil.pauseJob(triggerKeyName);
195
 			DynamicSchedulerUtil.pauseJob(triggerKeyName);
196
+			// update
197
+			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
198
+			if (jobInfo!=null) {
199
+				jobInfo.setJobStatus("PAUSED");
200
+				xxlJobInfoDao.update(jobInfo);
201
+			}
144
 			return ReturnT.SUCCESS;
202
 			return ReturnT.SUCCESS;
145
 		} catch (SchedulerException e) {
203
 		} catch (SchedulerException e) {
146
 			e.printStackTrace();
204
 			e.printStackTrace();
153
 	public ReturnT<String> resume(String triggerKeyName) {
211
 	public ReturnT<String> resume(String triggerKeyName) {
154
 		try {
212
 		try {
155
 			DynamicSchedulerUtil.resumeJob(triggerKeyName);
213
 			DynamicSchedulerUtil.resumeJob(triggerKeyName);
214
+			// update
215
+			XxlJobInfo jobInfo = xxlJobInfoDao.load(triggerKeyName);
216
+			if (jobInfo!=null) {
217
+				jobInfo.setJobStatus("NORMAL");
218
+				xxlJobInfoDao.update(jobInfo);
219
+			}
156
 			return ReturnT.SUCCESS;
220
 			return ReturnT.SUCCESS;
157
 		} catch (SchedulerException e) {
221
 		} catch (SchedulerException e) {
158
 			e.printStackTrace();
222
 			e.printStackTrace();

+ 36 - 2
xxl-job-admin/src/main/java/com/xxl/job/core/util/DynamicSchedulerUtil.java View File

23
 import org.quartz.TriggerBuilder;
23
 import org.quartz.TriggerBuilder;
24
 import org.quartz.TriggerKey;
24
 import org.quartz.TriggerKey;
25
 import org.quartz.impl.matchers.GroupMatcher;
25
 import org.quartz.impl.matchers.GroupMatcher;
26
+import org.quartz.impl.triggers.CronTriggerImpl;
26
 import org.slf4j.Logger;
27
 import org.slf4j.Logger;
27
 import org.slf4j.LoggerFactory;
28
 import org.slf4j.LoggerFactory;
28
 import org.springframework.beans.factory.InitializingBean;
29
 import org.springframework.beans.factory.InitializingBean;
29
 import org.springframework.util.Assert;
30
 import org.springframework.util.Assert;
30
 
31
 
32
+import com.xxl.job.core.model.XxlJobInfo;
33
+import com.xxl.job.dao.IXxlJobInfoDao;
31
 import com.xxl.job.dao.IXxlJobLogDao;
34
 import com.xxl.job.dao.IXxlJobLogDao;
32
 
35
 
33
 /**
36
 /**
43
     public void setXxlJobLogDao(IXxlJobLogDao xxlJobLogDao) {
46
     public void setXxlJobLogDao(IXxlJobLogDao xxlJobLogDao) {
44
 		DynamicSchedulerUtil.xxlJobLogDao = xxlJobLogDao;
47
 		DynamicSchedulerUtil.xxlJobLogDao = xxlJobLogDao;
45
 	}
48
 	}
46
-    public static IXxlJobLogDao getXxlJobLogDao() {
47
-		return xxlJobLogDao;
49
+    // xxlJobInfoDao
50
+    public static IXxlJobInfoDao xxlJobInfoDao;
51
+    @Resource
52
+    public void setXxlJobInfoDao(IXxlJobInfoDao xxlJobInfoDao) {
53
+		DynamicSchedulerUtil.xxlJobInfoDao = xxlJobInfoDao;
48
 	}
54
 	}
49
     
55
     
50
     // Scheduler
56
     // Scheduler
90
 		}
96
 		}
91
 		return jobList;
97
 		return jobList;
92
 	}
98
 	}
99
+	
100
+	// fill job info
101
+	public static void fillJobInfo(XxlJobInfo jobInfo) {
102
+		// TriggerKey : name + group
103
+        TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getJobName(), Scheduler.DEFAULT_GROUP);
104
+        JobKey jobKey = new JobKey(jobInfo.getJobName(), Scheduler.DEFAULT_GROUP);
105
+        try {
106
+			Trigger trigger = scheduler.getTrigger(triggerKey);
107
+			JobDetail jobDetail = scheduler.getJobDetail(jobKey);
108
+			TriggerState triggerState = scheduler.getTriggerState(triggerKey);
109
+			
110
+			// parse params
111
+			if (trigger!=null && trigger instanceof CronTriggerImpl) {
112
+				String cronExpression = ((CronTriggerImpl) trigger).getCronExpression();
113
+				jobInfo.setJobCron(cronExpression);
114
+			}
115
+			if (jobDetail!=null) {
116
+				String jobClass = jobDetail.getJobClass().getName();
117
+				jobInfo.setJobClass(jobClass);
118
+			}
119
+			if (triggerState!=null) {
120
+				jobInfo.setJobStatus(triggerState.name());
121
+			}
122
+			
123
+		} catch (SchedulerException e) {
124
+			e.printStackTrace();
125
+		}
126
+	}
93
 
127
 
94
 	// addJob 新增
128
 	// addJob 新增
95
     public static boolean addJob(String triggerKeyName, String cronExpression, Class<? extends Job> jobClass, Map<String, Object> jobData) throws SchedulerException {
129
     public static boolean addJob(String triggerKeyName, String cronExpression, Class<? extends Job> jobClass, Map<String, Object> jobData) throws SchedulerException {

+ 4 - 0
xxl-job-admin/src/main/java/com/xxl/job/dao/IXxlJobLogDao.java View File

6
 
6
 
7
 import com.xxl.job.core.model.XxlJobLog;
7
 import com.xxl.job.core.model.XxlJobLog;
8
 
8
 
9
+/**
10
+ * job log
11
+ * @author xuxueli 2016-1-12 18:03:06
12
+ */
9
 public interface IXxlJobLogDao {
13
 public interface IXxlJobLogDao {
10
 	
14
 	
11
 	public int save(XxlJobLog xxlJobLog);
15
 	public int save(XxlJobLog xxlJobLog);

+ 4 - 0
xxl-job-admin/src/main/java/com/xxl/job/dao/impl/XxlJobLogDaoImpl.java View File

12
 import com.xxl.job.core.model.XxlJobLog;
12
 import com.xxl.job.core.model.XxlJobLog;
13
 import com.xxl.job.dao.IXxlJobLogDao;
13
 import com.xxl.job.dao.IXxlJobLogDao;
14
 
14
 
15
+/**
16
+ * job log
17
+ * @author xuxueli 2016-1-12 18:03:06
18
+ */
15
 @Repository
19
 @Repository
16
 public class XxlJobLogDaoImpl implements IXxlJobLogDao {
20
 public class XxlJobLogDaoImpl implements IXxlJobLogDao {
17
 	
21
 	

+ 8 - 10
xxl-job-admin/src/main/java/com/xxl/job/service/job/HttpJobBean.java View File

3
 import java.util.Date;
3
 import java.util.Date;
4
 import java.util.HashMap;
4
 import java.util.HashMap;
5
 import java.util.Map;
5
 import java.util.Map;
6
-import java.util.Map.Entry;
7
 
6
 
8
 import org.apache.commons.lang.StringUtils;
7
 import org.apache.commons.lang.StringUtils;
9
 import org.quartz.JobExecutionContext;
8
 import org.quartz.JobExecutionContext;
16
 import com.xxl.job.client.handler.HandlerRepository;
15
 import com.xxl.job.client.handler.HandlerRepository;
17
 import com.xxl.job.client.util.HttpUtil;
16
 import com.xxl.job.client.util.HttpUtil;
18
 import com.xxl.job.client.util.JacksonUtil;
17
 import com.xxl.job.client.util.JacksonUtil;
18
+import com.xxl.job.core.model.XxlJobInfo;
19
 import com.xxl.job.core.model.XxlJobLog;
19
 import com.xxl.job.core.model.XxlJobLog;
20
 import com.xxl.job.core.util.DynamicSchedulerUtil;
20
 import com.xxl.job.core.util.DynamicSchedulerUtil;
21
 import com.xxl.job.core.util.PropertiesUtil;
21
 import com.xxl.job.core.util.PropertiesUtil;
27
 public class HttpJobBean extends QuartzJobBean {
27
 public class HttpJobBean extends QuartzJobBean {
28
 	private static Logger logger = LoggerFactory.getLogger(HttpJobBean.class);
28
 	private static Logger logger = LoggerFactory.getLogger(HttpJobBean.class);
29
 
29
 
30
+	@SuppressWarnings("unchecked")
30
 	@Override
31
 	@Override
31
 	protected void executeInternal(JobExecutionContext context)
32
 	protected void executeInternal(JobExecutionContext context)
32
 			throws JobExecutionException {
33
 			throws JobExecutionException {
33
-		
34
 		String triggerKey = context.getTrigger().getJobKey().getName();
34
 		String triggerKey = context.getTrigger().getJobKey().getName();
35
+		
35
 		// jobDataMap 2 params
36
 		// jobDataMap 2 params
36
-		Map<String, Object> jobDataMap = context.getMergedJobDataMap().getWrappedMap();
37
 		Map<String, String> params = new HashMap<String, String>();
37
 		Map<String, String> params = new HashMap<String, String>();
38
-		if (jobDataMap!=null && jobDataMap.size()>0) {
39
-			for (Entry<String, Object> item : jobDataMap.entrySet()) {
40
-				params.put(item.getKey(), String.valueOf(item.getValue()));
41
-			}
38
+		XxlJobInfo jobInfo = DynamicSchedulerUtil.xxlJobInfoDao.load(triggerKey);
39
+		if (jobInfo!=null && jobInfo.getJobData()!=null) {
40
+			params = JacksonUtil.readValue(jobInfo.getJobData(), Map.class);
42
 		}
41
 		}
43
 		
42
 		
44
 		// corn
43
 		// corn
53
 		jobLog.setJobName(triggerKey);
52
 		jobLog.setJobName(triggerKey);
54
 		jobLog.setJobCron(cornExp);
53
 		jobLog.setJobCron(cornExp);
55
 		jobLog.setJobClass(HttpJobBean.class.getName());
54
 		jobLog.setJobClass(HttpJobBean.class.getName());
56
-		jobLog.setJobData(JacksonUtil.writeValueAsString(params));
55
+		jobLog.setJobData(jobInfo.getJobData());
57
 		DynamicSchedulerUtil.xxlJobLogDao.save(jobLog);
56
 		DynamicSchedulerUtil.xxlJobLogDao.save(jobLog);
58
 		logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog);
57
 		logger.info(">>>>>>>>>>> xxl-job trigger start, jobLog:{}", jobLog);
59
 		
58
 		
70
 		jobLog.setTriggerTime(new Date());
69
 		jobLog.setTriggerTime(new Date());
71
 		jobLog.setTriggerStatus(HttpUtil.FAIL);
70
 		jobLog.setTriggerStatus(HttpUtil.FAIL);
72
 		jobLog.setTriggerMsg("[responseMsg]:"+responseMsg+"<br>[exceptionMsg]:"+exceptionMsg);
71
 		jobLog.setTriggerMsg("[responseMsg]:"+responseMsg+"<br>[exceptionMsg]:"+exceptionMsg);
73
-		if (StringUtils.isNotBlank(responseMsg)) {
74
-			@SuppressWarnings("unchecked")
72
+		if (StringUtils.isNotBlank(responseMsg) && responseMsg.indexOf("{")>-1 ) {
75
 			Map<String, String> responseMap = JacksonUtil.readValue(responseMsg, Map.class);
73
 			Map<String, String> responseMap = JacksonUtil.readValue(responseMsg, Map.class);
76
 			if (responseMap!=null && StringUtils.isNotBlank(responseMap.get(HttpUtil.status))) {
74
 			if (responseMap!=null && StringUtils.isNotBlank(responseMap.get(HttpUtil.status))) {
77
 				jobLog.setTriggerStatus(responseMap.get(HttpUtil.status));
75
 				jobLog.setTriggerStatus(responseMap.get(HttpUtil.status));

+ 1 - 1
xxl-job-admin/src/main/resources/applicationcontext-database.xml View File

31
 	
31
 	
32
 	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
32
 	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
33
 		<property name="dataSource" ref="dataSource" />
33
 		<property name="dataSource" ref="dataSource" />
34
-		<property name="mapperLocations" value="classpath*:com/xxl/job/core/model/mapper/*.xml"/>
34
+		<property name="mapperLocations" value="classpath*:mybatis-mapper/*.xml"/>
35
 	</bean>
35
 	</bean>
36
     
36
     
37
     <!-- scope must be "prototype" when junit -->
37
     <!-- scope must be "prototype" when junit -->

xxl-job-admin/src/main/java/com/xxl/job/core/model/mapper/XxlJobLogMapper.xml → xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml View File


+ 0 - 2
xxl-job-admin/src/main/webapp/WEB-INF/template/help.ftl View File

68
 	
68
 	
69
 	<!-- footer -->
69
 	<!-- footer -->
70
 	<@netCommon.commonFooter />
70
 	<@netCommon.commonFooter />
71
-	<!-- control -->
72
-	<@netCommon.commonControl />
73
 </div>
71
 </div>
74
 <@netCommon.commonScript />
72
 <@netCommon.commonScript />
75
 </body>
73
 </body>

+ 53 - 26
xxl-job-admin/src/main/webapp/WEB-INF/template/job/index.ftl View File

28
 		
28
 		
29
 		<!-- Main content -->
29
 		<!-- Main content -->
30
 	    <section class="content">
30
 	    <section class="content">
31
+	    
32
+	    	<div class="row">
33
+	            <div class="col-xs-4">
34
+	              	<div class="input-group">
35
+	                	<span class="input-group-addon">
36
+	                  		jobName
37
+	                	</span>
38
+	                	<input type="text" class="form-control" id="jobName" value="${jobName}" autocomplete="on" >
39
+	              	</div>
40
+	            </div>
41
+	            <div class="col-xs-2">
42
+	            	<button class="btn btn-block btn-info" id="searchBtn">搜索</button>
43
+	            </div>
44
+	            <div class="col-xs-2">
45
+	            	<button class="btn btn-block btn-success add" type="button">+新增任务</button>
46
+	            </div>
47
+          	</div>
48
+	    	
31
 			<div class="row">
49
 			<div class="row">
32
 				<div class="col-xs-12">
50
 				<div class="col-xs-12">
33
 					<div class="box">
51
 					<div class="box">
34
 			            <div class="box-header">
52
 			            <div class="box-header">
35
 			            	<h3 class="box-title">调度列表</h3>
53
 			            	<h3 class="box-title">调度列表</h3>
36
-			            	<button class="btn btn-info btn-xs add" type="button">+新增任务</button>
37
 			            </div>
54
 			            </div>
38
 			            <div class="box-body">
55
 			            <div class="box-body">
39
 			              	<table id="job_list" class="table table-bordered table-striped">
56
 			              	<table id="job_list" class="table table-bordered table-striped">
40
 				                <thead>
57
 				                <thead>
41
 					            	<tr>
58
 					            	<tr>
42
-					                	<th>调度key</th>
43
-					                  	<th>cron</th>
44
-					                  	<!--<th>类路径</th>-->
59
+					            		<th>id</th>
60
+					                	<th>任务Key</th>
61
+					                  	<th>任务Cron</th>
62
+					                  	<th>任务Class</th>
63
+					                  	<th>状态Status</th>
45
 					                  	<th>参数</th>
64
 					                  	<th>参数</th>
46
-					                  	<th>状态</th>
65
+					                  	<th>addTime</th>
66
+					                  	<th>updateTime</th>
47
 					                  	<th>操作</th>
67
 					                  	<th>操作</th>
48
 					                </tr>
68
 					                </tr>
49
 				                </thead>
69
 				                </thead>
50
 				                <tbody>
70
 				                <tbody>
71
+				                	<#--
51
 			                		<#if jobList?exists && jobList?size gt 0>
72
 			                		<#if jobList?exists && jobList?size gt 0>
52
 									<#list jobList as item>
73
 									<#list jobList as item>
53
 									<tr>
74
 									<tr>
54
 					            		<td>${item['TriggerKey'].name}</td>
75
 					            		<td>${item['TriggerKey'].name}</td>
55
 					                  	<td>${item['Trigger'].cronExpression}</td>
76
 					                  	<td>${item['Trigger'].cronExpression}</td>
56
-					                  	<!--<td>${item['JobDetail'].jobClass}</td>-->
77
+					                  	<td>${item['JobDetail'].jobClass}</td>
57
 					                  	<td>
78
 					                  	<td>
58
 					                  		<#assign jobDataMap = item['JobDetail'].jobDataMap />
79
 					                  		<#assign jobDataMap = item['JobDetail'].jobDataMap />
59
 					                  		<#if jobDataMap?exists && jobDataMap?keys?size gt 0>
80
 					                  		<#if jobDataMap?exists && jobDataMap?keys?size gt 0>
89
 					                </tr>
110
 					                </tr>
90
 									</#list>
111
 									</#list>
91
 									</#if>
112
 									</#if>
113
+									
114
+									-->
92
 				                </tbody>
115
 				                </tbody>
93
-				                <tfoot>
94
-					            	<tr>
95
-					                  	<th>调度key</th>
96
-					                  	<th>cron</th>
97
-					                  	<!--<th>类路径</th>-->
98
-					                  	<th>参数</th>
99
-					                  	<th>状态</th>
100
-					                  	<th>操作</th>
101
-					                </tr>
102
-				                </tfoot>
116
+				                <tfoot></tfoot>
103
 							</table>
117
 							</table>
104
 						</div>
118
 						</div>
105
 					</div>
119
 					</div>
110
 	
124
 	
111
 	<!-- footer -->
125
 	<!-- footer -->
112
 	<@netCommon.commonFooter />
126
 	<@netCommon.commonFooter />
113
-	<!-- control -->
114
-	<@netCommon.commonControl />
115
 </div>
127
 </div>
116
 
128
 
117
 <!-- job新增.模态框 -->
129
 <!-- job新增.模态框 -->
129
 					</div>
141
 					</div>
130
 					<div class="form-group">
142
 					<div class="form-group">
131
 						<label for="lastname" class="col-sm-3 control-label">任务Corn</label>
143
 						<label for="lastname" class="col-sm-3 control-label">任务Corn</label>
132
-						<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn[允许修改]" maxlength="100" ></div>
144
+						<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div>
133
 					</div>
145
 					</div>
134
 					<div class="form-group">
146
 					<div class="form-group">
135
 						<label for="lastname" class="col-sm-3 control-label">任务描述</label>
147
 						<label for="lastname" class="col-sm-3 control-label">任务描述</label>
136
-						<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述[不支持修改]" maxlength="200" ></div>
148
+						<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述" maxlength="200" ></div>
137
 					</div>
149
 					</div>
138
 					<div class="form-group">
150
 					<div class="form-group">
139
 						<label for="lastname" class="col-sm-3 control-label">任务URL</label>
151
 						<label for="lastname" class="col-sm-3 control-label">任务URL</label>
140
-						<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL[不支持修改]" maxlength="200" ></div>
152
+						<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL" maxlength="200" ></div>
141
 					</div>
153
 					</div>
142
 					<div class="form-group">
154
 					<div class="form-group">
143
 						<label for="lastname" class="col-sm-3 control-label">任务handler</label>
155
 						<label for="lastname" class="col-sm-3 control-label">任务handler</label>
144
-						<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler[不支持修改]" maxlength="200" ></div>
156
+						<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler" maxlength="200" ></div>
145
 					</div>
157
 					</div>
146
 					<div class="form-group">
158
 					<div class="form-group">
147
 						<div class="col-sm-offset-3 col-sm-9">
159
 						<div class="col-sm-offset-3 col-sm-9">
166
          	<div class="modal-body">
178
          	<div class="modal-body">
167
 				<form class="form-horizontal form" role="form" >
179
 				<form class="form-horizontal form" role="form" >
168
 					<div class="form-group">
180
 					<div class="form-group">
169
-						<label for="firstname" class="col-sm-2 control-label">任务Key</label>
170
-						<div class="col-sm-10"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" readonly ></div>
181
+						<label for="firstname" class="col-sm-3 control-label">任务Key</label>
182
+						<div class="col-sm-9"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" readonly ></div>
183
+					</div>
184
+					<div class="form-group">
185
+						<label for="lastname" class="col-sm-3 control-label">任务Corn</label>
186
+						<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div>
171
 					</div>
187
 					</div>
172
 					<div class="form-group">
188
 					<div class="form-group">
173
-						<label for="lastname" class="col-sm-2 control-label">任务Corn</label>
174
-						<div class="col-sm-10"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div>
189
+						<label for="lastname" class="col-sm-3 control-label">任务描述</label>
190
+						<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述" maxlength="200" ></div>
191
+					</div>
192
+					<div class="form-group">
193
+						<label for="lastname" class="col-sm-3 control-label">任务URL</label>
194
+						<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL" maxlength="200" ></div>
195
+					</div>
196
+					<div class="form-group">
197
+						<label for="lastname" class="col-sm-3 control-label">任务handler</label>
198
+						<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler" maxlength="200" ></div>
175
 					</div>
199
 					</div>
176
 					<div class="form-group">
200
 					<div class="form-group">
177
 						<div class="col-sm-offset-2 col-sm-10">
201
 						<div class="col-sm-offset-2 col-sm-10">
191
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
215
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
192
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
216
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
193
 <script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
217
 <script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
218
+<!-- daterangepicker -->
219
+<script src="${request.contextPath}/static/adminlte/plugins/daterangepicker/moment.min.js"></script>
220
+<script src="${request.contextPath}/static/adminlte/plugins/daterangepicker/daterangepicker.js"></script>
194
 <script>var base_url = '${request.contextPath}';</script>
221
 <script>var base_url = '${request.contextPath}';</script>
195
 <script src="${request.contextPath}/static/js/job.index.1.js"></script>
222
 <script src="${request.contextPath}/static/js/job.index.1.js"></script>
196
 </body>
223
 </body>

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

84
 	
84
 	
85
 	<!-- footer -->
85
 	<!-- footer -->
86
 	<@netCommon.commonFooter />
86
 	<@netCommon.commonFooter />
87
-	<!-- control -->
88
-	<@netCommon.commonControl />
89
 </div>
87
 </div>
90
 
88
 
91
 <@netCommon.commonScript />
89
 <@netCommon.commonScript />

+ 109 - 9
xxl-job-admin/src/main/webapp/static/js/job.index.1.js View File

1
 $(function() {
1
 $(function() {
2
 	// init date tables
2
 	// init date tables
3
-	$("#job_list").DataTable({
3
+	var jobTable = $("#job_list").dataTable({
4
+		"deferRender": true,
5
+		"processing" : true, 
6
+	    "serverSide": true,
7
+		"ajax": {
8
+			url: base_url + "/job/pageList",
9
+	        data : function ( d ) {
10
+                d.jobName = $('#jobName').val()
11
+            }
12
+	    },
13
+	    //"scrollX": true,	// X轴滚动条,取消自适应
14
+	    "columns": [
15
+	                { "data": 'id', "bSortable": false, "visible" : false},
16
+	                { "data": 'jobName', "bSortable": false},
17
+	                { "data": 'jobCron', "bSortable": false, "visible" : true},
18
+	                { "data": 'jobClass', "bSortable": false, "visible" : false},
19
+	                { "data": 'jobStatus', "bSortable": false, "visible" : true},
20
+	                { "data": 'jobData', "bSortable": false, "visible" : true},
21
+	                { 
22
+	                	"data": 'addTime', 
23
+	                	"bSortable": false, 
24
+	                	"render": function ( data, type, row ) {
25
+	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
26
+	                	}
27
+	                },
28
+	                { 
29
+	                	"data": 'updateTime', 
30
+	                	"bSortable": false, 
31
+	                	"render": function ( data, type, row ) {
32
+	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
33
+	                	}
34
+	                },
35
+	                { "data": '操作' , "bSortable": false,
36
+	                	"render": function ( data, type, row ) {
37
+	                		return function(){
38
+	                			// status
39
+	                			var pause_resume = "";
40
+	                			if ('NORMAL' == row.jobStatus) {
41
+	                				pause_resume = '<button class="btn btn-info btn-xs job_operate" type="job_pause" type="button">暂停</button>  ';
42
+								} else if ('PAUSED' == row.jobStatus){
43
+									pause_resume = '<button class="btn btn-info btn-xs job_operate" type="job_resume" type="button">恢复</button>  ';
44
+								}
45
+	                			// log url
46
+	                			var logUrl = base_url +'/joblog?jobName='+ row.jobName;
47
+	                			
48
+	                			// job data
49
+	                			var jobDataMap = eval('(' + row.jobData + ')');
50
+	                			
51
+	                			var html = '<p jobName="'+ row.jobName +'" '+
52
+	                							' cronExpression="'+ row.jobCron +'" '+
53
+	                							' job_desc="'+jobDataMap.job_desc +'" '+
54
+	                							' job_url="'+ jobDataMap.job_url +'" '+
55
+	                							' handleName="'+ jobDataMap.handleName +'" '+
56
+	                							'>'+
57
+	                					pause_resume +
58
+										'<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行</button>  '+
59
+										'<button class="btn btn-info btn-xs update" type="button">更新corn</button>  '+
60
+									  	'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>  '+
61
+									  	'<button class="btn btn-warning btn-xs" type="job_del" type="button" '+
62
+									  		'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button>'+
63
+									'</p>';
64
+									
65
+	                			
66
+	                			return html;
67
+	                		};
68
+	                	}
69
+	                }
70
+	            ],
71
+	    "searching": false,
72
+	    "ordering": true,
4
 		"language" : {
73
 		"language" : {
5
 			"sProcessing" : "处理中...",
74
 			"sProcessing" : "处理中...",
6
 			"sLengthMenu" : "每页 _MENU_ 条记录",
75
 			"sLengthMenu" : "每页 _MENU_ 条记录",
27
 		}
96
 		}
28
 	});
97
 	});
29
 	
98
 	
99
+	// 搜索按钮
100
+	$('#searchBtn').on('click', function(){
101
+		jobTable.fnDraw();
102
+	});
103
+	
30
 	// job operate
104
 	// job operate
31
-	$(".job_operate").click(function() {
105
+	$("#job_list").on('click', '.job_operate',function() {
32
 		var typeName;
106
 		var typeName;
33
 		var url;
107
 		var url;
34
 		var type = $(this).attr("type");
108
 		var type = $(this).attr("type");
48
 			return;
122
 			return;
49
 		}
123
 		}
50
 		
124
 		
51
-		var name = $(this).parent('p').attr("name");
52
-		var group = $(this).parent('p').attr("group");
125
+		var name = $(this).parent('p').attr("jobName");
53
 		
126
 		
54
 		ComConfirm.show("确认" + typeName + "?", function(){
127
 		ComConfirm.show("确认" + typeName + "?", function(){
55
 			$.ajax({
128
 			$.ajax({
56
 				type : 'POST',
129
 				type : 'POST',
57
 				url : url,
130
 				url : url,
58
 				data : {
131
 				data : {
59
-					"triggerKeyName" :	name,
60
-					"group"			 :	group
132
+					"triggerKeyName" :	name
61
 				},
133
 				},
62
 				dataType : "json",
134
 				dataType : "json",
63
 				success : function(data){
135
 				success : function(data){
64
 					if (data.code == 200) {
136
 					if (data.code == 200) {
65
 						ComAlert.show(1, typeName + "成功", function(){
137
 						ComAlert.show(1, typeName + "成功", function(){
66
-							window.location.reload();
138
+							//window.location.reload();
139
+							jobTable.fnDraw();
67
 						});
140
 						});
68
 					} else {
141
 					} else {
69
 						ComAlert.show(1, typeName + "失败");
142
 						ComAlert.show(1, typeName + "失败");
215
 	});
288
 	});
216
 	
289
 	
217
 	// 更新
290
 	// 更新
218
-	$(".update").click(function(){
219
-		$("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("name"));
291
+	$("#job_list").on('click', '.update',function() {
292
+		$("#updateModal .form input[name='triggerKeyName']").val($(this).parent('p').attr("jobName"));
220
 		$("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression"));
293
 		$("#updateModal .form input[name='cronExpression']").val($(this).parent('p').attr("cronExpression"));
294
+		$("#updateModal .form input[name='job_desc']").val($(this).parent('p').attr("job_desc"));
295
+		$("#updateModal .form input[name='job_url']").val($(this).parent('p').attr("job_url"));
296
+		$("#updateModal .form input[name='handleName']").val($(this).parent('p').attr("handleName"));
221
 		$('#updateModal').modal({backdrop: false, keyboard: false}).modal('show');
297
 		$('#updateModal').modal({backdrop: false, keyboard: false}).modal('show');
222
 	});
298
 	});
223
 	var updateModalValidate = $("#updateModal .form").validate({
299
 	var updateModalValidate = $("#updateModal .form").validate({
233
             cronExpression : {  
309
             cronExpression : {  
234
             	required : true ,
310
             	required : true ,
235
                 maxlength: 100
311
                 maxlength: 100
312
+            },  
313
+            job_desc : {  
314
+            	required : true ,
315
+                maxlength: 200
316
+            },
317
+            job_url : {
318
+            	required : true ,
319
+                maxlength: 200
320
+            },
321
+            handleName : {
322
+            	required : true ,
323
+                maxlength: 200
236
             }
324
             }
237
         }, 
325
         }, 
238
         messages : {  
326
         messages : {  
244
             cronExpression : {
332
             cronExpression : {
245
             	required :"请输入“任务Corn”."  ,
333
             	required :"请输入“任务Corn”."  ,
246
                 maxlength:"“任务Corn”不应超过100位"
334
                 maxlength:"“任务Corn”不应超过100位"
335
+            },  
336
+            job_desc : {
337
+            	required :"请输入“任务描述”."  ,
338
+                maxlength:"“任务描述”长度不应超过200位"
339
+            },  
340
+            job_url : {
341
+            	required :"请输入“任务URL”."  ,
342
+                maxlength:"“任务URL”长度不应超过200位"
343
+            },
344
+            handleName : {
345
+            	required : "请输入“任务handler”."  ,
346
+                maxlength: "“任务handler”长度不应超过200位"
247
             }
347
             }
248
         }, 
348
         }, 
249
 		highlight : function(element) {  
349
 		highlight : function(element) {  

+ 4 - 4
xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js View File

29
 	                { "data": 'triggerStatus', "bSortable": false},
29
 	                { "data": 'triggerStatus', "bSortable": false},
30
 	                { "data": 'triggerMsg',"bSortable": false,
30
 	                { "data": 'triggerMsg',"bSortable": false,
31
 	                	"render": function ( data, type, row ) {
31
 	                	"render": function ( data, type, row ) {
32
-	                		return data?'<a class="logTips" title="'+ data +'">调度日志</a>':"无";
32
+	                		return data?'<a class="logTips" href="javascript:;" >调度日志<span style="display:none;">'+ data +'</span></a>':"无";
33
 	                	}
33
 	                	}
34
 	                },
34
 	                },
35
 	                { 
35
 	                { 
42
 	                { "data": 'handleStatus',"bSortable": false},
42
 	                { "data": 'handleStatus',"bSortable": false},
43
 	                { "data": 'handleMsg' , "bSortable": false,
43
 	                { "data": 'handleMsg' , "bSortable": false,
44
 	                	"render": function ( data, type, row ) {
44
 	                	"render": function ( data, type, row ) {
45
-	                		return data?'<a class="logTips" title="'+ data +'">执行日志</a>':"无";
45
+	                		return data?'<a class="logTips" href="javascript:;" >执行日志<span style="display:none;">'+ data +'</span></a>':"无";
46
 	                	}
46
 	                	}
47
 	                }
47
 	                }
48
 	            ],
48
 	            ],
76
 	
76
 	
77
 	// 日志弹框提示
77
 	// 日志弹框提示
78
 	$('#joblog_list').on('click', '.logTips', function(){
78
 	$('#joblog_list').on('click', '.logTips', function(){
79
-		var title = $(this).attr('title');
80
-		ComAlertTec.show(title);
79
+		var msg = $(this).find('span').html();
80
+		ComAlertTec.show(msg);
81
 	});
81
 	});
82
 	
82
 	
83
 	// 过滤时间
83
 	// 过滤时间

+ 3 - 0
xxl-job-client/src/main/java/com/xxl/job/client/util/HttpUtil.java View File

64
 				responseMsg = EntityUtils.toString(entity, "UTF-8");
64
 				responseMsg = EntityUtils.toString(entity, "UTF-8");
65
 				EntityUtils.consume(entity);
65
 				EntityUtils.consume(entity);
66
 			}
66
 			}
67
+			if (response.getStatusLine().getStatusCode() != 200) {
68
+				exceptionMsg = "response.getStatusLine().getStatusCode() = " + response.getStatusLine().getStatusCode();
69
+			}
67
 		} catch (Exception e) {
70
 		} catch (Exception e) {
68
 			e.printStackTrace();
71
 			e.printStackTrace();
69
 			StringWriter out = new StringWriter();
72
 			StringWriter out = new StringWriter();