提交 94eeade6 authored 作者: thinking_fioa's avatar thinking_fioa

Merge branch 'master' into dev

<p align="center"> <p align="center">
<a href="http://www.xuxueli.com/xxl-job/">
<img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150"> <img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150">
</a>
<h3 align="center">XXL-JOB</h3> <h3 align="center">XXL-JOB</h3>
<p align="center"> <p align="center">
XXL-JOB, a lightweight distributed task scheduling framework. XXL-JOB, a lightweight distributed task scheduling framework.
<br> <br>
<a href="http://www.xuxueli.com/xxl-job/"><strong>-- Browse website. --</strong></a> <a href="http://www.xuxueli.com/xxl-job/"><strong>-- Home Page --</strong></a>
<br> <br>
<br> <br>
<a href="https://travis-ci.org/xuxueli/xxl-job"> <a href="https://travis-ci.org/xuxueli/xxl-job">
...@@ -71,7 +69,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -71,7 +69,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
- 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件; - 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
- 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用; - 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
- 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等; - 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
- 27、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
- 28、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
## Development ## Development
于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计…… 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
...@@ -150,6 +149,13 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是 ...@@ -150,6 +149,13 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
- 57、华夏票联(北京)科技有限公司 - 57、华夏票联(北京)科技有限公司
- 58、拍拍贷 - 58、拍拍贷
- 59、北京尚德机构在线教育有限公司 - 59、北京尚德机构在线教育有限公司
- 60、任子行股份有限公司
- 61、北京时态电子商务有限公司
- 62、深圳卷皮网络科技有限公司
- 63、北京安博通科技股份有限公司
- 64、未来无线网
- 65、厦门瓷禧网络有限公司
- 66、北京递蓝科软件股份有限公司
- …… - ……
> 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。 > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
...@@ -179,6 +185,6 @@ This product is open source and free, and will continue to provide free communit ...@@ -179,6 +185,6 @@ This product is open source and free, and will continue to provide free communit
## Donate ## Donate
No matter how much the amount is enough to express your thought, thank you very much :) [To donate](http://www.xuxueli.com/page/donate.html ) No matter how much the donation amount is enough to express your thought, thank you very much :) [To donate](http://www.xuxueli.com/page/donate.html )
无论金额多少都足够表达您这份心意,非常感谢 :) [前往捐赠](http://www.xuxueli.com/page/donate.html ) 无论捐赠金额多少都足够表达您这份心意,非常感谢 :) [前往捐赠](http://www.xuxueli.com/page/donate.html )
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
### 1.1 Overview ### 1.1 Overview
XXL-JOB is a lightweight distributed task scheduling framework, the core design goal is to develop quickly, learning simple, lightweight, easy to expand. Is now open source and access to a number of companies online product line, download and use it now. XXL-JOB is a lightweight distributed task scheduling framework, the core design goal is to develop quickly, learning simple, lightweight, easy to expand. Is now open source and access to a number of companies online product line, download and use it now.
> English document update slightly delayed, Please check the Chinese version for the latest document.
### 1.2 Features ### 1.2 Features
- 1.Simple: support through the Web page on the task CRUD operation, simple operation, a minute to get started; - 1.Simple: support through the Web page on the task CRUD operation, simple operation, a minute to get started;
- 2.Dynamic: support dynamic modification of task status, pause / resume tasks, and termination of running tasks,immediate effect; - 2.Dynamic: support dynamic modification of task status, pause / resume tasks, and termination of running tasks,immediate effect;
...@@ -105,6 +108,19 @@ So far, XXL-JOB has access to a number of companies online product line, access ...@@ -105,6 +108,19 @@ So far, XXL-JOB has access to a number of companies online product line, access
- 52、聚金资本 - 52、聚金资本
- 53、北京父母邦网络科技有限公司 - 53、北京父母邦网络科技有限公司
- 54、中山元赫软件科技有限公司 - 54、中山元赫软件科技有限公司
- 55、中商惠民(北京)电子商务有限公司
- 56、凯京集团
- 57、华夏票联(北京)科技有限公司
- 58、拍拍贷
- 59、北京尚德机构在线教育有限公司
- 60、任子行股份有限公司
- 61、北京时态电子商务有限公司
- 62、深圳卷皮网络科技有限公司
- 63、北京安博通科技股份有限公司
- 64、未来无线网
- 65、厦门瓷禧网络有限公司
- 66、北京递蓝科软件股份有限公司
- 67、郑州创海软件科技公司
- …… - ……
> The company that access and use this product is welcome to register at the [address](https://github.com/xuxueli/xxl-job/issues/1 ), only for product promotion. > The company that access and use this product is welcome to register at the [address](https://github.com/xuxueli/xxl-job/issues/1 ), only for product promotion.
...@@ -122,7 +138,7 @@ Welcome everyone's attention and use, XXL-JOB will also embrace changes, sustain ...@@ -122,7 +138,7 @@ Welcome everyone's attention and use, XXL-JOB will also embrace changes, sustain
Source repository address | Release Download Source repository address | Release Download
--- | --- --- | ---
[https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases) [https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases)
[http://git.oschina.net/xuxueli0323/xxl-job](http://git.oschina.net/xuxueli0323/xxl-job) | [Download](http://git.oschina.net/xuxueli0323/xxl-job/releases) [http://gitee.com/xuxueli0323/xxl-job](http://gitee.com/xuxueli0323/xxl-job) | [Download](http://gitee.com/xuxueli0323/xxl-job/releases)
#### Center repository address (The latest Release version:1.8.1) #### Center repository address (The latest Release version:1.8.1)
``` ```
...@@ -204,6 +220,9 @@ The concrete contet describe as follows: ...@@ -204,6 +220,9 @@ The concrete contet describe as follows:
### TOKEN used for communication between the executor and schedule center, enabled if it’s not null ### TOKEN used for communication between the executor and schedule center, enabled if it’s not null
xxl.job.accessToken= xxl.job.accessToken=
### Internationalized Settings, the default is Chinese version,Switch to English when the value is "en".
xxl.job.i18n=en
#### Step 2:Deploy: #### Step 2:Deploy:
If you has finished step 1,then you can compile the project in maven and deploy the war package to tomcat. If you has finished step 1,then you can compile the project in maven and deploy the war package to tomcat.
the url to visit is :http://localhost:8080/xxl-job-admin (this address will be used by executor and use it as callback url),the index page after login in is as follow the url to visit is :http://localhost:8080/xxl-job-admin (this address will be used by executor and use it as callback url),the index page after login in is as follow
......
差异被折叠。
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.9.0-SNAPSHOT</version> <version>1.9.2-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>${project.artifactId}</name> <name>${project.artifactId}</name>
...@@ -20,16 +20,16 @@ ...@@ -20,16 +20,16 @@
<javax.servlet-api.version>3.0.1</javax.servlet-api.version> <javax.servlet-api.version>3.0.1</javax.servlet-api.version>
<jsp-api.version>2.2</jsp-api.version> <jsp-api.version>2.2</jsp-api.version>
<spring.version>4.3.13.RELEASE</spring.version> <spring.version>4.3.14.RELEASE</spring.version>
<jackson.version>2.9.3</jackson.version> <jackson.version>2.9.4</jackson.version>
<aspectjweaver.version>1.8.13</aspectjweaver.version> <aspectjweaver.version>1.8.13</aspectjweaver.version>
<slf4j-api.version>1.7.25</slf4j-api.version> <slf4j-api.version>1.7.25</slf4j-api.version>
<freemarker.version>2.3.23</freemarker.version> <freemarker.version>2.3.23</freemarker.version>
<junit.version>4.12</junit.version> <junit.version>4.12</junit.version>
<jetty-server.version>9.2.22.v20170606</jetty-server.version> <jetty-server.version>9.2.24.v20180105</jetty-server.version>
<hessian.version>4.0.51</hessian.version> <hessian.version>4.0.51</hessian.version>
<httpclient.version>4.5.4</httpclient.version> <httpclient.version>4.5.5</httpclient.version>
<commons-exec.version>1.3</commons-exec.version> <commons-exec.version>1.3</commons-exec.version>
<commons-collections4.version>4.1</commons-collections4.version> <commons-collections4.version>4.1</commons-collections4.version>
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
<groovy-all.version>2.4.13</groovy-all.version> <groovy-all.version>2.4.13</groovy-all.version>
<quartz.version>2.3.0</quartz.version> <quartz.version>2.3.0</quartz.version>
<spring-boot.version>1.5.9.RELEASE</spring-boot.version> <spring-boot.version>1.5.10.RELEASE</spring-boot.version>
</properties> </properties>
<build> <build>
...@@ -59,6 +59,14 @@ ...@@ -59,6 +59,14 @@
<encoding>UTF8</encoding> <encoding>UTF8</encoding>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId> <artifactId>maven-war-plugin</artifactId>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.9.0-SNAPSHOT</version> <version>1.9.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-admin</artifactId> <artifactId>xxl-job-admin</artifactId>
<packaging>war</packaging> <packaging>war</packaging>
......
...@@ -2,6 +2,7 @@ package com.xxl.job.admin.controller; ...@@ -2,6 +2,7 @@ package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.annotation.PermessionLimit; import com.xxl.job.admin.controller.annotation.PermessionLimit;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.service.XxlJobService; import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
...@@ -40,11 +41,11 @@ public class IndexController { ...@@ -40,11 +41,11 @@ public class IndexController {
return "index"; return "index";
} }
@RequestMapping("/triggerChartDate") @RequestMapping("/chartInfo")
@ResponseBody @ResponseBody
public ReturnT<Map<String, Object>> triggerChartDate(Date startDate, Date endDate) { public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
ReturnT<Map<String, Object>> triggerChartDate = xxlJobService.triggerChartDate(startDate, endDate); ReturnT<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);
return triggerChartDate; return chartInfo;
} }
@RequestMapping("/toLogin") @RequestMapping("/toLogin")
...@@ -67,14 +68,14 @@ public class IndexController { ...@@ -67,14 +68,14 @@ public class IndexController {
// param // param
if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)){ if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)){
return new ReturnT<String>(500, "账号或密码为空"); return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
} }
boolean ifRem = (StringUtils.isNotBlank(ifRemember) && "on".equals(ifRemember))?true:false; boolean ifRem = (StringUtils.isNotBlank(ifRemember) && "on".equals(ifRemember))?true:false;
// do login // do login
boolean loginRet = PermissionInterceptor.login(response, userName, password, ifRem); boolean loginRet = PermissionInterceptor.login(response, userName, password, ifRem);
if (!loginRet) { if (!loginRet) {
return new ReturnT<String>(500, "账号或密码错误"); return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
} }
return ReturnT.SUCCESS; return ReturnT.SUCCESS;
} }
......
...@@ -2,6 +2,7 @@ package com.xxl.job.admin.controller; ...@@ -2,6 +2,7 @@ package com.xxl.job.admin.controller;
import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLogGlue; import com.xxl.job.admin.core.model.XxlJobLogGlue;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogGlueDao; import com.xxl.job.admin.dao.XxlJobLogGlueDao;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
...@@ -34,10 +35,10 @@ public class JobCodeController { ...@@ -34,10 +35,10 @@ public class JobCodeController {
List<XxlJobLogGlue> jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId); List<XxlJobLogGlue> jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId);
if (jobInfo == null) { if (jobInfo == null) {
throw new RuntimeException("抱歉,任务不存在."); throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
} }
if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) { if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) {
throw new RuntimeException("该任务非GLUE模式."); throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid"));
} }
// Glue类型-字典 // Glue类型-字典
...@@ -53,14 +54,14 @@ public class JobCodeController { ...@@ -53,14 +54,14 @@ public class JobCodeController {
public ReturnT<String> save(Model model, int id, String glueSource, String glueRemark) { public ReturnT<String> save(Model model, int id, String glueSource, String glueRemark) {
// valid // valid
if (glueRemark==null) { if (glueRemark==null) {
return new ReturnT<String>(500, "请输入备注"); return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")) );
} }
if (glueRemark.length()<4 || glueRemark.length()>100) { if (glueRemark.length()<4 || glueRemark.length()>100) {
return new ReturnT<String>(500, "备注长度应该在4至100之间"); return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_remark_limit"));
} }
XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(id); XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(id);
if (exists_jobInfo == null) { if (exists_jobInfo == null) {
return new ReturnT<String>(500, "参数异常"); return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
} }
// update new code // update new code
......
package com.xxl.job.admin.controller; package com.xxl.job.admin.controller;
import com.xxl.job.admin.core.model.XxlJobGroup; import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
...@@ -42,22 +43,22 @@ public class JobGroupController { ...@@ -42,22 +43,22 @@ public class JobGroupController {
// valid // valid
if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) { if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) {
return new ReturnT<String>(500, "请输入AppName"); return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
} }
if (xxlJobGroup.getAppName().length()>64) { if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>64) {
return new ReturnT<String>(500, "AppName长度限制为4~64"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appName_length") );
} }
if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) { if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
return new ReturnT<String>(500, "请输入名称"); return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
} }
if (xxlJobGroup.getAddressType()!=0) { if (xxlJobGroup.getAddressType()!=0) {
if (StringUtils.isBlank(xxlJobGroup.getAddressList())) { if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
return new ReturnT<String>(500, "手动录入注册方式,机器地址不可为空"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
} }
String[] addresss = xxlJobGroup.getAddressList().split(","); String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item: addresss) { for (String item: addresss) {
if (StringUtils.isBlank(item)) { if (StringUtils.isBlank(item)) {
return new ReturnT<String>(500, "机器地址非法"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
} }
} }
} }
...@@ -71,22 +72,22 @@ public class JobGroupController { ...@@ -71,22 +72,22 @@ public class JobGroupController {
public ReturnT<String> update(XxlJobGroup xxlJobGroup){ public ReturnT<String> update(XxlJobGroup xxlJobGroup){
// valid // valid
if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) { if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) {
return new ReturnT<String>(500, "请输入AppName"); return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
} }
if (xxlJobGroup.getAppName().length()>64) { if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>64) {
return new ReturnT<String>(500, "AppName长度限制为4~64"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appName_length") );
} }
if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) { if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
return new ReturnT<String>(500, "请输入名称"); return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
} }
if (xxlJobGroup.getAddressType()!=0) { if (xxlJobGroup.getAddressType()!=0) {
if (StringUtils.isBlank(xxlJobGroup.getAddressList())) { if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
return new ReturnT<String>(500, "手动录入注册方式,机器地址不可为空"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
} }
String[] addresss = xxlJobGroup.getAddressList().split(","); String[] addresss = xxlJobGroup.getAddressList().split(",");
for (String item: addresss) { for (String item: addresss) {
if (StringUtils.isBlank(item)) { if (StringUtils.isBlank(item)) {
return new ReturnT<String>(500, "机器地址非法"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
} }
} }
} }
...@@ -100,14 +101,14 @@ public class JobGroupController { ...@@ -100,14 +101,14 @@ public class JobGroupController {
public ReturnT<String> remove(int id){ public ReturnT<String> remove(int id){
// valid // valid
int count = xxlJobInfoDao.pageListCount(0, 10, id, null); int count = xxlJobInfoDao.pageListCount(0, 10, id, null, null);
if (count > 0) { if (count > 0) {
return new ReturnT<String>(500, "该分组使用中, 不可删除"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_0") );
} }
List<XxlJobGroup> allList = xxlJobGroupDao.findAll(); List<XxlJobGroup> allList = xxlJobGroupDao.findAll();
if (allList.size() == 1) { if (allList.size() == 1) {
return new ReturnT<String>(500, "删除失败, 系统需要至少预留一个默认分组"); return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_1") );
} }
int ret = xxlJobGroupDao.remove(id); int ret = xxlJobGroupDao.remove(id);
......
...@@ -53,9 +53,9 @@ public class JobInfoController { ...@@ -53,9 +53,9 @@ public class JobInfoController {
@ResponseBody @ResponseBody
public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start, public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
@RequestParam(required = false, defaultValue = "10") int length, @RequestParam(required = false, defaultValue = "10") int length,
int jobGroup, String executorHandler, String filterTime) { int jobGroup, String jobDesc, String executorHandler, String filterTime) {
return xxlJobService.pageList(start, length, jobGroup, executorHandler, filterTime); return xxlJobService.pageList(start, length, jobGroup, jobDesc, executorHandler, filterTime);
} }
@RequestMapping("/add") @RequestMapping("/add")
...@@ -64,10 +64,10 @@ public class JobInfoController { ...@@ -64,10 +64,10 @@ public class JobInfoController {
return xxlJobService.add(jobInfo); return xxlJobService.add(jobInfo);
} }
@RequestMapping("/reschedule") @RequestMapping("/update")
@ResponseBody @ResponseBody
public ReturnT<String> reschedule(XxlJobInfo jobInfo) { public ReturnT<String> update(XxlJobInfo jobInfo) {
return xxlJobService.reschedule(jobInfo); return xxlJobService.update(jobInfo);
} }
@RequestMapping("/remove") @RequestMapping("/remove")
......
...@@ -4,12 +4,14 @@ import com.xxl.job.admin.core.model.XxlJobGroup; ...@@ -4,12 +4,14 @@ import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobGroupDao; import com.xxl.job.admin.dao.XxlJobGroupDao;
import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.core.biz.ExecutorBiz; import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.LogResult; import com.xxl.job.core.biz.model.LogResult;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.glue.GlueTypeEnum;
import com.xxl.job.core.rpc.netcom.NetComClientProxy; import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
...@@ -50,6 +52,7 @@ public class JobLogController { ...@@ -50,6 +52,7 @@ public class JobLogController {
// 执行器列表 // 执行器列表
List<XxlJobGroup> jobGroupList = xxlJobGroupDao.findAll(); List<XxlJobGroup> jobGroupList = xxlJobGroupDao.findAll();
model.addAttribute("JobGroupList", jobGroupList); model.addAttribute("JobGroupList", jobGroupList);
model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());
// 任务 // 任务
if (jobId > 0) { if (jobId > 0) {
...@@ -105,7 +108,7 @@ public class JobLogController { ...@@ -105,7 +108,7 @@ public class JobLogController {
ReturnT<String> logStatue = ReturnT.SUCCESS; ReturnT<String> logStatue = ReturnT.SUCCESS;
XxlJobLog jobLog = xxlJobLogDao.load(id); XxlJobLog jobLog = xxlJobLogDao.load(id);
if (jobLog == null) { if (jobLog == null) {
throw new RuntimeException("抱歉,日志ID非法."); throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
} }
model.addAttribute("triggerCode", jobLog.getTriggerCode()); model.addAttribute("triggerCode", jobLog.getTriggerCode());
...@@ -145,10 +148,10 @@ public class JobLogController { ...@@ -145,10 +148,10 @@ public class JobLogController {
XxlJobLog log = xxlJobLogDao.load(id); XxlJobLog log = xxlJobLogDao.load(id);
XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId()); XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
if (jobInfo==null) { if (jobInfo==null) {
return new ReturnT<String>(500, "参数异常"); return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
} }
if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) { if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
return new ReturnT<String>(500, "调度失败,无法终止日志"); return new ReturnT<String>(500, I18nUtil.getString("joblog_kill_log_limit"));
} }
// request of kill // request of kill
...@@ -163,7 +166,7 @@ public class JobLogController { ...@@ -163,7 +166,7 @@ public class JobLogController {
if (ReturnT.SUCCESS_CODE == runResult.getCode()) { if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
log.setHandleCode(ReturnT.FAIL_CODE); log.setHandleCode(ReturnT.FAIL_CODE);
log.setHandleMsg("人为操作主动终止:" + (runResult.getMsg()!=null?runResult.getMsg():"")); log.setHandleMsg( I18nUtil.getString("joblog_kill_log_byman")+":" + (runResult.getMsg()!=null?runResult.getMsg():""));
log.setHandleTime(new Date()); log.setHandleTime(new Date());
xxlJobLogDao.updateHandleInfo(log); xxlJobLogDao.updateHandleInfo(log);
return new ReturnT<String>(runResult.getMsg()); return new ReturnT<String>(runResult.getMsg());
...@@ -197,7 +200,7 @@ public class JobLogController { ...@@ -197,7 +200,7 @@ public class JobLogController {
} else if (type == 9) { } else if (type == 9) {
clearBeforeNum = 0; // 清理所有日志数据 clearBeforeNum = 0; // 清理所有日志数据
} else { } else {
return new ReturnT<String>(ReturnT.FAIL_CODE, "清理类型参数异常"); return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid"));
} }
xxlJobLogDao.clearLog(jobGroup, jobId, clearBeforeTime, clearBeforeNum); xxlJobLogDao.clearLog(jobGroup, jobId, clearBeforeTime, clearBeforeNum);
......
package com.xxl.job.admin.controller.interceptor; package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.core.util.FtlUtil;
import com.xxl.job.admin.core.util.I18nUtil;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
...@@ -20,6 +22,7 @@ public class CookieInterceptor extends HandlerInterceptorAdapter { ...@@ -20,6 +22,7 @@ public class CookieInterceptor extends HandlerInterceptorAdapter {
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception { ModelAndView modelAndView) throws Exception {
// cookie
if (modelAndView!=null && ArrayUtils.isNotEmpty(request.getCookies())) { if (modelAndView!=null && ArrayUtils.isNotEmpty(request.getCookies())) {
HashMap<String, Cookie> cookieMap = new HashMap<String, Cookie>(); HashMap<String, Cookie> cookieMap = new HashMap<String, Cookie>();
for (Cookie ck : request.getCookies()) { for (Cookie ck : request.getCookies()) {
...@@ -28,6 +31,11 @@ public class CookieInterceptor extends HandlerInterceptorAdapter { ...@@ -28,6 +31,11 @@ public class CookieInterceptor extends HandlerInterceptorAdapter {
modelAndView.addObject("cookieMap", cookieMap); modelAndView.addObject("cookieMap", cookieMap);
} }
// static method
if (modelAndView != null) {
modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
}
super.postHandle(request, response, handler, modelAndView); super.postHandle(request, response, handler, modelAndView);
} }
......
package com.xxl.job.admin.controller.interceptor; package com.xxl.job.admin.controller.interceptor;
import com.xxl.job.admin.controller.annotation.PermessionLimit; import com.xxl.job.admin.controller.annotation.PermessionLimit;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.admin.core.util.CookieUtil; import com.xxl.job.admin.core.util.CookieUtil;
import com.xxl.job.admin.core.util.PropertiesUtil;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
...@@ -22,8 +22,8 @@ public class PermissionInterceptor extends HandlerInterceptorAdapter { ...@@ -22,8 +22,8 @@ public class PermissionInterceptor extends HandlerInterceptorAdapter {
public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY"; public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
public static final String LOGIN_IDENTITY_TOKEN; public static final String LOGIN_IDENTITY_TOKEN;
static { static {
String username = PropertiesUtil.getString("xxl.job.login.username"); String username = XxlJobAdminConfig.getAdminConfig().getLoginUsername();
String password = PropertiesUtil.getString("xxl.job.login.password"); String password = XxlJobAdminConfig.getAdminConfig().getLoginPassword();
// login token // login token
String tokenTmp = DigestUtils.md5Hex(username + "_" + password); String tokenTmp = DigestUtils.md5Hex(username + "_" + password);
......
...@@ -11,6 +11,7 @@ import org.springframework.web.servlet.ModelAndView; ...@@ -11,6 +11,7 @@ import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/** /**
* common exception resolver * common exception resolver
...@@ -24,18 +25,33 @@ public class WebExceptionResolver implements HandlerExceptionResolver { ...@@ -24,18 +25,33 @@ public class WebExceptionResolver implements HandlerExceptionResolver {
HttpServletResponse response, Object handler, Exception ex) { HttpServletResponse response, Object handler, Exception ex) {
logger.error("WebExceptionResolver:{}", ex); logger.error("WebExceptionResolver:{}", ex);
ModelAndView mv = new ModelAndView(); // if json
boolean isJson = false;
HandlerMethod method = (HandlerMethod)handler; HandlerMethod method = (HandlerMethod)handler;
ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class); ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
if (responseBody != null) { if (responseBody != null) {
response.setContentType("application/json;charset=UTF-8"); isJson = true;
mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT<String>(500, ex.toString().replaceAll("\n", "<br/>")))); }
mv.setViewName("/common/common.result");
// error result
ReturnT<String> errorResult = new ReturnT<String>(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", "<br/>"));
// response
ModelAndView mv = new ModelAndView();
if (isJson) {
try {
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(JacksonUtil.writeValueAsString(errorResult));
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return mv;
} else { } else {
mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "<br/>"));
mv.addObject("exceptionMsg", errorResult.getMsg());
mv.setViewName("/common/common.exception"); mv.setViewName("/common/common.exception");
}
return mv; return mv;
} }
}
} }
\ No newline at end of file
package com.xxl.job.admin.core.conf;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@Configuration
public class XxlJobAdminConfig implements InitializingBean{
private static XxlJobAdminConfig adminConfig = null;
public static XxlJobAdminConfig getAdminConfig() {
return adminConfig;
}
@Override
public void afterPropertiesSet() throws Exception {
adminConfig = this;
}
@Value("${xxl.job.mail.host}")
private String mailHost;
@Value("${xxl.job.mail.port}")
private String mailPort;
@Value("${xxl.job.mail.username}")
private String mailUsername;
@Value("${xxl.job.mail.password}")
private String mailPassword;
@Value("${xxl.job.mail.sendNick}")
private String mailSendNick;
@Value("${xxl.job.login.username}")
private String loginUsername;
@Value("${xxl.job.login.password}")
private String loginPassword;
@Value("${xxl.job.i18n}")
private String i18n;
public String getMailHost() {
return mailHost;
}
public String getMailPort() {
return mailPort;
}
public String getMailUsername() {
return mailUsername;
}
public String getMailPassword() {
return mailPassword;
}
public String getMailSendNick() {
return mailSendNick;
}
public String getLoginUsername() {
return loginUsername;
}
public String getLoginPassword() {
return loginPassword;
}
public String getI18n() {
return i18n;
}
}
package com.xxl.job.admin.core.enums; package com.xxl.job.admin.core.enums;
import com.xxl.job.admin.core.util.I18nUtil;
/** /**
* Created by xuxueli on 17/5/9. * Created by xuxueli on 17/5/9.
*/ */
public enum ExecutorFailStrategyEnum { public enum ExecutorFailStrategyEnum {
FAIL_ALARM("失败告警"), FAIL_ALARM(I18nUtil.getString("jobconf_fail_alarm")),
FAIL_RETRY("失败重试"); FAIL_RETRY(I18nUtil.getString("jobconf_fail_retry"));
private final String title; private final String title;
private ExecutorFailStrategyEnum(String title) { private ExecutorFailStrategyEnum(String title) {
......
package com.xxl.job.admin.core.route; package com.xxl.job.admin.core.route;
import com.xxl.job.admin.core.route.strategy.*; import com.xxl.job.admin.core.route.strategy.*;
import com.xxl.job.admin.core.util.I18nUtil;
/** /**
* Created by xuxueli on 17/3/10. * Created by xuxueli on 17/3/10.
*/ */
public enum ExecutorRouteStrategyEnum { public enum ExecutorRouteStrategyEnum {
FIRST("第一个", new ExecutorRouteFirst()), FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()),
LAST("最后一个", new ExecutorRouteLast()), LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()),
ROUND("轮询", new ExecutorRouteRound()), ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()),
RANDOM("随机", new ExecutorRouteRandom()), RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()),
CONSISTENT_HASH("一致性HASH", new ExecutorRouteConsistentHash()), CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()),
LEAST_FREQUENTLY_USED("最不经常使用", new ExecutorRouteLFU()), LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()),
LEAST_RECENTLY_USED("最近最久未使用", new ExecutorRouteLRU()), LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()),
FAILOVER("故障转移", new ExecutorRouteFailover()), FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()),
BUSYOVER("忙碌转移", new ExecutorRouteBusyover()), BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()),
SHARDING_BROADCAST("分片广播", null); SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null);
ExecutorRouteStrategyEnum(String title, ExecutorRouter router) { ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
this.title = title; this.title = title;
......
...@@ -3,6 +3,7 @@ package com.xxl.job.admin.core.route.strategy; ...@@ -3,6 +3,7 @@ package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.trigger.XxlJobTrigger; import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.ExecutorBiz; import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -33,7 +34,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter { ...@@ -33,7 +34,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
idleBeatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e ); idleBeatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
} }
idleBeatResultSB.append( (idleBeatResultSB.length()>0)?"<br><br>":"") idleBeatResultSB.append( (idleBeatResultSB.length()>0)?"<br><br>":"")
.append("空闲检测:") .append(I18nUtil.getString("jobconf_idleBeat") + ":")
.append("<br>address:").append(address) .append("<br>address:").append(address)
.append("<br>code:").append(idleBeatResult.getCode()) .append("<br>code:").append(idleBeatResult.getCode())
.append("<br>msg:").append(idleBeatResult.getMsg()); .append("<br>msg:").append(idleBeatResult.getMsg());
......
...@@ -3,6 +3,7 @@ package com.xxl.job.admin.core.route.strategy; ...@@ -3,6 +3,7 @@ package com.xxl.job.admin.core.route.strategy;
import com.xxl.job.admin.core.route.ExecutorRouter; import com.xxl.job.admin.core.route.ExecutorRouter;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.trigger.XxlJobTrigger; import com.xxl.job.admin.core.trigger.XxlJobTrigger;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.ExecutorBiz; import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -33,7 +34,7 @@ public class ExecutorRouteFailover extends ExecutorRouter { ...@@ -33,7 +34,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
beatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e ); beatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
} }
beatResultSB.append( (beatResultSB.length()>0)?"<br><br>":"") beatResultSB.append( (beatResultSB.length()>0)?"<br><br>":"")
.append("心跳检测:") .append(I18nUtil.getString("jobconf_beat") + ":")
.append("<br>address:").append(address) .append("<br>address:").append(address)
.append("<br>code:").append(beatResult.getCode()) .append("<br>code:").append(beatResult.getCode())
.append("<br>msg:").append(beatResult.getMsg()); .append("<br>msg:").append(beatResult.getMsg());
......
...@@ -4,6 +4,7 @@ import com.xxl.job.admin.core.model.XxlJobGroup; ...@@ -4,6 +4,7 @@ import com.xxl.job.admin.core.model.XxlJobGroup;
import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.admin.core.util.MailUtil;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler; import com.xxl.job.core.handler.IJobHandler;
...@@ -119,14 +120,14 @@ public class JobFailMonitorHelper { ...@@ -119,14 +120,14 @@ public class JobFailMonitorHelper {
// ---------------------- alarm ---------------------- // ---------------------- alarm ----------------------
// email alarm template // email alarm template
private static final String mailBodyTemplate = "<h5>监控告警明细:</span>" + private static final String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + ":</span>" +
"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" + "<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +
" <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" + " <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
" <tr>\n" + " <tr>\n" +
" <td>执行器</td>\n" + " <td>"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +
" <td>任务ID</td>\n" + " <td>"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +
" <td>任务描述</td>\n" + " <td>"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</td>\n" +
" <td>告警类型</td>\n" + " <td>"+ I18nUtil.getString("jobconf_monitor_alarm_title") +"</td>\n" +
" </tr>\n" + " </tr>\n" +
" <thead/>\n" + " <thead/>\n" +
" <tbody>\n" + " <tbody>\n" +
...@@ -134,7 +135,7 @@ public class JobFailMonitorHelper { ...@@ -134,7 +135,7 @@ public class JobFailMonitorHelper {
" <td>{0}</td>\n" + " <td>{0}</td>\n" +
" <td>{1}</td>\n" + " <td>{1}</td>\n" +
" <td>{2}</td>\n" + " <td>{2}</td>\n" +
" <td>调度失败</td>\n" + " <td>"+ I18nUtil.getString("jobconf_monitor_alarm_type") +"</td>\n" +
" </tr>\n" + " </tr>\n" +
" <tbody>\n" + " <tbody>\n" +
"</table>"; "</table>";
...@@ -154,7 +155,7 @@ public class JobFailMonitorHelper { ...@@ -154,7 +155,7 @@ public class JobFailMonitorHelper {
for (String email: emailSet) { for (String email: emailSet) {
XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup())); XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup()));
String title = "调度中心监控报警"; String title = I18nUtil.getString("jobconf_monitor");
String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc()); String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc());
MailUtil.sendMail(email, title, content); MailUtil.sendMail(email, title, content);
......
...@@ -7,6 +7,7 @@ import com.xxl.job.admin.core.model.XxlJobLog; ...@@ -7,6 +7,7 @@ import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum; import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler; import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
import com.xxl.job.admin.core.thread.JobFailMonitorHelper; import com.xxl.job.admin.core.thread.JobFailMonitorHelper;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.core.biz.ExecutorBiz; import com.xxl.job.core.biz.ExecutorBiz;
import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.biz.model.TriggerParam;
...@@ -67,17 +68,18 @@ public class XxlJobTrigger { ...@@ -67,17 +68,18 @@ public class XxlJobTrigger {
ReturnT<String> triggerResult = new ReturnT<String>(null); ReturnT<String> triggerResult = new ReturnT<String>(null);
StringBuffer triggerMsgSb = new StringBuffer(); StringBuffer triggerMsgSb = new StringBuffer();
triggerMsgSb.append("调度机器:").append(IpUtil.getIp()); triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
triggerMsgSb.append("<br>执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" ); triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
triggerMsgSb.append("<br>执行器-地址列表:").append(group.getRegistryList()); .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
triggerMsgSb.append("<br>路由策略:").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01 triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
triggerMsgSb.append("<br>阻塞处理策略:").append(blockStrategy.getTitle()); triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01
triggerMsgSb.append("<br>失败处理策略:").append(failStrategy.getTitle()); triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailStrategy")).append(":").append(failStrategy.getTitle());
// 3、trigger-valid // 3、trigger-valid
if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) { if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
triggerResult.setCode(ReturnT.FAIL_CODE); triggerResult.setCode(ReturnT.FAIL_CODE);
triggerMsgSb.append("<br>----------------------<br>").append("调度失败:").append("执行器地址为空"); triggerMsgSb.append("<br>----------------------<br>").append(I18nUtil.getString("jobconf_trigger_address_empty"));
} }
if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) { if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) {
...@@ -97,12 +99,12 @@ public class XxlJobTrigger { ...@@ -97,12 +99,12 @@ public class XxlJobTrigger {
// 4.2、trigger-run (route run / trigger remote executor) // 4.2、trigger-run (route run / trigger remote executor)
triggerResult = runExecutor(triggerParam, address); // update03 triggerResult = runExecutor(triggerParam, address); // update03
triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg()); triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
// 4.3、trigger (fail retry) // 4.3、trigger (fail retry)
if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) { if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
triggerResult = runExecutor(triggerParam, address); // update04 triggerResult = runExecutor(triggerParam, address); // update04
triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg()); triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_fail_retry") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
} }
} }
...@@ -112,7 +114,7 @@ public class XxlJobTrigger { ...@@ -112,7 +114,7 @@ public class XxlJobTrigger {
jobLog.setTriggerMsg(triggerMsgSb.toString()); jobLog.setTriggerMsg(triggerMsgSb.toString());
XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog); XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog);
// 6、monitor triger // 6、monitor trigger
JobFailMonitorHelper.monitor(jobLog.getId()); JobFailMonitorHelper.monitor(jobLog.getId());
logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
...@@ -134,17 +136,18 @@ public class XxlJobTrigger { ...@@ -134,17 +136,18 @@ public class XxlJobTrigger {
ReturnT<String> triggerResult = new ReturnT<String>(null); ReturnT<String> triggerResult = new ReturnT<String>(null);
StringBuffer triggerMsgSb = new StringBuffer(); StringBuffer triggerMsgSb = new StringBuffer();
triggerMsgSb.append("调度机器:").append(IpUtil.getIp()); triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
triggerMsgSb.append("<br>执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" ); triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
triggerMsgSb.append("<br>执行器-地址列表:").append(group.getRegistryList()); .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
triggerMsgSb.append("<br>路由策略:").append(executorRouteStrategyEnum.getTitle()); triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
triggerMsgSb.append("<br>阻塞处理策略:").append(blockStrategy.getTitle()); triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle());
triggerMsgSb.append("<br>失败处理策略:").append(failStrategy.getTitle()); triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailStrategy")).append(":").append(failStrategy.getTitle());
// 3、trigger-valid // 3、trigger-valid
if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) { if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
triggerResult.setCode(ReturnT.FAIL_CODE); triggerResult.setCode(ReturnT.FAIL_CODE);
triggerMsgSb.append("<br>----------------------<br>").append("调度失败:").append("执行器地址为空"); triggerMsgSb.append("<br>----------------------<br>").append(I18nUtil.getString("jobconf_trigger_address_empty"));
} }
if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) { if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) {
...@@ -164,12 +167,12 @@ public class XxlJobTrigger { ...@@ -164,12 +167,12 @@ public class XxlJobTrigger {
// 4.2、trigger-run (route run / trigger remote executor) // 4.2、trigger-run (route run / trigger remote executor)
triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList); triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg()); triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
// 4.3、trigger (fail retry) // 4.3、trigger (fail retry)
if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) { if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList); triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>调度失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg()); triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_fail_retry") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
} }
} }
...@@ -179,7 +182,7 @@ public class XxlJobTrigger { ...@@ -179,7 +182,7 @@ public class XxlJobTrigger {
jobLog.setTriggerMsg(triggerMsgSb.toString()); jobLog.setTriggerMsg(triggerMsgSb.toString());
XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog); XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog);
// 6、monitor triger // 6、monitor trigger
JobFailMonitorHelper.monitor(jobLog.getId()); JobFailMonitorHelper.monitor(jobLog.getId());
logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId()); logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
} }
...@@ -202,7 +205,7 @@ public class XxlJobTrigger { ...@@ -202,7 +205,7 @@ public class XxlJobTrigger {
runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e ); runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
} }
StringBuffer runResultSB = new StringBuffer("触发调度:"); StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":");
runResultSB.append("<br>address:").append(address); runResultSB.append("<br>address:").append(address);
runResultSB.append("<br>code:").append(runResult.getCode()); runResultSB.append("<br>code:").append(runResult.getCode());
runResultSB.append("<br>msg:").append(runResult.getMsg()); runResultSB.append("<br>msg:").append(runResult.getMsg());
......
package com.xxl.job.admin.core.util;
import freemarker.ext.beans.BeansWrapper;
import freemarker.template.TemplateHashModel;
/**
* ftl util
*
* @author xuxueli 2018-01-17 20:37:48
*/
public class FtlUtil {
public static TemplateHashModel generateStaticModel(String packageName) {
try {
BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
TemplateHashModel staticModels = wrapper.getStaticModels();
TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName);
return fileStatics;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.xxl.job.admin.core.util;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import com.xxl.job.core.util.JacksonUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* i18n util
*
* @author xuxueli 2018-01-17 20:39:06
*/
public class I18nUtil {
private static Logger logger = LoggerFactory.getLogger(I18nUtil.class);
private static Properties prop = null;
public static Properties loadI18nProp(){
if (prop != null) {
return prop;
}
try {
// bild i18n prop
String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
i18n = StringUtils.isNotBlank(i18n)?("_"+i18n):i18n;
String i18nFile = MessageFormat.format("i18n/message{0}.properties", i18n);
// load prop
Resource resource = new ClassPathResource(i18nFile);
EncodedResource encodedResource = new EncodedResource(resource,"UTF-8");
prop = PropertiesLoaderUtils.loadProperties(encodedResource);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
return prop;
}
/**
* get val of i18n key
*
* @param key
* @return
*/
public static String getString(String key) {
return loadI18nProp().getProperty(key);
}
/**
* get mult val of i18n mult key, as json
*
* @param keys
* @return
*/
public static String getMultString(String... keys) {
Map<String, String> map = new HashMap<>();
Properties prop = loadI18nProp();
if (keys!=null && keys.length>0) {
for (String key: keys) {
map.put(key, prop.getProperty(key));
}
} else {
for (String key: prop.stringPropertyNames()) {
map.put(key, prop.getProperty(key));
}
}
String json = JacksonUtil.writeValueAsString(map);
return json;
}
}
package com.xxl.job.admin.core.util;
import org.apache.commons.lang3.StringUtils;
import java.util.concurrent.ConcurrentHashMap;
/**
* local cache tool
*
* @author xuxueli 2018-01-22 21:37:34
*/
public class LocalCacheUtil {
private static ConcurrentHashMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<>();
private static class LocalCacheData{
private String key;
private Object val;
private long timeoutTime;
public LocalCacheData() {
}
public LocalCacheData(String key, Object val, long timeoutTime) {
this.key = key;
this.val = val;
this.timeoutTime = timeoutTime;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Object getVal() {
return val;
}
public void setVal(Object val) {
this.val = val;
}
public long getTimeoutTime() {
return timeoutTime;
}
public void setTimeoutTime(long timeoutTime) {
this.timeoutTime = timeoutTime;
}
}
/**
* set cache
*
* @param key
* @param val
* @param cacheTime
* @return
*/
public static boolean set(String key, Object val, long cacheTime){
// clean timeout cache, before set new cache (avoid cache too much)
cleanTimeutCache();
// set new cache
if (StringUtils.isBlank(key)) {
return false;
}
if (val == null) {
remove(key);
}
if (cacheTime <= 0) {
remove(key);
}
long timeoutTime = System.currentTimeMillis() + cacheTime;
LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime);
cacheRepository.put(localCacheData.getKey(), localCacheData);
return true;
}
/**
* remove cache
*
* @param key
* @return
*/
public static boolean remove(String key){
if (StringUtils.isBlank(key)) {
return false;
}
cacheRepository.remove(key);
return true;
}
/**
* get cache
*
* @param key
* @return
*/
public static Object get(String key){
if (StringUtils.isBlank(key)) {
return null;
}
LocalCacheData localCacheData = cacheRepository.get(key);
if (localCacheData!=null && System.currentTimeMillis()<localCacheData.getTimeoutTime()) {
return localCacheData.getVal();
} else {
remove(key);
return null;
}
}
/**
* clean timeout cache
*
* @return
*/
public static boolean cleanTimeutCache(){
if (!cacheRepository.keySet().isEmpty()) {
for (String key: cacheRepository.keySet()) {
LocalCacheData localCacheData = cacheRepository.get(key);
if (localCacheData!=null && System.currentTimeMillis()>=localCacheData.getTimeoutTime()) {
cacheRepository.remove(key);
}
}
}
return true;
}
}
package com.xxl.job.admin.core.util; package com.xxl.job.admin.core.util;
import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import org.apache.commons.mail.DefaultAuthenticator; import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.EmailException; import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail; import org.apache.commons.mail.HtmlEmail;
...@@ -16,19 +17,6 @@ import java.nio.charset.Charset; ...@@ -16,19 +17,6 @@ import java.nio.charset.Charset;
public class MailUtil { public class MailUtil {
private static Logger logger = LoggerFactory.getLogger(MailUtil.class); private static Logger logger = LoggerFactory.getLogger(MailUtil.class);
private static String host;
private static String port;
private static String username;
private static String password;
private static String sendNick;
static{
host = PropertiesUtil.getString("xxl.job.mail.host");
port = PropertiesUtil.getString("xxl.job.mail.port");
username = PropertiesUtil.getString("xxl.job.mail.username");
password = PropertiesUtil.getString("xxl.job.mail.password");
sendNick = PropertiesUtil.getString("xxl.job.mail.sendNick");
}
/** /**
* *
* @param toAddress 收件人邮箱 * @param toAddress 收件人邮箱
...@@ -46,13 +34,13 @@ public class MailUtil { ...@@ -46,13 +34,13 @@ public class MailUtil {
//email.setTLS(true); // 是否TLS校验,,某些邮箱需要TLS安全校验,同理有SSL校验 //email.setTLS(true); // 是否TLS校验,,某些邮箱需要TLS安全校验,同理有SSL校验
//email.setSSL(true); //email.setSSL(true);
email.setHostName(host); email.setHostName(XxlJobAdminConfig.getAdminConfig().getMailHost());
email.setSmtpPort(Integer.valueOf(port)); email.setSmtpPort(Integer.valueOf(XxlJobAdminConfig.getAdminConfig().getMailPort()));
//email.setSslSmtpPort(port); //email.setSslSmtpPort(port);
email.setAuthenticator(new DefaultAuthenticator(username, password)); email.setAuthenticator(new DefaultAuthenticator(XxlJobAdminConfig.getAdminConfig().getMailUsername(), XxlJobAdminConfig.getAdminConfig().getMailPassword()));
email.setCharset(Charset.defaultCharset().name()); email.setCharset(Charset.defaultCharset().name());
email.setFrom(username, sendNick); email.setFrom(XxlJobAdminConfig.getAdminConfig().getMailUsername(), XxlJobAdminConfig.getAdminConfig().getMailSendNick());
email.addTo(toAddress); email.addTo(toAddress);
email.setSubject(mailSubject); email.setSubject(mailSubject);
email.setMsg(mailBody); email.setMsg(mailBody);
......
package com.xxl.job.admin.core.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import java.io.IOException;
import java.util.Properties;
/**
* properties util
*
* @author xuxueli 2015-8-28 10:35:53
*/
public class PropertiesUtil {
private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class);
private static final String file_name = "xxl-job-admin.properties";
public static String getString(String key) {
Properties prop = null;
try {
Resource resource = new ClassPathResource(file_name);
EncodedResource encodedResource = new EncodedResource(resource,"UTF-8");
prop = PropertiesLoaderUtils.loadProperties(encodedResource);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
if (prop!=null) {
return prop.getProperty(key);
}
return null;
}
}
...@@ -12,8 +12,16 @@ import java.util.List; ...@@ -12,8 +12,16 @@ import java.util.List;
*/ */
public interface XxlJobInfoDao { public interface XxlJobInfoDao {
public List<XxlJobInfo> pageList(@Param("offset") int offset, @Param("pagesize") int pagesize, @Param("jobGroup") int jobGroup, @Param("executorHandler") String executorHandler); public List<XxlJobInfo> pageList(@Param("offset") int offset,
public int pageListCount(@Param("offset") int offset, @Param("pagesize") int pagesize, @Param("jobGroup") int jobGroup, @Param("executorHandler") String executorHandler); @Param("pagesize") int pagesize,
@Param("jobGroup") int jobGroup,
@Param("jobDesc") String jobDesc,
@Param("executorHandler") String executorHandler);
public int pageListCount(@Param("offset") int offset,
@Param("pagesize") int pagesize,
@Param("jobGroup") int jobGroup,
@Param("jobDesc") String jobDesc,
@Param("executorHandler") String executorHandler);
public int save(XxlJobInfo info); public int save(XxlJobInfo info);
......
...@@ -41,8 +41,7 @@ public interface XxlJobLogDao { ...@@ -41,8 +41,7 @@ public interface XxlJobLogDao {
public int triggerCountByHandleCode(@Param("handleCode") int handleCode); public int triggerCountByHandleCode(@Param("handleCode") int handleCode);
public List<Map<String, Object>> triggerCountByDay(@Param("from") Date from, public List<Map<String, Object>> triggerCountByDay(@Param("from") Date from,
@Param("to") Date to, @Param("to") Date to);
@Param("handleCode") int handleCode);
public int clearLog(@Param("jobGroup") int jobGroup, public int clearLog(@Param("jobGroup") int jobGroup,
@Param("jobId") int jobId, @Param("jobId") int jobId,
......
...@@ -14,22 +14,81 @@ import java.util.Map; ...@@ -14,22 +14,81 @@ import java.util.Map;
*/ */
public interface XxlJobService { public interface XxlJobService {
public Map<String, Object> pageList(int start, int length, int jobGroup, String executorHandler, String filterTime); /**
* page list
*
* @param start
* @param length
* @param jobGroup
* @param jobDesc
* @param executorHandler
* @param filterTime
* @return
*/
public Map<String, Object> pageList(int start, int length, int jobGroup, String jobDesc, String executorHandler, String filterTime);
/**
* add job
*
* @param jobInfo
* @return
*/
public ReturnT<String> add(XxlJobInfo jobInfo); public ReturnT<String> add(XxlJobInfo jobInfo);
public ReturnT<String> reschedule(XxlJobInfo jobInfo); /**
* update job
*
* @param jobInfo
* @return
*/
public ReturnT<String> update(XxlJobInfo jobInfo);
/**
* remove job
*
* @param id
* @return
*/
public ReturnT<String> remove(int id); public ReturnT<String> remove(int id);
/**
* pause job
*
* @param id
* @return
*/
public ReturnT<String> pause(int id); public ReturnT<String> pause(int id);
/**
* resume job
*
* @param id
* @return
*/
public ReturnT<String> resume(int id); public ReturnT<String> resume(int id);
/**
* trigger job
*
* @param id
* @return
*/
public ReturnT<String> triggerJob(int id); public ReturnT<String> triggerJob(int id);
/**
* dashboard info
*
* @return
*/
public Map<String,Object> dashboardInfo(); public Map<String,Object> dashboardInfo();
public ReturnT<Map<String,Object>> triggerChartDate(Date startDate, Date endDate); /**
* chart info
*
* @param startDate
* @param endDate
* @return
*/
public ReturnT<Map<String,Object>> chartInfo(Date startDate, Date endDate);
} }
...@@ -2,6 +2,7 @@ package com.xxl.job.admin.service.impl; ...@@ -2,6 +2,7 @@ package com.xxl.job.admin.service.impl;
import com.xxl.job.admin.core.model.XxlJobInfo; import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog; import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.core.util.I18nUtil;
import com.xxl.job.admin.dao.XxlJobInfoDao; import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao; import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.dao.XxlJobRegistryDao; import com.xxl.job.admin.dao.XxlJobRegistryDao;
...@@ -64,7 +65,7 @@ public class AdminBizImpl implements AdminBiz { ...@@ -64,7 +65,7 @@ public class AdminBizImpl implements AdminBiz {
if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) { if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId()); XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId());
if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) { if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) {
callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发子任务<<<<<<<<<<< </span><br>"; callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";
String[] childJobIds = xxlJobInfo.getChildJobId().split(","); String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
for (int i = 0; i < childJobIds.length; i++) { for (int i = 0; i < childJobIds.length; i++) {
...@@ -73,21 +74,27 @@ public class AdminBizImpl implements AdminBiz { ...@@ -73,21 +74,27 @@ public class AdminBizImpl implements AdminBiz {
ReturnT<String> triggerChildResult = xxlJobService.triggerJob(childJobId); ReturnT<String> triggerChildResult = xxlJobService.triggerJob(childJobId);
// add msg // add msg
callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>", callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
(i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg()); (i+1),
childJobIds.length,
childJobIds[i],
(triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")),
triggerChildResult.getMsg());
} else { } else {
callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>", callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
(i+1), childJobIds.length, childJobIds[i]); (i+1),
childJobIds.length,
childJobIds[i]);
} }
} }
} }
} else if (IJobHandler.FAIL_RETRY.getCode() == handleCallbackParam.getExecuteResult().getCode()){ } else if (IJobHandler.FAIL_RETRY.getCode() == handleCallbackParam.getExecuteResult().getCode()){
ReturnT<String> retryTriggerResult = xxlJobService.triggerJob(log.getJobId()); ReturnT<String> retryTriggerResult = xxlJobService.triggerJob(log.getJobId());
callbackMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>执行失败重试<<<<<<<<<<< </span><br>"; callbackMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_exe_fail_retry") +"<<<<<<<<<<< </span><br>";
callbackMsg += MessageFormat.format("触发{0}, 触发备注: {1}", callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_msg1"),
(retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), retryTriggerResult.getMsg()); (retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")), retryTriggerResult.getMsg());
} }
// handle msg // handle msg
......
admin_name=任务调度中心
admin_name_full=分布式任务调度平台XXL-JOB
admin_version=1.9.2 (快照版)
## system
system_tips=系统提示
system_ok=确定
system_close=关闭
system_save=保存
system_cancel=取消
system_search=搜索
system_status=状态
system_opt=操作
system_please_input=请输入
system_please_choose=请选择
system_success=成功
system_fail=失败
system_add_suc=新增成功
system_add_fail=新增失败
system_update_suc=更新成功
system_update_fail=更新失败
system_all=全部
system_api_error=接口异常
system_show=查看
system_empty=
system_opt_suc=操作成功
system_opt_fail=操作失败
system_opt_edit=编辑
system_opt_del=删除
system_unvalid=非法
system_not_found=不存在
system_nav=导航
## daterangepicker
daterangepicker_ranges_recent_hour=最近一小时
daterangepicker_ranges_today=今日
daterangepicker_ranges_yesterday=昨日
daterangepicker_ranges_this_month=本月
daterangepicker_ranges_last_month=上个月
daterangepicker_ranges_recent_week=最近一周
daterangepicker_ranges_recent_month=最近一月
daterangepicker_custom_name=自定义
daterangepicker_custom_starttime=起始时间
daterangepicker_custom_endtime=结束时间
daterangepicker_custom_daysofweek=日,一,二,三,四,五,六
daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月
## dataTable
dataTable_sProcessing=处理中...
dataTable_sLengthMenu=每页 _MENU_ 条记录
dataTable_sZeroRecords=没有匹配结果
dataTable_sInfo=第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 )
dataTable_sInfoEmpty=无记录
dataTable_sInfoFiltered=(由 _MAX_ 项结果过滤)
dataTable_sSearch=搜索
dataTable_sEmptyTable=表中数据为空
dataTable_sLoadingRecords=载入中...
dataTable_sFirst=首页
dataTable_sPrevious=上页
dataTable_sNext=下页
dataTable_sLast=末页
dataTable_sSortAscending=: 以升序排列此列
dataTable_sSortDescending=: 以降序排列此列
## login
login_btn=登录
login_remember_me=记住密码
login_username_placeholder=请输入登录账号
login_password_placeholder=请输入登录密码
login_username_empty=请输入登录账号
login_username_lt_5=登录账号不应低于5位
login_password_empty=请输入登录密码
login_password_lt_5=登录密码不应低于5位
login_success=登录成功
login_fail=登录失败
login_param_empty=账号或密码为空
login_param_unvalid=账号或密码错误
## logout
logout_btn=注销
logout_confirm=确认注销登录?
logout_success=注销成功
logout_fail=注销失败
## dashboard
job_dashboard_name=运行报表
job_dashboard_job_num=任务数量
job_dashboard_job_num_tip=调度中心运行的任务数量
job_dashboard_trigger_num=调度次数
job_dashboard_trigger_num_tip=调度中心触发的调度次数
job_dashboard_jobgroup_num=执行器数量
job_dashboard_jobgroup_num_tip=调度中心在线的执行器机器数量
job_dashboard_report=调度报表
job_dashboard_report_loaddata_fail=调度报表数据加载异常
job_dashboard_date_report=日期分布图
job_dashboard_rate_report=成功比例图
## job info
jobinfo_name=任务管理
jobinfo_job=任务
jobinfo_field_add=新增任务
jobinfo_field_update=更新任务
jobinfo_field_id=任务ID
jobinfo_field_jobgroup=执行器
jobinfo_field_jobdesc=任务描述
jobinfo_field_gluetype=运行模式
jobinfo_field_executorparam=任务参数
jobinfo_field_cron_unvalid=Cron格式非法
jobinfo_field_author=负责人
jobinfo_field_alarmemail=报警邮件
jobinfo_field_alarmemail_placeholder=请输入报警邮件,多个邮件地址则逗号分隔
jobinfo_field_executorRouteStrategy=路由策略
jobinfo_field_childJobId=子任务ID
jobinfo_field_childJobId_limit=子任务ID({0})不可与父任务重复
jobinfo_field_childJobId_placeholder=请输入子任务的任务ID,如存在多个则逗号分隔
jobinfo_field_executorBlockStrategy=阻塞处理策略
jobinfo_field_executorFailStrategy=失败处理策略
jobinfo_script_location=脚本位置
jobinfo_shard_index=分片序号
jobinfo_shard_total=分片总数
jobinfo_opt_pause=暂停
jobinfo_opt_resume=恢复
jobinfo_opt_log=日志
jobinfo_opt_run=执行
jobinfo_glue_remark=源码备注
jobinfo_glue_remark_limit=源码备注长度限制为4~100
jobinfo_glue_rollback=版本回溯
jobinfo_glue_jobid_unvalid=任务ID非法
jobinfo_glue_gluetype_unvalid=该任务非GLUE模式
## job log
joblog_name=调度日志
joblog_status=状态
joblog_status_all=全部
joblog_status_suc=成功
joblog_status_fail=失败
joblog_status_running=进行中
joblog_field_triggerTime=调度时间
joblog_field_triggerCode=调度结果
joblog_field_triggerMsg=调度备注
joblog_field_handleTime=执行时间
joblog_field_handleCode=执行结果
joblog_field_handleMsg=执行备注
joblog_field_executorAddress=执行器地址
joblog_clean=清理
joblog_clean_log=日志清理
joblog_clean_type=清理方式
joblog_clean_type_1=清理一个月之前日志数据
joblog_clean_type_2=清理三个月之前日志数据
joblog_clean_type_3=清理六个月之前日志数据
joblog_clean_type_4=清理一年之前日志数据
joblog_clean_type_5=清理一千条以前日志数据
joblog_clean_type_6=清理一万条以前日志数据
joblog_clean_type_7=清理三万条以前日志数据
joblog_clean_type_8=清理十万条以前日志数据
joblog_clean_type_9=清理所有日志数据
joblog_clean_type_unvalid=清理类型参数异常
joblog_handleCode_200=成功
joblog_handleCode_500=失败
joblog_handleCode_501=失败重试
joblog_kill_log=终止任务
joblog_kill_log_limit=调度失败,无法终止日志
joblog_kill_log_byman=人为操作主动终止
joblog_rolling_log=执行日志
joblog_rolling_log_refresh=刷新
joblog_rolling_log_triggerfail=任务发起调度失败,无法查看执行日志
joblog_rolling_log_failoften=终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志
joblog_logid_unvalid=日志ID非法
## job group
jobgroup_name=执行器管理
jobgroup_list=执行器列表
jobgroup_add=新增执行器
jobgroup_edit=编辑执行器
jobgroup_del=删除执行器
jobgroup_field_order=排序
jobgroup_field_title=名称
jobgroup_field_addressType=注册方式
jobgroup_field_addressType_0=自动注册
jobgroup_field_addressType_1=手动录入
jobgroup_field_addressType_limit=手动录入注册方式,机器地址不可为空
jobgroup_field_registryList=机器地址
jobgroup_field_registryList_unvalid=机器地址格式非法
jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔
jobgroup_field_appName_limit=限制以小写字母开头,由小写字母、数字和中划线组成
jobgroup_field_appName_length=AppName长度限制为4~64
jobgroup_field_title_length=名称长度限制为4~12
jobgroup_field_order_digits=请输入整数
jobgroup_field_orderrange=取值范围为1~1000
jobgroup_del_limit_0=拒绝删除,该执行器使用中
jobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器
## job conf
jobconf_fail_alarm=失败告警
jobconf_fail_retry=失败重试
jobconf_route_first=第一个
jobconf_route_last=最后一个
jobconf_route_round=轮询
jobconf_route_random=随机
jobconf_route_consistenthash=一致性HASH
jobconf_route_lfu=最不经常使用
jobconf_route_lru=最近最久未使用
jobconf_route_failover=故障转移
jobconf_route_busyover=忙碌转移
jobconf_route_shard=分片广播
jobconf_idleBeat=空闲检测
jobconf_beat=心跳检测
jobconf_monitor=调度中心监控报警
jobconf_monitor_detail=监控告警明细
jobconf_monitor_alarm_title=告警类型
jobconf_monitor_alarm_type=调度失败
jobconf_trigger_admin_adress=调度机器
jobconf_trigger_exe_regtype=执行器-注册方式
jobconf_trigger_exe_regaddress=执行器-地址列表
jobconf_trigger_address_empty=调度失败:执行器地址为空
jobconf_trigger_run=触发调度
jobconf_trigger_child_run=触发子任务
jobconf_trigger_fail_retry=调度失败重试
jobconf_exe_fail_retry=执行失败重试
jobconf_callback_child_msg1={0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>
jobconf_callback_child_msg2={0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>
jobconf_callback_msg1=触发{0}, 触发备注: {1} <br>
## help
job_help=使用教程
job_help_document=官方文档
\ No newline at end of file
admin_name=Scheduling Center
admin_name_full=Distributed Task Scheduling Platform XXL-JOB
admin_version=1.9.2 (SNAPSHOT)
## system
system_tips=System message
system_ok=Confirm
system_close=Close
system_save=Save
system_cancel=Cancel
system_search=Search
system_status=Status
system_opt=Operate
system_please_input=please input
system_please_choose=please choose
system_success=success
system_fail=fail
system_add_suc=add success
system_add_fail=add fail
system_update_suc=update success
system_update_fail=update fail
system_all=All
system_api_error=net error
system_show=Show
system_empty=Empty
system_opt_suc=operate success
system_opt_fail=operate fail
system_opt_edit=Edit
system_opt_del=Delete
system_unvalid=illegal
system_not_found=not exist
system_nav=Navigation
## daterangepicker
daterangepicker_ranges_recent_hour=recent one hour
daterangepicker_ranges_today=today
daterangepicker_ranges_yesterday=yesterday
daterangepicker_ranges_this_month=this month
daterangepicker_ranges_last_month=last month
daterangepicker_ranges_recent_week=recent one week
daterangepicker_ranges_recent_month=recent one month
daterangepicker_custom_name=custom
daterangepicker_custom_starttime=start time
daterangepicker_custom_endtime=end time
daterangepicker_custom_daysofweek=Sun,Mon,Tue,Wed,Thu,Fri,Sat
daterangepicker_custom_monthnames=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
## dataTable
dataTable_sProcessing=processing...
dataTable_sLengthMenu= _MENU_ records per page
dataTable_sZeroRecords=No matching results
dataTable_sInfo=page _PAGE_ ( Total _PAGES_ pages,_TOTAL_ records )
dataTable_sInfoEmpty=No Record
dataTable_sInfoFiltered=(Filtered by _MAX_ results)
dataTable_sSearch=Search
dataTable_sEmptyTable=Table data is empty
dataTable_sLoadingRecords=Loading...
dataTable_sFirst=FIRST PAGE
dataTable_sPrevious=Previous Page
dataTable_sNext=Next Page
dataTable_sLast=LAST PAGE
dataTable_sSortAscending=: Rank this column in ascending order
dataTable_sSortDescending=: Rank this column in descending order
## login
login_btn=Login
login_remember_me=Remember Me
login_username_placeholder=Please enter username
login_password_placeholder=Please enter password
login_username_empty=Please enter username
login_username_lt_5=Username length should not be less than 5
login_password_empty=Please enter password
login_password_lt_5=Password length should not be less than 5
login_success=Login success
login_fail=Login fail
login_param_empty=Username or password is empty
login_param_unvalid=Username or password error
## logout
logout_btn=Logout
logout_confirm=Confirm logout?
logout_success=Logout success
logout_fail=Logout fail
## dashboard
job_dashboard_name=Run report
job_dashboard_job_num=Job number
job_dashboard_job_num_tip=The number of tasks running in the scheduling center
job_dashboard_trigger_num=trigger number
job_dashboard_trigger_num_tip=The number of trigger record scheduled by the scheduling center
job_dashboard_jobgroup_num=Executor number
job_dashboard_jobgroup_num_tip=The number of online executor machines perceived by the scheduling center
job_dashboard_report=Scheduling report
job_dashboard_report_loaddata_fail=Scheduling report load data error
job_dashboard_date_report=Date distribution
job_dashboard_rate_report=Percentage distribution
## job info
jobinfo_name=Job Manage
jobinfo_job=Job
jobinfo_field_add=Add Job
jobinfo_field_update=Edit Job
jobinfo_field_id=Job ID
jobinfo_field_jobgroup=Executor
jobinfo_field_jobdesc=Job description
jobinfo_field_gluetype=GLUE Type
jobinfo_field_executorparam=Param
jobinfo_field_cron_unvalid=The Cron is illegal
jobinfo_field_author=Author
jobinfo_field_alarmemail=Alarm email
jobinfo_field_alarmemail_placeholder=Please enter alarm mail, if there are more than one comma separated
jobinfo_field_executorRouteStrategy=Route Strategy
jobinfo_field_childJobId=Child Job ID
jobinfo_field_childJobId_limit=Child job ID({0}) cannot be duplicated with the parent job.
jobinfo_field_childJobId_placeholder=Please enter the Child job ID, if there are more than one comma separated
jobinfo_field_executorBlockStrategy=Block Strategy
jobinfo_field_executorFailStrategy=Fail Strategy
jobinfo_script_location=Script location
jobinfo_shard_index=Shard index
jobinfo_shard_total=Shard total
jobinfo_opt_pause=Pause
jobinfo_opt_resume=Resume
jobinfo_opt_log=Log
jobinfo_opt_run=Run
jobinfo_glue_remark=Resource Remark
jobinfo_glue_remark_limit=Resource Remark length is limited to 4~100
jobinfo_glue_rollback=Version Backtrack
jobinfo_glue_jobid_unvalid=Job ID is illegal
jobinfo_glue_gluetype_unvalid=The job is not GLUE Type
## job log
joblog_name=Trigger Log
joblog_status=Status
joblog_status_all=All
joblog_status_suc=Success
joblog_status_fail=Fail
joblog_status_running=Running
joblog_field_triggerTime=Trigger Time
joblog_field_triggerCode=Trigger Result
joblog_field_triggerMsg=Trigger Msg
joblog_field_handleTime=Handle Time
joblog_field_handleCode=Handle Result
joblog_field_handleMsg=Trigger Msg
joblog_field_executorAddress=Executor Address
joblog_clean=Clean
joblog_clean_log=Clean Log
joblog_clean_type=Clean Type
joblog_clean_type_1=Clean up log data a month ago
joblog_clean_type_2=Clean up log data three month ago
joblog_clean_type_3=Clean up log data six month ago
joblog_clean_type_4=Clean up log data a year ago
joblog_clean_type_5=Clean up log data a thousand record ago
joblog_clean_type_6=Clean up log data ten thousand record ago
joblog_clean_type_7=Clean up log data thirty thousand record ago
joblog_clean_type_8=Clean up log data hundred thousand record ago
joblog_clean_type_9=Clean up all log data
joblog_clean_type_unvalid=Clean type is illegal
joblog_handleCode_200=Success
joblog_handleCode_500=Fail
joblog_handleCode_501=Fail retry
joblog_kill_log=Kill Job
joblog_kill_log_limit=Trigger Fail, can not kill job
joblog_kill_log_byman=Manual operation to active kill job
joblog_rolling_log=Rolling log
joblog_rolling_log_refresh=Refresh
joblog_rolling_log_triggerfail=The job trigger fail, can not view the rolling log
joblog_rolling_log_failoften=The request for the Rolling log is terminated, the number of failed requests exceeds the limit, Reload the log on the refresh page
joblog_logid_unvalid=Log ID is illegal
## job group
jobgroup_name=Executor Manage
jobgroup_list=Executor List
jobgroup_add=Add Executor
jobgroup_edit=Edit Executor
jobgroup_del=Delete Executor
jobgroup_field_order=Order
jobgroup_field_title=Title
jobgroup_field_addressType=Registry Type
jobgroup_field_addressType_0=Automatic registration
jobgroup_field_addressType_1=Manual registration
jobgroup_field_addressType_limit=Manually registration type, the machine address must not be empty
jobgroup_field_registryList=machine address
jobgroup_field_registryList_unvalid=registry machine address is illegal
jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated
jobgroup_field_appName_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and underscores.
jobgroup_field_appName_length=AppName length is limited to 4~64
jobgroup_field_title_length=Title length is limited to 4~12
jobgroup_field_order_digits=Please enter a positive integer
jobgroup_field_orderrange=Order is limited to 1~1000
jobgroup_del_limit_0=Refuse to delete, the executor is being used
jobgroup_del_limit_1=Refuses to delete, the system retains at least one executor
## job conf
jobconf_fail_alarm=Fail Alarm
jobconf_fail_retry=Fail Retry
jobconf_route_first=First
jobconf_route_last=Last
jobconf_route_round=Round
jobconf_route_random=Random
jobconf_route_consistenthash=Consistent Hash
jobconf_route_lfu=Least Frequently Used
jobconf_route_lru=Least Recently Used
jobconf_route_failover=Failover
jobconf_route_busyover=Busyover
jobconf_route_shard=Sharding Broadcast
jobconf_idleBeat=Idle check
jobconf_beat=Heartbeats
jobconf_monitor=Scheduling Center monitor alarm
jobconf_monitor_detail=monitor alarm details
jobconf_monitor_alarm_title=Alarm Type
jobconf_monitor_alarm_type=Trigger Fail
jobconf_trigger_admin_adress=Trigger machine address
jobconf_trigger_exe_regtype=Execotor-Registry Type
jobconf_trigger_exe_regaddress=Execotor-Registry Address
jobconf_trigger_address_empty=Trigger Fail:registry address is empty
jobconf_trigger_run=Trigger Job
jobconf_trigger_child_run=Trigger child job
jobconf_trigger_fail_retry=Trigger fail retry
jobconf_exe_fail_retry=Handle fail retry
jobconf_callback_child_msg1={0}/{1} [Job ID={2}], Trigger {3}, Trigger msg: {4} <br>
jobconf_callback_child_msg2={0}/{1} [Job ID={2}], Trigger Fail, Trigger msg: Job ID is illegal <br>
jobconf_callback_msg1=Trigger {0}, Trigger msg: {1} <br>
## help
job_help=Tutorial
job_help_document=Official Document
\ No newline at end of file
...@@ -58,6 +58,9 @@ ...@@ -58,6 +58,9 @@
<if test="jobGroup gt 0"> <if test="jobGroup gt 0">
AND t.job_group = #{jobGroup} AND t.job_group = #{jobGroup}
</if> </if>
<if test="jobDesc != null and jobDesc != ''">
AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
</if>
<if test="executorHandler != null and executorHandler != ''"> <if test="executorHandler != null and executorHandler != ''">
AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%') AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
</if> </if>
...@@ -73,6 +76,9 @@ ...@@ -73,6 +76,9 @@
<if test="jobGroup gt 0"> <if test="jobGroup gt 0">
AND t.job_group = #{jobGroup} AND t.job_group = #{jobGroup}
</if> </if>
<if test="jobDesc != null and jobDesc != ''">
AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
</if>
<if test="executorHandler != null and executorHandler != ''"> <if test="executorHandler != null and executorHandler != ''">
AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%') AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
</if> </if>
......
...@@ -163,12 +163,13 @@ ...@@ -163,12 +163,13 @@
</select> </select>
<select id="triggerCountByDay" resultType="java.util.Map" > <select id="triggerCountByDay" resultType="java.util.Map" >
SELECT DATE_FORMAT(trigger_time,'%Y-%m-%d') triggerDay, COUNT(id) triggerCount SELECT
DATE_FORMAT(trigger_time,'%Y-%m-%d') triggerDay,
COUNT(handle_code) triggerDayCount,
SUM(CASE WHEN handle_code = 0 then 1 else 0 end) as triggerDayCountRunning,
SUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc
FROM XXL_JOB_QRTZ_TRIGGER_LOG FROM XXL_JOB_QRTZ_TRIGGER_LOG
WHERE trigger_time BETWEEN #{from} and #{to} WHERE trigger_time BETWEEN #{from} and #{to}
<if test="handleCode gt 0">
AND handle_code = #{handleCode}
</if>
GROUP BY triggerDay; GROUP BY triggerDay;
</select> </select>
......
...@@ -20,7 +20,7 @@ org.quartz.jobStore.maxMisfiresToHandleAtATime: 1 ...@@ -20,7 +20,7 @@ org.quartz.jobStore.maxMisfiresToHandleAtATime: 1
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore #org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
# for cluster # for cluster
org.quartz.jobStore.tablePrefix = XXL_JOB_QRTZ_ org.quartz.jobStore.tablePrefix: XXL_JOB_QRTZ_
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.isClustered: true org.quartz.jobStore.isClustered: true
org.quartz.jobStore.clusterCheckinInterval: 5000 org.quartz.jobStore.clusterCheckinInterval: 5000
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
http://www.springframework.org/schema/context http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xxl.job.admin.service, com.xxl.job.admin.dao" /> <context:component-scan base-package="com.xxl.job.admin.core.conf, com.xxl.job.admin.service, com.xxl.job.admin.dao" />
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/template/" /> <property name="templateLoaderPath" value="/WEB-INF/template/" />
......
...@@ -17,3 +17,6 @@ xxl.job.login.password=123456 ...@@ -17,3 +17,6 @@ xxl.job.login.password=123456
### xxl-job, access token ### xxl-job, access token
xxl.job.accessToken= xxl.job.accessToken=
### xxl-job, i18n (default empty as chinese, "en" as english)
xxl.job.i18n=
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>应用程序异常 (500)</title> <title>Error</title>
<style type="text/css"> <style type="text/css">
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog { div.dialog {
...@@ -21,8 +21,9 @@ ...@@ -21,8 +21,9 @@
<body> <body>
<div class="dialog"> <div class="dialog">
<h1>应用程序异常</h1> <h1>System Error</h1>
<p>抱歉!您访问的页面出现异常,请稍后重试或联系管理员。</p> <p>Oops! Page not found.</p>
<a href="javascript:window.location.href='${request.contextPath}/'">Back</a>
</div> </div>
</body> </body>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>应用程序异常 (error)</title> <title>Error</title>
<style type="text/css"> <style type="text/css">
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; } body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
div.dialog { div.dialog {
...@@ -21,9 +21,9 @@ ...@@ -21,9 +21,9 @@
<body> <body>
<div class="dialog"> <div class="dialog">
<h1>应用程序异常</h1> <h1>System Error</h1>
<p>${exceptionMsg}</p> <p>${exceptionMsg}</p>
<a href="javascript:window.location.href='${request.contextPath}/'">返 回</a> <a href="javascript:window.location.href='${request.contextPath}/'">Back</a>
</p> </p>
</div> </div>
......
...@@ -29,6 +29,10 @@ ...@@ -29,6 +29,10 @@
<!-- pace --> <!-- pace -->
<link rel="stylesheet" href="${request.contextPath}/static/plugins/pace/themes/pace-theme-flash.css"> <link rel="stylesheet" href="${request.contextPath}/static/plugins/pace/themes/pace-theme-flash.css">
<#-- i18n -->
<#global I18n = I18nUtil.getMultString()?eval />
</#macro> </#macro>
<#macro commonScript> <#macro commonScript>
...@@ -53,7 +57,10 @@ ...@@ -53,7 +57,10 @@
<#-- common --> <#-- common -->
<script src="${request.contextPath}/static/js/common.1.js"></script> <script src="${request.contextPath}/static/js/common.1.js"></script>
<script>var base_url = '${request.contextPath}';</script> <script>
var base_url = '${request.contextPath}';
var I18n = ${I18nUtil.getMultString()};
</script>
</#macro> </#macro>
...@@ -61,7 +68,7 @@ ...@@ -61,7 +68,7 @@
<header class="main-header"> <header class="main-header">
<a href="${request.contextPath}/" class="logo"> <a href="${request.contextPath}/" class="logo">
<span class="logo-mini"><b>XXL</b></span> <span class="logo-mini"><b>XXL</b></span>
<span class="logo-lg"><b>任务调度中心</b></span> <span class="logo-lg"><b>${I18n.admin_name}</b></span>
</a> </a>
<nav class="navbar navbar-static-top" role="navigation"> <nav class="navbar navbar-static-top" role="navigation">
<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"><span class="sr-only">切换导航</span></a> <a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"><span class="sr-only">切换导航</span></a>
...@@ -69,7 +76,7 @@ ...@@ -69,7 +76,7 @@
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li class="dropdown user user-menu"> <li class="dropdown user user-menu">
<a href=";" id="logoutBtn" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false"> <a href=";" id="logoutBtn" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<span class="hidden-xs">注销</span> <span class="hidden-xs">${I18n.logout_btn}</span>
</a> </a>
</li> </li>
</ul> </ul>
...@@ -85,11 +92,11 @@ ...@@ -85,11 +92,11 @@
<section class="sidebar"> <section class="sidebar">
<!-- sidebar menu: : style can be found in sidebar.less --> <!-- sidebar menu: : style can be found in sidebar.less -->
<ul class="sidebar-menu"> <ul class="sidebar-menu">
<li class="header">常用模块</li> <li class="header">${I18n.system_nav}</li>
<li class="nav-click <#if pageName == "jobinfo">active</#if>" ><a href="${request.contextPath}/jobinfo"><i class="fa fa-circle-o text-aqua"></i><span>任务管理</span></a></li> <li class="nav-click <#if pageName == "jobinfo">active</#if>" ><a href="${request.contextPath}/jobinfo"><i class="fa fa-circle-o text-aqua"></i><span>${I18n.jobinfo_name}</span></a></li>
<li class="nav-click <#if pageName == "joblog">active</#if>" ><a href="${request.contextPath}/joblog"><i class="fa fa-circle-o text-yellow"></i><span>调度日志</span></a></li> <li class="nav-click <#if pageName == "joblog">active</#if>" ><a href="${request.contextPath}/joblog"><i class="fa fa-circle-o text-yellow"></i><span>${I18n.joblog_name}</span></a></li>
<li class="nav-click <#if pageName == "jobgroup">active</#if>" ><a href="${request.contextPath}/jobgroup"><i class="fa fa-circle-o text-green"></i><span>执行器管理</span></a></li> <li class="nav-click <#if pageName == "jobgroup">active</#if>" ><a href="${request.contextPath}/jobgroup"><i class="fa fa-circle-o text-green"></i><span>${I18n.jobgroup_name}</span></a></li>
<li class="nav-click <#if pageName == "help">active</#if>" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-gray"></i><span>使用教程</span></a></li> <li class="nav-click <#if pageName == "help">active</#if>" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-gray"></i><span>${I18n.job_help}</span></a></li>
</ul> </ul>
</section> </section>
<!-- /.sidebar --> <!-- /.sidebar -->
...@@ -175,7 +182,7 @@ ...@@ -175,7 +182,7 @@
<#macro commonFooter > <#macro commonFooter >
<footer class="main-footer"> <footer class="main-footer">
Powered by <b>XXL-JOB</b> 1.9.0(快照版本) Powered by <b>XXL-JOB</b> ${I18n.admin_version}
<div class="pull-right hidden-xs"> <div class="pull-right hidden-xs">
<strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp; <strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;
<a href="http://www.xuxueli.com/" target="_blank" >xuxueli</a> <a href="http://www.xuxueli.com/" target="_blank" >xuxueli</a>
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>任务调度中心</title>
<#import "/common/common.macro.ftl" as netCommon> <#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle /> <@netCommon.commonStyle />
<title>${I18n.admin_name}</title>
</head> </head>
<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> "> <body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
<div class="wrapper"> <div class="wrapper">
...@@ -16,25 +16,19 @@ ...@@ -16,25 +16,19 @@
<div class="content-wrapper"> <div class="content-wrapper">
<!-- Content Header (Page header) --> <!-- Content Header (Page header) -->
<section class="content-header"> <section class="content-header">
<h1>使用教程<small>任务调度中心</small></h1> <h1>${I18n.job_help}</h1>
<!--
<ol class="breadcrumb">
<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
<li class="active">使用教程</li>
</ol>
-->
</section> </section>
<!-- Main content --> <!-- Main content -->
<section class="content"> <section class="content">
<div class="callout callout-info"> <div class="callout callout-info">
<h4>分布式任务调度平台XXL-JOB</h4> <h4>${I18n.admin_name_full}</h4>
<br> <br>
<p> <p>
<a target="_blank" href="https://github.com/xuxueli/xxl-job">github</a>&nbsp;&nbsp;&nbsp;&nbsp; <a target="_blank" href="https://github.com/xuxueli/xxl-job">Github</a>&nbsp;&nbsp;&nbsp;&nbsp;
<iframe src="https://ghbtns.com/github-btn.html?user=xuxueli&repo=xxl-job&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px" style="margin-bottom:-5px;"></iframe> <iframe src="https://ghbtns.com/github-btn.html?user=xuxueli&repo=xxl-job&type=star&count=true" frameborder="0" scrolling="0" width="170px" height="20px" style="margin-bottom:-5px;"></iframe>
<br><br> <br><br>
<a target="_blank" href="http://www.xuxueli.com/xxl-job/">文档地址</a> <a target="_blank" href="http://www.xuxueli.com/xxl-job/">${I18n.job_help_document}</a>
<br><br> <br><br>
</p> </p>
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>任务调度中心</title>
<#import "/common/common.macro.ftl" as netCommon> <#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle /> <@netCommon.commonStyle />
<!-- daterangepicker --> <!-- daterangepicker -->
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/daterangepicker/daterangepicker.css"> <link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/daterangepicker/daterangepicker.css">
<title>${I18n.admin_name}</title>
</head> </head>
<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> "> <body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
<div class="wrapper"> <div class="wrapper">
...@@ -18,8 +18,9 @@ ...@@ -18,8 +18,9 @@
<div class="content-wrapper"> <div class="content-wrapper">
<!-- Content Header (Page header) --> <!-- Content Header (Page header) -->
<section class="content-header"> <section class="content-header">
<h1>运行报表<small>任务调度中心</small></h1> <h1>${I18n.job_dashboard_name}</h1>
<!-- <!--
<h1>运行报表<small>任务调度中心</small></h1>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li><a><i class="fa fa-dashboard"></i>调度中心</a></li> <li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
<li class="active">使用教程</li> <li class="active">使用教程</li>
...@@ -39,13 +40,13 @@ ...@@ -39,13 +40,13 @@
<span class="info-box-icon"><i class="fa fa-flag-o"></i></span> <span class="info-box-icon"><i class="fa fa-flag-o"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text">任务数量</span> <span class="info-box-text">${I18n.job_dashboard_job_num}</span>
<span class="info-box-number">${jobInfoCount}</span> <span class="info-box-number">${jobInfoCount}</span>
<div class="progress"> <div class="progress">
<div class="progress-bar" style="width: 100%"></div> <div class="progress-bar" style="width: 100%"></div>
</div> </div>
<span class="progress-description">调度中心运行的任务数量</span> <span class="progress-description">${I18n.job_dashboard_job_num_tip}</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -56,14 +57,14 @@ ...@@ -56,14 +57,14 @@
<span class="info-box-icon"><i class="fa fa-calendar"></i></span> <span class="info-box-icon"><i class="fa fa-calendar"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text">调度次数</span> <span class="info-box-text">${I18n.job_dashboard_trigger_num}</span>
<span class="info-box-number">${jobLogCount}</span> <span class="info-box-number">${jobLogCount}</span>
<div class="progress"> <div class="progress">
<div class="progress-bar" style="width: 100%" ></div> <div class="progress-bar" style="width: 100%" ></div>
</div> </div>
<span class="progress-description"> <span class="progress-description">
调度中心触发的调度次数 ${I18n.job_dashboard_trigger_num_tip}
<#--<#if jobLogCount gt 0> <#--<#if jobLogCount gt 0>
调度成功率:${(jobLogSuccessCount*100/jobLogCount)?string("0.00")}<small>%</small> 调度成功率:${(jobLogSuccessCount*100/jobLogCount)?string("0.00")}<small>%</small>
</#if>--> </#if>-->
...@@ -78,13 +79,13 @@ ...@@ -78,13 +79,13 @@
<span class="info-box-icon"><i class="fa ion-ios-settings-strong"></i></span> <span class="info-box-icon"><i class="fa ion-ios-settings-strong"></i></span>
<div class="info-box-content"> <div class="info-box-content">
<span class="info-box-text">执行器数量</span> <span class="info-box-text">${I18n.job_dashboard_jobgroup_num}</span>
<span class="info-box-number">${executorCount}</span> <span class="info-box-number">${executorCount}</span>
<div class="progress"> <div class="progress">
<div class="progress-bar" style="width: 100%"></div> <div class="progress-bar" style="width: 100%"></div>
</div> </div>
<span class="progress-description">调度中心在线的执行器机器数量</span> <span class="progress-description">${I18n.job_dashboard_jobgroup_num_tip}</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -96,7 +97,7 @@ ...@@ -96,7 +97,7 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="box"> <div class="box">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title">调度报表</h3> <h3 class="box-title">${I18n.job_dashboard_report}</h3>
<#--<input type="text" class="form-control" id="filterTime" readonly >--> <#--<input type="text" class="form-control" id="filterTime" readonly >-->
<!-- tools box --> <!-- tools box -->
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>任务调度中心</title>
<#import "/common/common.macro.ftl" as netCommon> <#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle /> <@netCommon.commonStyle />
<link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/lib/codemirror.css"> <link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/lib/codemirror.css">
<link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/addon/hint/show-hint.css"> <link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/addon/hint/show-hint.css">
<title>${I18n.admin_name}</title>
<style type="text/css"> <style type="text/css">
.CodeMirror { .CodeMirror {
font-size:16px; font-size:16px;
...@@ -35,7 +35,11 @@ ...@@ -35,7 +35,11 @@
<#-- left nav --> <#-- left nav -->
<div class="collapse navbar-collapse pull-left" id="navbar-collapse"> <div class="collapse navbar-collapse pull-left" id="navbar-collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li class="active" ><a href="javascript:;"><#list GlueTypeEnum as item><#if item == jobInfo.glueType>${item.desc}</#if></#list> 任务:${jobInfo.jobDesc}<span class="sr-only">(current)</span></a></li> <li class="active" ><a href="javascript:;">
<span class="sr-only">(current)</span>
<#list GlueTypeEnum as item><#if item == jobInfo.glueType>${item.desc}</#if></#list>
${jobInfo.jobDesc}
</a></li>
</ul> </ul>
</div> </div>
...@@ -43,7 +47,7 @@ ...@@ -43,7 +47,7 @@
<div class="navbar-custom-menu"> <div class="navbar-custom-menu">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">版本回溯 <span class="caret"></span></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">${I18n.jobinfo_glue_rollback} <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu"> <ul class="dropdown-menu" role="menu">
<li <#if jobLogGlues?exists && jobLogGlues?size gt 0 >style="display: none;"</#if> > <li <#if jobLogGlues?exists && jobLogGlues?size gt 0 >style="display: none;"</#if> >
<a href="javascript:;" class="source_version" version="version_now" glueType="${jobInfo.glueType}" > <a href="javascript:;" class="source_version" version="version_now" glueType="${jobInfo.glueType}" >
...@@ -66,7 +70,7 @@ ...@@ -66,7 +70,7 @@
<li id="save" > <li id="save" >
<a href="javascript:;" > <a href="javascript:;" >
<i class="fa fa-fw fa-save" ></i> <i class="fa fa-fw fa-save" ></i>
保存 ${I18n.system_save}
</a> </a>
</li> </li>
</ul> </ul>
...@@ -87,19 +91,19 @@ ...@@ -87,19 +91,19 @@
<div class="modal-dialog "> <div class="modal-dialog ">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header"> <div class="modal-header">
<h4 class="modal-title" ><i class="fa fa-fw fa-save"></i>保存</h4> <h4 class="modal-title" ><i class="fa fa-fw fa-save"></i>${I18n.system_save}</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<form class="form-horizontal form" role="form" > <form class="form-horizontal form" role="form" >
<div class="form-group"> <div class="form-group">
<label for="lastname" class="col-sm-2 control-label">源码备注<font color="red">*</font></label> <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_glue_remark}<font color="red">*</font></label>
<div class="col-sm-10"><input type="text" class="form-control" id="glueRemark" placeholder="请输入备注信息" maxlength="64" ></div> <div class="col-sm-10"><input type="text" class="form-control" id="glueRemark" placeholder="${I18n.system_please_input}${I18n.jobinfo_glue_remark}" maxlength="64" ></div>
</div> </div>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-3 col-sm-6"> <div class="col-sm-offset-3 col-sm-6">
<button type="button" class="btn btn-primary ok" >保存</button> <button type="button" class="btn btn-primary ok" >${I18n.system_save}</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button> <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
</div> </div>
</div> </div>
</form> </form>
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>任务调度中心</title> <#import "/common/common.macro.ftl" as netCommon>
<#import "/common/common.macro.ftl" as netCommon> <@netCommon.commonStyle />
<@netCommon.commonStyle /> <title>${I18n.admin_name}</title>
</head> </head>
<body class="hold-transition skin-blue layout-top-nav"> <body class="hold-transition skin-blue layout-top-nav">
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<div class="container"> <div class="container">
<#-- icon --> <#-- icon -->
<div class="navbar-header"> <div class="navbar-header">
<a class="navbar-brand"><b>执行日志</b>Console</a> <a class="navbar-brand"><b>${I18n.joblog_rolling_log}</b> Console</a>
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<i class="fa fa-bars"></i> <i class="fa fa-bars"></i>
</button> </button>
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
<li> <li>
<a href="javascript:window.location.reload();" > <a href="javascript:window.location.reload();" >
<i class="fa fa-fw fa-refresh" ></i> <i class="fa fa-fw fa-refresh" ></i>
刷新 ${I18n.joblog_rolling_log_refresh}
</a> </a>
</li> </li>
</ul> </ul>
......
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>调度中心</title>
<#import "/common/common.macro.ftl" as netCommon> <#import "/common/common.macro.ftl" as netCommon>
<@netCommon.commonStyle /> <@netCommon.commonStyle />
<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/iCheck/square/blue.css"> <link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/iCheck/square/blue.css">
<title>${I18n.admin_name}</title>
</head> </head>
<body class="hold-transition login-page"> <body class="hold-transition login-page">
<div class="login-box"> <div class="login-box">
...@@ -13,25 +13,25 @@ ...@@ -13,25 +13,25 @@
</div> </div>
<form id="loginForm" method="post" > <form id="loginForm" method="post" >
<div class="login-box-body"> <div class="login-box-body">
<p class="login-box-msg">任务调度中心</p> <p class="login-box-msg">${I18n.admin_name}</p>
<div class="form-group has-feedback"> <div class="form-group has-feedback">
<input type="text" name="userName" class="form-control" placeholder="请输入登录账号" value="admin" > <input type="text" name="userName" class="form-control" placeholder="${I18n.login_username_placeholder}" value="admin" maxlength="18" >
<span class="glyphicon glyphicon-envelope form-control-feedback"></span> <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
</div> </div>
<div class="form-group has-feedback"> <div class="form-group has-feedback">
<input type="password" name="password" class="form-control" placeholder="请输入登录密码" value="123456" > <input type="password" name="password" class="form-control" placeholder="${I18n.login_password_placeholder}" value="123456" maxlength="18" >
<span class="glyphicon glyphicon-lock form-control-feedback"></span> <span class="glyphicon glyphicon-lock form-control-feedback"></span>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-8"> <div class="col-xs-8">
<div class="checkbox icheck"> <div class="checkbox icheck">
<label> <label>
<input type="checkbox" name="ifRemember" > Remember Me <input type="checkbox" name="ifRemember" >${I18n.login_remember_me}
</label> </label>
</div> </div>
</div><!-- /.col --> </div><!-- /.col -->
<div class="col-xs-4"> <div class="col-xs-4">
<button type="submit" class="btn btn-primary btn-block btn-flat">登录</button> <button type="submit" class="btn btn-primary btn-block btn-flat">${I18n.login_btn}</button>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -2,27 +2,24 @@ $(function(){ ...@@ -2,27 +2,24 @@ $(function(){
// logout // logout
$("#logoutBtn").click(function(){ $("#logoutBtn").click(function(){
layer.confirm('确认注销登录?', {icon: 3, title:'系统提示'}, function(index){ layer.confirm( I18n.logout_confirm , {
icon: 3,
title: I18n.system_tips ,
btn: [ I18n.system_ok, I18n.system_cancel ]
}, function(index){
layer.close(index); layer.close(index);
$.post(base_url + "/logout", function(data, status) { $.post(base_url + "/logout", function(data, status) {
if (data.code == "200") { if (data.code == "200") {
layer.msg('注销成功'); layer.msg( I18n.logout_success );
setTimeout(function(){ setTimeout(function(){
window.location.href = base_url + "/"; window.location.href = base_url + "/";
}, 500); }, 500);
/*layer.open({
title: '系统提示',
content: '注销成功',
icon: '1',
end: function(layero, index){
window.location.href = base_url + "/";
}
});*/
} else { } else {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips ,
content: (data.msg || "操作失败"), btn: [ I18n.system_ok ],
content: (data.msg || I18n.logout_fail),
icon: '2' icon: '2'
}); });
} }
...@@ -68,14 +65,14 @@ $(function(){ ...@@ -68,14 +65,14 @@ $(function(){
} }
}); });
$(slideToTop).click(function () { $(slideToTop).click(function () {
$("body").animate({ $("html,body").animate({ // firefox ie not support body, chrome support body. but found that new version chrome not support body too.
scrollTop: 0 scrollTop: 0
}, 100); }, 100);
}); });
// 左侧菜单状态,js + 后端 + cookie方式(新) // left menu status v: js + server + cookie
$('.sidebar-toggle').click(function(){ $('.sidebar-toggle').click(function(){
var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings'); // 左侧菜单展开状态[xxljob_adminlte_settings]:on=展开,off=折叠 var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings'); // on=open,off=close
if ('off' == xxljob_adminlte_settings) { if ('off' == xxljob_adminlte_settings) {
xxljob_adminlte_settings = 'on'; xxljob_adminlte_settings = 'on';
} else { } else {
...@@ -83,7 +80,8 @@ $(function(){ ...@@ -83,7 +80,8 @@ $(function(){
} }
$.cookie('xxljob_adminlte_settings', xxljob_adminlte_settings, { expires: 7 }); //$.cookie('the_cookie', '', { expires: -1 }); $.cookie('xxljob_adminlte_settings', xxljob_adminlte_settings, { expires: 7 }); //$.cookie('the_cookie', '', { expires: -1 });
}); });
// 左侧菜单状态,js + cookie方式(遗弃)
// left menu status v1: js + cookie
/* /*
var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings'); var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings');
if (xxljob_adminlte_settings == 'off') { if (xxljob_adminlte_settings == 'off') {
......
/** /**
* Created by xuxueli on 17/4/24. * Created by xuxueli on 17/4/24.
*/ */
$(function () { $(function () {
// 过滤时间 // filter Time
var _startDate = moment().subtract(1, 'months'); // 默认,最近一月 var rangesConf = {};
var _endDate = moment(); rangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')];
rangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')];
rangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')];
rangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')];
rangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')];
rangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')];
$('#filterTime').daterangepicker({ $('#filterTime').daterangepicker({
autoApply:false, autoApply:false,
singleDatePicker:false, singleDatePicker:false,
...@@ -16,36 +20,28 @@ $(function () { ...@@ -16,36 +20,28 @@ $(function () {
timePickerIncrement: 10, // 时间的增量,单位为分钟 timePickerIncrement: 10, // 时间的增量,单位为分钟
timePicker24Hour : true, timePicker24Hour : true,
opens : 'left', //日期选择框的弹出位置 opens : 'left', //日期选择框的弹出位置
ranges: { ranges: rangesConf,
//'最近1小时': [moment().subtract(1, 'hours'), moment()],
'今日': [moment().startOf('day'), moment().endOf('day')],
'昨日': [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')],
'本月': [moment().startOf('month'), moment().endOf('month')],
'上个月': [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')],
'最近1周': [moment().subtract(1, 'weeks'), moment()],
'最近1月': [_startDate, _endDate]
},
locale : { locale : {
format: 'YYYY-MM-DD HH:mm:ss', format: 'YYYY-MM-DD HH:mm:ss',
separator : ' - ', separator : ' - ',
customRangeLabel : '自定义', customRangeLabel : I18n.daterangepicker_custom_name ,
applyLabel : '确定', applyLabel : I18n.system_ok ,
cancelLabel : '取消', cancelLabel : I18n.system_cancel ,
fromLabel : '起始时间', fromLabel : I18n.daterangepicker_custom_starttime ,
toLabel : '结束时间', toLabel : I18n.daterangepicker_custom_endtime ,
daysOfWeek : [ '日', '一', '二', '三', '四', '五', '六' ], daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') , // '日', '一', '二', '三', '四', '五', '六'
monthNames : [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ], monthNames : I18n.daterangepicker_custom_monthnames.split(',') , // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'
firstDay : 1 firstDay : 1
}, },
startDate:_startDate, startDate: rangesConf[I18n.daterangepicker_ranges_recent_month][0] ,
endDate: _endDate endDate: rangesConf[I18n.daterangepicker_ranges_recent_month][1]
}, function (start, end, label) { }, function (start, end, label) {
freshChartDate(start, end); freshChartDate(start, end);
}); });
freshChartDate(_startDate, _endDate); freshChartDate(rangesConf[I18n.daterangepicker_ranges_recent_month][0], rangesConf[I18n.daterangepicker_ranges_recent_month][1]);
/** /**
* 刷新报表 * fresh Chart Date
* *
* @param startDate * @param startDate
* @param endDate * @param endDate
...@@ -53,7 +49,7 @@ $(function () { ...@@ -53,7 +49,7 @@ $(function () {
function freshChartDate(startDate, endDate) { function freshChartDate(startDate, endDate) {
$.ajax({ $.ajax({
type : 'POST', type : 'POST',
url : base_url + '/triggerChartDate', url : base_url + '/chartInfo',
data : { data : {
'startDate':startDate.format('YYYY-MM-DD HH:mm:ss'), 'startDate':startDate.format('YYYY-MM-DD HH:mm:ss'),
'endDate':endDate.format('YYYY-MM-DD HH:mm:ss') 'endDate':endDate.format('YYYY-MM-DD HH:mm:ss')
...@@ -65,8 +61,9 @@ $(function () { ...@@ -65,8 +61,9 @@ $(function () {
pieChartInit(data); pieChartInit(data);
} else { } else {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips ,
content: (data.msg || '调度报表数据加载异常'), btn: [ I18n.system_ok ],
content: (data.msg || I18n.job_dashboard_report_loaddata_fail ),
icon: '2' icon: '2'
}); });
} }
...@@ -75,12 +72,12 @@ $(function () { ...@@ -75,12 +72,12 @@ $(function () {
} }
/** /**
* 折线图 * line Chart Init
*/ */
function lineChartInit(data) { function lineChartInit(data) {
var option = { var option = {
title: { title: {
text: '日期分布图' text: I18n.job_dashboard_date_report
}, },
tooltip : { tooltip : {
trigger: 'axis', trigger: 'axis',
...@@ -92,7 +89,7 @@ $(function () { ...@@ -92,7 +89,7 @@ $(function () {
} }
}, },
legend: { legend: {
data:['成功调度次数','失败调度次数'] data:[I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running]
}, },
toolbox: { toolbox: {
feature: { feature: {
...@@ -119,16 +116,16 @@ $(function () { ...@@ -119,16 +116,16 @@ $(function () {
], ],
series : [ series : [
{ {
name:'成功调度次数', name:I18n.joblog_status_suc,
type:'line', type:'line',
stack: '总量', stack: 'Total',
areaStyle: {normal: {}}, areaStyle: {normal: {}},
data: data.content.triggerDayCountSucList data: data.content.triggerDayCountSucList
}, },
{ {
name:'失败调度次数', name:I18n.joblog_status_fail,
type:'line', type:'line',
stack: '总量', stack: 'Total',
label: { label: {
normal: { normal: {
show: true, show: true,
...@@ -137,9 +134,16 @@ $(function () { ...@@ -137,9 +134,16 @@ $(function () {
}, },
areaStyle: {normal: {}}, areaStyle: {normal: {}},
data: data.content.triggerDayCountFailList data: data.content.triggerDayCountFailList
},
{
name:I18n.joblog_status_running,
type:'line',
stack: 'Total',
areaStyle: {normal: {}},
data: data.content.triggerDayCountRunningList
} }
], ],
color:['#00A65A', '#F39C12'] color:['#00A65A', '#c23632', '#F39C12']
}; };
var lineChart = echarts.init(document.getElementById('lineChart')); var lineChart = echarts.init(document.getElementById('lineChart'));
...@@ -147,38 +151,42 @@ $(function () { ...@@ -147,38 +151,42 @@ $(function () {
} }
/** /**
* 饼图 * pie Chart Init
*/ */
function pieChartInit(data) { function pieChartInit(data) {
var option = { var option = {
title : { title : {
text: '成功比例图', text: I18n.job_dashboard_rate_report ,
/*subtext: 'subtext',*/ /*subtext: 'subtext',*/
x:'center' x:'center'
}, },
tooltip : { tooltip : {
trigger: 'item', trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)" formatter: "{b} : {c} ({d}%)"
}, },
legend: { legend: {
orient: 'vertical', orient: 'vertical',
left: 'left', left: 'left',
data: ['成功调度次数','失败调度次数'] data: [I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running ]
}, },
series : [ series : [
{ {
name: '分布比例', //name: '分布比例',
type: 'pie', type: 'pie',
radius : '55%', radius : '55%',
center: ['50%', '60%'], center: ['50%', '60%'],
data:[ data:[
{ {
value:data.content.triggerCountSucTotal, name:I18n.joblog_status_suc,
name:'成功调度次数' value:data.content.triggerCountSucTotal
},
{
name:I18n.joblog_status_fail,
value:data.content.triggerCountFailTotal
}, },
{ {
value:data.content.triggerCountFailTotal, name:I18n.joblog_status_running,
name:'失败调度次数' value:data.content.triggerCountRunningTotal
} }
], ],
itemStyle: { itemStyle: {
...@@ -190,7 +198,7 @@ $(function () { ...@@ -190,7 +198,7 @@ $(function () {
} }
} }
], ],
color:['#00A65A', '#F39C12'] color:['#00A65A', '#c23632', '#F39C12']
}; };
var pieChart = echarts.init(document.getElementById('pieChart')); var pieChart = echarts.init(document.getElementById('pieChart'));
pieChart.setOption(option); pieChart.setOption(option);
......
$(function() { $(function() {
// init code editor // init code editor
/*var codeEditor = CodeMirror.fromTextArea(document.getElementById("glueSource"), {
mode : "text/x-java",
lineNumbers : true,
matchBrackets : true
});*/
var codeEditor; var codeEditor;
function initIde(glueSource) { function initIde(glueSource) {
if (codeEditor == null) { if (codeEditor == null) {
...@@ -44,16 +38,18 @@ $(function() { ...@@ -44,16 +38,18 @@ $(function() {
if (!glueRemark) { if (!glueRemark) {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips,
content: '请输入备注', btn: [ I18n.system_ok],
content: I18n.system_please_input + I18n.jobinfo_glue_remark ,
icon: '2' icon: '2'
}); });
return; return;
} }
if (glueRemark.length <4 || glueRemark.length > 100) { if (glueRemark.length <4 || glueRemark.length > 100) {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips ,
content: '备注长度应该在4至100之间', btn: [ I18n.system_ok ],
content: I18n.jobinfo_glue_remark_limit ,
icon: '2' icon: '2'
}); });
return; return;
...@@ -71,8 +67,9 @@ $(function() { ...@@ -71,8 +67,9 @@ $(function() {
success : function(data){ success : function(data){
if (data.code == 200) { if (data.code == 200) {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips,
content: '保存成功', btn: [ I18n.system_ok ],
content: (I18n.system_save + I18n.system_success) ,
icon: '1', icon: '1',
end: function(layero, index){ end: function(layero, index){
//$(window).unbind('beforeunload'); //$(window).unbind('beforeunload');
...@@ -81,8 +78,9 @@ $(function() { ...@@ -81,8 +78,9 @@ $(function() {
}); });
} else { } else {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips,
content: (data.msg || "保存失败"), btn: [ I18n.system_ok ],
content: (data.msg || (I18n.system_save + I18n.system_fail) ),
icon: '2' icon: '2'
}); });
} }
......
...@@ -4,7 +4,11 @@ $(function() { ...@@ -4,7 +4,11 @@ $(function() {
$('.remove').on('click', function(){ $('.remove').on('click', function(){
var id = $(this).attr('id'); var id = $(this).attr('id');
layer.confirm('确认删除分组?', {icon: 3, title:'系统提示'}, function(index){ layer.confirm( (I18n.system_ok + I18n.jobgroup_del + '?') , {
icon: 3,
title: I18n.system_tips ,
btn: [ I18n.system_ok, I18n.system_cancel ]
}, function(index){
layer.close(index); layer.close(index);
$.ajax({ $.ajax({
...@@ -15,8 +19,9 @@ $(function() { ...@@ -15,8 +19,9 @@ $(function() {
success : function(data){ success : function(data){
if (data.code == 200) { if (data.code == 200) {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips ,
content: '删除成功', btn: [ I18n.system_ok ],
content: (I18n.jobgroup_del + I18n.system_success),
icon: '1', icon: '1',
end: function(layero, index){ end: function(layero, index){
window.location.reload(); window.location.reload();
...@@ -24,8 +29,9 @@ $(function() { ...@@ -24,8 +29,9 @@ $(function() {
}); });
} else { } else {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips,
content: (data.msg || "删除失败"), btn: [ I18n.system_ok ],
content: (data.msg || (I18n.jobgroup_del + I18n.system_fail)),
icon: '2' icon: '2'
}); });
} }
...@@ -35,12 +41,12 @@ $(function() { ...@@ -35,12 +41,12 @@ $(function() {
}); });
// jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线 // jquery.validate “low letters start, limit contants、 letters、numbers and line-through.
jQuery.validator.addMethod("myValid01", function(value, element) { jQuery.validator.addMethod("myValid01", function(value, element) {
var length = value.length; var length = value.length;
var valid = /^[a-z][a-zA-Z0-9-]*$/; var valid = /^[a-z][a-zA-Z0-9-]*$/;
return this.optional(element) || valid.test(value); return this.optional(element) || valid.test(value);
}, "限制以小写字母开头,由小写字母、数字和下划线组成"); }, I18n.jobgroup_field_appName_limit );
$('.add').on('click', function(){ $('.add').on('click', function(){
$('#addModal').modal({backdrop: false, keyboard: false}).modal('show'); $('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
...@@ -67,18 +73,18 @@ $(function() { ...@@ -67,18 +73,18 @@ $(function() {
}, },
messages : { messages : {
appName : { appName : {
required :"请输入“AppName”", required : I18n.system_please_input+"AppName",
rangelength:"AppName长度限制为4~64", rangelength: I18n.jobgroup_field_appName_length ,
myValid01: "限制以小写字母开头,由小写字母、数字和中划线组成" myValid01: I18n.jobgroup_field_appName_limit
}, },
title : { title : {
required :"请输入“执行器名称”", required : I18n.system_please_input + I18n.jobgroup_field_title ,
rangelength:"长度限制为4~12" rangelength: I18n.jobgroup_field_title_length
}, },
order : { order : {
required :"请输入“排序”", required : I18n.system_please_input + I18n.jobgroup_field_order ,
digits: "请输入整数", digits: I18n.jobgroup_field_order_digits ,
range: "取值范围为1~1000" range: I18n.jobgroup_field_orderrange
} }
}, },
highlight : function(element) { highlight : function(element) {
...@@ -96,8 +102,9 @@ $(function() { ...@@ -96,8 +102,9 @@ $(function() {
if (data.code == "200") { if (data.code == "200") {
$('#addModal').modal('hide'); $('#addModal').modal('hide');
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips ,
content: '新增成功', btn: [ I18n.system_ok ],
content: I18n.system_add_suc ,
icon: '1', icon: '1',
end: function(layero, index){ end: function(layero, index){
window.location.reload(); window.location.reload();
...@@ -105,8 +112,9 @@ $(function() { ...@@ -105,8 +112,9 @@ $(function() {
}); });
} else { } else {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips,
content: (data.msg || "新增失败"), btn: [ I18n.system_ok ],
content: (data.msg || I18n.system_add_fail ),
icon: '2' icon: '2'
}); });
} }
...@@ -119,7 +127,7 @@ $(function() { ...@@ -119,7 +127,7 @@ $(function() {
$("#addModal .form .form-group").removeClass("has-error"); $("#addModal .form .form-group").removeClass("has-error");
}); });
// 注册方式,切换 // addressType change
$("#addModal input[name=addressType], #updateModal input[name=addressType]").click(function(){ $("#addModal input[name=addressType], #updateModal input[name=addressType]").click(function(){
var addressType = $(this).val(); var addressType = $(this).val();
var $addressList = $(this).parents("form").find("textarea[name=addressList]"); var $addressList = $(this).parents("form").find("textarea[name=addressList]");
...@@ -172,18 +180,18 @@ $(function() { ...@@ -172,18 +180,18 @@ $(function() {
}, },
messages : { messages : {
appName : { appName : {
required :"请输入“AppName”", required : I18n.system_please_input+"AppName",
rangelength:"AppName长度限制为4~64", rangelength: I18n.jobgroup_field_appName_length ,
myValid01: "限制以小写字母开头,由小写字母、数字和中划线组成" myValid01: I18n.jobgroup_field_appName_limit
}, },
title : { title : {
required :"请输入“执行器名称”", required : I18n.system_please_input + I18n.jobgroup_field_title ,
rangelength:"长度限制为4~12" rangelength: I18n.jobgroup_field_title_length
}, },
order : { order : {
required :"请输入“排序”", required : I18n.system_please_input + I18n.jobgroup_field_order ,
digits: "请输入整数", digits: I18n.jobgroup_field_order_digits ,
range: "取值范围为1~1000" range: I18n.jobgroup_field_orderrange
} }
}, },
highlight : function(element) { highlight : function(element) {
...@@ -202,8 +210,9 @@ $(function() { ...@@ -202,8 +210,9 @@ $(function() {
$('#addModal').modal('hide'); $('#addModal').modal('hide');
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips ,
content: '更新成功', btn: [ I18n.system_ok ],
content: I18n.system_update_suc ,
icon: '1', icon: '1',
end: function(layero, index){ end: function(layero, index){
window.location.reload(); window.location.reload();
...@@ -211,8 +220,9 @@ $(function() { ...@@ -211,8 +220,9 @@ $(function() {
}); });
} else { } else {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips,
content: (data.msg || "更新失败"), btn: [ I18n.system_ok ],
content: (data.msg || I18n.system_update_fail ),
icon: '2' icon: '2'
}); });
} }
......
...@@ -3,7 +3,7 @@ $(function() { ...@@ -3,7 +3,7 @@ $(function() {
// trigger fail, end // trigger fail, end
if (triggerCode != 200) { if (triggerCode != 200) {
$('#logConsoleRunning').hide(); $('#logConsoleRunning').hide();
$('#logConsole').append('<span style="color: red;">任务发起调度失败,无法查看执行日志</span>'); $('#logConsole').append('<span style="color: red;">'+ I18n.joblog_rolling_log_triggerfail +'</span>');
return; return;
} }
...@@ -13,7 +13,7 @@ $(function() { ...@@ -13,7 +13,7 @@ $(function() {
function pullLog() { function pullLog() {
// pullFailCount, max=20 // pullFailCount, max=20
if (pullFailCount++ > 20) { if (pullFailCount++ > 20) {
logRunStop('<span style="color: red;">终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志</span>'); logRunStop('<span style="color: red;">'+ I18n.joblog_rolling_log_failoften +'</span>');
return; return;
} }
......
$(function(){ $(function(){
// 复选框
// input iCheck
$('input').iCheck({ $('input').iCheck({
checkboxClass: 'icheckbox_square-blue', checkboxClass: 'icheckbox_square-blue',
radioClass: 'iradio_square-blue', radioClass: 'iradio_square-blue',
increaseArea: '20%' // optional increaseArea: '20%' // optional
}); });
// 登录.规则校验 // login Form Valid
var loginFormValid = $("#loginForm").validate({ var loginFormValid = $("#loginForm").validate({
errorElement : 'span', errorElement : 'span',
errorClass : 'help-block', errorClass : 'help-block',
...@@ -25,14 +26,13 @@ $(function(){ ...@@ -25,14 +26,13 @@ $(function(){
}, },
messages : { messages : {
userName : { userName : {
required :"请输入登录账号." , required : I18n.login_username_empty,
minlength:"登录账号不应低于5位", minlength : I18n.login_username_lt_5
maxlength:"登录账号不应超过18位"
}, },
password : { password : {
required :"请输入登录密码." , required : I18n.login_password_empty ,
minlength:"登录密码不应低于5位", minlength : I18n.login_password_lt_5
maxlength:"登录密码不应超过18位" /*,maxlength:"登录密码不应超过18位"*/
} }
}, },
highlight : function(element) { highlight : function(element) {
...@@ -48,22 +48,15 @@ $(function(){ ...@@ -48,22 +48,15 @@ $(function(){
submitHandler : function(form) { submitHandler : function(form) {
$.post(base_url + "/login", $("#loginForm").serialize(), function(data, status) { $.post(base_url + "/login", $("#loginForm").serialize(), function(data, status) {
if (data.code == "200") { if (data.code == "200") {
layer.msg('登录成功'); layer.msg( I18n.login_success );
setTimeout(function(){ setTimeout(function(){
window.location.href = base_url; window.location.href = base_url;
}, 500); }, 500);
/*layer.open({
title: '系统提示',
content: '登录成功',
icon: '1',
end: function(layero, index){
window.location.href = base_url;
}
});*/
} else { } else {
layer.open({ layer.open({
title: '系统提示', title: I18n.system_tips,
content: (data.msg || "登录失败"), btn: [ I18n.system_ok ],
content: (data.msg || I18n.login_fail ),
icon: '2' icon: '2'
}); });
} }
......
/*! layer mobile-v2.0.0 Web弹层组件 MIT License http://layer.layui.com/mobile By 贤心 */
;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'<h3 style="'+(e?n.title[1]:"")+'">'+(e?n.title[0]:n.title)+"</h3>":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type="1">'+n.btn[0]+"</span>",2===t&&(e='<span no type="0">'+n.btn[1]+"</span>"+e),'<div class="layui-m-layerbtn">'+e+"</div>"):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='<i></i><i class="layui-m-layerload"></i><i></i><p>'+(n.content||"")+"</p>"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"<div "+("string"==typeof n.shade?'style="'+n.shade+'"':"")+' class="layui-m-layershade"></div>':"")+'<div class="layui-m-layermain" '+(n.fixed?"":'style="position:static;"')+'><div class="layui-m-layersection"><div class="layui-m-layerchild '+(n.skin?"layui-m-layer-"+n.skin+" ":"")+(n.className?n.className:"")+" "+(n.anim?"layui-m-anim-"+n.anim:"")+'" '+(n.style?'style="'+n.style+'"':"")+">"+l+'<div class="layui-m-layercont">'+n.content+"</div>"+c+"</div></div></div>",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i]("layui-m-layershade")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:"2.0",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a("#"+o[0]+e)[0];n&&(n.innerHTML="",t.body.removeChild(n),clearTimeout(l.timer[e]),delete l.timer[e],"function"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute("index"))}},"function"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf("/")+1);n.getAttribute("merge")||document.head.appendChild(function(){var e=t.createElement("link");return e.href=a+"need/layer.css?2.0",e.type="text/css",e.rel="styleSheet",e.id="layermcss",e}())}()}(window);
\ No newline at end of file
.layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px}
\ No newline at end of file
package com.xxl.job.admin.controller; package com.xxl.job.admin.controller;
import com.xxl.job.admin.controller.interceptor.PermissionInterceptor; import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
import com.xxl.job.admin.core.util.PropertiesUtil; import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
...@@ -22,8 +22,8 @@ public class JobInfoControllerTest extends AbstractSpringMvcTest { ...@@ -22,8 +22,8 @@ public class JobInfoControllerTest extends AbstractSpringMvcTest {
MvcResult ret = mockMvc.perform( MvcResult ret = mockMvc.perform(
post("/login") post("/login")
.contentType(MediaType.APPLICATION_FORM_URLENCODED) .contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("userName", PropertiesUtil.getString("xxl.job.login.username")) .param("userName", XxlJobAdminConfig.getAdminConfig().getLoginUsername())
.param("password", PropertiesUtil.getString("xxl.job.login.password")) .param("password", XxlJobAdminConfig.getAdminConfig().getLoginPassword())
).andReturn(); ).andReturn();
cookie = ret.getResponse().getCookie(PermissionInterceptor.LOGIN_IDENTITY_KEY); cookie = ret.getResponse().getCookie(PermissionInterceptor.LOGIN_IDENTITY_KEY);
} }
......
...@@ -20,8 +20,8 @@ public class XxlJobInfoDaoTest { ...@@ -20,8 +20,8 @@ public class XxlJobInfoDaoTest {
@Test @Test
public void pageList(){ public void pageList(){
List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, 0, null); List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, 0, null, null);
int list_count = xxlJobInfoDao.pageListCount(0, 20, 0, null); int list_count = xxlJobInfoDao.pageListCount(0, 20, 0, null, null);
System.out.println(list); System.out.println(list);
System.out.println(list_count); System.out.println(list_count);
......
...@@ -50,7 +50,7 @@ public class XxlJobLogDaoTest { ...@@ -50,7 +50,7 @@ public class XxlJobLogDaoTest {
dto = xxlJobLogDao.load(log.getId()); dto = xxlJobLogDao.load(log.getId());
List<Map<String, Object>> list2 = xxlJobLogDao.triggerCountByDay(DateUtils.addDays(new Date(), 30), new Date(), 200); List<Map<String, Object>> list2 = xxlJobLogDao.triggerCountByDay(DateUtils.addDays(new Date(), 30), new Date());
int ret4 = xxlJobLogDao.clearLog(1, 1, new Date(), 100); int ret4 = xxlJobLogDao.clearLog(1, 1, new Date(), 100);
......
package com.xxl.job.admin.util;
import com.xxl.job.admin.core.util.I18nUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* email util test
*
* @author xuxueli 2017-12-22 17:16:23
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:spring/applicationcontext-*.xml")
public class I18nUtilTest {
@Test
public void test(){
System.out.println(I18nUtil.getString("admin_name"));
System.out.println(I18nUtil.getMultString("admin_name", "admin_name_full"));
System.out.println(I18nUtil.getMultString());
}
}
...@@ -2,6 +2,9 @@ package com.xxl.job.admin.util; ...@@ -2,6 +2,9 @@ package com.xxl.job.admin.util;
import com.xxl.job.admin.core.util.MailUtil; import com.xxl.job.admin.core.util.MailUtil;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.text.MessageFormat; import java.text.MessageFormat;
...@@ -10,6 +13,8 @@ import java.text.MessageFormat; ...@@ -10,6 +13,8 @@ import java.text.MessageFormat;
* *
* @author xuxueli 2017-12-22 17:16:23 * @author xuxueli 2017-12-22 17:16:23
*/ */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:spring/applicationcontext-*.xml")
public class MailUtilTest { public class MailUtilTest {
@Test @Test
......
package com.xxl.job.admin.util;
import com.xxl.job.admin.core.util.PropertiesUtil;
import org.junit.Test;
/**
* prop util test
*
* @author xuxueli 2017-12-25 15:17:36
*/
public class PropertiesUtilTest {
@Test
public void registryTest() throws Exception {
System.out.println(PropertiesUtil.getString("xxl.job.login.username"));
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.9.0-SNAPSHOT</version> <version>1.9.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-core</artifactId> <artifactId>xxl-job-core</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
......
...@@ -8,6 +8,7 @@ import com.xxl.job.core.handler.annotation.JobHandler; ...@@ -8,6 +8,7 @@ import com.xxl.job.core.handler.annotation.JobHandler;
import com.xxl.job.core.log.XxlJobFileAppender; import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.rpc.netcom.NetComClientProxy; import com.xxl.job.core.rpc.netcom.NetComClientProxy;
import com.xxl.job.core.rpc.netcom.NetComServerFactory; import com.xxl.job.core.rpc.netcom.NetComServerFactory;
import com.xxl.job.core.thread.JobLogFileCleanThread;
import com.xxl.job.core.thread.JobThread; import com.xxl.job.core.thread.JobThread;
import com.xxl.job.core.util.NetUtil; import com.xxl.job.core.util.NetUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
...@@ -28,32 +29,35 @@ public class XxlJobExecutor implements ApplicationContextAware { ...@@ -28,32 +29,35 @@ public class XxlJobExecutor implements ApplicationContextAware {
private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class); private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);
// ---------------------- param ---------------------- // ---------------------- param ----------------------
private String adminAddresses;
private String appName;
private String ip; private String ip;
private int port; private int port;
private String appName;
private String adminAddresses;
private String accessToken; private String accessToken;
private String logPath; private String logPath;
private int logRetentionDays;
public void setAdminAddresses(String adminAddresses) {
this.adminAddresses = adminAddresses;
}
public void setAppName(String appName) {
this.appName = appName;
}
public void setIp(String ip) { public void setIp(String ip) {
this.ip = ip; this.ip = ip;
} }
public void setPort(int port) { public void setPort(int port) {
this.port = port; this.port = port;
} }
public void setAppName(String appName) {
this.appName = appName;
}
public void setAdminAddresses(String adminAddresses) {
this.adminAddresses = adminAddresses;
}
public void setAccessToken(String accessToken) { public void setAccessToken(String accessToken) {
this.accessToken = accessToken; this.accessToken = accessToken;
} }
public void setLogPath(String logPath) { public void setLogPath(String logPath) {
this.logPath = logPath; this.logPath = logPath;
} }
public void setLogRetentionDays(int logRetentionDays) {
this.logRetentionDays = logRetentionDays;
}
// ---------------------- applicationContext ---------------------- // ---------------------- applicationContext ----------------------
private static ApplicationContext applicationContext; private static ApplicationContext applicationContext;
...@@ -79,6 +83,9 @@ public class XxlJobExecutor implements ApplicationContextAware { ...@@ -79,6 +83,9 @@ public class XxlJobExecutor implements ApplicationContextAware {
// init executor-server // init executor-server
initExecutorServer(port, ip, appName, accessToken); initExecutorServer(port, ip, appName, accessToken);
// init JobLogFileCleanThread
JobLogFileCleanThread.getInstance().start(logRetentionDays);
} }
public void destroy(){ public void destroy(){
// destory JobThreadRepository // destory JobThreadRepository
...@@ -91,6 +98,9 @@ public class XxlJobExecutor implements ApplicationContextAware { ...@@ -91,6 +98,9 @@ public class XxlJobExecutor implements ApplicationContextAware {
// destory executor-server // destory executor-server
stopExecutorServer(); stopExecutorServer();
// destory JobLogFileCleanThread
JobLogFileCleanThread.getInstance().toStop();
} }
......
...@@ -40,8 +40,8 @@ public class ScriptJobHandler extends IJobHandler { ...@@ -40,8 +40,8 @@ public class ScriptJobHandler extends IJobHandler {
String cmd = glueType.getCmd(); String cmd = glueType.getCmd();
// make script file // make script file
String scriptFileName = XxlJobFileAppender.getLogPath() String scriptFileName = XxlJobFileAppender.getGlueSrcPath()
.concat("/gluesource/") .concat("/")
.concat(String.valueOf(jobId)) .concat(String.valueOf(jobId))
.concat("_") .concat("_")
.concat(String.valueOf(glueUpdatetime)) .concat(String.valueOf(glueUpdatetime))
......
...@@ -20,8 +20,21 @@ public class XxlJobFileAppender { ...@@ -20,8 +20,21 @@ public class XxlJobFileAppender {
public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>(); public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();
// log base path /**
* log base path
*
* strut like:
* ---/
* ---/gluesource/
* ---/gluesource/10_1514171108000.js
* ---/gluesource/10_1514171108000.js
* ---/2017-12-25/
* ---/2017-12-25/639.log
* ---/2017-12-25/821.log
*
*/
private static String logBasePath = "/data/applogs/xxl-job/jobhandler"; private static String logBasePath = "/data/applogs/xxl-job/jobhandler";
private static String glueSrcPath = logBasePath.concat("/gluesource");
public static void initLogPath(String logPath){ public static void initLogPath(String logPath){
// init // init
if (logPath!=null && logPath.trim().length()>0) { if (logPath!=null && logPath.trim().length()>0) {
...@@ -39,11 +52,14 @@ public class XxlJobFileAppender { ...@@ -39,11 +52,14 @@ public class XxlJobFileAppender {
if (!glueBaseDir.exists()) { if (!glueBaseDir.exists()) {
glueBaseDir.mkdirs(); glueBaseDir.mkdirs();
} }
glueSrcPath = glueBaseDir.getPath();
} }
public static String getLogPath() { public static String getLogPath() {
return logBasePath; return logBasePath;
} }
public static String getGlueSrcPath() {
return glueSrcPath;
}
/** /**
* log filename, like "logPath/yyyy-MM-dd/9999.log" * log filename, like "logPath/yyyy-MM-dd/9999.log"
......
package com.xxl.job.core.thread;
import com.xxl.job.core.log.XxlJobFileAppender;
import com.xxl.job.core.util.FileUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* job file clean thread
*
* @author xuxueli 2017-12-29 16:23:43
*/
public class JobLogFileCleanThread extends Thread {
private static Logger logger = LoggerFactory.getLogger(JobLogFileCleanThread.class);
private static JobLogFileCleanThread instance = new JobLogFileCleanThread();
public static JobLogFileCleanThread getInstance(){
return instance;
}
private Thread localThread;
private volatile boolean toStop = false;
public void start(final long logRetentionDays){
// limit min value
if (logRetentionDays < 3 ) {
return;
}
localThread = new Thread(new Runnable() {
@Override
public void run() {
while (!toStop) {
try {
// clean log dir, over logRetentionDays
File[] childDirs = new File(XxlJobFileAppender.getLogPath()).listFiles();
if (childDirs!=null && childDirs.length>0) {
// today
Calendar todayCal = Calendar.getInstance();
todayCal.set(Calendar.HOUR_OF_DAY,0);
todayCal.set(Calendar.MINUTE,0);
todayCal.set(Calendar.SECOND,0);
todayCal.set(Calendar.MILLISECOND,0);
Date todayDate = todayCal.getTime();
for (File childFile: childDirs) {
// valid
if (!childFile.isDirectory()) {
continue;
}
if (childFile.getName().indexOf("-") == -1) {
continue;
}
// file create date
Date logFileCreateDate = null;
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
logFileCreateDate = simpleDateFormat.parse(childFile.getName());
} catch (ParseException e) {
logger.error(e.getMessage(), e);
}
if (logFileCreateDate == null) {
continue;
}
if ((todayDate.getTime()-logFileCreateDate.getTime()) >= logRetentionDays * (24 * 60 * 60 * 1000) ) {
FileUtil.deleteRecursively(childFile);
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
try {
TimeUnit.DAYS.sleep(1);
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
logger.info(">>>>>>>>>>> xxl-job, executor JobLogFileCleanThread thread destory.");
}
});
localThread.setDaemon(true);
localThread.start();
}
public void toStop() {
toStop = true;
if (localThread == null) {
return;
}
// interrupt and wait
localThread.interrupt();
try {
localThread.join();
} catch (InterruptedException e) {
logger.error(e.getMessage(), e);
}
}
}
package com.xxl.job.core.util;
import java.io.File;
/**
* file tool
*
* @author xuxueli 2017-12-29 17:56:48
*/
public class FileUtil {
public static boolean deleteRecursively(File root) {
if (root != null && root.exists()) {
if (root.isDirectory()) {
File[] children = root.listFiles();
if (children != null) {
for (File child : children) {
deleteRecursively(child);
}
}
}
return root.delete();
}
return false;
}
}
...@@ -59,7 +59,7 @@ public class ScriptUtil { ...@@ -59,7 +59,7 @@ public class ScriptUtil {
// 标准输出:print (null if watchdog timeout) // 标准输出:print (null if watchdog timeout)
// 错误输出:logging + 异常 (still exists if watchdog timeout) // 错误输出:logging + 异常 (still exists if watchdog timeout)
// 标准输入 // 标准输入
FileOutputStream fileOutputStream = new FileOutputStream(logFile, true); try (FileOutputStream fileOutputStream = new FileOutputStream(logFile, true)) {
PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null); PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
// command // command
...@@ -76,5 +76,6 @@ public class ScriptUtil { ...@@ -76,5 +76,6 @@ public class ScriptUtil {
int exitValue = exec.execute(commandline); // exit code: 0=success, 1=error int exitValue = exec.execute(commandline); // exit code: 0=success, 1=error
return exitValue; return exitValue;
} }
}
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.xuxueli</groupId> <groupId>com.xuxueli</groupId>
<artifactId>xxl-job</artifactId> <artifactId>xxl-job</artifactId>
<version>1.9.0-SNAPSHOT</version> <version>1.9.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>xxl-job-executor-samples</artifactId> <artifactId>xxl-job-executor-samples</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论