├── .gitignore
├── README.md
├── demo-images
├── httpjob-add.png
├── httpjob-logs.png
└── httpjob-manage.png
├── pom.xml
├── sql
└── create_table.sql
└── src
├── main
├── java
│ └── com
│ │ └── example
│ │ └── quartz
│ │ ├── QuartzApplication.java
│ │ ├── config
│ │ ├── datasource
│ │ │ └── DataSourceConfig.java
│ │ ├── exception
│ │ │ └── GlobalExceptionHandler.java
│ │ ├── fastjson
│ │ │ └── FastJsonConfig.java
│ │ ├── quartz
│ │ │ ├── JobFactory.java
│ │ │ └── QuartzConfig.java
│ │ └── response
│ │ │ ├── Response.java
│ │ │ └── ResultEnum.java
│ │ ├── constants
│ │ └── Constant.java
│ │ ├── controller
│ │ ├── HttpJobController.java
│ │ └── JobController.java
│ │ ├── entity
│ │ ├── HttpJobDetails.java
│ │ ├── HttpJobLogs.java
│ │ ├── Page.java
│ │ ├── param
│ │ │ └── AddHttpJobParam.java
│ │ └── vo
│ │ │ └── HttpJobDetailVO.java
│ │ ├── job
│ │ ├── HttpGetJob.java
│ │ ├── HttpPostFormDataJob.java
│ │ └── HttpPostJsonJob.java
│ │ ├── mapper
│ │ ├── HttpJobDetailsMapper.java
│ │ └── HttpJobLogsMapper.java
│ │ ├── service
│ │ ├── HttpJobService.java
│ │ ├── JobManageService.java
│ │ └── impl
│ │ │ ├── HttpJobServiceImpl.java
│ │ │ └── JobManageServiceImpl.java
│ │ └── util
│ │ ├── HttpClientUtil.java
│ │ ├── JobUtil.java
│ │ └── JsonValidUtil.java
└── resources
│ ├── application.properties
│ ├── mappings
│ ├── HttpJobDetailsMapper.xml
│ └── HttpJobLogsMapper.xml
│ ├── quartz.properties
│ └── static
│ ├── historyHttpJob.html
│ ├── httpJob.html
│ ├── httpJobLog.html
│ └── js
│ ├── axios.min.js
│ └── vue.min.js
└── test
└── java
└── com
└── example
└── quartz
└── QuartzApplicationTests.java
/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**
5 | !**/src/test/**
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 |
30 | ### VS Code ###
31 | .vscode/
32 |
33 | ### mvn ###
34 | mvnw*
35 | .mvn
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## quartz + springboot + httpclient
2 |
3 | ### 项目功能
4 | 1、springboot集成quartz,使用druid连接池
5 | 2、支持http请求任务定时调度,当前支持get、post表单(formdata)、post Json三种请求类型,并记录返回内容
6 | 3、通过web界面进行任务管理,包括任务暂停、恢复、修改、历史记录、历史任务查看功能
7 | 4、支持调用接口(/quartz/httpJob/add)进行http任务添加
8 | 5、根据jobname或jobgroup进行查询
9 |
10 | ### 部署方式
11 | 1、执行sql目录下的create_table.sql文件,建立quartz以及httpjob需要的数据库表
12 | 2、修改application.properties中的数据库连接方式
13 | 3、访问http://localhost:8080/httpJob.html可通过web界面进行httpjob管理
14 |
15 | ### 组件版本
16 | 1、quartz 2.2.3
17 | 2、springboot 2.1.0
18 | 3、jdbc 5.1.46
19 | 4、httpclient 4.5.6
20 |
21 | ### 注意事项
22 | `1、调用接口添加http定时请求任务时,requestType(请求类型)必填,只支持填入"GET"、 "POST_JSON"、 "POST_FORM",分别对应get, post json和post form-data三种类型;`
23 | `2、调用接口添加http定时请求任务时,params(请求参数)选填,若填写,必须组装为合法的json字符串格式。`
24 |
25 | ### demo
26 | HTTP请求任务管理
27 | 
28 |
29 | HTTP请求任务添加
30 | 
31 |
32 | HTTP请求任务执行记录
33 | 
34 |
--------------------------------------------------------------------------------
/demo-images/httpjob-add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloflygit/springboot-quartz/0df2e7d3b76919460699473739ebac70a29149e9/demo-images/httpjob-add.png
--------------------------------------------------------------------------------
/demo-images/httpjob-logs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloflygit/springboot-quartz/0df2e7d3b76919460699473739ebac70a29149e9/demo-images/httpjob-logs.png
--------------------------------------------------------------------------------
/demo-images/httpjob-manage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helloflygit/springboot-quartz/0df2e7d3b76919460699473739ebac70a29149e9/demo-images/httpjob-manage.png
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.example
7 | quartz
8 | 0.0.1-SNAPSHOT
9 | quartz
10 | Quartz for Spring Boot
11 |
12 |
13 | org.springframework.boot
14 | spring-boot-starter-parent
15 | 2.1.0.RELEASE
16 |
17 |
18 |
19 |
20 | UTF-8
21 | UTF-8
22 | 1.8
23 |
24 |
25 |
26 |
27 |
28 | org.springframework.boot
29 | spring-boot-starter
30 |
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 |
36 |
37 |
38 | org.springframework
39 | spring-context-support
40 |
41 |
42 |
43 | org.springframework.boot
44 | spring-boot-starter-test
45 | test
46 |
47 |
48 |
49 | mysql
50 | mysql-connector-java
51 | 5.1.46
52 | runtime
53 |
54 |
55 |
56 | org.mybatis.spring.boot
57 | mybatis-spring-boot-starter
58 | 1.3.2
59 |
60 |
61 |
62 |
63 | org.quartz-scheduler
64 | quartz
65 | 2.2.3
66 |
67 |
68 | org.quartz-scheduler
69 | quartz-jobs
70 | 2.2.3
71 |
72 |
73 |
74 |
75 | org.apache.httpcomponents
76 | httpclient
77 | 4.5.6
78 |
79 |
80 |
81 |
82 | org.apache.commons
83 | commons-lang3
84 | 3.8.1
85 |
86 |
87 |
88 |
89 | com.alibaba
90 | fastjson
91 | 1.2.53
92 |
93 |
94 |
95 |
96 | com.alibaba
97 | druid
98 | 1.1.9
99 |
100 |
101 |
102 |
103 |
104 |
105 | org.springframework.boot
106 | spring-boot-maven-plugin
107 |
108 |
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/sql/create_table.sql:
--------------------------------------------------------------------------------
1 | CREATE DATABASE `quartz` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
2 | USE quartz;
3 | -- QUARTZ_TABLE
4 | DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
5 | DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
6 | DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
7 | DROP TABLE IF EXISTS QRTZ_LOCKS;
8 | DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
9 | DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
10 | DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
11 | DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
12 | DROP TABLE IF EXISTS QRTZ_TRIGGERS;
13 | DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
14 | DROP TABLE IF EXISTS QRTZ_CALENDARS;
15 |
16 | CREATE TABLE QRTZ_JOB_DETAILS(
17 | SCHED_NAME VARCHAR(120) NOT NULL,
18 | JOB_NAME VARCHAR(200) NOT NULL,
19 | JOB_GROUP VARCHAR(200) NOT NULL,
20 | DESCRIPTION VARCHAR(250) NULL,
21 | JOB_CLASS_NAME VARCHAR(250) NOT NULL,
22 | IS_DURABLE VARCHAR(1) NOT NULL,
23 | IS_NONCONCURRENT VARCHAR(1) NOT NULL,
24 | IS_UPDATE_DATA VARCHAR(1) NOT NULL,
25 | REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
26 | JOB_DATA BLOB NULL,
27 | PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
28 | ENGINE=InnoDB;
29 |
30 | CREATE TABLE QRTZ_TRIGGERS (
31 | SCHED_NAME VARCHAR(120) NOT NULL,
32 | TRIGGER_NAME VARCHAR(200) NOT NULL,
33 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
34 | JOB_NAME VARCHAR(200) NOT NULL,
35 | JOB_GROUP VARCHAR(200) NOT NULL,
36 | DESCRIPTION VARCHAR(250) NULL,
37 | NEXT_FIRE_TIME BIGINT(13) NULL,
38 | PREV_FIRE_TIME BIGINT(13) NULL,
39 | PRIORITY INTEGER NULL,
40 | TRIGGER_STATE VARCHAR(16) NOT NULL,
41 | TRIGGER_TYPE VARCHAR(8) NOT NULL,
42 | START_TIME BIGINT(13) NOT NULL,
43 | END_TIME BIGINT(13) NULL,
44 | CALENDAR_NAME VARCHAR(200) NULL,
45 | MISFIRE_INSTR SMALLINT(2) NULL,
46 | JOB_DATA BLOB NULL,
47 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
48 | FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
49 | REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
50 | ENGINE=InnoDB;
51 |
52 | CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
53 | SCHED_NAME VARCHAR(120) NOT NULL,
54 | TRIGGER_NAME VARCHAR(200) NOT NULL,
55 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
56 | REPEAT_COUNT BIGINT(7) NOT NULL,
57 | REPEAT_INTERVAL BIGINT(12) NOT NULL,
58 | TIMES_TRIGGERED BIGINT(10) NOT NULL,
59 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
60 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
61 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
62 | ENGINE=InnoDB;
63 |
64 | CREATE TABLE QRTZ_CRON_TRIGGERS (
65 | SCHED_NAME VARCHAR(120) NOT NULL,
66 | TRIGGER_NAME VARCHAR(200) NOT NULL,
67 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
68 | CRON_EXPRESSION VARCHAR(120) NOT NULL,
69 | TIME_ZONE_ID VARCHAR(80),
70 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
71 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
72 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
73 | ENGINE=InnoDB;
74 |
75 | CREATE TABLE QRTZ_SIMPROP_TRIGGERS
76 | (
77 | SCHED_NAME VARCHAR(120) NOT NULL,
78 | TRIGGER_NAME VARCHAR(200) NOT NULL,
79 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
80 | STR_PROP_1 VARCHAR(512) NULL,
81 | STR_PROP_2 VARCHAR(512) NULL,
82 | STR_PROP_3 VARCHAR(512) NULL,
83 | INT_PROP_1 INT NULL,
84 | INT_PROP_2 INT NULL,
85 | LONG_PROP_1 BIGINT NULL,
86 | LONG_PROP_2 BIGINT NULL,
87 | DEC_PROP_1 NUMERIC(13,4) NULL,
88 | DEC_PROP_2 NUMERIC(13,4) NULL,
89 | BOOL_PROP_1 VARCHAR(1) NULL,
90 | BOOL_PROP_2 VARCHAR(1) NULL,
91 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
92 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
93 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
94 | ENGINE=InnoDB;
95 |
96 | CREATE TABLE QRTZ_BLOB_TRIGGERS (
97 | SCHED_NAME VARCHAR(120) NOT NULL,
98 | TRIGGER_NAME VARCHAR(200) NOT NULL,
99 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
100 | BLOB_DATA BLOB NULL,
101 | PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
102 | INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
103 | FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
104 | REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
105 | ENGINE=InnoDB;
106 |
107 | CREATE TABLE QRTZ_CALENDARS (
108 | SCHED_NAME VARCHAR(120) NOT NULL,
109 | CALENDAR_NAME VARCHAR(200) NOT NULL,
110 | CALENDAR BLOB NOT NULL,
111 | PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
112 | ENGINE=InnoDB;
113 |
114 | CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
115 | SCHED_NAME VARCHAR(120) NOT NULL,
116 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
117 | PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
118 | ENGINE=InnoDB;
119 |
120 | CREATE TABLE QRTZ_FIRED_TRIGGERS (
121 | SCHED_NAME VARCHAR(120) NOT NULL,
122 | ENTRY_ID VARCHAR(95) NOT NULL,
123 | TRIGGER_NAME VARCHAR(200) NOT NULL,
124 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
125 | INSTANCE_NAME VARCHAR(200) NOT NULL,
126 | FIRED_TIME BIGINT(13) NOT NULL,
127 | SCHED_TIME BIGINT(13) NOT NULL,
128 | PRIORITY INTEGER NOT NULL,
129 | STATE VARCHAR(16) NOT NULL,
130 | JOB_NAME VARCHAR(200) NULL,
131 | JOB_GROUP VARCHAR(200) NULL,
132 | IS_NONCONCURRENT VARCHAR(1) NULL,
133 | REQUESTS_RECOVERY VARCHAR(1) NULL,
134 | PRIMARY KEY (SCHED_NAME,ENTRY_ID))
135 | ENGINE=InnoDB;
136 |
137 | CREATE TABLE QRTZ_SCHEDULER_STATE (
138 | SCHED_NAME VARCHAR(120) NOT NULL,
139 | INSTANCE_NAME VARCHAR(200) NOT NULL,
140 | LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
141 | CHECKIN_INTERVAL BIGINT(13) NOT NULL,
142 | PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
143 | ENGINE=InnoDB;
144 |
145 | CREATE TABLE QRTZ_LOCKS (
146 | SCHED_NAME VARCHAR(120) NOT NULL,
147 | LOCK_NAME VARCHAR(40) NOT NULL,
148 | PRIMARY KEY (SCHED_NAME,LOCK_NAME))
149 | ENGINE=InnoDB;
150 |
151 | CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
152 | CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
153 |
154 | CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
155 | CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
156 | CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
157 | CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
158 | CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
159 | CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
160 | CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
161 | CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
162 | CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
163 | CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
164 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
165 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
166 |
167 | CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
168 | CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
169 | CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
170 | CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
171 | CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
172 | CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
173 |
174 | -- HTTPJOB_DETAILS TABLE
175 | DROP TABLE IF EXISTS HTTPJOB_DETAILS;
176 | CREATE TABLE HTTPJOB_DETAILS(
177 | ID INT(11) NOT NULL AUTO_INCREMENT,
178 | JOB_NAME VARCHAR(200) NOT NULL,
179 | JOB_GROUP VARCHAR(200) NOT NULL,
180 | DESCRIPTION varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
181 | REQUEST_TYPE varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
182 | HTTP_URL VARCHAR(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
183 | HTTP_PARAMS VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
184 | CREATE_TIME TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP,
185 | UPDATE_TIME TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0),
186 | PRIMARY KEY (ID))
187 | ENGINE=InnoDB;
188 |
189 | -- HTTPJOB_LOGS TABLE
190 | DROP TABLE IF EXISTS HTTPJOB_LOGS;
191 | CREATE TABLE HTTPJOB_LOGS(
192 | ID INT(11) NOT NULL AUTO_INCREMENT,
193 | JOB_NAME VARCHAR(200) NOT NULL,
194 | JOB_GROUP VARCHAR(200) NOT NULL,
195 | REQUEST_TYPE varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
196 | HTTP_URL VARCHAR(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
197 | HTTP_PARAMS VARCHAR(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
198 | FIRE_TIME TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP,
199 | RESULT VARCHAR(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
200 | PRIMARY KEY (ID))
201 | ENGINE=InnoDB;
202 |
203 | ALTER TABLE HTTPJOB_DETAILS ADD UNIQUE INDEX `UNIQUEIDX_HTTPJOB_JN_JG`(`JOB_NAME`, `JOB_GROUP`);
204 | ALTER TABLE HTTPJOB_LOGS ADD INDEX `IDX_HTTPJOBHISTORY_JN_JG`(`JOB_NAME`, `JOB_GROUP`);
205 |
206 | commit;
207 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/QuartzApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz;
2 |
3 | import org.mybatis.spring.annotation.MapperScan;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | @SpringBootApplication
8 | @MapperScan("com.example.quartz.mapper")
9 | public class QuartzApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(QuartzApplication.class, args);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/config/datasource/DataSourceConfig.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.config.datasource;
2 |
3 | import com.alibaba.druid.filter.Filter;
4 | import com.alibaba.druid.pool.DruidDataSource;
5 | import com.alibaba.druid.wall.WallConfig;
6 | import com.alibaba.druid.wall.WallFilter;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.context.annotation.Bean;
9 | import org.springframework.context.annotation.Configuration;
10 | import org.springframework.context.annotation.Primary;
11 |
12 | import javax.sql.DataSource;
13 | import java.sql.SQLException;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | /**
18 | * druid数据源配置类
19 | *
20 | * @author hellofly
21 | * @date 2019/4/9
22 | */
23 | @Configuration
24 | public class DataSourceConfig {
25 |
26 | @Value("${spring.datasource.url}")
27 | private String dbUrl;
28 |
29 | @Value("${spring.datasource.username}")
30 | private String userName;
31 |
32 | @Value("${spring.datasource.password}")
33 | private String password;
34 |
35 | @Value("${spring.datasource.driverClassName}")
36 | private String driverClassName;
37 |
38 | @Value("${spring.datasource.initialSize}")
39 | private int initialSize;
40 |
41 | @Value("${spring.datasource.minIdle}")
42 | private int minIdle;
43 |
44 | @Value("${spring.datasource.maxActive}")
45 | private int maxActive;
46 |
47 | @Value("${spring.datasource.maxWait}")
48 | private int maxWait;
49 |
50 | @Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
51 | private int timeBetweenEvictionRunsMillis;
52 |
53 | @Value("${spring.datasource.minEvictableIdleTimeMillis}")
54 | private int minEvictableIdleTimeMillis;
55 |
56 | @Value("${spring.datasource.validationQuery}")
57 | private String validationQuery;
58 |
59 | @Value("${spring.datasource.testWhileIdle}")
60 | private boolean testWhileIdle;
61 |
62 | @Value("${spring.datasource.testOnBorrow}")
63 | private boolean testOnBorrow;
64 |
65 | @Value("${spring.datasource.testOnReturn}")
66 | private boolean testOnReturn;
67 |
68 | @Value("${spring.datasource.poolPreparedStatements}")
69 | private boolean poolPreparedStatements;
70 |
71 | @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize}")
72 | private int maxPoolPreparedStatementPerConnectionSize;
73 |
74 | @Value("${spring.datasource.filters}")
75 | private String filters;
76 |
77 | @Value("{spring.datasource.connectionProperties}")
78 | private String connectionProperties;
79 |
80 |
81 | @Primary
82 | @Bean
83 | public DataSource dataSource() {
84 | DruidDataSource datasource = new DruidDataSource();
85 | datasource.setUrl(this.dbUrl);
86 | datasource.setUsername(userName);
87 | datasource.setPassword(password);
88 | datasource.setDriverClassName(driverClassName);
89 |
90 | //configuration
91 | datasource.setInitialSize(initialSize);
92 | datasource.setMinIdle(minIdle);
93 | datasource.setMaxActive(maxActive);
94 | datasource.setMaxWait(maxWait);
95 | datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
96 | datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
97 | datasource.setValidationQuery(validationQuery);
98 | datasource.setTestWhileIdle(testWhileIdle);
99 | datasource.setTestOnBorrow(testOnBorrow);
100 | datasource.setTestOnReturn(testOnReturn);
101 | datasource.setPoolPreparedStatements(poolPreparedStatements);
102 | datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
103 |
104 | WallConfig wallConfig = new WallConfig();
105 | wallConfig.setMultiStatementAllow(true);
106 | WallFilter wallFilter= new WallFilter();
107 | wallFilter.setConfig(wallConfig);
108 | List filterList = new ArrayList<>();
109 | filterList.add(wallFilter);
110 | datasource.setProxyFilters(filterList);
111 |
112 | try {
113 | datasource.setFilters(filters);
114 | } catch (SQLException e) {
115 | e.printStackTrace();
116 | }
117 | datasource.setConnectionProperties(connectionProperties);
118 |
119 | return datasource;
120 | }
121 |
122 | }
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/config/exception/GlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.config.exception;
2 |
3 | import com.example.quartz.config.response.Response;
4 | import com.example.quartz.config.response.ResultEnum;
5 | import org.apache.commons.lang3.StringUtils;
6 | import org.apache.logging.log4j.LogManager;
7 | import org.apache.logging.log4j.Logger;
8 | import org.springframework.http.HttpStatus;
9 | import org.springframework.validation.BindException;
10 | import org.springframework.web.bind.annotation.ControllerAdvice;
11 | import org.springframework.web.bind.annotation.ExceptionHandler;
12 | import org.springframework.web.bind.annotation.ResponseStatus;
13 | import org.springframework.web.bind.annotation.RestController;
14 |
15 | /**
16 | * 全局异常处理
17 | *
18 | * @author hellofly
19 | * @date 2019/4/11
20 | */
21 | @ControllerAdvice
22 | @RestController
23 | public class GlobalExceptionHandler {
24 |
25 | private static final Logger logger = LogManager.getLogger(GlobalExceptionHandler.class);
26 |
27 |
28 | /**
29 | * BindingResult参数校验
30 | *
31 | * @param e
32 | * @return
33 | */
34 | @ResponseStatus(HttpStatus.OK)
35 | @ExceptionHandler(BindException.class)
36 | public Response handleBindException(BindException e) {
37 | String bindingResultError = e.getBindingResult().getFieldError().getDefaultMessage();
38 | String errorMessage = StringUtils.isEmpty(bindingResultError) ? ResultEnum.ERROR.getMessage() : bindingResultError;
39 | return Response.error(errorMessage);
40 | }
41 |
42 | /**
43 | * 全局异常
44 | *
45 | * @param e
46 | * @return
47 | */
48 | @ResponseStatus(HttpStatus.OK)
49 | @ExceptionHandler(Exception.class)
50 | public Response handleException(Exception e) {
51 | logger.error("Exception happened: ", e);
52 | String errorMessage = StringUtils.isEmpty(e.getMessage()) ? ResultEnum.ERROR.getMessage() : e.getMessage();
53 | return Response.error(errorMessage);
54 | }
55 |
56 | }
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/config/fastjson/FastJsonConfig.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.config.fastjson;
2 |
3 | import com.alibaba.fastjson.serializer.SerializerFeature;
4 | import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
5 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.context.annotation.Configuration;
8 | import org.springframework.http.converter.HttpMessageConverter;
9 |
10 | /**
11 | * fastJson配置类
12 | *
13 | * @author hellofly
14 | * @date 2019/4/9
15 | */
16 | @Configuration
17 | public class FastJsonConfig {
18 |
19 | @Bean
20 | public HttpMessageConverters fastJsonHttpMessageConverters() {
21 | FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
22 | com.alibaba.fastjson.support.config.FastJsonConfig fastJsonConfig = new com.alibaba.fastjson.support.config.FastJsonConfig();
23 | fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
24 | fastConverter.setFastJsonConfig(fastJsonConfig);
25 | HttpMessageConverter> converter = fastConverter;
26 | return new HttpMessageConverters(converter);
27 |
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/config/quartz/JobFactory.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.config.quartz;
2 |
3 | import org.quartz.spi.TriggerFiredBundle;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
6 | import org.springframework.scheduling.quartz.AdaptableJobFactory;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * QuartzJob工厂类
11 | *
12 | * @author hellofly
13 | * @date 2019/4/9
14 | */
15 | @Component
16 | public class JobFactory extends AdaptableJobFactory {
17 |
18 | @Autowired
19 | private AutowireCapableBeanFactory beanFactory;
20 |
21 | @Override
22 | protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
23 | final Object job = super.createJobInstance(bundle);
24 | beanFactory.autowireBean(job);
25 | return job;
26 | }
27 | }
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/config/quartz/QuartzConfig.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.config.quartz;
2 |
3 | import org.quartz.Scheduler;
4 | import org.springframework.beans.factory.annotation.Autowired;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.core.io.ClassPathResource;
8 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
9 |
10 | import javax.sql.DataSource;
11 | import java.io.IOException;
12 | import java.util.Properties;
13 |
14 | /**
15 | * Quartz配置类
16 | *
17 | * @author hellofly
18 | * @date 2019/4/9
19 | */
20 | @Configuration
21 | public class QuartzConfig {
22 |
23 | @Autowired
24 | private DataSource dataSource;
25 |
26 | @Autowired
27 | private JobFactory jobFactory;
28 |
29 | @Bean
30 | public SchedulerFactoryBean schedulerFactoryBean() {
31 | SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
32 | try {
33 | schedulerFactoryBean.setAutoStartup(true);
34 | schedulerFactoryBean.setDataSource(dataSource);
35 | schedulerFactoryBean.setJobFactory(jobFactory);
36 | schedulerFactoryBean.setQuartzProperties(properties());
37 | schedulerFactoryBean.setOverwriteExistingJobs(true);
38 | // 延迟3s启动quartz
39 | schedulerFactoryBean.setStartupDelay(3);
40 | schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(true);
41 | } catch (IOException e) {
42 | e.printStackTrace();
43 | }
44 | return schedulerFactoryBean;
45 |
46 | }
47 |
48 | @Bean
49 | public Properties properties() throws IOException {
50 | Properties prop = new Properties();
51 | prop.load(new ClassPathResource("/quartz.properties").getInputStream());
52 | return prop;
53 | }
54 |
55 | @Bean(name = "scheduler")
56 | public Scheduler scheduler() {
57 | return schedulerFactoryBean().getScheduler();
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/config/response/Response.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.config.response;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * 接口返回结果封装类
7 | *
8 | * @author hellofly
9 | * @date 2019/4/9
10 | */
11 | public class Response implements Serializable {
12 |
13 | private static final long serialVersionUID = 676473785338095291L;
14 |
15 | private int status;
16 |
17 | private String message;
18 |
19 | private T data;
20 |
21 | public Response() {
22 | }
23 |
24 | public Response(int status, String message) {
25 | this.status = status;
26 | this.message = message;
27 | }
28 |
29 | public Response(ResultEnum resultEnum) {
30 | this.status = resultEnum.getStatus();
31 | this.message = resultEnum.getMessage();
32 | }
33 |
34 | public Response(ResultEnum resultEnum, T data) {
35 | this.status = resultEnum.getStatus();
36 | this.message = resultEnum.getMessage();
37 | this.data = data;
38 | }
39 |
40 | public static Response error() {
41 | return new Response(ResultEnum.ERROR);
42 | }
43 |
44 | public static Response error(String errorMessage) {
45 | return new Response(ResultEnum.ERROR.getStatus(), errorMessage);
46 | }
47 |
48 | public static Response success() {
49 | return new Response(ResultEnum.SUCCESS);
50 | }
51 |
52 | public static Response success(T data) {
53 | return new Response(ResultEnum.SUCCESS, data);
54 | }
55 |
56 | public int getStatus() {
57 | return status;
58 | }
59 |
60 | public void setStatus(int status) {
61 | this.status = status;
62 | }
63 |
64 | public String getMessage() {
65 | return message;
66 | }
67 |
68 | public void setMessage(String message) {
69 | this.message = message;
70 | }
71 |
72 | public T getData() {
73 | return data;
74 | }
75 |
76 | public void setData(T data) {
77 | this.data = data;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/config/response/ResultEnum.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.config.response;
2 |
3 | /**
4 | * 接口返回状态码及异常信息枚举类
5 | *
6 | * @author hellofly
7 | * @date 2019/4/9
8 | */
9 | public enum ResultEnum {
10 |
11 | SUCCESS(0, "Success"),
12 | ERROR(-1, "Error");
13 |
14 | private int status;
15 |
16 | private String message;
17 |
18 | ResultEnum(int status, String message) {
19 | this.status = status;
20 | this.message = message;
21 | }
22 |
23 | public int getStatus() {
24 | return status;
25 | }
26 |
27 | public void setStatus(int status) {
28 | this.status = status;
29 | }
30 |
31 | public String getMessage() {
32 | return message;
33 | }
34 |
35 | public void setMessage(String message) {
36 | this.message = message;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/constants/Constant.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.constants;
2 |
3 | /**
4 | * 常量类
5 | *
6 | * @author hellofly
7 | * @date 2019/4/9
8 | */
9 | public class Constant {
10 |
11 | /**
12 | * trigger名称前缀
13 | */
14 | public static final String TRIGGER_PREFIX = "Trigger_";
15 |
16 | public static final String URL = "url";
17 |
18 | public static final String PARAMS = "params";
19 |
20 | public static final String REQUEST_TYPE = "requestType";
21 |
22 | /**
23 | * RequestType请求类型
24 | */
25 | public static final String POST_JSON = "POST_JSON";
26 |
27 | public static final String POST_FORM_DATA = "POST_FORM";
28 |
29 | public static final String GET = "GET";
30 |
31 | /**
32 | * job状态 NORMAL
33 | */
34 | public static final String JOB_STATUS_NORMAL = "NORMAL";
35 |
36 | /**
37 | * job状态 PAUSED
38 | */
39 | public static final String JOB_STATUS_PAUSED = "PAUSED";
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/controller/HttpJobController.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.controller;
2 |
3 | import com.example.quartz.config.response.Response;
4 | import com.example.quartz.entity.HttpJobLogs;
5 | import com.example.quartz.entity.Page;
6 | import com.example.quartz.entity.param.AddHttpJobParam;
7 | import com.example.quartz.entity.vo.HttpJobDetailVO;
8 | import com.example.quartz.service.HttpJobService;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.http.ResponseEntity;
11 | import org.springframework.ui.ModelMap;
12 | import org.springframework.web.bind.annotation.*;
13 |
14 | import javax.validation.Valid;
15 |
16 | /**
17 | * Http类型任务Controller
18 | *
19 | * @author hellofly
20 | * @date 2019/4/9
21 | */
22 | @RestController
23 | @RequestMapping(value = "/quartz/httpJob")
24 | public class HttpJobController {
25 |
26 | @Autowired
27 | private HttpJobService httpJobService;
28 |
29 | @RequestMapping(value = "/add", method = RequestMethod.POST)
30 | public Response addPostJsonJob(@RequestBody @Valid AddHttpJobParam addHttpJobParam) {
31 |
32 | httpJobService.addHttpJob(addHttpJobParam);
33 | return Response.success();
34 | }
35 |
36 | @RequestMapping(value = "/jobs")
37 | public Response> getJobs(@RequestParam(name = "searchParam", required = false) String searchParam,
38 | @RequestParam(name = "pageSize", required = false, defaultValue = "15") Integer pageSize,
39 | @RequestParam(name = "pageNum", required = false, defaultValue = "1") Integer pageNum) {
40 |
41 | Page result = httpJobService.getHttpJobs(searchParam, pageSize, pageNum);
42 | return Response.success(result);
43 | }
44 |
45 | @RequestMapping(value = "/historyJobs")
46 | public Response> getHistoryJobs(@RequestParam(name = "searchParam", required = false) String searchParam,
47 | @RequestParam(name = "pageSize", required = false, defaultValue = "15") Integer pageSize,
48 | @RequestParam(name = "pageNum", required = false, defaultValue = "1") Integer pageNum) {
49 |
50 | Page result = httpJobService.getHistoryHttpJobs(searchParam, pageSize, pageNum);
51 | return Response.success(result);
52 |
53 | }
54 |
55 | @RequestMapping(value = "/jobLogs")
56 | public Response> getJobLogs(@RequestParam(name = "jobName", required = false) String jobName,
57 | @RequestParam(name = "jobGroup", required = false) String jobGroup,
58 | @RequestParam(name = "searchParam", required = false) String searchParam,
59 | @RequestParam(name = "pageSize", required = false, defaultValue = "15") Integer pageSize,
60 | @RequestParam(name = "pageNum", required = false, defaultValue = "1") Integer pageNum) {
61 |
62 | Page result = httpJobService.getHttpJobLogs(jobName, jobGroup, searchParam, pageSize, pageNum);
63 | return Response.success(result);
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/controller/JobController.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.controller;
2 |
3 | import com.example.quartz.config.response.Response;
4 | import com.example.quartz.service.JobManageService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.web.bind.annotation.RequestMapping;
7 | import org.springframework.web.bind.annotation.RequestMethod;
8 | import org.springframework.web.bind.annotation.RequestParam;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 | /**
12 | * job操作Controller
13 | *
14 | * @author hellofly
15 | * @date 2019/4/9
16 | */
17 | @RestController
18 | @RequestMapping(value = "/quartz/job")
19 | public class JobController {
20 |
21 | @Autowired
22 | private JobManageService jobManageService;
23 |
24 | @RequestMapping(value = "/pause", method = RequestMethod.POST)
25 | public Response pauseJob(@RequestParam(name = "jobName") String jobName,
26 | @RequestParam(name = "jobGroup") String jobGroup) {
27 |
28 | jobManageService.pauseJob(jobName, jobGroup);
29 | return Response.success();
30 | }
31 |
32 | @RequestMapping(value = "/resume", method = RequestMethod.POST)
33 | public Response resumeJob(@RequestParam(name = "jobName") String jobName,
34 | @RequestParam(name = "jobGroup") String jobGroup) {
35 |
36 | jobManageService.resumeJob(jobName, jobGroup);
37 | return Response.success();
38 | }
39 |
40 | @RequestMapping(value = "/delete", method = RequestMethod.POST)
41 | public Response deleteJob(@RequestParam(name = "jobName") String jobName,
42 | @RequestParam(name = "jobGroup") String jobGroup) {
43 |
44 | jobManageService.deleteJob(jobName, jobGroup);
45 | return Response.success();
46 | }
47 |
48 | @RequestMapping(value = "/update", method = RequestMethod.POST)
49 | public Response updateJob(@RequestParam(name = "jobName") String jobName,
50 | @RequestParam(name = "jobGroup") String jobGroup,
51 | @RequestParam(name = "cronExpression") String cronExpression) {
52 |
53 | jobManageService.updateCronExpression(jobName, jobGroup, cronExpression);
54 | return Response.success();
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/entity/HttpJobDetails.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.entity;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | import java.io.Serializable;
6 | import java.util.Date;
7 |
8 | public class HttpJobDetails implements Serializable {
9 |
10 | private static final long serialVersionUID = -50190044894125802L;
11 |
12 | private Integer id;
13 |
14 | private String jobName;
15 |
16 | private String jobGroup;
17 |
18 | private String description;
19 |
20 | private String requestType;
21 |
22 | private String httpUrl;
23 |
24 | private String httpParams;
25 |
26 | @JSONField(format = "yyyy-MM-dd HH:mm:ss")
27 | private Date createTime;
28 |
29 | @JSONField(format = "yyyy-MM-dd HH:mm:ss")
30 | private Date updateTime;
31 |
32 | public Integer getId() {
33 | return id;
34 | }
35 |
36 | public void setId(Integer id) {
37 | this.id = id;
38 | }
39 |
40 | public String getJobName() {
41 | return jobName;
42 | }
43 |
44 | public void setJobName(String jobName) {
45 | this.jobName = jobName;
46 | }
47 |
48 | public String getJobGroup() {
49 | return jobGroup;
50 | }
51 |
52 | public void setJobGroup(String jobGroup) {
53 | this.jobGroup = jobGroup;
54 | }
55 |
56 | public String getDescription() {
57 | return description;
58 | }
59 |
60 | public void setDescription(String description) {
61 | this.description = description;
62 | }
63 |
64 | public String getRequestType() {
65 | return requestType;
66 | }
67 |
68 | public void setRequestType(String requestType) {
69 | this.requestType = requestType;
70 | }
71 |
72 | public String getHttpUrl() {
73 | return httpUrl;
74 | }
75 |
76 | public void setHttpUrl(String httpUrl) {
77 | this.httpUrl = httpUrl;
78 | }
79 |
80 | public String getHttpParams() {
81 | return httpParams;
82 | }
83 |
84 | public void setHttpParams(String httpParams) {
85 | this.httpParams = httpParams;
86 | }
87 |
88 | public Date getCreateTime() {
89 | return createTime;
90 | }
91 |
92 | public void setCreateTime(Date createTime) {
93 | this.createTime = createTime;
94 | }
95 |
96 | public Date getUpdateTime() {
97 | return updateTime;
98 | }
99 |
100 | public void setUpdateTime(Date updateTime) {
101 | this.updateTime = updateTime;
102 | }
103 |
104 | @Override
105 | public String toString() {
106 | return "HttpJobDetails{" +
107 | "id=" + id +
108 | ", jobName='" + jobName + '\'' +
109 | ", jobGroup='" + jobGroup + '\'' +
110 | ", description='" + description + '\'' +
111 | ", requestType='" + requestType + '\'' +
112 | ", httpUrl='" + httpUrl + '\'' +
113 | ", httpParams='" + httpParams + '\'' +
114 | ", createTime=" + createTime +
115 | ", updateTime=" + updateTime +
116 | '}';
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/entity/HttpJobLogs.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.entity;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | import java.io.Serializable;
6 | import java.util.Date;
7 |
8 | public class HttpJobLogs implements Serializable {
9 |
10 | private static final long serialVersionUID = 2259203435361774854L;
11 |
12 | private Integer id;
13 |
14 | private String jobName;
15 |
16 | private String jobGroup;
17 |
18 | private String requestType;
19 |
20 | private String httpUrl;
21 |
22 | private String httpParams;
23 |
24 | @JSONField(format = "yyyy-MM-dd HH:mm:ss")
25 | private Date fireTime;
26 |
27 | private String result;
28 |
29 | public Integer getId() {
30 | return id;
31 | }
32 |
33 | public void setId(Integer id) {
34 | this.id = id;
35 | }
36 |
37 | public String getJobName() {
38 | return jobName;
39 | }
40 |
41 | public void setJobName(String jobName) {
42 | this.jobName = jobName;
43 | }
44 |
45 | public String getJobGroup() {
46 | return jobGroup;
47 | }
48 |
49 | public void setJobGroup(String jobGroup) {
50 | this.jobGroup = jobGroup;
51 | }
52 |
53 | public String getRequestType() {
54 | return requestType;
55 | }
56 |
57 | public void setRequestType(String requestType) {
58 | this.requestType = requestType;
59 | }
60 |
61 | public String getHttpUrl() {
62 | return httpUrl;
63 | }
64 |
65 | public void setHttpUrl(String httpUrl) {
66 | this.httpUrl = httpUrl;
67 | }
68 |
69 | public String getHttpParams() {
70 | return httpParams;
71 | }
72 |
73 | public void setHttpParams(String httpParams) {
74 | this.httpParams = httpParams;
75 | }
76 |
77 | public Date getFireTime() {
78 | return fireTime;
79 | }
80 |
81 | public void setFireTime(Date fireTime) {
82 | this.fireTime = fireTime;
83 | }
84 |
85 | public String getResult() {
86 | return result;
87 | }
88 |
89 | public void setResult(String result) {
90 | this.result = result;
91 | }
92 |
93 | @Override
94 | public String toString() {
95 | return "HttpJobLogs{" +
96 | "id=" + id +
97 | ", jobName='" + jobName + '\'' +
98 | ", jobGroup='" + jobGroup + '\'' +
99 | ", requestType='" + requestType + '\'' +
100 | ", httpUrl='" + httpUrl + '\'' +
101 | ", httpParams='" + httpParams + '\'' +
102 | ", fireTime=" + fireTime +
103 | ", result='" + result + '\'' +
104 | '}';
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/entity/Page.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.entity;
2 |
3 | import java.util.List;
4 |
5 | public class Page {
6 |
7 | private Integer pageNum;
8 |
9 | private Integer pageSize;
10 |
11 | private Integer count;
12 |
13 | private Integer pageCount;
14 |
15 | private Integer totalCount;
16 |
17 | private List resultList;
18 |
19 | public Integer getPageNum() {
20 | return pageNum;
21 | }
22 |
23 | public void setPageNum(Integer pageNum) {
24 | this.pageNum = pageNum;
25 | }
26 |
27 | public Integer getPageSize() {
28 | return pageSize;
29 | }
30 |
31 | public void setPageSize(Integer pageSize) {
32 | this.pageSize = pageSize;
33 | }
34 |
35 | public Integer getCount() {
36 | return count;
37 | }
38 |
39 | public void setCount(Integer count) {
40 | this.count = count;
41 | }
42 |
43 | public Integer getPageCount() {
44 | return pageCount;
45 | }
46 |
47 | public void setPageCount(Integer pageCount) {
48 | this.pageCount = pageCount;
49 | }
50 |
51 | public Integer getTotalCount() {
52 | return totalCount;
53 | }
54 |
55 | public void setTotalCount(Integer totalCount) {
56 | this.totalCount = totalCount;
57 |
58 | if (totalCount % pageSize == 0) {
59 | this.pageCount = totalCount / pageSize;
60 | } else {
61 | this.pageCount = totalCount / pageSize + 1;
62 | }
63 | }
64 |
65 | public List getResultList() {
66 | return resultList;
67 | }
68 |
69 | public void setResultList(List resultList) {
70 | this.resultList = resultList;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/entity/param/AddHttpJobParam.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.entity.param;
2 |
3 |
4 | import javax.validation.constraints.NotEmpty;
5 |
6 | public class AddHttpJobParam {
7 |
8 | @NotEmpty(message = "任务名称不能为空")
9 | private String jobName;
10 |
11 | @NotEmpty(message = "任务分组不能为空")
12 | private String jobGroup;
13 |
14 | private String description;
15 |
16 | @NotEmpty(message = "请求类型不能为空")
17 | private String requestType;
18 |
19 | @NotEmpty(message = "请求URL不能为空")
20 | private String url;
21 |
22 | private String params;
23 |
24 | @NotEmpty(message = "cron表达式不能为空")
25 | private String cronExpression;
26 |
27 | public String getJobName() {
28 | return jobName;
29 | }
30 |
31 | public void setJobName(String jobName) {
32 | this.jobName = jobName;
33 | }
34 |
35 | public String getJobGroup() {
36 | return jobGroup;
37 | }
38 |
39 | public void setJobGroup(String jobGroup) {
40 | this.jobGroup = jobGroup;
41 | }
42 |
43 | public String getDescription() {
44 | return description;
45 | }
46 |
47 | public void setDescription(String description) {
48 | this.description = description;
49 | }
50 |
51 | public String getRequestType() {
52 | return requestType;
53 | }
54 |
55 | public void setRequestType(String requestType) {
56 | this.requestType = requestType;
57 | }
58 |
59 | public String getUrl() {
60 | return url;
61 | }
62 |
63 | public void setUrl(String url) {
64 | this.url = url;
65 | }
66 |
67 | public String getParams() {
68 | return params;
69 | }
70 |
71 | public void setParams(String params) {
72 | this.params = params;
73 | }
74 |
75 | public String getCronExpression() {
76 | return cronExpression;
77 | }
78 |
79 | public void setCronExpression(String cronExpression) {
80 | this.cronExpression = cronExpression;
81 | }
82 |
83 | @Override
84 | public String toString() {
85 | return "AddHttpJobParam{" +
86 | "jobName='" + jobName + '\'' +
87 | ", jobGroup='" + jobGroup + '\'' +
88 | ", requestType='" + requestType + '\'' +
89 | ", url='" + url + '\'' +
90 | ", params='" + params + '\'' +
91 | ", cronExpression='" + cronExpression + '\'' +
92 | '}';
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/entity/vo/HttpJobDetailVO.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.entity.vo;
2 |
3 | import com.alibaba.fastjson.annotation.JSONField;
4 |
5 | import java.util.Date;
6 |
7 | public class HttpJobDetailVO {
8 |
9 | private String jobName;
10 |
11 | private String jobGroup;
12 |
13 | private String description;
14 |
15 | private String jobStatusInfo;
16 |
17 | private String requestType;
18 |
19 | private String httpUrl;
20 |
21 | private String httpParams;
22 |
23 | @JSONField(format = "yyyy-MM-dd HH:mm:ss")
24 | private Date nextFireTime;
25 |
26 | @JSONField(format = "yyyy-MM-dd HH:mm:ss")
27 | private Date createTime;
28 |
29 | private String cronExpression;
30 |
31 | public String getJobName() {
32 | return jobName;
33 | }
34 |
35 | public void setJobName(String jobName) {
36 | this.jobName = jobName;
37 | }
38 |
39 | public String getJobGroup() {
40 | return jobGroup;
41 | }
42 |
43 | public void setJobGroup(String jobGroup) {
44 | this.jobGroup = jobGroup;
45 | }
46 |
47 | public String getDescription() {
48 | return description;
49 | }
50 |
51 | public void setDescription(String description) {
52 | this.description = description;
53 | }
54 |
55 | public String getJobStatusInfo() {
56 | return jobStatusInfo;
57 | }
58 |
59 | public void setJobStatusInfo(String jobStatusInfo) {
60 | this.jobStatusInfo = jobStatusInfo;
61 | }
62 |
63 | public String getRequestType() {
64 | return requestType;
65 | }
66 |
67 | public void setRequestType(String requestType) {
68 | this.requestType = requestType;
69 | }
70 |
71 | public String getHttpUrl() {
72 | return httpUrl;
73 | }
74 |
75 | public void setHttpUrl(String httpUrl) {
76 | this.httpUrl = httpUrl;
77 | }
78 |
79 | public String getHttpParams() {
80 | return httpParams;
81 | }
82 |
83 | public void setHttpParams(String httpParams) {
84 | this.httpParams = httpParams;
85 | }
86 |
87 | public Date getNextFireTime() {
88 | return nextFireTime;
89 | }
90 |
91 | public void setNextFireTime(Date nextFireTime) {
92 | this.nextFireTime = nextFireTime;
93 | }
94 |
95 | public Date getCreateTime() {
96 | return createTime;
97 | }
98 |
99 | public void setCreateTime(Date createTime) {
100 | this.createTime = createTime;
101 | }
102 |
103 | public String getCronExpression() {
104 | return cronExpression;
105 | }
106 |
107 | public void setCronExpression(String cronExpression) {
108 | this.cronExpression = cronExpression;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/job/HttpGetJob.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.job;
2 |
3 | import com.example.quartz.constants.Constant;
4 | import com.example.quartz.entity.HttpJobLogs;
5 | import com.example.quartz.mapper.HttpJobLogsMapper;
6 | import com.example.quartz.util.HttpClientUtil;
7 | import org.apache.logging.log4j.LogManager;
8 | import org.apache.logging.log4j.Logger;
9 | import org.quartz.*;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 |
12 | import java.util.Map;
13 |
14 | @DisallowConcurrentExecution
15 | public class HttpGetJob implements Job {
16 |
17 | private static final Logger logger = LogManager.getLogger(HttpPostJsonJob.class);
18 |
19 | @Autowired
20 | private HttpJobLogsMapper httpJobLogsMapper;
21 |
22 | @Override
23 | public void execute(JobExecutionContext jobExecutionContext) {
24 | JobDetail jobDetail = jobExecutionContext.getJobDetail();
25 | String jobName = jobDetail.getKey().getName();
26 | String jobGroup = jobDetail.getKey().getGroup();
27 |
28 | Map jobParamsMap = jobDetail.getJobDataMap();
29 |
30 | String requestType = (String) jobParamsMap.get(Constant.REQUEST_TYPE);
31 | String url = (String) jobParamsMap.get(Constant.URL);
32 | Map paramMap = (Map) jobParamsMap.get(Constant.PARAMS);
33 |
34 | HttpJobLogs httpJobLogs = new HttpJobLogs();
35 | httpJobLogs.setJobName(jobName);
36 | httpJobLogs.setJobGroup(jobGroup);
37 | httpJobLogs.setRequestType(requestType);
38 | httpJobLogs.setHttpUrl(url);
39 | if (null != paramMap && paramMap.size() > 0) {
40 | httpJobLogs.setHttpParams(paramMap.toString());
41 | }
42 |
43 | String result = HttpClientUtil.getMap(url, paramMap);
44 | httpJobLogs.setResult(result);
45 |
46 | logger.info("Success in execute [{}_{}]", jobName, jobGroup);
47 |
48 | httpJobLogsMapper.insertSelective(httpJobLogs);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/job/HttpPostFormDataJob.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.job;
2 |
3 | import com.example.quartz.constants.Constant;
4 | import com.example.quartz.entity.HttpJobLogs;
5 | import com.example.quartz.mapper.HttpJobLogsMapper;
6 | import com.example.quartz.util.HttpClientUtil;
7 | import org.apache.logging.log4j.LogManager;
8 | import org.apache.logging.log4j.Logger;
9 | import org.quartz.*;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 |
12 | import java.util.Map;
13 |
14 | @DisallowConcurrentExecution
15 | public class HttpPostFormDataJob implements Job {
16 |
17 | private static final Logger logger = LogManager.getLogger(HttpPostJsonJob.class);
18 |
19 | @Autowired
20 | private HttpJobLogsMapper httpJobLogsMapper;
21 |
22 | @Override
23 | public void execute(JobExecutionContext jobExecutionContext) {
24 | JobDetail jobDetail = jobExecutionContext.getJobDetail();
25 | String jobName = jobDetail.getKey().getName();
26 | String jobGroup = jobDetail.getKey().getGroup();
27 |
28 | Map jobParamsMap = jobDetail.getJobDataMap();
29 |
30 | String requestType = (String) jobParamsMap.get(Constant.REQUEST_TYPE);
31 | String url = (String) jobParamsMap.get(Constant.URL);
32 | Map formDataParamMap = (Map) jobParamsMap.get(Constant.PARAMS);
33 |
34 | HttpJobLogs httpJobLogs = new HttpJobLogs();
35 | httpJobLogs.setJobName(jobName);
36 | httpJobLogs.setJobGroup(jobGroup);
37 | httpJobLogs.setRequestType(requestType);
38 | httpJobLogs.setHttpUrl(url);
39 | if (null != formDataParamMap && formDataParamMap.size() > 0) {
40 | httpJobLogs.setHttpParams(formDataParamMap.toString());
41 | }
42 |
43 | String result = HttpClientUtil.postFormData(url, formDataParamMap);
44 | httpJobLogs.setResult(result);
45 |
46 | logger.info("Success in execute [{}_{}]", jobName, jobGroup);
47 |
48 | httpJobLogsMapper.insertSelective(httpJobLogs);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/job/HttpPostJsonJob.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.job;
2 |
3 | import com.example.quartz.constants.Constant;
4 | import com.example.quartz.entity.HttpJobLogs;
5 | import com.example.quartz.mapper.HttpJobLogsMapper;
6 | import com.example.quartz.util.HttpClientUtil;
7 | import org.apache.logging.log4j.LogManager;
8 | import org.apache.logging.log4j.Logger;
9 | import org.quartz.*;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 |
12 | import java.util.Map;
13 |
14 | @DisallowConcurrentExecution
15 | public class HttpPostJsonJob implements Job {
16 |
17 | private static final Logger logger = LogManager.getLogger(HttpPostJsonJob.class);
18 |
19 | @Autowired
20 | private HttpJobLogsMapper httpJobLogsMapper;
21 |
22 | @Override
23 | public void execute(JobExecutionContext jobExecutionContext) {
24 | JobDetail jobDetail = jobExecutionContext.getJobDetail();
25 | String jobName = jobDetail.getKey().getName();
26 | String jobGroup = jobDetail.getKey().getGroup();
27 |
28 | Map jobParamsMap = jobDetail.getJobDataMap();
29 |
30 | String requestType = (String) jobParamsMap.get(Constant.REQUEST_TYPE);
31 | String url = (String) jobParamsMap.get(Constant.URL);
32 | String jsonParam = (String) jobParamsMap.get(Constant.PARAMS);
33 |
34 | HttpJobLogs httpJobLogs = new HttpJobLogs();
35 | httpJobLogs.setJobName(jobName);
36 | httpJobLogs.setJobGroup(jobGroup);
37 | httpJobLogs.setRequestType(requestType);
38 | httpJobLogs.setHttpUrl(url);
39 | httpJobLogs.setHttpParams(jsonParam);
40 |
41 | String result = HttpClientUtil.postJson(url, jsonParam);
42 | httpJobLogs.setResult(result);
43 |
44 | logger.info("Success in execute [{}_{}]", jobName, jobGroup);
45 |
46 | httpJobLogsMapper.insertSelective(httpJobLogs);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/mapper/HttpJobDetailsMapper.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.mapper;
2 |
3 | import com.example.quartz.entity.HttpJobDetails;
4 | import com.example.quartz.entity.vo.HttpJobDetailVO;
5 | import org.apache.ibatis.annotations.Param;
6 | import org.springframework.stereotype.Repository;
7 |
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | @Repository
12 | public interface HttpJobDetailsMapper {
13 |
14 | HttpJobDetails selectByJobNameAndJobGroup(@Param("jobName") String jobName, @Param("jobGroup") String jobGroup);
15 |
16 | int insertSelective(HttpJobDetails httpJobDetails);
17 |
18 | List selectHttpJobs(Map map);
19 |
20 | Integer selectHttpJobsCount(Map map);
21 |
22 | List selectHistoryHttpJobs(Map map);
23 |
24 | Integer selectHistoryHttpJobsCount(Map map);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/mapper/HttpJobLogsMapper.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.mapper;
2 |
3 | import com.example.quartz.entity.HttpJobLogs;
4 | import org.springframework.stereotype.Repository;
5 |
6 | import java.util.List;
7 | import java.util.Map;
8 |
9 | @Repository
10 | public interface HttpJobLogsMapper {
11 |
12 | int insertSelective(HttpJobLogs httpJobLogs);
13 |
14 | List selectHttpJobLogs(Map map);
15 |
16 | Integer selectHttpJobLogsCount(Map map);
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/service/HttpJobService.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.service;
2 |
3 | import com.example.quartz.entity.HttpJobLogs;
4 | import com.example.quartz.entity.Page;
5 | import com.example.quartz.entity.param.AddHttpJobParam;
6 | import com.example.quartz.entity.vo.HttpJobDetailVO;
7 |
8 | /**
9 | * Http类型任务Service
10 | *
11 | * @author hellofly
12 | * @date 2019/4/9
13 | */
14 | public interface HttpJobService {
15 |
16 | /**
17 | * 添加http类型job
18 | *
19 | * @param addHttpJobParam
20 | */
21 | void addHttpJob(AddHttpJobParam addHttpJobParam);
22 |
23 | /**
24 | * 查看正在进行的http类型job
25 | *
26 | * @param searchParam
27 | * @param pageSize
28 | * @param pageNum
29 | * @return
30 | */
31 | Page getHttpJobs(String searchParam, Integer pageSize, Integer pageNum);
32 |
33 | /**
34 | * 查看历史http类型job
35 | *
36 | * @param searchParam
37 | * @param pageSize
38 | * @param pageNum
39 | * @return
40 | */
41 | Page getHistoryHttpJobs(String searchParam, Integer pageSize, Integer pageNum);
42 |
43 | /**
44 | * 查看http类型的job执行记录
45 | *
46 | * @param jobName
47 | * @param jobGroup
48 | * @param searchParam
49 | * @param pageSize
50 | * @param pageNum
51 | * @return
52 | */
53 | Page getHttpJobLogs(String jobName, String jobGroup, String searchParam, Integer pageSize, Integer pageNum);
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/service/JobManageService.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.service;
2 |
3 | public interface JobManageService {
4 |
5 | /**
6 | * 暂停任务
7 | *
8 | * @param jobName
9 | * @param jobGroup
10 | */
11 | void pauseJob(String jobName, String jobGroup);
12 |
13 | /**
14 | * 恢复任务
15 | *
16 | * @param jobName
17 | * @param jobGroup
18 | */
19 | void resumeJob(String jobName, String jobGroup);
20 |
21 | /**
22 | * 删除任务
23 | *
24 | * @param jobName
25 | * @param jobGroup
26 | */
27 | void deleteJob(String jobName, String jobGroup);
28 |
29 | /**
30 | * 更新任务cron表达式
31 | *
32 | * @param jobName
33 | * @param jobGroup
34 | * @param cronExpression
35 | */
36 | void updateCronExpression(String jobName, String jobGroup, String cronExpression);
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/service/impl/HttpJobServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.service.impl;
2 |
3 | import com.alibaba.fastjson.JSON;
4 | import com.example.quartz.constants.Constant;
5 | import com.example.quartz.entity.HttpJobDetails;
6 | import com.example.quartz.entity.HttpJobLogs;
7 | import com.example.quartz.entity.Page;
8 | import com.example.quartz.entity.param.AddHttpJobParam;
9 | import com.example.quartz.entity.vo.HttpJobDetailVO;
10 | import com.example.quartz.job.HttpGetJob;
11 | import com.example.quartz.job.HttpPostFormDataJob;
12 | import com.example.quartz.job.HttpPostJsonJob;
13 | import com.example.quartz.mapper.HttpJobDetailsMapper;
14 | import com.example.quartz.mapper.HttpJobLogsMapper;
15 | import com.example.quartz.service.HttpJobService;
16 | import com.example.quartz.util.JobUtil;
17 | import com.example.quartz.util.JsonValidUtil;
18 | import org.apache.commons.lang3.StringUtils;
19 | import org.apache.logging.log4j.LogManager;
20 | import org.apache.logging.log4j.Logger;
21 | import org.quartz.*;
22 | import org.springframework.beans.factory.annotation.Autowired;
23 | import org.springframework.stereotype.Service;
24 | import org.springframework.transaction.annotation.Transactional;
25 |
26 | import javax.annotation.Resource;
27 | import java.util.HashMap;
28 | import java.util.List;
29 | import java.util.Map;
30 |
31 | /**
32 | * Http类型任务Service
33 | *
34 | * @author hellofly
35 | * @date 2019/4/9
36 | */
37 | @Service
38 | public class HttpJobServiceImpl implements HttpJobService {
39 |
40 | private static final Logger logger = LogManager.getLogger(HttpJobServiceImpl.class);
41 |
42 | @Autowired
43 | private Scheduler scheduler;
44 |
45 | @Autowired
46 | private HttpJobLogsMapper httpJobLogsMapper;
47 |
48 | @Autowired
49 | private HttpJobDetailsMapper httpJobDetailsMapper;
50 |
51 | @Resource
52 | private JobUtil jobUtil;
53 |
54 | @Override
55 | @Transactional(rollbackFor = Exception.class)
56 | public void addHttpJob(AddHttpJobParam addHttpJobParam) {
57 |
58 | String jobName = addHttpJobParam.getJobName();
59 | String jobGroup = addHttpJobParam.getJobGroup();
60 | HttpJobDetails httpJobDetails = httpJobDetailsMapper.selectByJobNameAndJobGroup(jobName, jobGroup);
61 | if (httpJobDetails != null) {
62 | //通过jobName和jobGroup确保任务的唯一性
63 | throw new RuntimeException("任务名称重复!");
64 | }
65 |
66 | String requestType = addHttpJobParam.getRequestType();
67 | String description = addHttpJobParam.getDescription();
68 | String cronExpression = addHttpJobParam.getCronExpression();
69 | String url = addHttpJobParam.getUrl();
70 | String jsonParamsStr = addHttpJobParam.getParams();
71 |
72 | httpJobDetails = new HttpJobDetails();
73 | httpJobDetails.setJobName(jobName);
74 | httpJobDetails.setJobGroup(jobGroup);
75 | httpJobDetails.setDescription(description);
76 | httpJobDetails.setRequestType(requestType);
77 | httpJobDetails.setHttpUrl(url);
78 | if (!JsonValidUtil.isJson(jsonParamsStr)) {
79 | throw new RuntimeException("请将请求参数转为合法的json字符串!");
80 | }
81 |
82 | Map jobParamsMap = new HashMap<>();
83 | jobParamsMap.put(Constant.URL, url);
84 | jobParamsMap.put(Constant.PARAMS, jsonParamsStr);
85 |
86 | JobDetail jobDetail = null;
87 | //根据不同类型的job构建job信息
88 | switch (requestType) {
89 | //postJson
90 | case Constant.POST_JSON:
91 | jobDetail = JobBuilder.newJob(HttpPostJsonJob.class)
92 | .withIdentity(jobName, jobGroup)
93 | .build();
94 |
95 | //jsonStr的参数直接用
96 | if (StringUtils.isNotEmpty(jsonParamsStr)) {
97 | httpJobDetails.setHttpParams(jsonParamsStr);
98 | }
99 | break;
100 |
101 | //postFormData
102 | case Constant.POST_FORM_DATA:
103 | jobDetail = JobBuilder.newJob(HttpPostFormDataJob.class)
104 | .withIdentity(jobName, jobGroup)
105 | .build();
106 |
107 | //jsonStr参数转为formData的Map
108 | Map formDataParamMap;
109 | if (StringUtils.isEmpty(jsonParamsStr)) {
110 | formDataParamMap = null;
111 | } else {
112 | formDataParamMap = JSON.parseObject(jsonParamsStr, Map.class);
113 | httpJobDetails.setHttpParams(formDataParamMap.toString());
114 | }
115 | jobParamsMap.put(Constant.PARAMS, formDataParamMap);
116 |
117 | break;
118 |
119 | //get
120 | case Constant.GET:
121 | jobDetail = JobBuilder.newJob(HttpGetJob.class)
122 | .withIdentity(jobName, jobGroup)
123 | .build();
124 |
125 | //jsonStr参数转为formData的Map
126 | Map paramMap;
127 | if (StringUtils.isEmpty(jsonParamsStr)) {
128 | paramMap = null;
129 | } else {
130 | paramMap = JSON.parseObject(jsonParamsStr, Map.class);
131 | httpJobDetails.setHttpParams(paramMap.toString());
132 | }
133 | jobParamsMap.put(Constant.PARAMS, paramMap);
134 |
135 | break;
136 | }
137 |
138 | //任务信息
139 | jobDetail.getJobDataMap().putAll(jobParamsMap);
140 | jobDetail.getJobDataMap().put(Constant.REQUEST_TYPE, requestType);
141 |
142 | //表达式调度构建器(即任务执行的时间)
143 | CronScheduleBuilder scheduleBuilder;
144 | try {
145 | scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
146 | } catch (Exception e) {
147 | throw new RuntimeException("Illegal CronExpression!");
148 | }
149 |
150 | TriggerKey triggerKey = jobUtil.getTriggerKeyByJob(jobName, jobGroup);
151 |
152 | //构建一个trigger
153 | CronTrigger trigger = TriggerBuilder.newTrigger()
154 | .withIdentity(triggerKey)
155 | .startNow()
156 | .withSchedule(scheduleBuilder).build();
157 |
158 | try {
159 | // 调度容器设置JobDetail和Trigger
160 | scheduler.scheduleJob(jobDetail, trigger);
161 | // 启动
162 | if (!scheduler.isShutdown()) {
163 | scheduler.start();
164 | }
165 | } catch (Exception e) {
166 | throw new RuntimeException("Schedule Exception.", e);
167 | }
168 |
169 | httpJobDetailsMapper.insertSelective(httpJobDetails);
170 | logger.info("Success in addJob, [{}]-[{}]", jobName, jobGroup);
171 |
172 | }
173 |
174 | @Override
175 | public Page getHttpJobs(String searchParam, Integer pageSize, Integer pageNum) {
176 | Integer beginIndex = (pageNum - 1) * pageSize;
177 |
178 | Map sqlMap = new HashMap<>();
179 | sqlMap.put("searchParam", searchParam);
180 | sqlMap.put("pageSize", pageSize);
181 | sqlMap.put("beginIndex", beginIndex);
182 |
183 | List httpJobDetailVOList = httpJobDetailsMapper.selectHttpJobs(sqlMap);
184 |
185 | for (HttpJobDetailVO httpJobDetailVO : httpJobDetailVOList) {
186 | //设置jobStatusInfo
187 | String jobStatusInfo = jobUtil.getJobStatusInfo(httpJobDetailVO.getJobName(), httpJobDetailVO.getJobGroup());
188 | httpJobDetailVO.setJobStatusInfo(jobStatusInfo);
189 | //任务状态正常,根据cron表达式计算下次运行时间
190 | if (StringUtils.equals(jobStatusInfo, Constant.JOB_STATUS_NORMAL)) {
191 | httpJobDetailVO.setNextFireTime(jobUtil.getNextFireDate(httpJobDetailVO.getCronExpression()));
192 | }
193 | }
194 |
195 | Page httpJobDetailVOPageVO = new Page<>();
196 | httpJobDetailVOPageVO.setPageNum(pageNum);
197 | httpJobDetailVOPageVO.setPageSize(pageSize);
198 | httpJobDetailVOPageVO.setCount(httpJobDetailVOList.size());
199 | httpJobDetailVOPageVO.setTotalCount(httpJobDetailsMapper.selectHttpJobsCount(sqlMap));
200 | httpJobDetailVOPageVO.setResultList(httpJobDetailVOList);
201 |
202 | return httpJobDetailVOPageVO;
203 | }
204 |
205 | @Override
206 | public Page getHistoryHttpJobs(String searchParam, Integer pageSize, Integer pageNum) {
207 | Integer beginIndex = (pageNum - 1) * pageSize;
208 |
209 | Map sqlMap = new HashMap<>();
210 | sqlMap.put("searchParam", searchParam);
211 | sqlMap.put("pageSize", pageSize);
212 | sqlMap.put("beginIndex", beginIndex);
213 |
214 | List httpJobDetailVOList = httpJobDetailsMapper.selectHistoryHttpJobs(sqlMap);
215 |
216 | Page httpJobDetailVOPageVO = new Page<>();
217 | httpJobDetailVOPageVO.setPageNum(pageNum);
218 | httpJobDetailVOPageVO.setPageSize(pageSize);
219 | httpJobDetailVOPageVO.setCount(httpJobDetailVOList.size());
220 | httpJobDetailVOPageVO.setTotalCount(httpJobDetailsMapper.selectHistoryHttpJobsCount(sqlMap));
221 | httpJobDetailVOPageVO.setResultList(httpJobDetailVOList);
222 |
223 | return httpJobDetailVOPageVO;
224 | }
225 |
226 | @Override
227 | public Page getHttpJobLogs(String jobName, String jobGroup, String searchParam, Integer pageSize, Integer pageNum) {
228 | Integer beginIndex = (pageNum - 1) * pageSize;
229 |
230 | Map sqlMap = new HashMap<>();
231 | sqlMap.put("jobName", jobName);
232 | sqlMap.put("jobGroup", jobGroup);
233 | sqlMap.put("searchParam", searchParam);
234 | sqlMap.put("pageSize", pageSize);
235 | sqlMap.put("beginIndex", beginIndex);
236 |
237 | List httpJobLogsList = httpJobLogsMapper.selectHttpJobLogs(sqlMap);
238 |
239 | Page httpJobDetailVOPageVO = new Page<>();
240 | httpJobDetailVOPageVO.setPageNum(pageNum);
241 | httpJobDetailVOPageVO.setPageSize(pageSize);
242 | httpJobDetailVOPageVO.setCount(httpJobLogsList.size());
243 | httpJobDetailVOPageVO.setTotalCount(httpJobLogsMapper.selectHttpJobLogsCount(sqlMap));
244 | httpJobDetailVOPageVO.setResultList(httpJobLogsList);
245 |
246 | return httpJobDetailVOPageVO;
247 | }
248 |
249 | }
250 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/service/impl/JobManageServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.service.impl;
2 |
3 | import com.example.quartz.constants.Constant;
4 | import com.example.quartz.service.JobManageService;
5 | import com.example.quartz.util.JobUtil;
6 | import org.apache.commons.lang3.StringUtils;
7 | import org.quartz.*;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Service;
10 |
11 | import javax.annotation.Resource;
12 |
13 | @Service
14 | public class JobManageServiceImpl implements JobManageService {
15 |
16 | @Autowired
17 | private Scheduler scheduler;
18 |
19 | @Resource
20 | private JobUtil jobUtil;
21 |
22 | @Override
23 | public void pauseJob(String jobName, String jobGroup) {
24 | String jobStatusInfo = jobUtil.getJobStatusInfo(jobName, jobGroup);
25 | if (StringUtils.equals(jobStatusInfo, Constant.JOB_STATUS_PAUSED)) {
26 | throw new RuntimeException("当前任务已是暂停状态!");
27 | }
28 | JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
29 | try {
30 | scheduler.pauseJob(jobKey);
31 | } catch (SchedulerException e) {
32 | throw new RuntimeException(e);
33 | }
34 | }
35 |
36 | @Override
37 | public void resumeJob(String jobName, String jobGroup) {
38 | String jobStatusInfo = jobUtil.getJobStatusInfo(jobName, jobGroup);
39 | if (!StringUtils.equals(jobStatusInfo, Constant.JOB_STATUS_PAUSED)) {
40 | throw new RuntimeException("任务仅在暂停状态时才能恢复!");
41 | }
42 | JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
43 | try {
44 | scheduler.resumeJob(jobKey);
45 | } catch (SchedulerException e) {
46 | throw new RuntimeException(e);
47 | }
48 | }
49 |
50 | @Override
51 | public void deleteJob(String jobName, String jobGroup) {
52 | JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
53 | TriggerKey triggerKey = jobUtil.getTriggerKeyByJob(jobName, jobGroup);
54 | try {
55 | scheduler.pauseTrigger(triggerKey);
56 | scheduler.unscheduleJob(triggerKey);
57 | scheduler.deleteJob(jobKey);
58 | } catch (SchedulerException e) {
59 | throw new RuntimeException(e);
60 | }
61 | }
62 |
63 | @Override
64 | public void updateCronExpression(String jobName, String jobGroup, String cronExpression) {
65 | TriggerKey triggerKey = jobUtil.getTriggerKeyByJob(jobName, jobGroup);
66 |
67 | //表达式调度构建器(即任务执行的时间)
68 | CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
69 |
70 | //按新的cronExpression重新构建trigger
71 | CronTrigger trigger = TriggerBuilder.newTrigger()
72 | .withIdentity(triggerKey)
73 | .withSchedule(scheduleBuilder).build();
74 | try {
75 | scheduler.rescheduleJob(triggerKey, trigger);
76 | } catch (SchedulerException e) {
77 | throw new RuntimeException(e);
78 | }
79 |
80 | }
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/util/HttpClientUtil.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.util;
2 |
3 | import org.apache.commons.codec.Charsets;
4 | import org.apache.commons.lang3.StringUtils;
5 | import org.apache.http.NameValuePair;
6 | import org.apache.http.client.config.RequestConfig;
7 | import org.apache.http.client.entity.UrlEncodedFormEntity;
8 | import org.apache.http.client.methods.CloseableHttpResponse;
9 | import org.apache.http.client.methods.HttpGet;
10 | import org.apache.http.client.methods.HttpPost;
11 | import org.apache.http.client.utils.HttpClientUtils;
12 | import org.apache.http.client.utils.URIBuilder;
13 | import org.apache.http.entity.StringEntity;
14 | import org.apache.http.impl.client.CloseableHttpClient;
15 | import org.apache.http.impl.client.HttpClients;
16 | import org.apache.http.message.BasicNameValuePair;
17 | import org.apache.http.util.EntityUtils;
18 | import org.apache.logging.log4j.LogManager;
19 | import org.apache.logging.log4j.Logger;
20 |
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.Map;
24 | import java.util.Map.Entry;
25 |
26 | /**
27 | * Httpclient请求工具类
28 | *
29 | * @author hellofly
30 | * @date 2019/4/9
31 | */
32 | public class HttpClientUtil {
33 |
34 | /**
35 | * 连接主机超时(30s)
36 | */
37 | public static final int HTTP_CONNECT_TIMEOUT_30S = 30 * 1000;
38 |
39 | /**
40 | * 从主机读取数据超时(3min)
41 | */
42 | public static final int HTTP_READ_TIMEOUT_3MIN = 180 * 1000;
43 |
44 | /**
45 | * HTTP成功状态码(200)
46 | */
47 | public static final int HTTP_SUCCESS_STATUS_CODE = 200;
48 |
49 | private static final Logger logger = LogManager.getLogger(HttpClientUtil.class);
50 |
51 | private HttpClientUtil() {
52 | }
53 |
54 | /**
55 | * get请求
56 | *
57 | * @param url
58 | * @param formDataParam
59 | * @return
60 | */
61 | public static String getMap(String url, Map formDataParam) {
62 | CloseableHttpClient httpclient = HttpClients.createDefault();
63 | CloseableHttpResponse response = null;
64 | String result = "";
65 | // 超时时间设置
66 | RequestConfig requestConfig = RequestConfig.custom()
67 | .setSocketTimeout(HTTP_READ_TIMEOUT_3MIN)
68 | .setConnectTimeout(HTTP_CONNECT_TIMEOUT_30S).build();
69 |
70 | try {
71 | URIBuilder builder = new URIBuilder(url);
72 | if (null != formDataParam && formDataParam.size() > 0) {
73 | // 创建参数队列
74 | List formParams = new ArrayList<>();
75 | for (Entry entry : formDataParam.entrySet()) {
76 | formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
77 | }
78 | builder.setParameters(formParams);
79 | }
80 | // 设置参数
81 | HttpGet httpGet = new HttpGet(builder.build());
82 | httpGet.setConfig(requestConfig);
83 |
84 | // 发送请求
85 | response = httpclient.execute(httpGet);
86 | result = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
87 | if (response.getStatusLine().getStatusCode() != HTTP_SUCCESS_STATUS_CODE) {
88 | logger.error("Error in getMap. Request URL is [{}], params [{}]. Result:[{}]", url, formDataParam, result);
89 | }
90 | } catch (Exception e) {
91 | logger.error("Error in getMap", e);
92 | } finally {
93 | HttpClientUtils.closeQuietly(httpclient);
94 | HttpClientUtils.closeQuietly(response);
95 | }
96 | return result;
97 | }
98 |
99 | /**
100 | * postFormData
101 | *
102 | * @param url
103 | * @param formDataParam
104 | * @return
105 | */
106 | public static String postFormData(String url, Map formDataParam) {
107 | CloseableHttpClient httpclient = HttpClients.createDefault();
108 | CloseableHttpResponse response = null;
109 | String result = "";
110 | // 超时时间设置
111 | RequestConfig requestConfig = RequestConfig.custom()
112 | .setSocketTimeout(HTTP_READ_TIMEOUT_3MIN)
113 | .setConnectTimeout(HTTP_CONNECT_TIMEOUT_30S).build();
114 |
115 | HttpPost httpPost = new HttpPost(url);
116 | httpPost.setConfig(requestConfig);
117 | try {
118 | if (null != formDataParam && formDataParam.size() > 0) {
119 | // 创建参数队列
120 | List formParams = new ArrayList<>();
121 | for (Entry entry : formDataParam.entrySet()) {
122 | formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
123 | }
124 | // 设置参数
125 | UrlEncodedFormEntity urlEntity = new UrlEncodedFormEntity(formParams, Charsets.UTF_8);
126 | httpPost.setEntity(urlEntity);
127 | }
128 |
129 | // 发送请求
130 | response = httpclient.execute(httpPost);
131 | result = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
132 | if (response.getStatusLine().getStatusCode() != HTTP_SUCCESS_STATUS_CODE) {
133 | logger.error("Error in postFormData. Request URL is [{}], params [{}]. Result:[{}]", url, formDataParam, result);
134 | }
135 | } catch (Exception e) {
136 | logger.error("Error in postFormData", e);
137 | } finally {
138 | HttpClientUtils.closeQuietly(httpclient);
139 | HttpClientUtils.closeQuietly(response);
140 | }
141 | return result;
142 | }
143 |
144 | /**
145 | * postJson
146 | *
147 | * @param url
148 | * @param jsonParam
149 | * @return
150 | */
151 | public static String postJson(String url, String jsonParam) {
152 | CloseableHttpClient httpclient = HttpClients.createDefault();
153 | CloseableHttpResponse response = null;
154 | String result = "";
155 | // 超时时间设置
156 | RequestConfig requestConfig = RequestConfig.custom()
157 | .setSocketTimeout(HTTP_READ_TIMEOUT_3MIN)
158 | .setConnectTimeout(HTTP_CONNECT_TIMEOUT_30S).build();
159 |
160 | HttpPost httpPost = new HttpPost(url);
161 | httpPost.setConfig(requestConfig);
162 | // 设置请求头和请求参数
163 | if (StringUtils.isNotEmpty(jsonParam)) {
164 | StringEntity entity = new StringEntity(jsonParam, "utf-8");
165 | entity.setContentEncoding("UTF-8");
166 | entity.setContentType("application/json");
167 | httpPost.setEntity(entity);
168 | }
169 |
170 | try {
171 | // 发送请求
172 | response = httpclient.execute(httpPost);
173 | result = EntityUtils.toString(response.getEntity(), Charsets.UTF_8);
174 | if (response.getStatusLine().getStatusCode() != HTTP_SUCCESS_STATUS_CODE) {
175 | logger.error("Error in postJson. Request URL is [{}], params [{}]. Result:[{}]", url, jsonParam, result);
176 | }
177 | } catch (Exception e) {
178 | logger.error("Error in postJson", e);
179 | } finally {
180 | HttpClientUtils.closeQuietly(httpclient);
181 | HttpClientUtils.closeQuietly(response);
182 | }
183 | return result;
184 | }
185 |
186 | }
187 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/util/JobUtil.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.util;
2 |
3 | import com.example.quartz.constants.Constant;
4 | import org.quartz.CronExpression;
5 | import org.quartz.Scheduler;
6 | import org.quartz.SchedulerException;
7 | import org.quartz.TriggerKey;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Component;
10 |
11 | import java.text.ParseException;
12 | import java.util.Date;
13 |
14 | /**
15 | * job工具类
16 | *
17 | * @author hellofly
18 | * @date 2019/4/9
19 | */
20 | @Component
21 | public class JobUtil {
22 |
23 | @Autowired
24 | private Scheduler scheduler;
25 |
26 | /**
27 | * 根据jobName和jobGroup生成triggerKey
28 | *
29 | * @param jobName
30 | * @param jobGroup
31 | * @return
32 | */
33 | public TriggerKey getTriggerKeyByJob(String jobName, String jobGroup) {
34 | String triggerName = Constant.TRIGGER_PREFIX + jobName;
35 | String triggerGroup = Constant.TRIGGER_PREFIX + jobGroup;
36 | return TriggerKey.triggerKey(triggerName, triggerGroup);
37 | }
38 |
39 | /**
40 | * 获取job状态
41 | *
42 | * @param jobName
43 | * @param jobGroup
44 | * @return
45 | */
46 | public String getJobStatusInfo(String jobName, String jobGroup) {
47 | String jobStatusInfo = "";
48 | TriggerKey triggerKey = getTriggerKeyByJob(jobName, jobGroup);
49 | try {
50 | jobStatusInfo = scheduler.getTriggerState(triggerKey).name();
51 | } catch (SchedulerException e) {
52 | throw new RuntimeException(e);
53 | }
54 | return jobStatusInfo;
55 | }
56 |
57 | /**
58 | * 根据cron表达式获取下次执行时间
59 | *
60 | * @param cronExpression
61 | * @return
62 | */
63 | public Date getNextFireDate(String cronExpression) {
64 | try {
65 | CronExpression cron = new CronExpression(cronExpression);
66 | Date nextFireDate = cron.getNextValidTimeAfter(new Date());
67 | return nextFireDate;
68 | } catch (ParseException e) {
69 | throw new RuntimeException(e);
70 | }
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/example/quartz/util/JsonValidUtil.java:
--------------------------------------------------------------------------------
1 | package com.example.quartz.util;
2 |
3 | import com.alibaba.fastjson.JSONObject;
4 |
5 | /**
6 | * JSON校验工具类
7 | *
8 | * @author hellofly
9 | * @date 2019/4/9
10 | */
11 | public class JsonValidUtil {
12 |
13 | /**
14 | * 判断字符串是否为json格式
15 | *
16 | * @param jsonStr
17 | * @return
18 | */
19 | public static boolean isJson(String jsonStr) {
20 | try {
21 | JSONObject.parseObject(jsonStr);
22 | return true;
23 | } catch (Exception e) {
24 | return false;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=8080
2 |
3 | #UTF-8字符过滤
4 | spring.http.encoding.charset=UTF-8
5 | spring.http.encoding.enabled=true
6 | spring.http.encoding.force=true
7 |
8 | # mysql
9 | spring.datasource.url=jdbc:mysql://your_db/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false
10 | spring.datasource.username=username
11 | spring.datasource.password=password
12 | spring.datasource.driverClassName=com.mysql.jdbc.Driver
13 |
14 | # druid连接池的配置信息
15 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
16 | spring.datasource.initialSize=5
17 | spring.datasource.minIdle=5
18 | spring.datasource.maxActive=20
19 | spring.datasource.maxWait=60000
20 | spring.datasource.timeBetweenEvictionRunsMillis=60000
21 | spring.datasource.minEvictableIdleTimeMillis=300000
22 | spring.datasource.validationQuery=SELECT 1 FROM DUAL
23 | spring.datasource.testWhileIdle=true
24 | spring.datasource.testOnBorrow=false
25 | spring.datasource.testOnReturn=false
26 | spring.datasource.poolPreparedStatements=true
27 | spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
28 | spring.datasource.filters=stat
29 | spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
30 |
31 | # mybatis Mapper文件
32 | mybatis.mapper-locations=classpath*:mappings/*.xml
33 | # mybatis别名配置
34 | mybatis.type-aliases-package=com.example.quartz.model
35 |
--------------------------------------------------------------------------------
/src/main/resources/mappings/HttpJobDetailsMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | ID,JOB_NAME,JOB_GROUP,DESCRIPTION,REQUEST_TYPE,HTTP_URL,HTTP_PARAMS,CREATE_TIME,UPDATE_TIME
19 |
20 |
21 |
27 |
28 |
29 | insert into HTTPJOB_DETAILS
30 |
31 |
32 | JOB_NAME,
33 |
34 |
35 | JOB_GROUP,
36 |
37 |
38 | DESCRIPTION,
39 |
40 |
41 | REQUEST_TYPE,
42 |
43 |
44 | HTTP_URL,
45 |
46 |
47 | HTTP_PARAMS,
48 |
49 |
50 |
51 |
52 | #{jobName,jdbcType=VARCHAR},
53 |
54 |
55 | #{jobGroup,jdbcType=VARCHAR},
56 |
57 |
58 | #{description,jdbcType=VARCHAR},
59 |
60 |
61 | #{requestType,jdbcType=VARCHAR},
62 |
63 |
64 | #{httpUrl,jdbcType=VARCHAR},
65 |
66 |
67 | #{httpParams,jdbcType=VARCHAR},
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
107 |
108 |
121 |
122 |
144 |
145 |
157 |
158 |
--------------------------------------------------------------------------------
/src/main/resources/mappings/HttpJobLogsMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ID,JOB_NAME,JOB_GROUP,REQUEST_TYPE,HTTP_URL,HTTP_PARAMS,FIRE_TIME,RESULT
18 |
19 |
20 |
21 | insert into HTTPJOB_LOGS
22 |
23 |
24 | JOB_NAME,
25 |
26 |
27 | JOB_GROUP,
28 |
29 |
30 | REQUEST_TYPE,
31 |
32 |
33 | HTTP_URL,
34 |
35 |
36 | HTTP_PARAMS,
37 |
38 |
39 | FIRE_TIME,
40 |
41 |
42 | RESULT,
43 |
44 |
45 |
46 |
47 | #{jobName,jdbcType=VARCHAR},
48 |
49 |
50 | #{jobGroup,jdbcType=VARCHAR},
51 |
52 |
53 | #{requestType,jdbcType=VARCHAR},
54 |
55 |
56 | #{httpUrl,jdbcType=VARCHAR},
57 |
58 |
59 | #{httpParams,jdbcType=VARCHAR},
60 |
61 |
62 | #{fireTime,jdbcType=TIMESTAMP},
63 |
64 |
65 | #{result,jdbcType=VARCHAR},
66 |
67 |
68 |
69 |
70 |
91 |
92 |
109 |
110 |
--------------------------------------------------------------------------------
/src/main/resources/quartz.properties:
--------------------------------------------------------------------------------
1 | #quartz集群配置
2 | # ===========================================================================
3 | # Configure Main Scheduler Properties 调度器属性
4 | # ===========================================================================
5 | #调度标识名 集群中每一个实例都必须使用相同的名称
6 | org.quartz.scheduler.instanceName: MyQuartzScheduler
7 | #ID设置为自动获取 每一个必须不同
8 | org.quartz.scheduler.instanceId: AUTO
9 | #============================================================================
10 | # Configure ThreadPool
11 | #============================================================================
12 | #线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
13 | org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
14 | #指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
15 | org.quartz.threadPool.threadCount: 25
16 | #设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
17 | org.quartz.threadPool.threadPriority: 5
18 | #============================================================================
19 | # Configure JobStore
20 | #============================================================================
21 | # 信息保存时间 默认值60秒,misfire任务为错过调度触发时间的任务,超过60000ms后被判定为misfire
22 | org.quartz.jobStore.misfireThreshold: 60000
23 | #数据保存方式为数据库持久化
24 | org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
25 | #数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
26 | org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
27 | #JobDataMaps是否都为String类型
28 | org.quartz.jobStore.useProperties: false
29 | #数据库别名 随便取
30 | org.quartz.jobStore.dataSource: myDS
31 | #表的前缀,默认QRTZ_
32 | org.quartz.jobStore.tablePrefix: QRTZ_
33 | #是否加入集群
34 | org.quartz.jobStore.isClustered: true
35 | #调度实例失效的检查时间间隔
36 | org.quartz.jobStore.clusterCheckinInterval: 20000
37 | #避免集群环境下job重复执行
38 | org.quartz.jobStore.acquireTriggersWithinLock: true
39 |
--------------------------------------------------------------------------------
/src/main/resources/static/historyHttpJob.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 历史任务
6 |
7 |
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
查询
30 |
31 | 执行记录
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 执行记录
48 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/src/main/resources/static/httpJob.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 定时任务管理
6 |
7 |
8 |
9 |
10 |
11 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
添加任务
48 |
50 |
查询
51 |
52 | 执行记录
53 |
54 |
55 | 历史任务
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | {{scope.row.jobStatusInfo}}
66 | {{scope.row.jobStatusInfo}}
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | 执行记录
81 |
82 | 暂停
83 | 恢复
84 | 删除
85 | 修改
86 |
87 |
88 |
89 |
90 |
91 |
92 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
148 |
149 |
150 |
151 |
152 |
392 |
393 |
394 |
--------------------------------------------------------------------------------
/src/main/resources/static/httpJobLog.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 任务执行记录
6 |
7 |
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
查询
30 |
31 | 返回
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/src/main/resources/static/js/axios.min.js:
--------------------------------------------------------------------------------
1 | /* axios v0.19.0 | (c) 2019 by Matt Zabriskie */
2 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(5),a=n(22),u=n(11),c=r(u);c.Axios=i,c.create=function(e){return r(a(c.defaults,e))},c.Cancel=n(23),c.CancelToken=n(24),c.isCancel=n(10),c.all=function(e){return Promise.all(e)},c.spread=n(25),e.exports=c,e.exports.default=c},function(e,t,n){"use strict";function r(e){return"[object Array]"===j.call(e)}function o(e){return"[object ArrayBuffer]"===j.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===j.call(e)}function d(e){return"[object File]"===j.call(e)}function l(e){return"[object Blob]"===j.call(e)}function h(e){return"[object Function]"===j.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function g(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n
6 | * @license MIT
7 | */
8 | e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(2),s=n(6),i=n(7),a=n(8),u=n(22);r.prototype.request=function(e){"string"==typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=u(this.defaults,e),e.method=e.method?e.method.toLowerCase():"get";var t=[a,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},r.prototype.getUri=function(e){return e=u(this.defaults,e),s(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},o.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(o.merge(n||{},{method:e,url:t}))}}),o.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(o.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}if(s){var a=e.indexOf("#");a!==-1&&(e=e.slice(0,a)),e+=(e.indexOf("?")===-1?"?":"&")+s}return e}},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(9),i=n(10),a=n(11),u=n(20),c=n(21);e.exports=function(e){r(e),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||a.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process)?e=n(13):"undefined"!=typeof XMLHttpRequest&&(e=n(13)),e}var s=n(2),i=n(12),a={"Content-Type":"application/x-www-form-urlencoded"},u={adapter:o(),transformRequest:[function(e,t){return i(t,"Accept"),i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};u.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){u.headers[e]={}}),s.forEach(["post","put","patch"],function(e){u.headers[e]=s.merge(a)}),e.exports=u},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(14),s=n(6),i=n(17),a=n(18),u=n(15);e.exports=function(e){return new Promise(function(t,c){var f=e.data,p=e.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest;if(e.auth){var l=e.auth.username||"",h=e.auth.password||"";p.Authorization="Basic "+btoa(l+":"+h)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d.onreadystatechange=function(){if(d&&4===d.readyState&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?d.response:d.responseText,s={data:r,status:d.status,statusText:d.statusText,headers:n,config:e,request:d};o(t,c,s),d=null}},d.onabort=function(){d&&(c(u("Request aborted",e,"ECONNABORTED",d)),d=null)},d.onerror=function(){c(u("Network Error",e,null,d)),d=null},d.ontimeout=function(){c(u("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",d)),d=null},r.isStandardBrowserEnv()){var m=n(19),y=(e.withCredentials||a(e.url))&&e.xsrfCookieName?m.read(e.xsrfCookieName):void 0;y&&(p[e.xsrfHeaderName]=y)}if("setRequestHeader"in d&&r.forEach(p,function(e,t){"undefined"==typeof f&&"content-type"===t.toLowerCase()?delete p[t]:d.setRequestHeader(t,e)}),e.withCredentials&&(d.withCredentials=!0),e.responseType)try{d.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&d.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&d.upload&&d.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){d&&(d.abort(),c(e),d=null)}),void 0===f&&(f=null),d.send(f)})}},function(e,t,n){"use strict";var r=n(15);e.exports=function(e,t,n){var o=n.config.validateStatus;!o||o(n.status)?e(n):t(r("Request failed with status code "+n.status,n.config,null,n.request,n))}},function(e,t,n){"use strict";var r=n(16);e.exports=function(e,t,n,o,s){var i=new Error(e);return r(i,t,n,o,s)}},function(e,t){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e.isAxiosError=!0,e.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code}},e}},function(e,t,n){"use strict";var r=n(2),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,s,i={};return e?(r.forEach(e.split("\n"),function(e){if(s=e.indexOf(":"),t=r.trim(e.substr(0,s)).toLowerCase(),n=r.trim(e.substr(s+1)),t){if(i[t]&&o.indexOf(t)>=0)return;"set-cookie"===t?i[t]=(i[t]?i[t]:[]).concat([n]):i[t]=i[t]?i[t]+", "+n:n}}),i):i}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,s,i){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(s)&&a.push("domain="+s),i===!0&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){t=t||{};var n={};return r.forEach(["url","method","params","data"],function(e){"undefined"!=typeof t[e]&&(n[e]=t[e])}),r.forEach(["headers","auth","proxy"],function(o){r.isObject(t[o])?n[o]=r.deepMerge(e[o],t[o]):"undefined"!=typeof t[o]?n[o]=t[o]:r.isObject(e[o])?n[o]=r.deepMerge(e[o]):"undefined"!=typeof e[o]&&(n[o]=e[o])}),r.forEach(["baseURL","transformRequest","transformResponse","paramsSerializer","timeout","withCredentials","adapter","responseType","xsrfCookieName","xsrfHeaderName","onUploadProgress","onDownloadProgress","maxContentLength","validateStatus","maxRedirects","httpAgent","httpsAgent","cancelToken","socketPath"],function(r){"undefined"!=typeof t[r]?n[r]=t[r]:"undefined"!=typeof e[r]&&(n[r]=e[r])}),n}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(23);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])});
9 | //# sourceMappingURL=axios.min.map
--------------------------------------------------------------------------------
/src/main/resources/static/js/vue.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Vue.js v2.5.16
3 | * (c) 2014-2018 Evan You
4 | * Released under the MIT License.
5 | */
6 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Vue=t()}(this,function(){"use strict";var y=Object.freeze({});function M(e){return null==e}function D(e){return null!=e}function S(e){return!0===e}function T(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function P(e){return null!==e&&"object"==typeof e}var r=Object.prototype.toString;function l(e){return"[object Object]"===r.call(e)}function i(e){var t=parseFloat(String(e));return 0<=t&&Math.floor(t)===t&&isFinite(e)}function t(e){return null==e?"":"object"==typeof e?JSON.stringify(e,null,2):String(e)}function F(e){var t=parseFloat(e);return isNaN(t)?e:t}function s(e,t){for(var n=Object.create(null),r=e.split(","),i=0;ie.id;)n--;bt.splice(n+1,0,e)}else bt.push(e);Ct||(Ct=!0,Ze(At))}}(this)},St.prototype.run=function(){if(this.active){var e=this.get();if(e!==this.value||P(e)||this.deep){var t=this.value;if(this.value=e,this.user)try{this.cb.call(this.vm,e,t)}catch(e){Fe(e,this.vm,'callback for watcher "'+this.expression+'"')}else this.cb.call(this.vm,e,t)}}},St.prototype.evaluate=function(){this.value=this.get(),this.dirty=!1},St.prototype.depend=function(){for(var e=this.deps.length;e--;)this.deps[e].depend()},St.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||f(this.vm._watchers,this);for(var e=this.deps.length;e--;)this.deps[e].removeSub(this);this.active=!1}};var Tt={enumerable:!0,configurable:!0,get:$,set:$};function Et(e,t,n){Tt.get=function(){return this[t][n]},Tt.set=function(e){this[t][n]=e},Object.defineProperty(e,n,Tt)}function jt(e){e._watchers=[];var t=e.$options;t.props&&function(n,r){var i=n.$options.propsData||{},o=n._props={},a=n.$options._propKeys=[];n.$parent&&ge(!1);var e=function(e){a.push(e);var t=Ie(e,r,i,n);Ce(o,e,t),e in n||Et(n,"_props",e)};for(var t in r)e(t);ge(!0)}(e,t.props),t.methods&&function(e,t){e.$options.props;for(var n in t)e[n]=null==t[n]?$:v(t[n],e)}(e,t.methods),t.data?function(e){var t=e.$options.data;l(t=e._data="function"==typeof t?function(e,t){se();try{return e.call(t,t)}catch(e){return Fe(e,t,"data()"),{}}finally{ce()}}(t,e):t||{})||(t={});var n=Object.keys(t),r=e.$options.props,i=(e.$options.methods,n.length);for(;i--;){var o=n[i];r&&p(r,o)||(void 0,36!==(a=(o+"").charCodeAt(0))&&95!==a&&Et(e,"_data",o))}var a;we(t,!0)}(e):we(e._data={},!0),t.computed&&function(e,t){var n=e._computedWatchers=Object.create(null),r=Y();for(var i in t){var o=t[i],a="function"==typeof o?o:o.get;r||(n[i]=new St(e,a||$,$,Nt)),i in e||Lt(e,i,o)}}(e,t.computed),t.watch&&t.watch!==G&&function(e,t){for(var n in t){var r=t[n];if(Array.isArray(r))for(var i=0;iparseInt(this.max)&&bn(a,s[0],s,this._vnode)),t.data.keepAlive=!0}return t||e&&e[0]}}};$n=hn,Cn={get:function(){return j}},Object.defineProperty($n,"config",Cn),$n.util={warn:re,extend:m,mergeOptions:Ne,defineReactive:Ce},$n.set=xe,$n.delete=ke,$n.nextTick=Ze,$n.options=Object.create(null),k.forEach(function(e){$n.options[e+"s"]=Object.create(null)}),m(($n.options._base=$n).options.components,kn),$n.use=function(e){var t=this._installedPlugins||(this._installedPlugins=[]);if(-1=a&&l()};setTimeout(function(){c\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/,oo="[a-zA-Z_][\\w\\-\\.]*",ao="((?:"+oo+"\\:)?"+oo+")",so=new RegExp("^<"+ao),co=/^\s*(\/?)>/,lo=new RegExp("^<\\/"+ao+"[^>]*>"),uo=/^]+>/i,fo=/^",""":'"',"&":"&","
":"\n"," ":"\t"},go=/&(?:lt|gt|quot|amp);/g,_o=/&(?:lt|gt|quot|amp|#10|#9);/g,bo=s("pre,textarea",!0),$o=function(e,t){return e&&bo(e)&&"\n"===t[0]};var wo,Co,xo,ko,Ao,Oo,So,To,Eo=/^@|^v-on:/,jo=/^v-|^@|^:/,No=/([^]*?)\s+(?:in|of)\s+([^]*)/,Lo=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,Io=/^\(|\)$/g,Mo=/:(.*)$/,Do=/^:|^v-bind:/,Po=/\.[^.]+/g,Fo=e(eo);function Ro(e,t,n){return{type:1,tag:e,attrsList:t,attrsMap:function(e){for(var t={},n=0,r=e.length;n]*>)","i")),n=i.replace(t,function(e,t,n){return r=n.length,ho(o)||"noscript"===o||(t=t.replace(//g,"$1").replace(//g,"$1")),$o(o,t)&&(t=t.slice(1)),d.chars&&d.chars(t),""});a+=i.length-n.length,i=n,A(o,a-r,a)}else{var s=i.indexOf("<");if(0===s){if(fo.test(i)){var c=i.indexOf("--\x3e");if(0<=c){d.shouldKeepComment&&d.comment(i.substring(4,c)),C(c+3);continue}}if(po.test(i)){var l=i.indexOf("]>");if(0<=l){C(l+2);continue}}var u=i.match(uo);if(u){C(u[0].length);continue}var f=i.match(lo);if(f){var p=a;C(f[0].length),A(f[1],p,a);continue}var _=x();if(_){k(_),$o(v,i)&&C(1);continue}}var b=void 0,$=void 0,w=void 0;if(0<=s){for($=i.slice(s);!(lo.test($)||so.test($)||fo.test($)||po.test($)||(w=$.indexOf("<",1))<0);)s+=w,$=i.slice(s);b=i.substring(0,s),C(s)}s<0&&(b=i,i=""),d.chars&&b&&d.chars(b)}if(i===e){d.chars&&d.chars(i);break}}function C(e){a+=e,i=i.substring(e)}function x(){var e=i.match(so);if(e){var t,n,r={tagName:e[1],attrs:[],start:a};for(C(e[0].length);!(t=i.match(co))&&(n=i.match(io));)C(n[0].length),r.attrs.push(n);if(t)return r.unarySlash=t[1],C(t[0].length),r.end=a,r}}function k(e){var t=e.tagName,n=e.unarySlash;m&&("p"===v&&ro(t)&&A(v),g(t)&&v===t&&A(t));for(var r,i,o,a=y(t)||!!n,s=e.attrs.length,c=new Array(s),l=0;l-1"+("true"===d?":("+l+")":":_q("+l+","+d+")")),Ar(c,"change","var $$a="+l+",$$el=$event.target,$$c=$$el.checked?("+d+"):("+v+");if(Array.isArray($$a)){var $$v="+(f?"_n("+p+")":p)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Er(l,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Er(l,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Er(l,"$$c")+"}",null,!0);else if("input"===$&&"radio"===w)r=e,i=_,a=(o=b)&&o.number,s=Or(r,"value")||"null",Cr(r,"checked","_q("+i+","+(s=a?"_n("+s+")":s)+")"),Ar(r,"change",Er(i,s),null,!0);else if("input"===$||"textarea"===$)!function(e,t,n){var r=e.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,l=o?"change":"range"===r?Pr:"input",u="$event.target.value";s&&(u="$event.target.value.trim()"),a&&(u="_n("+u+")");var f=Er(t,u);c&&(f="if($event.target.composing)return;"+f),Cr(e,"value","("+t+")"),Ar(e,l,f,null,!0),(s||a)&&Ar(e,"blur","$forceUpdate()")}(e,_,b);else if(!j.isReservedTag($))return Tr(e,_,b),!1;return!0},text:function(e,t){t.value&&Cr(e,"textContent","_s("+t.value+")")},html:function(e,t){t.value&&Cr(e,"innerHTML","_s("+t.value+")")}},isPreTag:function(e){return"pre"===e},isUnaryTag:to,mustUseProp:Sn,canBeLeftOpenTag:no,isReservedTag:Un,getTagNamespace:Vn,staticKeys:(Go=Wo,Go.reduce(function(e,t){return e.concat(t.staticKeys||[])},[]).join(","))},Qo=e(function(e){return s("type,tag,attrsList,attrsMap,plain,parent,children,attrs"+(e?","+e:""))});function ea(e,t){e&&(Zo=Qo(t.staticKeys||""),Xo=t.isReservedTag||O,function e(t){t.static=function(e){if(2===e.type)return!1;if(3===e.type)return!0;return!(!e.pre&&(e.hasBindings||e.if||e.for||c(e.tag)||!Xo(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(Zo)))}(t);if(1===t.type){if(!Xo(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var n=0,r=t.children.length;n|^function\s*\(/,na=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/,ra={esc:27,tab:9,enter:13,space:32,up:38,left:37,right:39,down:40,delete:[8,46]},ia={esc:"Escape",tab:"Tab",enter:"Enter",space:" ",up:["Up","ArrowUp"],left:["Left","ArrowLeft"],right:["Right","ArrowRight"],down:["Down","ArrowDown"],delete:["Backspace","Delete"]},oa=function(e){return"if("+e+")return null;"},aa={stop:"$event.stopPropagation();",prevent:"$event.preventDefault();",self:oa("$event.target !== $event.currentTarget"),ctrl:oa("!$event.ctrlKey"),shift:oa("!$event.shiftKey"),alt:oa("!$event.altKey"),meta:oa("!$event.metaKey"),left:oa("'button' in $event && $event.button !== 0"),middle:oa("'button' in $event && $event.button !== 1"),right:oa("'button' in $event && $event.button !== 2")};function sa(e,t,n){var r=t?"nativeOn:{":"on:{";for(var i in e)r+='"'+i+'":'+ca(i,e[i])+",";return r.slice(0,-1)+"}"}function ca(t,e){if(!e)return"function(){}";if(Array.isArray(e))return"["+e.map(function(e){return ca(t,e)}).join(",")+"]";var n=na.test(e.value),r=ta.test(e.value);if(e.modifiers){var i="",o="",a=[];for(var s in e.modifiers)if(aa[s])o+=aa[s],ra[s]&&a.push(s);else if("exact"===s){var c=e.modifiers;o+=oa(["ctrl","shift","alt","meta"].filter(function(e){return!c[e]}).map(function(e){return"$event."+e+"Key"}).join("||"))}else a.push(s);return a.length&&(i+="if(!('button' in $event)&&"+a.map(la).join("&&")+")return null;"),o&&(i+=o),"function($event){"+i+(n?"return "+e.value+"($event)":r?"return ("+e.value+")($event)":e.value)+"}"}return n||r?e.value:"function($event){"+e.value+"}"}function la(e){var t=parseInt(e,10);if(t)return"$event.keyCode!=="+t;var n=ra[e],r=ia[e];return"_k($event.keyCode,"+JSON.stringify(e)+","+JSON.stringify(n)+",$event.key,"+JSON.stringify(r)+")"}var ua={on:function(e,t){e.wrapListeners=function(e){return"_g("+e+","+t.value+")"}},bind:function(t,n){t.wrapData=function(e){return"_b("+e+",'"+t.tag+"',"+n.value+","+(n.modifiers&&n.modifiers.prop?"true":"false")+(n.modifiers&&n.modifiers.sync?",true":"")+")"}},cloak:$},fa=function(e){this.options=e,this.warn=e.warn||$r,this.transforms=wr(e.modules,"transformCode"),this.dataGenFns=wr(e.modules,"genData"),this.directives=m(m({},ua),e.directives);var t=e.isReservedTag||O;this.maybeComponent=function(e){return!t(e.tag)},this.onceId=0,this.staticRenderFns=[]};function pa(e,t){var n=new fa(t);return{render:"with(this){return "+(e?da(e,n):'_c("div")')+"}",staticRenderFns:n.staticRenderFns}}function da(e,t){if(e.staticRoot&&!e.staticProcessed)return va(e,t);if(e.once&&!e.onceProcessed)return ha(e,t);if(e.for&&!e.forProcessed)return f=t,v=(u=e).for,h=u.alias,m=u.iterator1?","+u.iterator1:"",y=u.iterator2?","+u.iterator2:"",u.forProcessed=!0,(d||"_l")+"(("+v+"),function("+h+m+y+"){return "+(p||da)(u,f)+"})";if(e.if&&!e.ifProcessed)return ma(e,t);if("template"!==e.tag||e.slotTarget){if("slot"===e.tag)return function(e,t){var n=e.slotName||'"default"',r=_a(e,t),i="_t("+n+(r?","+r:""),o=e.attrs&&"{"+e.attrs.map(function(e){return g(e.name)+":"+e.value}).join(",")+"}",a=e.attrsMap["v-bind"];!o&&!a||r||(i+=",null");o&&(i+=","+o);a&&(i+=(o?"":",null")+","+a);return i+")"}(e,t);var n;if(e.component)a=e.component,c=t,l=(s=e).inlineTemplate?null:_a(s,c,!0),n="_c("+a+","+ya(s,c)+(l?","+l:"")+")";else{var r=e.plain?void 0:ya(e,t),i=e.inlineTemplate?null:_a(e,t,!0);n="_c('"+e.tag+"'"+(r?","+r:"")+(i?","+i:"")+")"}for(var o=0;o':'',0