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

基于xxl-job点评内部定制版本

上级 9c791795
## dianping-job[任务调度平台]
分层: 调度和任务拆分, 支持动态扩充, 管理任务
1. 调度模块:dianping-job-web, 维护任务的调度信息,负责定时/周期性的发出调度请求.
2. 任务模块:dianping-job-client, 具体的任务逻辑,负责接收调度模块的调度请求,执行任务逻辑.
3. 通讯模块:dianping-job-client, 负责调度模块和任务模块之间的通讯.
说明:
1. 调度模块集群部署[HA].
2. 任务串行执行.
3. 记录调度日系.
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dianping</groupId>
<artifactId>dianping-job</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>dianping-job-client-demo</artifactId>
<packaging>war</packaging>
<name>dianping-job-client-demo</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>3.2.14.RELEASE</spring.version>
</properties>
<dependencies>
<!-- springframe start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- springframe end -->
<!-- aspectjweaver (support spring aop) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<!-- dianping-job-client -->
<dependency>
<groupId>com.dianping</groupId>
<artifactId>dianping-job-client</artifactId>
<version>1.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
</plugins>
</build>
</project>
\ No newline at end of file
package com.dianping.job.service.handler;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.dianping.job.client.handler.HandlerRepository;
import com.dianping.job.client.handler.IJobHandler;
/**
* demo job handler
* @author xuxueli 2015-12-19 19:43:36
*/
@Service
public class DemoJobHandler extends IJobHandler {
private static transient Logger logger = LoggerFactory.getLogger(DemoJobHandler.class);
public DemoJobHandler() {
HandlerRepository.regist(DemoJobHandler.class.getName(), this);
}
@Override
public JobHandleStatus handle(Map<String, String> param) throws Exception {
logger.info(" ... param:{}", param);
TimeUnit.SECONDS.sleep(new Random().nextInt(5));
return JobHandleStatus.SUCCESS;
}
public static void main(String[] args) {
System.out.println(DemoJobHandler.class.getName());
System.out.println(DemoJobHandler.class);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config />
<context:component-scan base-package="com.dianping.job.service" />
</beans>
\ No newline at end of file
log4j.rootLogger=info,console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d - dianping-job-client-demo - %p [%c] - <%m>%n
log4j.appender.logFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logFile.File=${catalina.base}/logs/dianping-job-client-demo.log
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=%d - dianping-job-client-demo - %p [%c] - <%m>%n
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationcontext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Dianping Job Servlet -->
<servlet>
<servlet-name>DianpingJobServlet</servlet-name>
<servlet-class>com.dianping.job.client.netcom.http.DianpingJobServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DianpingJobServlet</servlet-name>
<url-pattern>/dianpingJobServlet</url-pattern>
</servlet-mapping>
<display-name>clock-job-web</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
\ No newline at end of file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dianping</groupId>
<artifactId>dianping-job</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>dianping-job-client</artifactId>
<version>1.0.1-SNAPSHOT</version>
<name>dianping-job-client</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<!-- jackson -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF8</encoding>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>jdk-1.6</id>
<activation>
<activeByDefault>true</activeByDefault>
<jdk>1.6</jdk>
</activation>
<properties>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.compiler.compilerVersion>1.6</maven.compiler.compilerVersion>
</properties>
</profile>
</profiles>
</project>
\ No newline at end of file
package com.dianping.job.client.handler;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.dianping.job.client.handler.IJobHandler.JobHandleStatus;
import com.dianping.job.client.handler.IJobHandler.JobTriggerStatus;
/**
* handler repository
* @author xuxueli 2015-12-19 19:28:44
*/
public class HandlerRepository {
private static Logger logger = LoggerFactory.getLogger(HandlerRepository.class);
public static final String triggerUuid = "triggerUuid";
public static final String handleName = "handleName";
// handler class map
private static ConcurrentHashMap<String, IJobHandler> handlerClassMap = new ConcurrentHashMap<String, IJobHandler>();
// handler thread map
private static ConcurrentHashMap<String, HandlerThread> handlerTreadMap = new ConcurrentHashMap<String, HandlerThread>();
// handler date queue map
private static ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>> handlerDataQueueMap = new ConcurrentHashMap<String, LinkedBlockingQueue<Map<String, String>>>();
// regist handler
public static void regist(String handleName, IJobHandler handler){
handlerClassMap.put(handleName, handler);
LinkedBlockingQueue<Map<String, String>> handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
handlerDataQueueMap.put(handleName, handlerDateQueue);
HandlerThread handlerThread = new HandlerThread(handleName);
handlerThread.start();
handlerTreadMap.put(handleName, handlerThread);
logger.info(">>>>>>>>>>> dianping-job regist handler success, handleName:{}, handler:{}, handlerDateQueue:{}, handlerThread:{}",
new Object[]{handleName, handler, handlerDateQueue, handlerThread});
}
// create handler thread
static class HandlerThread extends Thread{
private String _handleName;
public HandlerThread(String _handleName) {
this._handleName = _handleName;
}
public boolean isValid = true;
public void stopThread(){
isValid = false;
}
@Override
public void run() {
while (isValid) {
LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(_handleName);
Map<String, String> handlerDate = handlerDateQueue.poll();
if (handlerDate!=null) {
JobHandleStatus jobHandleStatus = null;
String jobHandleDetail = null;
try {
IJobHandler handler = handlerClassMap.get(_handleName);
jobHandleStatus = handler.handle(handlerDate);
} catch (Exception e) {
e.printStackTrace();
jobHandleStatus = JobHandleStatus.FAIL;
StringWriter out = new StringWriter();
e.printStackTrace(new PrintWriter(out));
jobHandleDetail = out.toString();
}
String _triggerUuid = handlerDate.get(triggerUuid);
logger.info("<<<<<<<<<<< dianping-job thread handle, _triggerUuid:{}, _handleName:{}, jobHandleStatus:{}, jobHandleDetail:{}, thread:{}",
new Object[]{_triggerUuid, _handleName, jobHandleStatus, jobHandleDetail, this});
} else {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
// handler push to queue
public static String pushHandleQueue(String triggerUuid, String handleName, Map<String, String> _param) {
JobTriggerStatus _triggerStatus = JobTriggerStatus.FAIL;
String _triggerDetailLog = null;
try {
if (handleName!=null && handleName.trim().length()>0) {
IJobHandler handler = handlerClassMap.get(handleName);
if (handler != null) {
// push data to handler queue
LinkedBlockingQueue<Map<String, String>> handlerDateQueue = handlerDataQueueMap.get(handleName);
if (handlerDateQueue == null) {
handlerDateQueue = new LinkedBlockingQueue<Map<String, String>>();
handlerDataQueueMap.put(handleName, handlerDateQueue);
logger.info(">>>>>>>>>>> dianping-job handler lazy fresh handlerDateQueue, handleName:{}, handler:{}, handlerDateQueue:{}",
new Object[]{handleName, handler, handlerDateQueue});
}
handlerDateQueue.offer(_param);
// check handler thread
HandlerThread handlerThreadOld = handlerTreadMap.get(handleName);
if (!handlerThreadOld.isAlive()) {
handlerThreadOld.stopThread();
HandlerThread handlerThread = new HandlerThread(handleName);
handlerThread.start();
handlerTreadMap.put(handleName, handlerThread);
logger.info(">>>>>>>>>>> dianping-job handler lazy fresh thread, handleName:{}, handler:{}, handlerThread:{}",
new Object[]{handleName, handler, handlerThread});
}
_triggerStatus = JobTriggerStatus.SUCCESS;
}
}
} catch (Exception e) {
e.printStackTrace();
_triggerStatus = JobTriggerStatus.FAIL;
StringWriter out = new StringWriter();
e.printStackTrace(new PrintWriter(out));
_triggerDetailLog = out.toString();
}
logger.info(">>>>>>>>>>> dianping-job pushHandleQueue, triggerUuid:{}, handleName, _triggerStatus:{}, _triggerDetailLog",
new Object[]{triggerUuid, handleName, _triggerStatus, _triggerDetailLog});
String responseBody = _triggerStatus.name();
if (JobTriggerStatus.SUCCESS != _triggerStatus) {
responseBody += "#" + _triggerDetailLog;
}
return responseBody;
/**
* trigger-log :
* trigger side : store trigger-info >> trigger request >> update trigger-response-status
* job side : handler trigger >> update trigger-result
*/
}
}
package com.dianping.job.client.handler;
import java.util.Map;
/**
* remote job handler
* @author xuxueli 2015-12-19 19:06:38
*/
public abstract class IJobHandler extends HandlerRepository{
/**
* job handler <br><br>
* the return Object will be and stored
* @param param
* @return
* @throws Exception
*/
public abstract JobHandleStatus handle(Map<String, String> param) throws Exception;
public enum JobHandleStatus{
/**
* handle success
*/
SUCCESS,
/**
* handle fail
*/
FAIL,
/**
* handle not found
*/
NOT_FOUND;
}
public enum JobTriggerStatus{
/**
* trigger success
*/
SUCCESS,
/**
* trigger fail
*/
FAIL;
}
}
package com.dianping.job.client.netcom.http;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dianping.job.client.handler.HandlerRepository;
/**
* remote job client on http
* @author xuxueli 2015-12-19 18:36:47
*/
public class DianpingJobServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* Default constructor.
*/
public DianpingJobServlet() {
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
Map<String, String> _param = new HashMap<String, String>();
if (request.getParameterMap()!=null && request.getParameterMap().size()>0) {
for (Object paramKey : request.getParameterMap().keySet()) {
if (paramKey!=null) {
String paramKeyStr = paramKey.toString();
_param.put(paramKeyStr, request.getParameter(paramKeyStr));
}
}
}
String _triggerUuid = _param.get(HandlerRepository.triggerUuid);
String _handleName = _param.get(HandlerRepository.handleName);
String resp = HandlerRepository.pushHandleQueue(_triggerUuid, _handleName, _param);
response.getWriter().append(resp);
return;
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
package com.dianping.job.client.util;
import java.io.IOException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
/**
* http util to send hex data
* @author xuxueli
* @version 2015-11-28 15:30:59
*/
public class HttpUtil {
public static String sendHex(String reqURL, String queryString) {
String responseContent = null;
if (queryString != null && !queryString.equals("")) {
reqURL = reqURL + "?data=" + queryString;
}
HttpGet httpGet = new HttpGet(reqURL);
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(3000).setConnectTimeout(3000).build();
httpGet.setConfig(requestConfig);
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
if (null != entity) {
responseContent = EntityUtils.toString(entity, "UTF-8");
EntityUtils.consume(entity);
if (responseContent!=null) {
responseContent = responseContent.trim();
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
httpGet.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return responseContent;
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dianping</groupId>
<artifactId>dianping-job</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>dianping-job-web</artifactId>
<version>1.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>dianping-job-web</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>3.2.14.RELEASE</spring.version>
</properties>
<dependencies>
<!-- springframe start -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- springframe end -->
<!-- aspectjweaver (support spring aop) -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<!-- jackson (support spring json) -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<!-- freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.20</version>
</dependency>
<!-- commons-beanutils -->
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.2</version>
</dependency>
<!-- commons-lang -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.2.8</version>
</dependency>
<!-- mysql-connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.29</version>
</dependency>
<!-- quartz :quartz-2.2.1/c3p0-0.9.1.1/slf4j-api-1.6.6 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<!-- httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.3.6</version>
</dependency>
<!-- dianping-job-client -->
<dependency>
<groupId>com.dianping</groupId>
<artifactId>dianping-job-client</artifactId>
<version>1.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<encoding>UTF8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.2</version>
<configuration>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.dianping.job.controller;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.quartz.CronExpression;
import org.quartz.Job;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.dianping.job.client.handler.HandlerRepository;
import com.dianping.job.core.model.ReturnT;
import com.dianping.job.core.util.DynamicSchedulerUtil;
import com.dianping.job.service.job.HttpJobBean;
/**
* index controller
* @author xuxueli 2015-12-19 16:13:16
*/
@Controller
public class IndexController {
@RequestMapping("")
public String index(Model model) {
List<Map<String, Object>> jobList = DynamicSchedulerUtil.getJobList();
model.addAttribute("jobList", jobList);
return "job/index";
}
@RequestMapping("/help")
public String help(Model model) {
return "job/help";
}
@RequestMapping("/job/add")
@ResponseBody
public ReturnT<String> add(HttpServletRequest request) {
String triggerKeyName = null;
String cronExpression = null;
Map<String, Object> jobData = new HashMap<String, Object>();
try {
request.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
@SuppressWarnings("unchecked")
Set<Map.Entry<String, String[]>> paramSet = request.getParameterMap().entrySet();
for (Entry<String, String[]> param : paramSet) {
if (param.getKey().equals("triggerKeyName")) {
triggerKeyName = param.getValue()[0];
} else if (param.getKey().equals("cronExpression")) {
cronExpression = param.getValue()[0];
} else {
jobData.put(param.getKey(), param.getValue().length>0?param.getValue()[0]:param.getValue());
}
}
// triggerKeyName
if (StringUtils.isBlank(triggerKeyName)) {
return new ReturnT<String>(500, "请输入“任务key”");
}
// cronExpression
if (StringUtils.isBlank(cronExpression)) {
return new ReturnT<String>(500, "请输入“任务corn”");
}
if (!CronExpression.isValidExpression(cronExpression)) {
return new ReturnT<String>(500, "“任务corn”不合法");
}
// jobData
if (jobData.get(DynamicSchedulerUtil.job_desc)==null || jobData.get(DynamicSchedulerUtil.job_desc).toString().trim().length()==0) {
return new ReturnT<String>(500, "请输入“任务描述”");
}
if (jobData.get(DynamicSchedulerUtil.job_url)==null || jobData.get(DynamicSchedulerUtil.job_url).toString().trim().length()==0) {
return new ReturnT<String>(500, "请输入“任务URL”");
}
if (jobData.get(HandlerRepository.handleName)==null || jobData.get(HandlerRepository.handleName).toString().trim().length()==0) {
return new ReturnT<String>(500, "请输入“任务handler”");
}
// jobClass
Class<? extends Job> jobClass = HttpJobBean.class;
try {
boolean result = DynamicSchedulerUtil.addJob(triggerKeyName, cronExpression, jobClass, jobData);
if (!result) {
return new ReturnT<String>(500, "任务ID重复,请更换确认");
}
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
}
return ReturnT.FAIL;
}
@RequestMapping("/job/reschedule")
@ResponseBody
public ReturnT<String> reschedule(String triggerKeyName, String cronExpression) {
// triggerKeyName
if (StringUtils.isBlank(triggerKeyName)) {
return new ReturnT<String>(500, "请输入“任务key”");
}
// cronExpression
if (StringUtils.isBlank(cronExpression)) {
return new ReturnT<String>(500, "请输入“任务corn”");
}
if (!CronExpression.isValidExpression(cronExpression)) {
return new ReturnT<String>(500, "“任务corn”不合法");
}
try {
DynamicSchedulerUtil.rescheduleJob(triggerKeyName, cronExpression);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
}
return ReturnT.FAIL;
}
@RequestMapping("/job/remove")
@ResponseBody
public ReturnT<String> remove(String triggerKeyName) {
try {
DynamicSchedulerUtil.removeJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
@RequestMapping("/job/pause")
@ResponseBody
public ReturnT<String> pause(String triggerKeyName) {
try {
DynamicSchedulerUtil.pauseJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
@RequestMapping("/job/resume")
@ResponseBody
public ReturnT<String> resume(String triggerKeyName) {
try {
DynamicSchedulerUtil.resumeJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
@RequestMapping("/job/trigger")
@ResponseBody
public ReturnT<String> triggerJob(String triggerKeyName) {
try {
DynamicSchedulerUtil.triggerJob(triggerKeyName);
return ReturnT.SUCCESS;
} catch (SchedulerException e) {
e.printStackTrace();
return ReturnT.FAIL;
}
}
}
package com.dianping.job.core.model;
import java.util.Date;
/**
* dianping job log, used to track trigger process
* @author xuxueli 2015-12-19 23:19:09
*/
public class DianpingJobLog {
private String jobTriggerUuid;
private String jobHandleName;
// trigger info
private Date triggerTime;
private String triggerStatus;
private String triggerDetailLog;
// handle info
private Date handleTime;
private String handleStatus;
private String handleDetailLog;
public String getJobTriggerUuid() {
return jobTriggerUuid;
}
public void setJobTriggerUuid(String jobTriggerUuid) {
this.jobTriggerUuid = jobTriggerUuid;
}
public String getJobHandleName() {
return jobHandleName;
}
public void setJobHandleName(String jobHandleName) {
this.jobHandleName = jobHandleName;
}
public Date getTriggerTime() {
return triggerTime;
}
public void setTriggerTime(Date triggerTime) {
this.triggerTime = triggerTime;
}
public String getTriggerStatus() {
return triggerStatus;
}
public void setTriggerStatus(String triggerStatus) {
this.triggerStatus = triggerStatus;
}
public String getTriggerDetailLog() {
return triggerDetailLog;
}
public void setTriggerDetailLog(String triggerDetailLog) {
this.triggerDetailLog = triggerDetailLog;
}
public Date getHandleTime() {
return handleTime;
}
public void setHandleTime(Date handleTime) {
this.handleTime = handleTime;
}
public String getHandleStatus() {
return handleStatus;
}
public void setHandleStatus(String handleStatus) {
this.handleStatus = handleStatus;
}
public String getHandleDetailLog() {
return handleDetailLog;
}
public void setHandleDetailLog(String handleDetailLog) {
this.handleDetailLog = handleDetailLog;
}
@Override
public String toString() {
return "DianpingJobLog [jobTriggerUuid=" + jobTriggerUuid + ", jobHandleName=" + jobHandleName
+ ", triggerTime=" + triggerTime + ", triggerStatus=" + triggerStatus + ", triggerDetailLog="
+ triggerDetailLog + ", handleTime=" + handleTime + ", handleStatus=" + handleStatus
+ ", handleDetailLog=" + handleDetailLog + "]";
}
}
package com.dianping.job.core.model;
/**
* common return
* @author xuxueli 2015-12-4 16:32:31
* @param <T>
*/
public class ReturnT<T> {
public static final ReturnT<String> SUCCESS = new ReturnT<String>(null);
public static final ReturnT<String> FAIL = new ReturnT<String>(500, null);
private int code;
private String msg;
private T content;
public ReturnT(int code, String msg) {
this.code = code;
this.msg = msg;
}
public ReturnT(T content) {
this.code = 200;
this.content = content;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
@Override
public String toString() {
return "ReturnT [code=" + code + ", msg=" + msg + ", content="
+ content + "]";
}
}
package com.dianping.job.core.util;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* base quartz scheduler util
* @author xuxueli 2015-12-19 16:13:53
*/
public final class DynamicSchedulerUtil implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(DynamicSchedulerUtil.class);
// Scheduler
private static Scheduler scheduler;
public static void setScheduler(Scheduler scheduler) {
DynamicSchedulerUtil.scheduler = scheduler;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(scheduler, "quartz scheduler is null");
logger.info(">>>>>>>>> init quartz scheduler success.[{}]", scheduler);
}
// getJobKeys
public static List<Map<String, Object>> getJobList(){
List<Map<String, Object>> jobList = new ArrayList<Map<String,Object>>();
try {
if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
return null;
}
String groupName = scheduler.getJobGroupNames().get(0);
Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
if (jobKeys!=null && jobKeys.size()>0) {
for (JobKey jobKey : jobKeys) {
TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
Trigger trigger = scheduler.getTrigger(triggerKey);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
TriggerState triggerState = scheduler.getTriggerState(triggerKey);
Map<String, Object> jobMap = new HashMap<String, Object>();
jobMap.put("TriggerKey", triggerKey);
jobMap.put("Trigger", trigger);
jobMap.put("JobDetail", jobDetail);
jobMap.put("TriggerState", triggerState);
jobList.add(jobMap);
}
}
} catch (SchedulerException e) {
e.printStackTrace();
return null;
}
return jobList;
}
public static final String job_desc = "job_desc";
public static final String job_url = "job_url";
// addJob 新增
public static boolean addJob(String triggerKeyName, String cronExpression, Class<? extends Job> jobClass, Map<String, Object> jobData) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
// TriggerKey valid if_exists
if (scheduler.checkExists(triggerKey)) {
Trigger trigger = scheduler.getTrigger(triggerKey);
logger.info(">>>>>>>>> Already exist trigger [" + trigger + "] by key [" + triggerKey + "] in Scheduler");
return false;
}
// CronTrigger : TriggerKey + cronExpression
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
// JobDetail : jobClass
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(triggerKeyName, group).build();
if (jobData!=null && jobData.size() > 0) {
JobDataMap jobDataMap = jobDetail.getJobDataMap();
jobDataMap.putAll(jobData); // JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
}
// schedule : jobDetail + cronTrigger
Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
logger.info(">>>>>>>>>>> addJob success, jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date);
return true;
}
// reschedule 重置cron
public static boolean rescheduleJob(String triggerKeyName, String cronExpression) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
// CronTrigger : TriggerKey + cronExpression
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
Date date = scheduler.rescheduleJob(triggerKey, cronTrigger);
result = true;
logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}, cronExpression:{}, date:{}", triggerKey, cronExpression, date);
} else {
logger.info(">>>>>>>>>>> resumeJob fail, triggerKey:{}, cronExpression:{}", triggerKey, cronExpression);
}
return result;
}
// unscheduleJob 删除
public static boolean removeJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
result = scheduler.unscheduleJob(triggerKey);
}
logger.info(">>>>>>>>>>> removeJob, triggerKey:{}, result [{}]", triggerKey, result);
return result;
}
// Pause 暂停
public static boolean pauseJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
scheduler.pauseTrigger(triggerKey);
result = true;
logger.info(">>>>>>>>>>> pauseJob success, triggerKey:{}", triggerKey);
} else {
logger.info(">>>>>>>>>>> pauseJob fail, triggerKey:{}", triggerKey);
}
return result;
}
// resume 重启
public static boolean resumeJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
TriggerKey triggerKey = TriggerKey.triggerKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(triggerKey)) {
scheduler.resumeTrigger(triggerKey);
result = true;
logger.info(">>>>>>>>>>> resumeJob success, triggerKey:{}", triggerKey);
} else {
logger.info(">>>>>>>>>>> resumeJob fail, triggerKey:{}", triggerKey);
}
return result;
}
// run 执行一次
public static boolean triggerJob(String triggerKeyName) throws SchedulerException {
// TriggerKey : name + group
String group = Scheduler.DEFAULT_GROUP;
JobKey jobKey = JobKey.jobKey(triggerKeyName, group);
boolean result = false;
if (scheduler.checkExists(jobKey)) {
scheduler.triggerJob(jobKey);
result = true;
logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey);
} else {
logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey);
}
return result;
}
}
\ No newline at end of file
package com.dianping.job.service;
/**
* local trigger, only exists in local jvm
* @author xuxueli 2015-12-17 17:29:23
*/
public interface ITriggerService {
public void beat();
}
package com.dianping.job.service.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.dianping.job.service.ITriggerService;
/**
* local trigger, only exists in local jvm
* @author xuxueli 2015-12-17 17:31:24
*/
@Service("triggerService")
public class TriggerServiceImpl implements ITriggerService {
private static transient Logger logger = LoggerFactory.getLogger(TriggerServiceImpl.class);
public void beat() {
logger.info(">>>>>>>>>>> dianping-clock beat success.");
}
}
package com.dianping.job.service.job;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import com.dianping.job.client.handler.HandlerRepository;
import com.dianping.job.client.handler.IJobHandler.JobTriggerStatus;
import com.dianping.job.core.model.DianpingJobLog;
import com.dianping.job.core.util.DynamicSchedulerUtil;
/**
* http job bean
* @author xuxueli 2015-12-17 18:20:34
*/
public class HttpJobBean extends QuartzJobBean {
private static Logger logger = LoggerFactory.getLogger(HttpJobBean.class);
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
String triggerKey = context.getTrigger().getKey().getName();
String triggerGroup = context.getTrigger().getKey().getGroup();
Map<String, Object> jobDataMap = context.getMergedJobDataMap().getWrappedMap();
// jobDataMap 2 params
Map<String, String> params = new HashMap<String, String>();
if (jobDataMap!=null && jobDataMap.size()>0) {
for (Entry<String, Object> item : jobDataMap.entrySet()) {
params.put(item.getKey(), String.valueOf(item.getValue()));
}
}
String job_url = params.get(DynamicSchedulerUtil.job_url);
triggerPost(job_url, params);
logger.info(">>>>>>>>>>> dianping-clock run :jobId:{}, group:{}, jobDataMap:{}",
new Object[]{triggerKey, triggerGroup, jobDataMap});
}
public static void triggerPost(String reqURL, Map<String, String> params){
// save log
DianpingJobLog jobLog = new DianpingJobLog();
jobLog.setJobTriggerUuid(UUID.randomUUID().toString());
jobLog.setJobHandleName(params.get(HandlerRepository.handleName));
jobLog.setTriggerTime(new Date());
logger.info(">>>>>>>>>>> dianping-clock trigger start :jobLog:{}", jobLog);
// post
String responseContent = null;
HttpPost httpPost = new HttpPost(reqURL);
CloseableHttpClient httpClient = HttpClients.createDefault();
try{
if (params != null && !params.isEmpty()) {
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
for(Map.Entry<String,String> entry : params.entrySet()){
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
httpPost.setEntity(new UrlEncodedFormEntity(formParams, "UTF-8"));
}
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).build();
httpPost.setConfig(requestConfig);
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
if (null != entity) {
responseContent = EntityUtils.toString(entity, "UTF-8");
EntityUtils.consume(entity);
}
logger.info(">>>>>>>>>>> dianping-clock trigger ing :jobLog:{}, response:{}, responseContent:{}", jobLog, response, responseContent);
} catch (Exception e) {
e.printStackTrace();
StringWriter out = new StringWriter();
e.printStackTrace(new PrintWriter(out));
responseContent = out.toString();
} finally{
httpPost.releaseConnection();
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
// update trigger status
if (responseContent!=null && responseContent.equals(JobTriggerStatus.SUCCESS.name())) {
jobLog.setTriggerStatus(JobTriggerStatus.SUCCESS.name());
} else {
jobLog.setTriggerStatus(JobTriggerStatus.FAIL.name());
}
jobLog.setTriggerDetailLog(responseContent);
if (jobLog.getTriggerDetailLog()!=null && jobLog.getTriggerDetailLog().length()>1000) {
jobLog.setTriggerDetailLog(jobLog.getTriggerDetailLog().substring(0, 1000));
}
logger.info(">>>>>>>>>>> dianping-clock trigger end :jobLog:{}", jobLog);
}
}
public static void main(String[] args) {
String url = "http://localhost:8080/dianping-job-client-demo/dianpingJobServlet";
for (int i = 0; i < 3; i++) {
Map<String, String> params = new HashMap<String, String>();
params.put(HandlerRepository.handleName, "com.dianping.job.service.handler.DemoJobHandler");
params.put(HandlerRepository.triggerUuid, i+"");
params.put("key", i+"");
triggerPost(url, params);
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<context:annotation-config />
<context:component-scan base-package="com.dianping.job.service" />
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/template/" />
<property name="freemarkerSettings">
<bean class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:freemarker.properties" />
</bean>
</property>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="fileEncoding" value="utf-8" />
<property name="locations">
<list>
<value>classpath*:jdbc.properties</value>
</list>
</property>
</bean>
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.xxl.service.impl, com.xxl.dao.impl" />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${c3p0.driverClass}" />
<property name="jdbcUrl" value="${c3p0.url}" />
<property name="user" value="${c3p0.user}" />
<property name="password" value="${c3p0.password}" />
<property name="initialPoolSize" value="3" />
<property name="minPoolSize" value="2" />
<property name="maxPoolSize" value="10" />
<property name="maxIdleTime" value="60" />
<property name="acquireRetryDelay" value="1000" />
<property name="acquireRetryAttempts" value="10" />
<property name="preferredTestQuery" value="SELECT 1" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath*:com/xxl/core/model/mapper/*.xml"/>
</bean>
<!-- scope must be "prototype" when junit -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
<constructor-arg index="0" ref="sqlSessionFactory" />
</bean>
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="quartzScheduler" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="autoStartup" value="true" />
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties"/>
</bean>
<!-- 协同-调度器 -->
<bean id="dynamicSchedulerUtil" class="com.dianping.job.core.util.DynamicSchedulerUtil">
<!-- (轻易不要变更“调度器名称”, 任务创建时会绑定该“调度器名称”) -->
<property name="scheduler" ref="quartzScheduler"/>
</bean>
</beans>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean id="beatJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="triggerService" />
<property name="targetMethod" value="beat" />
<property name="concurrent" value="false" />
</bean>
<bean id="beatTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="beatJobDetail" />
<property name="cronExpression" value="0/10 * * * * ? *" />
</bean>
<!-- 进程-调度器 -->
<bean name="jvmQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<!-- <ref bean="beatTrigger" /> -->
</list>
</property>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="detail*" propagation="SUPPORTS" />
<tx:method name="visit*" propagation="SUPPORTS" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="find*" propagation="SUPPORTS" />
<tx:method name="check*" propagation="SUPPORTS" />
<tx:method name="list*" propagation="SUPPORTS" />
<tx:method name="*" propagation="REQUIRED" rollback-for="exception" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txoperation" expression="execution(* com.xxl.service.imp.*.*(..))" />
<aop:advisor pointcut-ref="txoperation" advice-ref="txAdvice" />
</aop:config>
</beans>
\ No newline at end of file
template_update_delay=0
default_encoding=UTF-8
output_encoding=UTF-8
locale=zh_CN
number_format=0.##########
date_format=yyyy-MM-dd
time_format=HH:mm:ss
datetime_format=yyyy-MM-dd HH:mm:s
classic_compatible=true
template_exception_handler=ignore
\ No newline at end of file
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.url=jdbc:mysql://localhost:3306/test?Unicode=true&amp;characterEncoding=UTF-8
c3p0.user=root
c3p0.password=root_pwd
\ No newline at end of file
log4j.rootLogger=info,console,logFile
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d - dianping-job-web - %p [%c] - <%m>%n
log4j.appender.logFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logFile.File=${catalina.base}/logs/dianping-job-web.log
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
log4j.appender.logFile.layout.ConversionPattern=%d - dianping-job-web - %p [%c] - <%m>%n
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# for cluster
org.quartz.jobStore.tablePrefix = WED_qrtz_
org.quartz.scheduler.instanceId: AUTO
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.isClustered: true
org.quartz.jobStore.clusterCheckinInterval: 1000
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.dianping.job.controller" />
<mvc:resources mapping="/favicon.ico" location="/favicon.ico" />
<mvc:resources mapping="/static/**" location="/static/" />
<mvc:resources mapping="/**/*.html" location="/" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.freemarker.FreeMarkerView" />
<property name="prefix" value="" />
<property name="suffix" value=".ftl" />
<property name="contentType" value="text/html;charset=UTF-8" />
<property name="exposeSpringMacroHelpers" value="true" />
<property name="exposeRequestAttributes" value="true" />
<property name="exposeSessionAttributes" value="true" />
<property name="requestContextAttribute" value="request" />
<property name="cache" value="true" />
<property name="order" value="0" />
</bean>
<!--
// 自定义拦截器,支持SSO登陆拦截
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.xxl.controller.interceptor.PermissionInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<bean id="exceptionResolver" class="com.xxl.controller.resolver.WebExceptionResolver" />
-->
</beans>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>应用程序异常 (500)</title>
<style type="text/css">
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog {
width: 80%;
padding: 1em 4em;
margin: 4em auto 0 auto;
border: 1px solid #ccc;
border-right-color: #999;
border-bottom-color: #999;
}
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
</style>
</head>
</head>
<body>
<div class="dialog">
<h1>应用程序异常</h1>
<p>抱歉!您访问的页面出现异常,请稍后重试或联系管理员。</p>
<p><a href="javascript:showErr();">详 情</a>
<a href="javascript:window.location.href='${request.contextPath}'">返 回</a>
</p>
<div style="display:none;text-align: left;" id="err">${exceptionMsg}</div>
</div>
<script type="text/javascript">
function showErr(){
document.getElementById("err").style.display = "";
}
</script>
</body>
</html>
\ No newline at end of file
<#macro commonStyle>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Tell the browser to be responsive to screen width -->
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<!-- Bootstrap 3.3.5 -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/bootstrap/css/bootstrap.min.css">
<!-- Font Awesome -->
<!-- <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"> -->
<link rel="stylesheet" href="${request.contextPath}/static/plugins/font-awesome-4.3.0/css/font-awesome.min.css">
<!-- Ionicons -->
<!-- <link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"> -->
<link rel="stylesheet" href="${request.contextPath}/static/plugins/ionicons-2.0.1/css/ionicons.min.css">
<!-- Theme style -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/AdminLTE.min.css">
<!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/skins/_all-skins.min.css">
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- scrollup -->
<link rel="stylesheet" href="${request.contextPath}/static/plugins/scrollup/image.css">
</#macro>
<#macro commonScript>
<!-- jQuery 2.1.4 -->
<script src="${request.contextPath}/static/adminlte/plugins/jQuery/jQuery-2.1.4.min.js"></script>
<!-- Bootstrap 3.3.5 -->
<script src="${request.contextPath}/static/adminlte/bootstrap/js/bootstrap.min.js"></script>
<!-- FastClick -->
<script src="${request.contextPath}/static/adminlte/plugins/fastclick/fastclick.js"></script>
<!-- AdminLTE App -->
<script src="${request.contextPath}/static/adminlte/dist/js/app.min.js"></script>
<!-- scrollup -->
<script src="${request.contextPath}/static/plugins/scrollup/jquery.scrollUp.min.js"></script>
<script src="${request.contextPath}/static/js/common.1.js"></script>
</#macro>
<#macro commonHeader>
<header class="main-header">
<a href="${request.contextPath}/" class="logo">
<span class="logo-mini"><b>X</b>XL</span>
<span class="logo-lg"><b>任务调度</b>中心</span>
</a>
<nav class="navbar navbar-static-top" role="navigation">
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"><span class="sr-only">切换导航</span></a>
<div class="navbar-custom-menu"></div>
</nav>
</header>
</#macro>
<#macro commonLeft>
<!-- Left side column. contains the logo and sidebar -->
<aside class="main-sidebar">
<!-- sidebar: style can be found in sidebar.less -->
<section class="sidebar">
<!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu">
<li class="header">常用模块</li>
<li class="nav-click" ><a href="${request.contextPath}//"><i class="fa fa-circle-o text-red"></i> <span>调度中心</span></a></li>
<li class="nav-click" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-yellow"></i><span>使用教程</span></a></li>
</ul>
</section>
<!-- /.sidebar -->
</aside>
</#macro>
<#macro commonControl >
<!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark">
<!-- Create the tabs -->
<ul class="nav nav-tabs nav-justified control-sidebar-tabs">
<li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
<li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<!-- Home tab content -->
<div class="tab-pane active" id="control-sidebar-home-tab">
<h3 class="control-sidebar-heading">近期活动</h3>
<ul class="control-sidebar-menu">
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-birthday-cake bg-red"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">张三今天过生日</h4>
<p>2015-09-10</p>
</div>
</a>
</li>
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-user bg-yellow"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Frodo 更新了资料</h4>
<p>更新手机号码 +1(800)555-1234</p>
</div>
</a>
</li>
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-envelope-o bg-light-blue"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">Nora 加入邮件列表</h4>
<p>nora@example.com</p>
</div>
</a>
</li>
<li>
<a href="javascript::;">
<i class="menu-icon fa fa-file-code-o bg-green"></i>
<div class="menu-info">
<h4 class="control-sidebar-subheading">001号定时作业调度</h4>
<p>5秒前执行</p>
</div>
</a>
</li>
</ul>
<!-- /.control-sidebar-menu -->
</div>
<!-- /.tab-pane -->
<!-- Settings tab content -->
<div class="tab-pane" id="control-sidebar-settings-tab">
<form method="post">
<h3 class="control-sidebar-heading">个人设置</h3>
<div class="form-group">
<label class="control-sidebar-subheading"> 左侧菜单自适应
<input type="checkbox" class="pull-right" checked>
</label>
<p>左侧菜单栏样式自适应</p>
</div>
<!-- /.form-group -->
</form>
</div>
<!-- /.tab-pane -->
</div>
</aside>
<!-- /.control-sidebar -->
<!-- Add the sidebar's background. This div must be placed immediately after the control sidebar -->
<div class="control-sidebar-bg"></div>
</#macro>
<#macro commonFooter >
<footer class="main-footer">
<div class="pull-right hidden-xs">
<b>Version</b> 1.0
</div>
<strong>Copyright &copy; 2015-2015 &nbsp;
<a href="https://github.com/xuxueli/xxl-job" target="_blank" >github</a>&nbsp;
<a href="http://www.cnblogs.com/xuxueli/p/5021979.html" target="_blank" >cnblog</a>.
</strong> All rights reserved.
</footer>
</#macro>
<#macro comAlert >
<!-- ComAlert.模态框Modal -->
<div class="modal fade" id="ComAlert" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<!-- <div class="modal-header"><h4 class="modal-title"><strong>提示:</strong></h4></div> -->
<div class="modal-body"><div class="alert alert-success"></div></div>
<div class="modal-footer">
<div class="text-center" >
<button type="button" class="btn btn-default ok" data-dismiss="modal" >确认</button>
</div>
</div>
</div>
</div>
</div>
<!-- ComConfirm.模态框Modal -->
<div class="modal fade" id="ComConfirm" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body"><div class="alert alert-success"></div></div>
<div class="modal-footer">
<div class="text-center" >
<button type="button" class="btn btn-primary ok" data-dismiss="modal" >确认</button>
<button type="button" class="btn btn-default cancel" data-dismiss="modal" >取消</button>
</div>
</div>
</div>
</div>
</div>
<script>
// 通用提示
var ComAlert = {
show:function(type, msg, callback){
// 弹框初始
if (type == 1) {
$('#ComAlert .alert').attr('class', 'alert alert-success');
} else {
$('#ComAlert .alert').attr('class', 'alert alert-warning');
}
$('#ComAlert .alert').html(msg);
$('#ComAlert').modal('show');
$('#ComAlert .ok').click(function(){
$('#ComAlert').modal('hide');
if(typeof callback == 'function') {
callback();
}
});
// $("#ComAlert").on('hide.bs.modal', function () { }); // 监听关闭
}
};
// 通用确认弹框
var ComConfirm = {
show:function(msg, callback){
// 弹框初始
$('#ComConfirm .alert').attr('class', 'alert alert-warning');
$('#ComConfirm .alert').html(msg);
$('#ComConfirm').modal('show');
$('#ComConfirm .ok').unbind("click"); // 解绑陈旧事件
$('#ComConfirm .ok').click(function(){
$('#ComConfirm').modal('hide');
if(typeof callback == 'function') {
callback();
return;
}
});
$('#ComConfirm .cancel').click(function(){
$('#ComConfirm').modal('hide');
return;
});
}
};
</script>
</#macro>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<title>调度中心</title>
<#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle />
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- header -->
<@netCommon.commonHeader />
<!-- left -->
<@netCommon.commonLeft />
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>使用教程<small>调度管理平台</small></h1>
<ol class="breadcrumb">
<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
<li class="active">使用教程</li>
</ol>
</section>
<!-- Main content -->
<section class="content">
<div class="callout callout-info">
<h4>简介:DIANPING_CLOCK</h4>
<p>基于quartz封装实现的的集群任务调度管理平台.</p>
<p></p>
</div>
<div class="callout callout-default">
<h4>特点:</h4>
<p>1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手.</p>
<p>2、动态:支持动态修改任务状态,动态暂停/恢复任务,即时生效.</p>
<p>3、集群:任务信息持久化到mysql中,支持Job服务器集群(高可用),一个任务只会在其中一台服务器上执行.</p>
</div>
<div class="callout callout-default">
<h4>分层模型:</h4>
<p>1、基础:基于quartz封装底层调度层,通过CORN自定义任务执行周期,最终执行自定义JobBean的execute方法,如需多个任务,需要开发多个JobBean实现.</p>
<p>2、分层:上述基础调度模型存在一定局限,调度层和任务层耦合,当新任务上线势必影响任务的正常调度,因此规划将调度系统分层为:调度层 + 任务层 + 通讯层.</p>
<p>
<div class="row">
<div class="col-xs-offset-1 col-xs-11">
<p>》调度模块:维护任务的调度信息,负责定时/周期性的发出调度请求.</p>
<p>》任务模块:具体的任务逻辑,负责接收调度模块的调度请求,执行任务逻辑.</p>
<p>》通讯模块:负责调度模块和任务模块之间的通讯.</p>
<p>(总而言之,一条完整任务由 “调度信息” 和 “任务信息” 组成.)</p>
</div>
</div>
</p>
</div>
<div class="callout callout-default">
<h4>调度属性解析 : 发出HTTP调度请求</h4>
<p>1、调度Key【必填】:调度信息的全局唯一标识.</p>
<p>2、调度Corn【必填】:调度执行的时间表达式.</p>
<p>3、调度描述【必填】:调度的简述.</p>
<p>4、调度URL【必填】:调度执行时发出HTTP请求的目标URL地址.</p>
<p>5、+args【选填】:调度执行时发出HTTP请求的附带的POST参数.</p>
</div>
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<!-- footer -->
<@netCommon.commonFooter />
<!-- control -->
<@netCommon.commonControl />
</div>
<@netCommon.commonScript />
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<title>调度中心</title>
<#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle />
<!-- DataTables -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
</head>
<body class="hold-transition skin-blue sidebar-mini">
<div class="wrapper">
<!-- header -->
<@netCommon.commonHeader />
<!-- left -->
<@netCommon.commonLeft />
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<section class="content-header">
<h1>调度中心<small>调度管理</small></h1>
<ol class="breadcrumb">
<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
<li class="active">调度管理</li>
</ol>
</section>
<!-- Main content -->
<section class="content">
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">调度列表</h3>
<button class="btn btn-info btn-xs add" type="button">+新增任务</button>
</div>
<div class="box-body">
<table id="job_list" class="table table-bordered table-striped">
<thead>
<tr>
<th>调度key</th>
<th>cron</th>
<!--<th>类路径</th>-->
<th>参数</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<#if jobList?exists && jobList?size gt 0>
<#list jobList as item>
<tr>
<td>${item['TriggerKey'].name}</td>
<td>${item['Trigger'].cronExpression}</td>
<!--<td>${item['JobDetail'].jobClass}</td>-->
<td>
<#assign jobDataMap = item['JobDetail'].jobDataMap />
<#if jobDataMap?exists && jobDataMap?keys?size gt 0>
<#list jobDataMap?keys as key>
${key} = ${jobDataMap[key]} <br>
</#list>
</#if>
</td>
<td state="${item['TriggerState']}" >
<#if item['TriggerState'] == 'NORMAL'>
<button class="btn btn-block btn-success" type="button">运行ing</button>
<#elseif item['TriggerState'] == 'PAUSED'>
<button class="btn btn-block btn-warning" type="button">暂停ing</button>
<#else>
<button class="btn btn-block" type="button">${item['TriggerState']}</button>
</#if>
</td>
<td>
<p name="${item['TriggerKey'].name}" group="${item['TriggerKey'].group}"
cronExpression="${item['Trigger'].cronExpression}" jobClassName="${item['JobDetail'].jobClass}" jobDesc="${job_desc?if_exists}" >
<#if item['TriggerState'] == 'NORMAL'>
<button class="btn btn-info btn-xs job_operate" type="job_pause" type="button">暂停</button>
<#elseif item['TriggerState'] == 'PAUSED'>
<button class="btn btn-info btn-xs job_operate" type="job_resume" type="button">恢复</button>
</#if>
<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行一次</button>
<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>
<button class="btn btn-info btn-xs update" type="button">更新corn</button>
</p>
</td>
</tr>
</#list>
</#if>
</tbody>
<tfoot>
<tr>
<th>调度key</th>
<th>cron</th>
<!--<th>类路径</th>-->
<th>参数</th>
<th>状态</th>
<th>操作</th>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</section>
</div>
<!-- footer -->
<@netCommon.commonFooter />
<!-- control -->
<@netCommon.commonControl />
</div>
<!-- job新增.模态框 -->
<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" >新增调度信息</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label for="firstname" class="col-sm-3 control-label">任务Key</label>
<div class="col-sm-9"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务Corn</label>
<div class="col-sm-9"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn[允许修改]" maxlength="100" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务描述</label>
<div class="col-sm-9"><input type="text" class="form-control" name="job_desc" placeholder="请输入任务描述[不支持修改]" maxlength="200" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务URL</label>
<div class="col-sm-9"><input type="text" class="form-control" name="job_url" placeholder="请输入任务URL[不支持修改]" maxlength="200" ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-3 control-label">任务handler</label>
<div class="col-sm-9"><input type="text" class="form-control" name="handleName" placeholder="请输入任务handler[不支持修改]" maxlength="200" ></div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-primary" >保存</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button type="button" class="btn btn-info pull-right addParam">+ arg</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 更新.模态框 -->
<div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" >更新corn</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label for="firstname" class="col-sm-2 control-label">任务Key</label>
<div class="col-sm-10"><input type="text" class="form-control" name="triggerKeyName" placeholder="请输入任务Key" minlength="4" maxlength="100" readonly ></div>
</div>
<div class="form-group">
<label for="lastname" class="col-sm-2 control-label">任务Corn</label>
<div class="col-sm-10"><input type="text" class="form-control" name="cronExpression" placeholder="请输入任务Corn" maxlength="100" ></div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary" >保存</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<@netCommon.commonScript />
<@netCommon.comAlert />
<!-- DataTables -->
<script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
<script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
<script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
<script>var base_url = '${request.contextPath}';</script>
<script src="${request.contextPath}/static/js/job.index.1.js"></script>
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>dianping-job-web</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationcontext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springmvc-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/500.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/500.html</location>
</error-page>
</web-app>
\ No newline at end of file
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论