Pārlūkot izejas kodu

Merge pull request #2 from xuxueli/master

同步xuxueli/xxl-job最新代码
thinking_fioa 7 gadi atpakaļ
vecāks
revīzija
60eb19094b
86 mainītis faili ar 2098 papildinājumiem un 899 dzēšanām
  1. 13 7
      README.md
  2. 20 1
      doc/XXL-JOB-English-Documentation.md
  3. 91 31
      doc/XXL-JOB官方文档.md
  4. BIN
      doc/XXL-JOB架构图.pptx
  5. 14 6
      pom.xml
  6. 1 1
      xxl-job-admin/pom.xml
  7. 7 6
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java
  8. 6 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java
  9. 16 15
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java
  10. 5 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java
  11. 8 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java
  12. 9 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java
  13. 3 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java
  14. 23 7
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java
  15. 81 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java
  16. 4 2
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/enums/ExecutorFailStrategyEnum.java
  17. 11 10
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java
  18. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java
  19. 2 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java
  20. 8 7
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java
  21. 24 21
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java
  22. 25 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java
  23. 82 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java
  24. 134 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java
  25. 5 17
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/MailUtil.java
  26. 0 38
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/PropertiesUtil.java
  27. 10 2
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java
  28. 1 2
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java
  29. 69 10
      xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java
  30. 15 8
      xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java
  31. 65 48
      xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java
  32. 226 0
      xxl-job-admin/src/main/resources/i18n/message.properties
  33. 226 0
      xxl-job-admin/src/main/resources/i18n/message_en.properties
  34. 6 0
      xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml
  35. 8 7
      xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml
  36. 1 1
      xxl-job-admin/src/main/resources/quartz.properties
  37. 1 1
      xxl-job-admin/src/main/resources/spring/applicationcontext-base.xml
  38. 4 1
      xxl-job-admin/src/main/resources/xxl-job-admin.properties
  39. 4 3
      xxl-job-admin/src/main/webapp/500.html
  40. 3 3
      xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.exception.ftl
  41. 16 9
      xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.macro.ftl
  42. 0 1
      xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.result.ftl
  43. 5 11
      xxl-job-admin/src/main/webapp/WEB-INF/template/help.ftl
  44. 10 9
      xxl-job-admin/src/main/webapp/WEB-INF/template/index.ftl
  45. 13 9
      xxl-job-admin/src/main/webapp/WEB-INF/template/jobcode/jobcode.index.ftl
  46. 38 38
      xxl-job-admin/src/main/webapp/WEB-INF/template/jobgroup/jobgroup.index.ftl
  47. 81 82
      xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl
  48. 6 6
      xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.detail.ftl
  49. 45 45
      xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.index.ftl
  50. 6 6
      xxl-job-admin/src/main/webapp/WEB-INF/template/login.ftl
  51. 15 17
      xxl-job-admin/src/main/webapp/static/js/common.1.js
  52. 54 46
      xxl-job-admin/src/main/webapp/static/js/index.js
  53. 12 14
      xxl-job-admin/src/main/webapp/static/js/jobcode.index.1.js
  54. 48 38
      xxl-job-admin/src/main/webapp/static/js/jobgroup.index.1.js
  55. 105 85
      xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js
  56. 2 2
      xxl-job-admin/src/main/webapp/static/js/joblog.detail.1.js
  57. 102 91
      xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js
  58. 13 20
      xxl-job-admin/src/main/webapp/static/js/login.1.js
  59. 0 1
      xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/layer.js
  60. 0 0
      xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/need/layer.css
  61. 3 3
      xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java
  62. 2 2
      xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java
  63. 1 1
      xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogDaoTest.java
  64. 25 0
      xxl-job-admin/src/test/java/com/xxl/job/admin/util/I18nUtilTest.java
  65. 5 0
      xxl-job-admin/src/test/java/com/xxl/job/admin/util/MailUtilTest.java
  66. 0 18
      xxl-job-admin/src/test/java/com/xxl/job/admin/util/PropertiesUtilTest.java
  67. 1 1
      xxl-job-core/pom.xml
  68. 19 9
      xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java
  69. 2 2
      xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java
  70. 18 2
      xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java
  71. 118 0
      xxl-job-core/src/main/java/com/xxl/job/core/thread/JobLogFileCleanThread.java
  72. 27 0
      xxl-job-core/src/main/java/com/xxl/job/core/util/FileUtil.java
  73. 15 14
      xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java
  74. 1 1
      xxl-job-executor-samples/pom.xml
  75. 1 1
      xxl-job-executor-samples/xxl-job-executor-sample-jfinal/pom.xml
  76. 4 3
      xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/config/JFinalCoreConfig.java
  77. 5 3
      xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/resources/xxl-job-executor.properties
  78. 1 1
      xxl-job-executor-samples/xxl-job-executor-sample-nutz/pom.xml
  79. 4 3
      xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/config/NutzSetup.java
  80. 5 3
      xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/xxl-job-executor.properties
  81. 1 1
      xxl-job-executor-samples/xxl-job-executor-sample-spring/pom.xml
  82. 8 6
      xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml
  83. 6 4
      xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties
  84. 1 1
      xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml
  85. 14 9
      xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java
  86. 7 5
      xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties

+ 13 - 7
README.md

@@ -1,12 +1,10 @@
 <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">
-    </a>
+    <img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150">
     <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是一个轻量级分布式任务调度框架,其核心设计目标是
 - 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是一个轻量级分布式任务调度框架,其核心设计目标是
     - 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
 
 
 
 
 ## 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 )

+ 20 - 1
doc/XXL-JOB-English-Documentation.md

@@ -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
     - 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
 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)
 ```
 ```
@@ -203,6 +219,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.

+ 91 - 31
doc/XXL-JOB官方文档.md

@@ -40,6 +40,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 - 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
 - 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
 - 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
 - 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
 - 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
 - 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
+- 27、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
+- 28、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
 
 
 ### 1.3 发展
 ### 1.3 发展
 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
@@ -52,12 +54,18 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 
 
 于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。
 于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。
 
 
+于2017-10-22,又拍云 Open Talk 联合 Spring Cloud 中国社区举办的 "[进击的微服务实战派上海站](https://opentalk.upyun.com/303.html)",我登台对XXL-JOB做了演讲,现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流
+
 于2017-12-11,XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》,并被拍拍贷架构总监"杨波老师"在专题 "[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)" 中现场介绍。
 于2017-12-11,XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》,并被拍拍贷架构总监"杨波老师"在专题 "[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)" 中现场介绍。
 
 
+于2017-12-18,XXL-JOB参与"[2017年度最受欢迎中国开源软件](http://www.oschina.net/project/top_cn_2017?sort=1)"评比,在当时已录入的约九千个国产开源项目中角逐,最终进入了前30强。
+
+于2018-01-15,XXL-JOB参与"[2017码云最火开源项目](https://www.oschina.net/news/92438/2017-mayun-top-50)"评比,在当时已录入的约六千五百个码云项目中角逐,最终进去了前20强。
+
 > 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。
 > 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。
 据最新统计, 自2016-01-21接入至2017-12-01期间,该系统已调度约100万次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。
 据最新统计, 自2016-01-21接入至2017-12-01期间,该系统已调度约100万次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。
 
 
-至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于:
+至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止最新统计时间为止,XXL-JOB已接入的公司包括不限于:
     
     
 	- 1、大众点评;
 	- 1、大众点评;
 	- 2、山东学而网络科技有限公司;
 	- 2、山东学而网络科技有限公司;
@@ -118,6 +126,14 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
     - 57、华夏票联(北京)科技有限公司
     - 57、华夏票联(北京)科技有限公司
     - 58、拍拍贷
     - 58、拍拍贷
     - 59、北京尚德机构在线教育有限公司
     - 59、北京尚德机构在线教育有限公司
+    - 60、任子行股份有限公司
+    - 61、北京时态电子商务有限公司
+    - 62、深圳卷皮网络科技有限公司
+    - 63、北京安博通科技股份有限公司
+    - 64、未来无线网
+    - 65、厦门瓷禧网络有限公司
+    - 66、北京递蓝科软件股份有限公司
+    - 67、郑州创海软件科技公司
 	- ……
 	- ……
 
 
 > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
 > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
@@ -137,7 +153,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 源码仓库地址 | Release Download
 源码仓库地址 | 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)
 
 
 
 
 #### 中央仓库地址
 #### 中央仓库地址
@@ -147,7 +163,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 <dependency>
 <dependency>
     <groupId>com.xuxueli</groupId>
     <groupId>com.xuxueli</groupId>
     <artifactId>xxl-job-core</artifactId>
     <artifactId>xxl-job-core</artifactId>
-    <version>1.8.2</version>
+    <version>${最新稳定版本}</version>
 </dependency>
 </dependency>
 ```
 ```
 
 
@@ -222,6 +238,9 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
     
     
     ### 调度中心通讯TOKEN,非空时启用
     ### 调度中心通讯TOKEN,非空时启用
     xxl.job.accessToken=
     xxl.job.accessToken=
+    
+    ### 调度中心国际化设置,默认为中文版本,值设置为“en”时切换为英文版本
+    xxl.job.i18n=
 
 
 #### 步骤二:部署项目:
 #### 步骤二:部署项目:
 如果已经正确进行上述配置,可将项目编译打war包并部署到tomcat中。
 如果已经正确进行上述配置,可将项目编译打war包并部署到tomcat中。
@@ -263,12 +282,15 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
     xxl.job.executor.ip=
     xxl.job.executor.ip=
     xxl.job.executor.port=9999
     xxl.job.executor.port=9999
     
     
+    ### xxl-job, access token:执行器通讯TOKEN,非空时启用
+    xxl.job.accessToken=
+        
     ### xxl-job log path:执行器运行日志文件存储的磁盘位置,需要对该路径拥有读写权限
     ### xxl-job log path:执行器运行日志文件存储的磁盘位置,需要对该路径拥有读写权限
     xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
     xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
     
     
-    ### xxl-job, access token:执行器通讯TOKEN,非空时启用
-    xxl.job.accessToken=
-
+    ### xxl-job log retention days:执行器Log文件定期清理功能,指定日志保存天数,日志文件过期自动删除。限制至少保持3天,否则功能不生效;
+    xxl.job.executor.logretentiondays=-1
+    
 
 
 #### 步骤三:执行器组件配置
 #### 步骤三:执行器组件配置
 
 
@@ -282,35 +304,42 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
 <!-- 配置01、JobHandler 扫描路径:自动扫描容器中JobHandler -->
 <!-- 配置01、JobHandler 扫描路径:自动扫描容器中JobHandler -->
 <context:component-scan base-package="com.xxl.job.executor.service.jobhandler" />
 <context:component-scan base-package="com.xxl.job.executor.service.jobhandler" />
 
 
-<!-- 配置02、执行器Excutor配置:执行器核心配置 -->
+<!-- 配置02、执行器 -->
 <bean id="xxlJobExecutor" class="com.xxl.job.core.executor.XxlJobExecutor" init-method="start" destroy-method="destroy" >
 <bean id="xxlJobExecutor" class="com.xxl.job.core.executor.XxlJobExecutor" init-method="start" destroy-method="destroy" >
+    <!-- 执行器注册中心地址[选填],为空则关闭自动注册 -->
+    <property name="adminAddresses" value="${xxl.job.admin.addresses}" />
+    <!-- 执行器AppName[选填],为空则关闭自动注册 -->
+    <property name="appName" value="${xxl.job.executor.appname}" />
     <!-- 执行器IP[选填],为空则自动获取 -->
     <!-- 执行器IP[选填],为空则自动获取 -->
     <property name="ip" value="${xxl.job.executor.ip}" />
     <property name="ip" value="${xxl.job.executor.ip}" />
     <!-- 执行器端口号[选填],为空则自动获取 -->
     <!-- 执行器端口号[选填],为空则自动获取 -->
     <property name="port" value="${xxl.job.executor.port}" />
     <property name="port" value="${xxl.job.executor.port}" />
-    <!-- 执行器AppName[选填],为空则关闭自动注册 -->
-    <property name="appName" value="${xxl.job.executor.appname}" />
-    <!-- 执行器注册中心地址[选填],为空则关闭自动注册 -->
-    <property name="adminAddresses" value="${xxl.job.admin.addresses}" />
-    <!-- 执行器日志路径[选填],为空则使用默认路径 -->
-    <property name="logPath" value="${xxl.job.executor.logpath}" />
     <!-- 访问令牌[选填],非空则进行匹配校验 -->
     <!-- 访问令牌[选填],非空则进行匹配校验 -->
     <property name="accessToken" value="${xxl.job.accessToken}" />
     <property name="accessToken" value="${xxl.job.accessToken}" />
+    <!-- 执行器日志路径[选填],为空则使用默认路径 -->
+    <property name="logPath" value="${xxl.job.executor.logpath}" />
+    <!-- 日志保存天数[选填],值大于3时生效 -->
+    <property name="logRetentionDays" value="${xxl.job.executor.logretentiondays}" />
 </bean>
 </bean>
 ```
 ```
 
 
 #### 步骤四:部署执行器项目:
 #### 步骤四:部署执行器项目:
-如果已经正确进行上述配置,可将执行器项目编译打部署,系统提供三个执行器Sample示例项目,选择其中一个即可,各自的部署方式如下。
+如果已经正确进行上述配置,可将执行器项目编译打部署,系统提供多种执行器Sample示例项目,选择其中一个即可,各自的部署方式如下。
 
 
-    xxl-job-executor-sample-spring:项目编译打包成WAR包,并部署到tomcat中。
     xxl-job-executor-sample-springboot:项目编译打包成springboot类型的可执行JAR包,命令启动即可;
     xxl-job-executor-sample-springboot:项目编译打包成springboot类型的可执行JAR包,命令启动即可;
+    xxl-job-executor-sample-spring:项目编译打包成WAR包,并部署到tomcat中。
+    xxl-job-executor-sample-jfinal:同上
+    xxl-job-executor-sample-nutz:同上
+    
 
 
 至此“执行器”项目已经部署结束。
 至此“执行器”项目已经部署结束。
 
 
 #### 步骤五:执行器集群(可选):
 #### 步骤五:执行器集群(可选):
 执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。
 执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。
 
 
-集群部署唯一要求为:保证集群中每个执行器的配置项 "xxl.job.admin.addresses/调度中心地址" 保持一致,执行器根据该配置进行执行器自动注册等操作。 
+执行器集群部署时,几点要求和建议:
+- 执行器回调地址(xxl.job.admin.addresses)需要保持一致;执行器根据该配置进行执行器自动注册等操作。 
+- 同一个执行器集群内AppName(xxl.job.executor.appname)需要保持一致;调度中心根据该配置动态发现不同集群的在线执行器列表。
 
 
 
 
 ### 2.5 开发第一个任务“Hello World”       
 ### 2.5 开发第一个任务“Hello World”       
@@ -602,7 +631,7 @@ XXL-JOB首先定制了Quartz原生表结构前缀(XXL_JOB_QRTZ_)。
 
 
 #### 5.3.3 架构图
 #### 5.3.3 架构图
 
 
-![输入图片说明](https://static.oschina.net/uploads/img/201707/17190028_aEE2.png "在这里输入图片标题")
+![输入图片说明](https://static.oschina.net/uploads/img/201801/03103007_Qohm.png "在这里输入图片标题")
 
 
 ### 5.4 调度模块剖析
 ### 5.4 调度模块剖析
 #### 5.4.1 quartz的不足
 #### 5.4.1 quartz的不足
@@ -639,15 +668,22 @@ org.quartz.threadPool.threadPriority: 5
 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
 ```
 ```
 
 
-XXL-JOB系统中业务逻辑在远程执行器执行,调度中心每次触发调度时仅发送一次调度请求,执行器会将请求存入执行队列并且立即响应调度中心;相比直接在quartz的QuartzJobBean中执行业务逻辑,极大的降低了调度线程占用;
+XXL-JOB系统中业务逻辑在远程执行器执行,全异步化设计,调度中心每次触发调度时仅发送一次调度请求,执行器会将请求存入执行队列并且立即响应调度中心,异步运行;相比直接在quartz的QuartzJobBean中执行业务逻辑,极大的降低了调度线程占用时间
 
 
 XXL-JOB调度中心中每个JOB逻辑非常 “轻”,单个JOB一次运行平均耗时基本在 "10ms" 之内(基本为一次请求的网络开销);因此,可以保证使用有限的线程支撑大量的JOB并发运行;
 XXL-JOB调度中心中每个JOB逻辑非常 “轻”,单个JOB一次运行平均耗时基本在 "10ms" 之内(基本为一次请求的网络开销);因此,可以保证使用有限的线程支撑大量的JOB并发运行;
 
 
-理论上采用推荐机器配置 "4核4G内存"情况下,单线程可以承担 100(quartz最小时间粒度1000ms/触发一次任务耗时10ms)个密集任务(每秒执行一次)的正常调度触发。因此,默认配置的15个线程理论上可以承担起1500个密集任务的正常运行。
+理论支撑任务量公式如下:
+
+    理论支撑任务量 = 线程数配置 / 平均调度频率(每秒) * 平均触发耗时(单位s)
+
+理论上采用推荐机器配置 "4核4G内存" + "配置1s运行1次密集任务" + "调度中心与执行器ping延迟10ms(0.01s)" 的情况下,
+
+    - 单线程支撑任务量  :1 / 1 * 0.01 = 100个任务
+    - 15个线程支撑任务量:15 / 1 * 0.01 = 1500个任务
 
 
-实际场景中,调度请求网络耗时不同、DB读写耗时不同、任务密集或稀疏调度情况不同,会导致任务量上限会上下波动。
+实际场景中,由于调度中心与执行器ping延迟不同、DB读写耗时不同、任务调度密集程度不同,会导致任务量上限会上下波动。
 
 
-如若需要支撑更多的任务量,可以通过 "调大调度线程数" 和 "提升机器配置" 两种方式实现。
+如若需要支撑更多的任务量,可以通过 "调大调度线程数" 、"降低调度中心与执行器ping延迟" 和 "提升机器配置" 几种方式实现。
 
 
 #### 5.4.5 @DisallowConcurrentExecution
 #### 5.4.5 @DisallowConcurrentExecution
 XXL-JOB调度模块的“调度中心”默认不使用该注解,即默认开启并行机制,因为RemoteHttpJobBean为公共QuartzJobBean,这样在多线程调度的情况下,调度模块被阻塞的几率很低,大大提高了调度系统的承载量。
 XXL-JOB调度模块的“调度中心”默认不使用该注解,即默认开启并行机制,因为RemoteHttpJobBean为公共QuartzJobBean,这样在多线程调度的情况下,调度模块被阻塞的几率很低,大大提高了调度系统的承载量。
@@ -1074,7 +1110,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 9、调度中心任务监控线程销毁时,批量对失败任务告警,防止告警信息丢失;
 - 9、调度中心任务监控线程销毁时,批量对失败任务告警,防止告警信息丢失;
 - 10、任务日志文件路径时间戳格式化时SimpleDateFormat并发问题解决;
 - 10、任务日志文件路径时间戳格式化时SimpleDateFormat并发问题解决;
 
 
-### 6.20 版本 V1.9.0 特性[迭代中]
+### 6.20 版本 V1.9.0 特性[2017-12-29]
 - 1、新增Nutz执行器Sample示例项目;
 - 1、新增Nutz执行器Sample示例项目;
 - 2、新增任务运行模式 "GLUE模式(NodeJS) ",支持NodeJS脚本任务;
 - 2、新增任务运行模式 "GLUE模式(NodeJS) ",支持NodeJS脚本任务;
 - 3、脚本任务Shell、Python和Nodejs等支持获取分片参数;
 - 3、脚本任务Shell、Python和Nodejs等支持获取分片参数;
@@ -1084,13 +1120,13 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 7、调度报表优化,支持时间区间筛选;
 - 7、调度报表优化,支持时间区间筛选;
 - 8、Log组件支持输出异常栈信息,底层实现优化;
 - 8、Log组件支持输出异常栈信息,底层实现优化;
 - 9、告警邮件样式优化,调整为表格形式,邮件组件调整为commons-email简化邮件操作;
 - 9、告警邮件样式优化,调整为表格形式,邮件组件调整为commons-email简化邮件操作;
-- 10、项目依赖升级,如spring、jackson等;
+- 10、项目依赖全量升级至较新稳定版本,如spring、jackson等;
 - 11、任务日志,记录发起调度的机器信息;
 - 11、任务日志,记录发起调度的机器信息;
 - 12、交互优化,如登陆注销;
 - 12、交互优化,如登陆注销;
 - 13、任务Cron长度扩展支持至128位,支持负责类型Cron设置;
 - 13、任务Cron长度扩展支持至128位,支持负责类型Cron设置;
 - 14、执行器地址录入交互优化,地址长度扩展支持至512位,支持大规模执行器集群配置;
 - 14、执行器地址录入交互优化,地址长度扩展支持至512位,支持大规模执行器集群配置;
 - 15、任务参数“IJobHandler.execute”入参改为“String params”,增强入参通用性。
 - 15、任务参数“IJobHandler.execute”入参改为“String params”,增强入参通用性。
-- 16、JobHandler提供init/destroy方法,支持在JobHandler初始化和销毁时进行附加操作;
+- 16、IJobHandler提供init/destroy方法,支持在相应任务线程初始化和销毁时进行附加操作;
 - 17、任务注解调整为 “@JobHandler”,与任务抽象接口统一;
 - 17、任务注解调整为 “@JobHandler”,与任务抽象接口统一;
 - 18、修复任务监控线程被耗时任务阻塞的问题;
 - 18、修复任务监控线程被耗时任务阻塞的问题;
 - 19、修复任务监控线程无法监控任务触发和执行状态均未0的问题;
 - 19、修复任务监控线程无法监控任务触发和执行状态均未0的问题;
@@ -1104,6 +1140,24 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly;
 - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly;
 - 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。
 - 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。
 - 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环;
 - 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环;
+- 30、任务列表新增筛选条件 "任务描述",快速检索任务;
+- 31、执行器Log文件定期清理功能:执行器新增配置项("xxl.job.executor.logretentiondays")日志保存天数,日志文件过期自动删除。
+
+### 6.21 版本 V1.9.1 特性[2018-02-22]
+- 1、国际化:调度中心实现国际化,支持中文、英文两种语言,默认为中文。
+- 2、调度报表新增"运行中"中状态项;
+- 3、调度报表优化,报表SQL调优并且新增LocalCache缓存(缓存时间60s),提高大数据量下报表加载速度;
+- 4、修复打包部署时资源文件乱码问题;
+- 5、修复新版本chrome滚动到顶部失效问题;
+- 6、调度中心配置加载优化,取消对配置文件名的强依赖,支持加载磁盘配置;
+- 7、修复脚本任务Log文件未正常close的问题;
+- 8、项目依赖全量升级至较新稳定版本,如spring、jackson等等;
+
+### 6.22 版本 V1.9.2 特性[迭代中]
+- 1、[迭代中]支持通过API服务操作任务信息;
+- 2、[迭代中]任务告警逻辑调整:任务调度,以及任务回调失败时,均推送监控队列。后期考虑通过任务Log字段控制告警状态;
+- 3、[迭代中]任务超时设置,超时任务主动终止;
+
 
 
 ### TODO LIST
 ### TODO LIST
 - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限;
 - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限;
@@ -1114,12 +1168,18 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 - 6、调度任务优先级;
 - 6、调度任务优先级;
 - 7、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。
 - 7、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。
 - 8、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用;
 - 8、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用;
-- 9、国际化:调度中心界面。
-- 10、任务告警逻辑调整:任务调度,以及任务回调失败时,均推送监控队列。后期考虑通过任务Log字段控制告警状态;
-- 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件;
-- 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性;
-- 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发;
-- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题;
+- 9、多数据库支持;
+- 10、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件;
+- 11、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性;
+- 12、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发;
+- 13、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题;
+- 14、分片任务某一分片失败,支持分片转移;
+- 15、调度中心触发任务后,先推送触发队列,异步触发,然后立即返回。降低quartz线程占用时长。
+- 16、新增API服务 "XxlJobService" ,支持通过API服务来维护管理任务信息;
+- 17、新增任务默认运行状态,任务更新时运行状态保持不变;
+- 18、告警邮件中展示失败告警信息;
+- 19、提供多版本执行器:不依赖容器版本、不内嵌Jetty版本(通过配置executoraddress替换jetty通讯)等;
+
 
 
 
 
 ## 七、其他
 ## 七、其他
@@ -1138,4 +1198,4 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
 
 
 ---
 ---
 ### 捐赠
 ### 捐赠
-无论金额多少都足够表达您这份心意,非常感谢 :)      [前往捐赠](http://www.xuxueli.com/page/donate.html )
+无论捐赠金额多少都足够表达您这份心意,非常感谢 :)      [前往捐赠](http://www.xuxueli.com/page/donate.html )

BIN
doc/XXL-JOB架构图.pptx


+ 14 - 6
pom.xml

@@ -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 @@
 		<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>
-		<jackson.version>2.9.3</jackson.version>
+		<spring.version>4.3.14.RELEASE</spring.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 @@
 		<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 @@
 					<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>

+ 1 - 1
xxl-job-admin/pom.xml

@@ -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>

+ 7 - 6
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java

@@ -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 {
 		return "index";
 		return "index";
 	}
 	}
 
 
-    @RequestMapping("/triggerChartDate")
+    @RequestMapping("/chartInfo")
 	@ResponseBody
 	@ResponseBody
-	public ReturnT<Map<String, Object>> triggerChartDate(Date startDate, Date endDate) {
-        ReturnT<Map<String, Object>> triggerChartDate = xxlJobService.triggerChartDate(startDate, endDate);
-        return triggerChartDate;
+	public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
+        ReturnT<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);
+        return chartInfo;
     }
     }
 	
 	
 	@RequestMapping("/toLogin")
 	@RequestMapping("/toLogin")
@@ -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;
 	}
 	}

+ 6 - 5
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java

@@ -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 {
 		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 {
 	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

+ 16 - 15
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java

@@ -1,6 +1,7 @@
 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 {
 
 
 		// 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) {
-			return new ReturnT<String>(500, "AppName长度限制为4~64");
+		if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>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 {
 	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) {
-			return new ReturnT<String>(500, "AppName长度限制为4~64");
+		if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>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 {
 	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);

+ 5 - 5
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java

@@ -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 {
 		return xxlJobService.add(jobInfo);
 		return xxlJobService.add(jobInfo);
 	}
 	}
 	
 	
-	@RequestMapping("/reschedule")
+	@RequestMapping("/update")
 	@ResponseBody
 	@ResponseBody
-	public ReturnT<String> reschedule(XxlJobInfo jobInfo) {
-		return xxlJobService.reschedule(jobInfo);
+	public ReturnT<String> update(XxlJobInfo jobInfo) {
+		return xxlJobService.update(jobInfo);
 	}
 	}
 	
 	
 	@RequestMapping("/remove")
 	@RequestMapping("/remove")

+ 8 - 5
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java

@@ -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 {
 		// 执行器列表
 		// 执行器列表
 		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 {
 		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 {
 		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 {
 
 
 		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 {
 		} 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);

+ 9 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java

@@ -1,5 +1,7 @@
 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;
@@ -19,7 +21,8 @@ public class CookieInterceptor extends HandlerInterceptorAdapter {
 	@Override
 	@Override
 	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()) {
@@ -27,6 +30,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);
 	}
 	}

+ 3 - 3
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java

@@ -1,8 +1,8 @@
 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 {
 	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 password = PropertiesUtil.getString("xxl.job.login.password");
+        String username = XxlJobAdminConfig.getAdminConfig().getLoginUsername();
+        String password = XxlJobAdminConfig.getAdminConfig().getLoginPassword();
 
 
         // login token
         // login token
         String tokenTmp = DigestUtils.md5Hex(username + "_" + password);
         String tokenTmp = DigestUtils.md5Hex(username + "_" + password);

+ 23 - 7
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java

@@ -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
@@ -23,19 +24,34 @@ public class WebExceptionResolver implements HandlerExceptionResolver {
 	public ModelAndView resolveException(HttpServletRequest request,
 	public ModelAndView resolveException(HttpServletRequest request,
 			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");
-			mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT<String>(500, ex.toString().replaceAll("\n", "<br/>"))));
-			mv.setViewName("/common/common.result");
+			isJson = true;
+		}
+
+		// 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;
 	}
 	}
 	
 	
 }
 }

+ 81 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java

@@ -0,0 +1,81 @@
+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;
+    }
+
+}

+ 4 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/core/enums/ExecutorFailStrategyEnum.java

@@ -1,13 +1,15 @@
 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) {

+ 11 - 10
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java

@@ -1,22 +1,23 @@
 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()),
-    LAST("最后一个", new ExecutorRouteLast()),
-    ROUND("轮询", new ExecutorRouteRound()),
-    RANDOM("随机", new ExecutorRouteRandom()),
-    CONSISTENT_HASH("一致性HASH", new ExecutorRouteConsistentHash()),
-    LEAST_FREQUENTLY_USED("最不经常使用", new ExecutorRouteLFU()),
-    LEAST_RECENTLY_USED("最近最久未使用", new ExecutorRouteLRU()),
-    FAILOVER("故障转移", new ExecutorRouteFailover()),
-    BUSYOVER("忙碌转移", new ExecutorRouteBusyover()),
-    SHARDING_BROADCAST("分片广播", null);
+    FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()),
+    LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()),
+    ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()),
+    RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()),
+    CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()),
+    LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()),
+    LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()),
+    FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()),
+    BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()),
+    SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null);
 
 
     ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
     ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
         this.title = title;
         this.title = title;

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java

@@ -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 {
                 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());

+ 2 - 1
xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java

@@ -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 {
                 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());

+ 8 - 7
xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java

@@ -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 {
 	// ---------------------- 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>任务ID</td>\n" +
-			"         <td>任务描述</td>\n" +
-			"         <td>告警类型</td>\n" +
+			"         <td>"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +
+			"         <td>"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +
+			"         <td>"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</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 {
 			"         <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 {
 			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);

+ 24 - 21
xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java

@@ -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 {
 
 
                 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("<br>执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" );
-                triggerMsgSb.append("<br>执行器-地址列表:").append(group.getRegistryList());
-                triggerMsgSb.append("<br>路由策略:").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01
-                triggerMsgSb.append("<br>阻塞处理策略:").append(blockStrategy.getTitle());
-                triggerMsgSb.append("<br>失败处理策略:").append(failStrategy.getTitle());
+                triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
+                        .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01
+                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 {
 
 
                     // 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 {
                 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 {
 
 
             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("<br>执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" );
-            triggerMsgSb.append("<br>执行器-地址列表:").append(group.getRegistryList());
-            triggerMsgSb.append("<br>路由策略:").append(executorRouteStrategyEnum.getTitle());
-            triggerMsgSb.append("<br>阻塞处理策略:").append(blockStrategy.getTitle());
-            triggerMsgSb.append("<br>失败处理策略:").append(failStrategy.getTitle());
+            triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
+                    .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.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 {
 
 
                 // 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 {
             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 {
             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());

+ 25 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java

@@ -0,0 +1,25 @@
+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;
+    }
+
+}

+ 82 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java

@@ -0,0 +1,82 @@
+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;
+    }
+
+}

+ 134 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java

@@ -0,0 +1,134 @@
+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;
+    }
+
+}

+ 5 - 17
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/MailUtil.java

@@ -1,5 +1,6 @@
 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;
 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 {
 			//email.setTLS(true);		// 是否TLS校验,,某些邮箱需要TLS安全校验,同理有SSL校验
 			//email.setTLS(true);		// 是否TLS校验,,某些邮箱需要TLS安全校验,同理有SSL校验
 			//email.setSSL(true);
 			//email.setSSL(true);
 
 
-			email.setHostName(host);
-			email.setSmtpPort(Integer.valueOf(port));
+			email.setHostName(XxlJobAdminConfig.getAdminConfig().getMailHost());
+			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);

+ 0 - 38
xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/PropertiesUtil.java

@@ -1,38 +0,0 @@
-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;
-	}
-
-}

+ 10 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java

@@ -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 int pageListCount(@Param("offset") int offset, @Param("pagesize") int pagesize, @Param("jobGroup") int jobGroup, @Param("executorHandler") String executorHandler);
+	public List<XxlJobInfo> pageList(@Param("offset") int offset,
+									 @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);
 
 

+ 1 - 2
xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java

@@ -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("handleCode") int handleCode);
+													   @Param("to") Date to);
 
 
 	public int clearLog(@Param("jobGroup") int jobGroup,
 	public int clearLog(@Param("jobGroup") int jobGroup,
 						@Param("jobId") int jobId,
 						@Param("jobId") int jobId,

+ 69 - 10
xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java

@@ -13,23 +13,82 @@ import java.util.Map;
  * @author xuxueli 2016-5-28 15:30:33
  * @author xuxueli 2016-5-28 15:30:33
  */
  */
 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);
 
 
 }
 }

+ 15 - 8
xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java

@@ -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 {
         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 {
                         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>",
-                                (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg());
+                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
+                                (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>",
-                                (i+1), childJobIds.length, childJobIds[i]);
+                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
+                                (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}",
-                   (retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), retryTriggerResult.getMsg());
+            callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_msg1"),
+                   (retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")), retryTriggerResult.getMsg());
         }
         }
 
 
         // handle msg
         // handle msg

+ 65 - 48
xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java

@@ -5,6 +5,8 @@ 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.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.util.I18nUtil;
+import com.xxl.job.admin.core.util.LocalCacheUtil;
 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;
@@ -45,11 +47,11 @@ public class XxlJobServiceImpl implements XxlJobService {
 	private XxlJobLogGlueDao xxlJobLogGlueDao;
 	private XxlJobLogGlueDao xxlJobLogGlueDao;
 	
 	
 	@Override
 	@Override
-	public Map<String, Object> pageList(int start, int length, int jobGroup, String executorHandler, String filterTime) {
+	public Map<String, Object> pageList(int start, int length, int jobGroup, String jobDesc, String executorHandler, String filterTime) {
 
 
 		// page list
 		// page list
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, executorHandler);
-		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, executorHandler);
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobDesc, executorHandler);
+		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobDesc, executorHandler);
 		
 		
 		// fill job info
 		// fill job info
 		if (list!=null && list.size()>0) {
 		if (list!=null && list.size()>0) {
@@ -71,31 +73,31 @@ public class XxlJobServiceImpl implements XxlJobService {
 		// valid
 		// valid
 		XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
 		XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
 		if (group == null) {
 		if (group == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请选择“执行器”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")) );
 		}
 		}
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入格式正确的“Cron”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
 		}
 		}
 		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
 		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“任务描述”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
 		}
 		}
 		if (StringUtils.isBlank(jobInfo.getAuthor())) {
 		if (StringUtils.isBlank(jobInfo.getAuthor())) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“负责人”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
 		}
 		}
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "路由策略非法");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
 		}
 		}
 		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
 		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "阻塞处理策略非法");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
 		}
 		}
 		if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) {
 		if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "失败处理策略非法");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorFailStrategy")+I18nUtil.getString("system_unvalid")) );
 		}
 		}
 		if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
 		if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "运行模式非法非法");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
 		}
 		}
 		if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringUtils.isBlank(jobInfo.getExecutorHandler())) {
 		if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringUtils.isBlank(jobInfo.getExecutorHandler())) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“JobHandler”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
 		}
 		}
 
 
 		// fix "\r" in shell
 		// fix "\r" in shell
@@ -110,10 +112,12 @@ public class XxlJobServiceImpl implements XxlJobService {
 				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
 				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
 					if (childJobInfo==null) {
 					if (childJobInfo==null) {
-						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem));
+						return new ReturnT<String>(ReturnT.FAIL_CODE,
+								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
 					}
 					}
 				} else {
 				} else {
-					return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem));
+					return new ReturnT<String>(ReturnT.FAIL_CODE,
+							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
 				}
 				}
 			}
 			}
 			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
 			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
@@ -122,7 +126,7 @@ public class XxlJobServiceImpl implements XxlJobService {
 		// add in db
 		// add in db
 		xxlJobInfoDao.save(jobInfo);
 		xxlJobInfoDao.save(jobInfo);
 		if (jobInfo.getId() < 1) {
 		if (jobInfo.getId() < 1) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "新增任务失败");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
 		}
 		}
 
 
 		// add in quartz
 		// add in quartz
@@ -140,31 +144,31 @@ public class XxlJobServiceImpl implements XxlJobService {
             } catch (SchedulerException e1) {
             } catch (SchedulerException e1) {
                 logger.error(e.getMessage(), e1);
                 logger.error(e.getMessage(), e1);
             }
             }
-            return new ReturnT<String>(ReturnT.FAIL_CODE, "新增任务失败:" + e.getMessage());
+            return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail"))+":" + e.getMessage());
         }
         }
 	}
 	}
 
 
 	@Override
 	@Override
-	public ReturnT<String> reschedule(XxlJobInfo jobInfo) {
+	public ReturnT<String> update(XxlJobInfo jobInfo) {
 
 
 		// valid
 		// valid
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入格式正确的“Cron”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
 		}
 		}
 		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
 		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“任务描述”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
 		}
 		}
 		if (StringUtils.isBlank(jobInfo.getAuthor())) {
 		if (StringUtils.isBlank(jobInfo.getAuthor())) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“负责人”");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
 		}
 		}
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "路由策略非法");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
 		}
 		}
 		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
 		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "阻塞处理策略非法");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
 		}
 		}
 		if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) {
 		if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "失败处理策略非法");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorFailStrategy")+I18nUtil.getString("system_unvalid")));
 		}
 		}
 
 
 		// ChildJobId valid
 		// ChildJobId valid
@@ -174,14 +178,16 @@ public class XxlJobServiceImpl implements XxlJobService {
 				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
 				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
 					if (childJobInfo==null) {
 					if (childJobInfo==null) {
-						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem));
+						return new ReturnT<String>(ReturnT.FAIL_CODE,
+								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
 					}
 					}
 					// avoid cycle relate
 					// avoid cycle relate
 					if (childJobInfo.getId() == jobInfo.getId()) {
 					if (childJobInfo.getId() == jobInfo.getId()) {
-						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem));
+						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format(I18nUtil.getString("jobinfo_field_childJobId_limit"), childJobIdItem));
 					}
 					}
 				} else {
 				} else {
-					return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem));
+					return new ReturnT<String>(ReturnT.FAIL_CODE,
+							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
 				}
 				}
 			}
 			}
 			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
 			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
@@ -190,7 +196,7 @@ public class XxlJobServiceImpl implements XxlJobService {
 		// stage job info
 		// stage job info
 		XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
 		XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
 		if (exists_jobInfo == null) {
 		if (exists_jobInfo == null) {
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "参数异常");
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_not_found")) );
 		}
 		}
 		//String old_cron = exists_jobInfo.getJobCron();
 		//String old_cron = exists_jobInfo.getJobCron();
 
 
@@ -271,7 +277,7 @@ public class XxlJobServiceImpl implements XxlJobService {
 	public ReturnT<String> triggerJob(int id) {
 	public ReturnT<String> triggerJob(int id) {
         XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
         XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
         if (xxlJobInfo == null) {
         if (xxlJobInfo == null) {
-        	return new ReturnT<String>(ReturnT.FAIL_CODE, "任务ID非法");
+        	return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_unvalid")) );
 		}
 		}
 
 
         String group = String.valueOf(xxlJobInfo.getJobGroup());
         String group = String.valueOf(xxlJobInfo.getJobGroup());
@@ -315,38 +321,42 @@ public class XxlJobServiceImpl implements XxlJobService {
 		return dashboardMap;
 		return dashboardMap;
 	}
 	}
 
 
+	private static final String TRIGGER_CHART_DATA_CACHE = "trigger_chart_data_cache";
 	@Override
 	@Override
-	public ReturnT<Map<String, Object>> triggerChartDate(Date startDate, Date endDate) {
+	public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
+		// get cache
+		String cacheKey = TRIGGER_CHART_DATA_CACHE + "_" + startDate.getTime() + "_" + endDate.getTime();
+		Map<String, Object> chartInfo = (Map<String, Object>) LocalCacheUtil.get(cacheKey);
+		if (chartInfo != null) {
+			return new ReturnT<Map<String, Object>>(chartInfo);
+		}
+
+		// process
 		List<String> triggerDayList = new ArrayList<String>();
 		List<String> triggerDayList = new ArrayList<String>();
+		List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
 		List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
 		List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
 		List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
 		List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
+		int triggerCountRunningTotal = 0;
 		int triggerCountSucTotal = 0;
 		int triggerCountSucTotal = 0;
 		int triggerCountFailTotal = 0;
 		int triggerCountFailTotal = 0;
 
 
-		List<Map<String, Object>> triggerCountMapAll = xxlJobLogDao.triggerCountByDay(startDate, endDate, -1);
-		List<Map<String, Object>> triggerCountMapSuc = xxlJobLogDao.triggerCountByDay(startDate, endDate, ReturnT.SUCCESS_CODE);
+		List<Map<String, Object>> triggerCountMapAll = xxlJobLogDao.triggerCountByDay(startDate, endDate);
 		if (CollectionUtils.isNotEmpty(triggerCountMapAll)) {
 		if (CollectionUtils.isNotEmpty(triggerCountMapAll)) {
 			for (Map<String, Object> item: triggerCountMapAll) {
 			for (Map<String, Object> item: triggerCountMapAll) {
 				String day = String.valueOf(item.get("triggerDay"));
 				String day = String.valueOf(item.get("triggerDay"));
-				int dayAllCount = Integer.valueOf(String.valueOf(item.get("triggerCount")));
-				int daySucCount = 0;
-				int dayFailCount = dayAllCount - daySucCount;
-
-				if (CollectionUtils.isNotEmpty(triggerCountMapSuc)) {
-					for (Map<String, Object> sucItem: triggerCountMapSuc) {
-						String daySuc = String.valueOf(sucItem.get("triggerDay"));
-						if (day.equals(daySuc)) {
-							daySucCount = Integer.valueOf(String.valueOf(sucItem.get("triggerCount")));
-							dayFailCount = dayAllCount - daySucCount;
-						}
-					}
-				}
+				int triggerDayCount = Integer.valueOf(String.valueOf(item.get("triggerDayCount")));
+				int triggerDayCountRunning = Integer.valueOf(String.valueOf(item.get("triggerDayCountRunning")));
+				int triggerDayCountSuc = Integer.valueOf(String.valueOf(item.get("triggerDayCountSuc")));
+				int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;
 
 
 				triggerDayList.add(day);
 				triggerDayList.add(day);
-				triggerDayCountSucList.add(daySucCount);
-				triggerDayCountFailList.add(dayFailCount);
-				triggerCountSucTotal += daySucCount;
-				triggerCountFailTotal += dayFailCount;
+				triggerDayCountRunningList.add(triggerDayCountRunning);
+				triggerDayCountSucList.add(triggerDayCountSuc);
+				triggerDayCountFailList.add(triggerDayCountFail);
+
+				triggerCountRunningTotal += triggerDayCountRunning;
+				triggerCountSucTotal += triggerDayCountSuc;
+				triggerCountFailTotal += triggerDayCountFail;
 			}
 			}
 		} else {
 		} else {
             for (int i = 4; i > -1; i--) {
             for (int i = 4; i > -1; i--) {
@@ -358,10 +368,17 @@ public class XxlJobServiceImpl implements XxlJobService {
 
 
 		Map<String, Object> result = new HashMap<String, Object>();
 		Map<String, Object> result = new HashMap<String, Object>();
 		result.put("triggerDayList", triggerDayList);
 		result.put("triggerDayList", triggerDayList);
+		result.put("triggerDayCountRunningList", triggerDayCountRunningList);
 		result.put("triggerDayCountSucList", triggerDayCountSucList);
 		result.put("triggerDayCountSucList", triggerDayCountSucList);
 		result.put("triggerDayCountFailList", triggerDayCountFailList);
 		result.put("triggerDayCountFailList", triggerDayCountFailList);
+
+		result.put("triggerCountRunningTotal", triggerCountRunningTotal);
 		result.put("triggerCountSucTotal", triggerCountSucTotal);
 		result.put("triggerCountSucTotal", triggerCountSucTotal);
 		result.put("triggerCountFailTotal", triggerCountFailTotal);
 		result.put("triggerCountFailTotal", triggerCountFailTotal);
+
+		// set cache
+		LocalCacheUtil.set(cacheKey, result, 60*1000);     // cache 60s
+
 		return new ReturnT<Map<String, Object>>(result);
 		return new ReturnT<Map<String, Object>>(result);
 	}
 	}
 
 

+ 226 - 0
xxl-job-admin/src/main/resources/i18n/message.properties

@@ -0,0 +1,226 @@
+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=官方文档

+ 226 - 0
xxl-job-admin/src/main/resources/i18n/message_en.properties

@@ -0,0 +1,226 @@
+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

+ 6 - 0
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobInfoMapper.xml

@@ -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 @@
 			<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>

+ 8 - 7
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml

@@ -163,13 +163,14 @@
 	</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
-        FROM XXL_JOB_QRTZ_TRIGGER_LOG
-        WHERE trigger_time BETWEEN #{from} and #{to}
-		<if test="handleCode gt 0">
-			AND handle_code = #{handleCode}
-		</if>
-        GROUP BY triggerDay;
+		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
+		WHERE trigger_time BETWEEN #{from} and #{to}
+		GROUP BY triggerDay;
     </select>
     </select>
 
 
 	<delete id="clearLog" >
 	<delete id="clearLog" >

+ 1 - 1
xxl-job-admin/src/main/resources/quartz.properties

@@ -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

+ 1 - 1
xxl-job-admin/src/main/resources/spring/applicationcontext-base.xml

@@ -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/" />

+ 4 - 1
xxl-job-admin/src/main/resources/xxl-job-admin.properties

@@ -16,4 +16,7 @@ xxl.job.login.username=admin
 xxl.job.login.password=123456
 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=

+ 4 - 3
xxl-job-admin/src/main/webapp/500.html

@@ -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 @@
 <body> 
 <body> 
 
 
 	<div class="dialog"> 
 	<div class="dialog"> 
-	    <h1>应用程序异常</h1> 
-	    <p>抱歉!您访问的页面出现异常,请稍后重试或联系管理员。</p> 
+	    <h1>System Error</h1>
+	    <p>Oops! Page not found.</p>
+		<a href="javascript:window.location.href='${request.contextPath}/'">Back</a>
 	</div>
 	</div>
 
 
 </body>
 </body>

+ 3 - 3
xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.exception.ftl

@@ -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 @@
 <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>
 
 

+ 16 - 9
xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.macro.ftl

@@ -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 @@
 
 
 	<#-- 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 @@
 	<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 @@
 				<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 @@
 		<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="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 == "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 == "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 == "help">active</#if>" ><a href="${request.contextPath}/help"><i class="fa fa-circle-o text-gray"></i><span>使用教程</span></a></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>${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>${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>${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>${I18n.job_help}</span></a></li>
 			</ul>
 			</ul>
 		</section>
 		</section>
 		<!-- /.sidebar -->
 		<!-- /.sidebar -->
@@ -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>

+ 0 - 1
xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.result.ftl

@@ -1 +0,0 @@
-${result?if_exists}

+ 5 - 11
xxl-job-admin/src/main/webapp/WEB-INF/template/help.ftl

@@ -1,9 +1,9 @@
 <!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 @@
 	<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>
-			<!--
-			<ol class="breadcrumb">
-				<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
-				<li class="active">使用教程</li>
-			</ol>
-			-->
+			<h1>${I18n.job_help}</h1>
 		</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>

+ 10 - 9
xxl-job-admin/src/main/webapp/WEB-INF/template/index.ftl

@@ -1,11 +1,11 @@
 <!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 @@
 	<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 @@
                         <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 @@
                         <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 @@
                         <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 @@
                 <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 -->

+ 13 - 9
xxl-job-admin/src/main/webapp/WEB-INF/template/jobcode/jobcode.index.ftl

@@ -1,11 +1,11 @@
 <!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 @@
                     <#-- 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 @@
                     <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 @@
                             <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 @@
         <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>
-                            <div class="col-sm-10"><input type="text" class="form-control" id="glueRemark" placeholder="请输入备注信息" maxlength="64" ></div>
+                            <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="${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-default" data-dismiss="modal">取消</button>
+                                <button type="button" class="btn btn-primary ok" >${I18n.system_save}</button>
+                                <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
                             </div>
                             </div>
                         </div>
                         </div>
                     </form>
                     </form>

+ 38 - 38
xxl-job-admin/src/main/webapp/WEB-INF/template/jobgroup/jobgroup.index.ftl

@@ -1,11 +1,11 @@
 <!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 />
 	<!-- DataTables -->
 	<!-- DataTables -->
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.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,7 +18,7 @@
 	<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.jobgroup_name}</h1>
 		</section>
 		</section>
 
 
 		<!-- Main content -->
 		<!-- Main content -->
@@ -28,20 +28,20 @@
 				<div class="col-xs-12">
 				<div class="col-xs-12">
 					<div class="box">
 					<div class="box">
 			            <div class="box-header">
 			            <div class="box-header">
-							<h3 class="box-title">执行器列表</h3>&nbsp;&nbsp;
-                            <button class="btn btn-info btn-xs pull-left2 add" >+新增执行器</button>
+							<h3 class="box-title">${I18n.jobgroup_list}</h3>&nbsp;&nbsp;
+                            <button class="btn btn-info btn-xs pull-left2 add" >${I18n.jobgroup_add}</button>
 						</div>
 						</div>
 			            <div class="box-body">
 			            <div class="box-body">
 			              	<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
 			              	<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
 				                <thead>
 				                <thead>
 					            	<tr>
 					            	<tr>
                                         <#--<th name="id" >ID</th>-->
                                         <#--<th name="id" >ID</th>-->
-                                        <th name="order" >排序</th>
+                                        <th name="order" >${I18n.jobgroup_field_order}</th>
                                         <th name="appName" >AppName</th>
                                         <th name="appName" >AppName</th>
-                                        <th name="title" >名称</th>
-                                        <th name="addressType" >注册方式</th>
-                                        <th name="registryList" >OnLine 机器</th>
-                                        <th name="operate" >操作</th>
+                                        <th name="title" >${I18n.jobgroup_field_title}</th>
+                                        <th name="addressType" >${I18n.jobgroup_field_addressType}</th>
+                                        <th name="registryList" >OnLine ${I18n.jobgroup_field_registryList}</th>
+                                        <th name="operate" >${I18n.system_opt}</th>
 					                </tr>
 					                </tr>
 				                </thead>
 				                </thead>
                                 <tbody>
                                 <tbody>
@@ -52,7 +52,7 @@
                                         <td>${group.order}</td>
                                         <td>${group.order}</td>
                                         <td>${group.appName}</td>
                                         <td>${group.appName}</td>
                                         <td>${group.title}</td>
                                         <td>${group.title}</td>
-                                        <td><#if group.addressType==0>自动注册<#else>手动录入</#if></td>
+                                        <td><#if group.addressType==0>${I18n.jobgroup_field_addressType_0}<#else>${I18n.jobgroup_field_addressType_1}</#if></td>
                                         <td>
                                         <td>
                                             <#if group.registryList?exists>
                                             <#if group.registryList?exists>
                                                 <#list group.registryList as item>
                                                 <#list group.registryList as item>
@@ -74,8 +74,8 @@
                                                     title="${group.title}"
                                                     title="${group.title}"
                                                     order="${group.order}"
                                                     order="${group.order}"
                                                     addressType="${group.addressType}"
                                                     addressType="${group.addressType}"
-                                                    addressList="${group.addressList}" >编辑</button>
-                                            <button class="btn btn-danger btn-xs remove" id="${group.id}" >删除</button>
+                                                    addressList="${group.addressList}" >${I18n.system_opt_edit}</button>
+                                            <button class="btn btn-danger btn-xs remove" id="${group.id}" >${I18n.system_opt_del}</button>
 										</td>
 										</td>
 									</tr>
 									</tr>
 								</#list>
 								</#list>
@@ -94,41 +94,41 @@
         <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" >新增执行器</h4>
+                    <h4 class="modal-title" >${I18n.jobgroup_add}</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">AppName<font color="red">*</font></label>
                             <label for="lastname" class="col-sm-2 control-label">AppName<font color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="请输入“AppName”" maxlength="64" ></div>
+                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="${I18n.system_please_input}AppName" maxlength="64" ></div>
                         </div>
                         </div>
                         <div class="form-group">
                         <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">名称<font color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="请输入“名称”" maxlength="12" ></div>
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font color="red">*</font></label>
+                            <div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_title}" maxlength="12" ></div>
                         </div>
                         </div>
                         <div class="form-group">
                         <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div>
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_order}<font color="red">*</font></label>
+                            <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_order}" maxlength="50" ></div>
                         </div>
                         </div>
                         <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.jobgroup_field_addressType}<font color="red">*</font></label>
                             <div class="col-sm-10">
                             <div class="col-sm-10">
-                                <input type="radio" name="addressType" value="0" checked />自动注册
+                                <input type="radio" name="addressType" value="0" checked />${I18n.jobgroup_field_addressType_0}
                                 &nbsp;&nbsp;&nbsp;&nbsp;
                                 &nbsp;&nbsp;&nbsp;&nbsp;
-                                <input type="radio" name="addressType" value="1" />手动录入
+                                <input type="radio" name="addressType" value="1" />${I18n.jobgroup_field_addressType_1}
                             </div>
                             </div>
                         </div>
                         </div>
                         <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.jobgroup_field_registryList}<font color="red">*</font></label>
                             <div class="col-sm-10">
                             <div class="col-sm-10">
-                                <textarea class="textarea" name="addressList" maxlength="512" placeholder="请输入执行器地址列表,多地址逗号分隔" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 10px; border: 1px solid #dddddd; padding: 10px;"></textarea>
+                                <textarea class="textarea" name="addressList" maxlength="512" placeholder="${I18n.jobgroup_field_registryList_placeholder}" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 10px; border: 1px solid #dddddd; padding: 10px;"></textarea>
                             </div>
                             </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="submit" class="btn btn-primary"  >保存</button>
-                                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
+                                <button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
+                                <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
                             </div>
                             </div>
                         </div>
                         </div>
                     </form>
                     </form>
@@ -142,41 +142,41 @@
         <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" >编辑执行器</h4>
+                    <h4 class="modal-title" >${I18n.jobgroup_edit}</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">AppName<font color="red">*</font></label>
                             <label for="lastname" class="col-sm-2 control-label">AppName<font color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="请输入“AppName”" maxlength="64" ></div>
+                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="${I18n.system_please_input}AppName" maxlength="64" ></div>
                         </div>
                         </div>
                         <div class="form-group">
                         <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">名称<font color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="请输入“名称”" maxlength="12" ></div>
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font color="red">*</font></label>
+                            <div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_title}" maxlength="12" ></div>
                         </div>
                         </div>
                         <div class="form-group">
                         <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div>
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_order}<font color="red">*</font></label>
+                            <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="${I18n.system_please_input}${I18n.jobgroup_field_order}" maxlength="50" ></div>
                         </div>
                         </div>
                         <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.jobgroup_field_addressType}<font color="red">*</font></label>
                             <div class="col-sm-10">
                             <div class="col-sm-10">
-                                <input type="radio" name="addressType" value="0" />自动注册
+                                <input type="radio" name="addressType" value="0" />${I18n.jobgroup_field_addressType_0}
                                 &nbsp;&nbsp;&nbsp;&nbsp;
                                 &nbsp;&nbsp;&nbsp;&nbsp;
-                                <input type="radio" name="addressType" value="1" />手动录入
+                                <input type="radio" name="addressType" value="1" />${I18n.jobgroup_field_addressType_1}
                             </div>
                             </div>
                         </div>
                         </div>
                         <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.jobgroup_field_registryList}<font color="red">*</font></label>
                             <div class="col-sm-10">
                             <div class="col-sm-10">
-                                <textarea class="textarea" name="addressList" maxlength="512" placeholder="请输入执行器地址列表,多地址逗号分隔" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 10px; border: 1px solid #dddddd; padding: 10px;"></textarea>
+                                <textarea class="textarea" name="addressList" maxlength="512" placeholder="${I18n.jobgroup_field_registryList_placeholder}" readonly="readonly" style="background-color:#eee; width: 100%; height: 100px; font-size: 14px; line-height: 10px; border: 1px solid #dddddd; padding: 10px;"></textarea>
                             </div>
                             </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="submit" class="btn btn-primary"  >保存</button>
-                                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
+                                <button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
+                                <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
                                 <input type="hidden" name="id" >
                                 <input type="hidden" name="id" >
                             </div>
                             </div>
                         </div>
                         </div>

+ 81 - 82
xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/jobinfo.index.ftl

@@ -1,12 +1,11 @@
 <!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 />
 	<!-- DataTables -->
 	<!-- DataTables -->
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.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">
@@ -19,22 +18,16 @@
 	<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>
-			<!--
-			<ol class="breadcrumb">
-				<li><a><i class="fa fa-dashboard"></i>调度管理</a></li>
-				<li class="active">调度中心</li>
-			</ol>
-			-->
+			<h1>${I18n.jobinfo_name}</h1>
 		</section>
 		</section>
 		
 		
 		<!-- Main content -->
 		<!-- Main content -->
 	    <section class="content">
 	    <section class="content">
 	    
 	    
 	    	<div class="row">
 	    	<div class="row">
-	    		<div class="col-xs-4">
+	    		<div class="col-xs-3">
 	              	<div class="input-group">
 	              	<div class="input-group">
-	                	<span class="input-group-addon">执行器</span>
+	                	<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
                 		<select class="form-control" id="jobGroup" >
                 		<select class="form-control" id="jobGroup" >
                 			<#list JobGroupList as group>
                 			<#list JobGroupList as group>
                 				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
                 				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
@@ -42,43 +35,48 @@
 	                  	</select>
 	                  	</select>
 	              	</div>
 	              	</div>
 	            </div>
 	            </div>
-                <div class="col-xs-4">
+                <div class="col-xs-3">
+                    <div class="input-group">
+                        <span class="input-group-addon">${I18n.jobinfo_field_jobdesc}</span>
+                        <input type="text" class="form-control" id="jobDesc" autocomplete="on" >
+                    </div>
+                </div>
+                <div class="col-xs-3">
                     <div class="input-group">
                     <div class="input-group">
                         <span class="input-group-addon">JobHandler</span>
                         <span class="input-group-addon">JobHandler</span>
                         <input type="text" class="form-control" id="executorHandler" autocomplete="on" >
                         <input type="text" class="form-control" id="executorHandler" autocomplete="on" >
                     </div>
                     </div>
                 </div>
                 </div>
-	            <div class="col-xs-2">
-	            	<button class="btn btn-block btn-info" id="searchBtn">搜索</button>
+	            <div class="col-xs-1">
+	            	<button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
 	            </div>
 	            </div>
 	            <div class="col-xs-2">
 	            <div class="col-xs-2">
-	            	<button class="btn btn-block btn-success add" type="button">+新增任务</button>
+	            	<button class="btn btn-block btn-success add" type="button">${I18n.jobinfo_field_add}</button>
 	            </div>
 	            </div>
           	</div>
           	</div>
 	    	
 	    	
 			<div class="row">
 			<div class="row">
 				<div class="col-xs-12">
 				<div class="col-xs-12">
 					<div class="box">
 					<div class="box">
-			            <div class="box-header hide">
+			            <#--<div class="box-header hide">
 			            	<h3 class="box-title">调度列表</h3>
 			            	<h3 class="box-title">调度列表</h3>
-			            </div>
+			            </div>-->
 			            <div class="box-body" >
 			            <div class="box-body" >
 			              	<table id="job_list" class="table table-bordered table-striped" width="100%" >
 			              	<table id="job_list" class="table table-bordered table-striped" width="100%" >
 				                <thead>
 				                <thead>
 					            	<tr>
 					            	<tr>
-					            		<th name="id" >任务ID</th>
-					                	<th name="jobGroup" >jobGroup</th>
-					                  	<th name="jobDesc" >描述</th>
-                                        <th name="glueType" >运行模式</th>
-					                  	<th name="executorParam" >任务参数</th>
+					            		<th name="id" >${I18n.jobinfo_field_id}</th>
+					                	<th name="jobGroup" >${I18n.jobinfo_field_jobgroup}</th>
+					                  	<th name="jobDesc" >${I18n.jobinfo_field_jobdesc}</th>
+                                        <th name="glueType" >${I18n.jobinfo_field_gluetype}</th>
+					                  	<th name="executorParam" >${I18n.jobinfo_field_executorparam}</th>
                                         <th name="jobCron" >Cron</th>
                                         <th name="jobCron" >Cron</th>
-					                  	<th name="addTime" >新增时间</th>
-					                  	<th name="updateTime" >更新时间</th>
-					                  	<th name="author" >负责人</th>
-					                  	<th name="alarmEmail" >报警邮件</th>
-					                  	<th name="glueType" >运行模式</th>
-					                  	<th name="jobStatus" >状态</th>
-					                  	<th>操作</th>
+					                  	<th name="addTime" >addTime</th>
+					                  	<th name="updateTime" >updateTime</th>
+					                  	<th name="author" >${I18n.jobinfo_field_author}</th>
+					                  	<th name="alarmEmail" >${I18n.jobinfo_field_alarmemail}</th>
+					                  	<th name="jobStatus" >${I18n.system_status}</th>
+					                  	<th>${I18n.system_opt}</th>
 					                </tr>
 					                </tr>
 				                </thead>
 				                </thead>
 				                <tbody></tbody>
 				                <tbody></tbody>
@@ -100,12 +98,12 @@
 	<div class="modal-dialog modal-lg">
 	<div class="modal-dialog modal-lg">
 		<div class="modal-content">
 		<div class="modal-content">
 			<div class="modal-header">
 			<div class="modal-header">
-            	<h4 class="modal-title" >新增任务</h4>
+            	<h4 class="modal-title" >${I18n.jobinfo_field_add}</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="firstname" class="col-sm-2 control-label">执行器<font color="red">*</font></label>
+						<label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
 						<div class="col-sm-4">
 						<div class="col-sm-4">
 							<select class="form-control" name="jobGroup" >
 							<select class="form-control" name="jobGroup" >
 		            			<#list JobGroupList as group>
 		            			<#list JobGroupList as group>
@@ -113,11 +111,11 @@
 		            			</#list>
 		            			</#list>
 		                  	</select>
 		                  	</select>
 						</div>
 						</div>
-                        <label for="lastname" class="col-sm-2 control-label">任务描述<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="请输入“描述”" maxlength="50" ></div>
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}" maxlength="50" ></div>
 					</div>
 					</div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">路由策略<font color="red">*</font></label>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control" name="executorRouteStrategy" >
                             <select class="form-control" name="executorRouteStrategy" >
 							<#list ExecutorRouteStrategyEnum as item>
 							<#list ExecutorRouteStrategyEnum as item>
@@ -126,10 +124,10 @@
                             </select>
                             </select>
                         </div>
                         </div>
                         <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
                         <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="请输入“Cron”" maxlength="128" ></div>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">运行模式<font color="red">*</font></label>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control glueType" name="glueType" >
                             <select class="form-control glueType" name="glueType" >
 								<#list GlueTypeEnum as item>
 								<#list GlueTypeEnum as item>
@@ -138,16 +136,16 @@
                             </select>
                             </select>
                         </div>
                         </div>
                         <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
                         <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="请输入“JobHandler”" maxlength="100" ></div>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入“执行参数”" maxlength="512" ></div>
-                        <label for="lastname" class="col-sm-2 control-label">子任务ID<font color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="请输入子任务的任务ID,如存在多个逗号分隔" maxlength="100" ></div>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}" maxlength="512" ></div>
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">阻塞处理策略<font color="red">*</font></label>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control" name="executorBlockStrategy" >
                             <select class="form-control" name="executorBlockStrategy" >
 								<#list ExecutorBlockStrategyEnum as item>
 								<#list ExecutorBlockStrategyEnum as item>
@@ -155,7 +153,7 @@
 								</#list>
 								</#list>
                             </select>
                             </select>
 						</div>
 						</div>
-                        <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_field_executorFailStrategy}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control" name="executorFailStrategy" >
                             <select class="form-control" name="executorFailStrategy" >
 								<#list ExecutorFailStrategyEnum as item>
 								<#list ExecutorFailStrategyEnum as item>
@@ -165,17 +163,17 @@
 						</div>
 						</div>
                     </div>
                     </div>
 					<div class="form-group">
 					<div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">负责人<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="50" ></div>
-						<label for="lastname" class="col-sm-2 control-label">报警邮件<font color="black">*</font></label>
-						<div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="100" ></div>
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}" maxlength="50" ></div>
+						<label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
+						<div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></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="submit" class="btn btn-primary"  >保存</button>
-							<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
+							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
+							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
 						</div>
 						</div>
 					</div>
 					</div>
 
 
@@ -202,10 +200,10 @@ public class DemoGlueJobHandler extends IJobHandler {
 #!/bin/bash
 #!/bin/bash
 echo "xxl-job: hello shell"
 echo "xxl-job: hello shell"
 
 
-echo "脚本位置:$0"
-echo "任务参数:$1"
-echo "分片序号 = $2"
-echo "分片总数 = $3"
+echo "${I18n.jobinfo_script_location}:$0"
+echo "${I18n.jobinfo_field_executorparam}:$1"
+echo "${I18n.jobinfo_shard_index} = $2"
+echo "${I18n.jobinfo_shard_total} = $3"
 <#--echo "参数数量:$#"
 <#--echo "参数数量:$#"
 for param in $*
 for param in $*
 do
 do
@@ -224,10 +222,10 @@ import sys
 
 
 print "xxl-job: hello python"
 print "xxl-job: hello python"
 
 
-print "脚本文件:", sys.argv[0]
-print "任务参数:", sys.argv[1]
-print "分片序号:", sys.argv[2]
-print "分片总数:", sys.argv[3]
+print "${I18n.jobinfo_script_location}:", sys.argv[0]
+print "${I18n.jobinfo_field_executorparam}:", sys.argv[1]
+print "${I18n.jobinfo_shard_index}:", sys.argv[2]
+print "${I18n.jobinfo_shard_total}:", sys.argv[3]
 <#--for i in range(1, len(sys.argv)):
 <#--for i in range(1, len(sys.argv)):
 	time.sleep(1)
 	time.sleep(1)
 	print "参数", i, sys.argv[i]-->
 	print "参数", i, sys.argv[i]-->
@@ -246,10 +244,10 @@ console.log("xxl-job: hello nodejs")
 
 
 var arguments = process.argv
 var arguments = process.argv
 
 
-console.log("脚本文件: " + arguments[1])
-console.log("任务参数: " + arguments[2])
-console.log("分片序号: " + arguments[3])
-console.log("分片总数: " + arguments[4])
+console.log("${I18n.jobinfo_script_location}: " + arguments[1])
+console.log("${I18n.jobinfo_field_executorparam}: " + arguments[2])
+console.log("${I18n.jobinfo_shard_index}: " + arguments[3])
+console.log("${I18n.jobinfo_shard_total}: " + arguments[4])
 <#--for (var i = 2; i < arguments.length; i++){
 <#--for (var i = 2; i < arguments.length; i++){
 	console.log("参数 %s = %s", (i-1), arguments[i]);
 	console.log("参数 %s = %s", (i-1), arguments[i]);
 }-->
 }-->
@@ -268,12 +266,12 @@ process.exit(0)
 	<div class="modal-dialog modal-lg">
 	<div class="modal-dialog modal-lg">
 		<div class="modal-content">
 		<div class="modal-content">
 			<div class="modal-header">
 			<div class="modal-header">
-            	<h4 class="modal-title" >更新任务</h4>
+            	<h4 class="modal-title" >${I18n.jobinfo_field_update}</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">
-                        <label for="firstname" class="col-sm-2 control-label">执行器<font color="red">*</font></label>
+					<div class="form-group">
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control" name="jobGroup" disabled >
                             <select class="form-control" name="jobGroup" disabled >
 							<#list JobGroupList as group>
 							<#list JobGroupList as group>
@@ -281,11 +279,11 @@ process.exit(0)
 							</#list>
 							</#list>
                             </select>
                             </select>
                         </div>
                         </div>
-                        <label for="lastname" class="col-sm-2 control-label">任务描述<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="请输入“描述”" maxlength="50" ></div>
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}" maxlength="50" ></div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">路由策略<font color="red">*</font></label>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control" name="executorRouteStrategy" >
                             <select class="form-control" name="executorRouteStrategy" >
 							<#list ExecutorRouteStrategyEnum as item>
 							<#list ExecutorRouteStrategyEnum as item>
@@ -294,10 +292,10 @@ process.exit(0)
                             </select>
                             </select>
                         </div>
                         </div>
                         <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
                         <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="请输入“Cron”" maxlength="128" ></div>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">运行模式<font color="red">*</font></label>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control glueType" name="glueType" disabled >
                             <select class="form-control glueType" name="glueType" disabled >
 							<#list GlueTypeEnum as item>
 							<#list GlueTypeEnum as item>
@@ -306,16 +304,16 @@ process.exit(0)
                             </select>
                             </select>
                         </div>
                         </div>
                         <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
                         <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="请输入“JobHandler”" maxlength="100" ></div>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入“执行参数”" maxlength="512" ></div>
-                        <label for="lastname" class="col-sm-2 control-label">子任务ID<font color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="请输入子任务的任务ID,如存在多个逗号分隔" maxlength="100" ></div>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}" maxlength="512" ></div>
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">阻塞处理策略<font color="red">*</font></label>
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control" name="executorBlockStrategy" >
                             <select class="form-control" name="executorBlockStrategy" >
 							<#list ExecutorBlockStrategyEnum as item>
 							<#list ExecutorBlockStrategyEnum as item>
@@ -323,7 +321,7 @@ process.exit(0)
 							</#list>
 							</#list>
                             </select>
                             </select>
                         </div>
                         </div>
-                        <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_field_executorFailStrategy}<font color="red">*</font></label>
                         <div class="col-sm-4">
                         <div class="col-sm-4">
                             <select class="form-control" name="executorFailStrategy" >
                             <select class="form-control" name="executorFailStrategy" >
 							<#list ExecutorFailStrategyEnum as item>
 							<#list ExecutorFailStrategyEnum as item>
@@ -333,20 +331,21 @@ process.exit(0)
                         </div>
                         </div>
                     </div>
                     </div>
                     <div class="form-group">
                     <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">负责人<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="50" ></div>
-                        <label for="lastname" class="col-sm-2 control-label">报警邮件<font color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="100" ></div>
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}" maxlength="50" ></div>
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
+                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></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="submit" class="btn btn-primary"  >保存</button>
-							<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
+							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
+							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
                             <input type="hidden" name="id" >
                             <input type="hidden" name="id" >
 						</div>
 						</div>
 					</div>
 					</div>
+
 				</form>
 				</form>
          	</div>
          	</div>
 		</div>
 		</div>

+ 6 - 6
xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.detail.ftl

@@ -1,9 +1,9 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html>
 <html>
 <head>
 <head>
-    <title>任务调度中心</title>
-<#import "/common/common.macro.ftl" as netCommon>
-<@netCommon.commonStyle />
+    <#import "/common/common.macro.ftl" as netCommon>
+    <@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">
 
 
@@ -12,9 +12,9 @@
     <header class="main-header">
     <header class="main-header">
         <nav class="navbar navbar-static-top">
         <nav class="navbar navbar-static-top">
             <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 @@
                         <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>

+ 45 - 45
xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.index.ftl

@@ -1,13 +1,13 @@
 <!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 />
 	<!-- DataTables -->
 	<!-- DataTables -->
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
   	<!-- 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">
@@ -20,13 +20,7 @@
 	<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>
-			<!--
-			<ol class="breadcrumb">
-				<li><a><i class="fa fa-dashboard"></i>调度日志</a></li>
-				<li class="active">调度管理</li>
-			</ol>
-			-->
+			<h1>${I18n.joblog_name}</h1>
 		</section>
 		</section>
 		
 		
 		<!-- Main content -->
 		<!-- Main content -->
@@ -34,9 +28,9 @@
 	    	<div class="row">
 	    	<div class="row">
 	    		<div class="col-xs-2">
 	    		<div class="col-xs-2">
  					<div class="input-group">
  					<div class="input-group">
-	                	<span class="input-group-addon">执行器</span>
+	                	<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
                 		<select class="form-control" id="jobGroup"  paramVal="<#if jobInfo?exists>${jobInfo.jobGroup}</#if>" >
                 		<select class="form-control" id="jobGroup"  paramVal="<#if jobInfo?exists>${jobInfo.jobGroup}</#if>" >
-                            <option value="0" >全部</option>
+                            <option value="0" >${I18n.system_all}</option>
                 			<#list JobGroupList as group>
                 			<#list JobGroupList as group>
                 				<option value="${group.id}" >${group.title}</option>
                 				<option value="${group.id}" >${group.title}</option>
                 			</#list>
                 			</#list>
@@ -45,21 +39,21 @@
 	            </div>
 	            </div>
 	            <div class="col-xs-2">
 	            <div class="col-xs-2">
 	              	<div class="input-group">
 	              	<div class="input-group">
-	                	<span class="input-group-addon">任务</span>
+	                	<span class="input-group-addon">${I18n.jobinfo_job}</span>
                         <select class="form-control" id="jobId" paramVal="<#if jobInfo?exists>${jobInfo.id}</#if>" >
                         <select class="form-control" id="jobId" paramVal="<#if jobInfo?exists>${jobInfo.id}</#if>" >
-                            <option value="0" >全部</option>
+                            <option value="0" >${I18n.system_all}</option>
 						</select>
 						</select>
 	              	</div>
 	              	</div>
 	            </div>
 	            </div>
 
 
                 <div class="col-xs-2">
                 <div class="col-xs-2">
                     <div class="input-group">
                     <div class="input-group">
-                        <span class="input-group-addon">状态</span>
+                        <span class="input-group-addon">${I18n.joblog_status}</span>
                         <select class="form-control" id="logStatus" >
                         <select class="form-control" id="logStatus" >
-                            <option value="-1" >全部</option>
-                            <option value="1" >成功</option>
-                            <option value="2" >失败</option>
-                            <option value="3" >进行中</option>
+                            <option value="-1" >${I18n.joblog_status_all}</option>
+                            <option value="1" >${I18n.joblog_status_suc}</option>
+                            <option value="2" >${I18n.joblog_status_fail}</option>
+                            <option value="3" >${I18n.joblog_status_running}</option>
                         </select>
                         </select>
                     </div>
                     </div>
                 </div>
                 </div>
@@ -67,41 +61,41 @@
 	            <div class="col-xs-4">
 	            <div class="col-xs-4">
               		<div class="input-group">
               		<div class="input-group">
                 		<span class="input-group-addon">
                 		<span class="input-group-addon">
-	                  		调度时间
+	                  		${I18n.joblog_field_triggerTime}
 	                	</span>
 	                	</span>
 	                	<input type="text" class="form-control" id="filterTime" readonly >
 	                	<input type="text" class="form-control" id="filterTime" readonly >
 	              	</div>
 	              	</div>
 	            </div>
 	            </div>
 
 
                 <div class="col-xs-1">
                 <div class="col-xs-1">
-                    <button class="btn btn-block btn-info" id="searchBtn">搜索</button>
+                    <button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
                 </div>
                 </div>
 
 
 	            <div class="col-xs-1">
 	            <div class="col-xs-1">
-                    <button class="btn btn-block btn-nomal" id="clearLog">清理</button>
+                    <button class="btn btn-block btn-nomal" id="clearLog">${I18n.joblog_clean}</button>
 	            </div>
 	            </div>
           	</div>
           	</div>
 			
 			
 			<div class="row">
 			<div class="row">
 				<div class="col-xs-12">
 				<div class="col-xs-12">
 					<div class="box">
 					<div class="box">
-			            <div class="box-header hide"><h3 class="box-title">调度日志</h3></div>
+			            <#--<div class="box-header hide"><h3 class="box-title">调度日志</h3></div>-->
 			            <div class="box-body">
 			            <div class="box-body">
 			              	<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
 			              	<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
 				                <thead>
 				                <thead>
 					            	<tr>
 					            	<tr>
-                                        <th name="jobId" >任务ID</th>
-                                        <th name="jobGroup" >执行器ID</th>
+                                        <th name="jobId" >${I18n.jobinfo_field_id}</th>
+                                        <th name="jobGroup" >jobGroup</th>
 										<#--<th name="executorAddress" >执行器地址</th>
 										<#--<th name="executorAddress" >执行器地址</th>
 										<th name="glueType" >运行模式</th>
 										<th name="glueType" >运行模式</th>
                                       	<th name="executorParam" >任务参数</th>-->
                                       	<th name="executorParam" >任务参数</th>-->
-                                        <th name="triggerTime" >调度时间</th>
-                                        <th name="triggerCode" >调度结果</th>
-                                        <th name="triggerMsg" >调度备注</th>
-					                  	<th name="handleTime" >执行时间</th>
-					                  	<th name="handleCode" >执行结果</th>
-					                  	<th name="handleMsg" >执行备注</th>
-					                  	<th name="handleMsg" >操作</th>
+                                        <th name="triggerTime" >${I18n.joblog_field_triggerTime}</th>
+                                        <th name="triggerCode" >${I18n.joblog_field_triggerCode}</th>
+                                        <th name="triggerMsg" >${I18n.joblog_field_triggerMsg}</th>
+					                  	<th name="handleTime" >${I18n.joblog_field_handleTime}</th>
+					                  	<th name="handleCode" >${I18n.joblog_field_handleCode}</th>
+					                  	<th name="handleMsg" >${I18n.joblog_field_handleMsg}</th>
+					                  	<th name="handleMsg" >${I18n.system_opt}</th>
 					                </tr>
 					                </tr>
 				                </thead>
 				                </thead>
 				                <tbody></tbody>
 				                <tbody></tbody>
@@ -122,12 +116,12 @@
     <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" >日志清理</h4>
+                <h4 class="modal-title" >${I18n.joblog_clean_log}</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 class="col-sm-3 control-label"">执行器:</label>
+                        <label class="col-sm-3 control-label"">${I18n.jobinfo_field_jobgroup}:</label>
                         <div class="col-sm-9">
                         <div class="col-sm-9">
                             <input type="text" class="form-control jobGroupText" readonly >
                             <input type="text" class="form-control jobGroupText" readonly >
 							<input type="hidden" name="jobGroup" >
 							<input type="hidden" name="jobGroup" >
@@ -135,7 +129,7 @@
                     </div>
                     </div>
 
 
                     <div class="form-group">
                     <div class="form-group">
-                        <label class="col-sm-3 control-label"">任务:</label>
+                        <label class="col-sm-3 control-label"">${I18n.jobinfo_job}:</label>
                         <div class="col-sm-9">
                         <div class="col-sm-9">
                             <input type="text" class="form-control jobIdText" readonly >
                             <input type="text" class="form-control jobIdText" readonly >
                             <input type="hidden" name="jobId" >
                             <input type="hidden" name="jobId" >
@@ -143,18 +137,18 @@
                     </div>
                     </div>
 
 
                     <div class="form-group">
                     <div class="form-group">
-                        <label class="col-sm-3 control-label"">清理类型:</label>
+                        <label class="col-sm-3 control-label"">${I18n.joblog_clean_type}:</label>
                         <div class="col-sm-9">
                         <div class="col-sm-9">
                             <select class="form-control" name="type" >
                             <select class="form-control" name="type" >
-                                <option value="1" >清理一个月之前日志数据</option>
-                                <option value="2" >清理三个月之前日志数据</option>
-                                <option value="3" >清理六个月之前日志数据</option>
-                                <option value="4" >清理一年之前日志数据</option>
-                                <option value="5" >清理一千条以前日志数据</option>
-                                <option value="6" >清理一万条以前日志数据</option>
-                                <option value="7" >清理三万条以前日志数据</option>
-                                <option value="8" >清理十万条以前日志数据</option>
-                                <option value="9" >清理所有日志数据</option>
+                                <option value="1" >${I18n.joblog_clean_type_1}</option>
+                                <option value="2" >${I18n.joblog_clean_type_2}</option>
+                                <option value="3" >${I18n.joblog_clean_type_3}</option>
+                                <option value="4" >${I18n.joblog_clean_type_4}</option>
+                                <option value="5" >${I18n.joblog_clean_type_5}</option>
+                                <option value="6" >${I18n.joblog_clean_type_6}</option>
+                                <option value="7" >${I18n.joblog_clean_type_7}</option>
+                                <option value="8" >${I18n.joblog_clean_type_8}</option>
+                                <option value="9" >${I18n.joblog_clean_type_9}</option>
                             </select>
                             </select>
                         </div>
                         </div>
                     </div>
                     </div>
@@ -162,8 +156,8 @@
                     <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-default" data-dismiss="modal">取消</button>
+                            <button type="button" class="btn btn-primary ok" >${I18n.system_ok}</button>
+                            <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
                         </div>
                         </div>
                     </div>
                     </div>
                 </form>
                 </form>
@@ -173,6 +167,12 @@
 </div>
 </div>
 
 
 <@netCommon.commonScript />
 <@netCommon.commonScript />
+<script>
+    var GlueTypeEnum = {};
+    <#list GlueTypeEnum as item>
+    GlueTypeEnum['${item}'] = '${item.desc}';
+    </#list>
+</script>
 <!-- DataTables -->
 <!-- DataTables -->
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.min.js"></script>

+ 6 - 6
xxl-job-admin/src/main/webapp/WEB-INF/template/login.ftl

@@ -1,10 +1,10 @@
 <!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 @@
 		</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>

+ 15 - 17
xxl-job-admin/src/main/webapp/static/js/common.1.js

@@ -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: '系统提示',
-						content: (data.msg || "操作失败"),
+						title: I18n.system_tips ,
+                        btn: [ I18n.system_ok ],
+						content: (data.msg || I18n.logout_fail),
 						icon: '2'
 						icon: '2'
 					});
 					});
 				}
 				}
@@ -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,11 +80,12 @@ $(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') {
-	 $('body').addClass('sidebar-collapse');
+	 	$('body').addClass('sidebar-collapse');
 	 }
 	 }
 	 */
 	 */
 	
 	

+ 54 - 46
xxl-job-admin/src/main/webapp/static/js/index.js

@@ -1,13 +1,17 @@
 /**
 /**
  * Created by xuxueli on 17/4/24.
  * Created by xuxueli on 17/4/24.
  */
  */
-
-
 $(function () {
 $(function () {
 
 
-    // 过滤时间
-    var _startDate = moment().subtract(1, 'months');    // 默认,最近一月
-    var _endDate = moment();
+    // filter Time
+    var rangesConf = {};
+    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 () {
         timePickerIncrement: 10, 	// 时间的增量,单位为分钟
         timePickerIncrement: 10, 	// 时间的增量,单位为分钟
         timePicker24Hour : true,
         timePicker24Hour : true,
         opens : 'left', //日期选择框的弹出位置
         opens : 'left', //日期选择框的弹出位置
-        ranges: {
-            //'最近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]
-        },
+        ranges: rangesConf,
         locale : {
         locale : {
             format: 'YYYY-MM-DD HH:mm:ss',
             format: 'YYYY-MM-DD HH:mm:ss',
             separator : ' - ',
             separator : ' - ',
-            customRangeLabel : '自定义',
-            applyLabel : '确定',
-            cancelLabel : '取消',
-            fromLabel : '起始时间',
-            toLabel : '结束时间',
-            daysOfWeek : [ '日', '一', '二', '三', '四', '五', '六' ],
-            monthNames : [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ],
+            customRangeLabel : I18n.daterangepicker_custom_name ,
+            applyLabel : I18n.system_ok ,
+            cancelLabel : I18n.system_cancel ,
+            fromLabel : I18n.daterangepicker_custom_starttime ,
+            toLabel : I18n.daterangepicker_custom_endtime ,
+            daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') ,        // '日', '一', '二', '三', '四', '五', '六'
+            monthNames : I18n.daterangepicker_custom_monthnames.split(',') ,        // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'
             firstDay : 1
             firstDay : 1
         },
         },
-        startDate:_startDate,
-        endDate: _endDate
+        startDate: rangesConf[I18n.daterangepicker_ranges_recent_month][0] ,
+        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 () {
     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 () {
                     pieChartInit(data);
                     pieChartInit(data);
                 } else {
                 } else {
                     layer.open({
                     layer.open({
-                        title: '系统提示',
-                        content: (data.msg || '调度报表数据加载异常'),
+                        title: I18n.system_tips ,
+                        btn: [ I18n.system_ok ],
+                        content: (data.msg || I18n.job_dashboard_report_loaddata_fail ),
                         icon: '2'
                         icon: '2'
                     });
                     });
                 }
                 }
@@ -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 () {
                    }
                    }
                },
                },
                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 () {
                ],
                ],
                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 () {
                        },
                        },
                        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 () {
     }
     }
 
 
     /**
     /**
-     * 饼图
+     * 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:'成功调度次数'
+                            name:I18n.joblog_status_suc,
+                            value:data.content.triggerCountSucTotal
+                        },
+                        {
+                            name:I18n.joblog_status_fail,
+                            value:data.content.triggerCountFailTotal
                         },
                         },
                         {
                         {
-                            value:data.content.triggerCountFailTotal,
-                            name:'失败调度次数'
+                            name:I18n.joblog_status_running,
+                            value:data.content.triggerCountRunningTotal
                         }
                         }
                     ],
                     ],
                     itemStyle: {
                     itemStyle: {
@@ -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);

+ 12 - 14
xxl-job-admin/src/main/webapp/static/js/jobcode.index.1.js

@@ -1,12 +1,6 @@
 $(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() {
 		
 		
 		if (!glueRemark) {
 		if (!glueRemark) {
 			layer.open({
 			layer.open({
-				title: '系统提示',
-				content: '请输入备注',
+				title: I18n.system_tips,
+                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: '系统提示',
-				content: '备注长度应该在4至100之间',
+				title: I18n.system_tips ,
+                btn: [ I18n.system_ok ],
+				content: I18n.jobinfo_glue_remark_limit ,
 				icon: '2'
 				icon: '2'
 			});
 			});
 			return;
 			return;
@@ -71,8 +67,9 @@ $(function() {
 			success : function(data){
 			success : function(data){
 				if (data.code == 200) {
 				if (data.code == 200) {
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: '保存成功',
+						title: I18n.system_tips,
+                        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() {
 					});
 					});
 				} else {
 				} else {
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: (data.msg || "保存失败"),
+						title: I18n.system_tips,
+                        btn: [ I18n.system_ok ],
+						content: (data.msg || (I18n.system_save + I18n.system_fail) ),
 						icon: '2'
 						icon: '2'
 					});
 					});
 				}
 				}

+ 48 - 38
xxl-job-admin/src/main/webapp/static/js/jobgroup.index.1.js

@@ -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() {
 				success : function(data){
 				success : function(data){
 					if (data.code == 200) {
 					if (data.code == 200) {
 						layer.open({
 						layer.open({
-							title: '系统提示',
-							content: '删除成功',
+							title: I18n.system_tips ,
+                            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() {
 						});
 						});
 					} else {
 					} else {
 						layer.open({
 						layer.open({
-							title: '系统提示',
-							content: (data.msg || "删除失败"),
+							title: I18n.system_tips,
+                            btn: [ I18n.system_ok ],
+							content: (data.msg || (I18n.jobgroup_del + I18n.system_fail)),
 							icon: '2'
 							icon: '2'
 						});
 						});
 					}
 					}
@@ -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() {
 		},
 		},
 		messages : {
 		messages : {
 			appName : {
 			appName : {
-				required :"请输入“AppName",
-				rangelength:"AppName长度限制为4~64",
-				myValid01: "限制以小写字母开头,由小写字母、数字和中划线组成"
+				required : I18n.system_please_input+"AppName",
+				rangelength: I18n.jobgroup_field_appName_length ,
+				myValid01: I18n.jobgroup_field_appName_limit
 			},
 			},
 			title : {
 			title : {
-				required :"请输入“执行器名称”",
-				rangelength:"长度限制为4~12"
+				required : I18n.system_please_input + I18n.jobgroup_field_title ,
+				rangelength: I18n.jobgroup_field_title_length
 			},
 			},
 			order : {
 			order : {
-				required :"请输入“排序”",
-				digits: "请输入整数",
-				range: "取值范围为1~1000"
+				required : I18n.system_please_input + I18n.jobgroup_field_order ,
+				digits: I18n.jobgroup_field_order_digits ,
+				range: I18n.jobgroup_field_orderrange
 			}
 			}
 		},
 		},
 		highlight : function(element) {
 		highlight : function(element) {
@@ -96,8 +102,9 @@ $(function() {
 				if (data.code == "200") {
 				if (data.code == "200") {
 					$('#addModal').modal('hide');
 					$('#addModal').modal('hide');
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: '新增成功',
+						title: I18n.system_tips ,
+                        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() {
 					});
 					});
 				} else {
 				} else {
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: (data.msg || "新增失败"),
+						title: I18n.system_tips,
+                        btn: [ I18n.system_ok ],
+						content: (data.msg || I18n.system_add_fail  ),
 						icon: '2'
 						icon: '2'
 					});
 					});
 				}
 				}
@@ -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]");
@@ -171,20 +179,20 @@ $(function() {
 			}
 			}
 		},
 		},
 		messages : {
 		messages : {
-			appName : {
-				required :"请输入“AppName”",
-				rangelength:"AppName长度限制为4~64",
-				myValid01: "限制以小写字母开头,由小写字母、数字和中划线组成"
-			},
-			title : {
-				required :"请输入“执行器名称”",
-				rangelength:"长度限制为4~12"
-			},
-			order : {
-				required :"请输入“排序”",
-				digits: "请输入整数",
-				range: "取值范围为1~1000"
-			}
+            appName : {
+                required : I18n.system_please_input+"AppName",
+                rangelength: I18n.jobgroup_field_appName_length ,
+                myValid01: I18n.jobgroup_field_appName_limit
+            },
+            title : {
+                required : I18n.system_please_input + I18n.jobgroup_field_title ,
+                rangelength: I18n.jobgroup_field_title_length
+            },
+            order : {
+                required : I18n.system_please_input + I18n.jobgroup_field_order ,
+                digits: I18n.jobgroup_field_order_digits ,
+                range: I18n.jobgroup_field_orderrange
+            }
 		},
 		},
 		highlight : function(element) {
 		highlight : function(element) {
 			$(element).closest('.form-group').addClass('has-error');
 			$(element).closest('.form-group').addClass('has-error');
@@ -202,8 +210,9 @@ $(function() {
 					$('#addModal').modal('hide');
 					$('#addModal').modal('hide');
 
 
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: '更新成功',
+						title: I18n.system_tips ,
+                        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() {
 					});
 					});
 				} else {
 				} else {
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: (data.msg || "更新失败"),
+						title: I18n.system_tips,
+                        btn: [ I18n.system_ok ],
+						content: (data.msg || I18n.system_update_fail  ),
 						icon: '2'
 						icon: '2'
 					});
 					});
 				}
 				}

+ 105 - 85
xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js

@@ -1,4 +1,5 @@
 $(function() {
 $(function() {
+
 	// init date tables
 	// init date tables
 	var jobTable = $("#job_list").dataTable({
 	var jobTable = $("#job_list").dataTable({
 		"deferRender": true,
 		"deferRender": true,
@@ -10,6 +11,7 @@ $(function() {
 	        data : function ( d ) {
 	        data : function ( d ) {
 	        	var obj = {};
 	        	var obj = {};
 	        	obj.jobGroup = $('#jobGroup').val();
 	        	obj.jobGroup = $('#jobGroup').val();
+                obj.jobDesc = $('#jobDesc').val();
 	        	obj.executorHandler = $('#executorHandler').val();
 	        	obj.executorHandler = $('#executorHandler').val();
 	        	obj.start = d.start;
 	        	obj.start = d.start;
 	        	obj.length = d.length;
 	        	obj.length = d.length;
@@ -18,12 +20,18 @@ $(function() {
 	    },
 	    },
 	    "searching": false,
 	    "searching": false,
 	    "ordering": false,
 	    "ordering": false,
-	    //"scrollX": true,	// X轴滚动条,取消自适应
+	    //"scrollX": true,	// scroll x,close self-adaption
 	    "columns": [
 	    "columns": [
-	                { "data": 'id', "bSortable": false, "visible" : true},
+	                {
+	                	"data": 'id',
+						"bSortable": false,
+						"visible" : true,
+						"width":'10%'
+					},
 	                { 
 	                { 
 	                	"data": 'jobGroup', 
 	                	"data": 'jobGroup', 
 	                	"visible" : false,
 	                	"visible" : false,
+						"width":'20%',
 	                	"render": function ( data, type, row ) {
 	                	"render": function ( data, type, row ) {
 	            			var groupMenu = $("#jobGroup").find("option");
 	            			var groupMenu = $("#jobGroup").find("option");
 	            			for ( var index in $("#jobGroup").find("option")) {
 	            			for ( var index in $("#jobGroup").find("option")) {
@@ -34,28 +42,30 @@ $(function() {
 	            			return data;
 	            			return data;
 	            		}
 	            		}
             		},
             		},
-	                { "data": 'jobDesc', "visible" : true,"width":'20%'},
+	                {
+	                	"data": 'jobDesc',
+						"visible" : true,
+						"width":'20%'
+					},
 					{
 					{
 						"data": 'glueType',
 						"data": 'glueType',
 						"width":'20%',
 						"width":'20%',
 						"visible" : true,
 						"visible" : true,
 						"render": function ( data, type, row ) {
 						"render": function ( data, type, row ) {
-							if ('GLUE_GROOVY'==row.glueType) {
-								return "GLUE模式(Java)";
-							} else if ('GLUE_SHELL'==row.glueType) {
-								return "GLUE模式(Shell)";
-							} else if ('GLUE_PYTHON'==row.glueType) {
-								return "GLUE模式(Python)";
-							}else if  ('GLUE_NODEJS'==row.glueType){
-								return "GLUE模式(Nodejs)";
-							} else if ('BEAN'==row.glueType) {
-								return "BEAN模式:" + row.executorHandler;
-							}
-							return row.executorHandler;
+							var glueTypeTitle = findGlueTypeTitle(row.glueType);
+                            if (row.executorHandler) {
+                                return glueTypeTitle +":" + row.executorHandler;
+                            } else {
+                                return glueTypeTitle;
+                            }
 						}
 						}
 					},
 					},
 	                { "data": 'executorParam', "visible" : false},
 	                { "data": 'executorParam', "visible" : false},
-					{ "data": 'jobCron', "visible" : true,"width":'10%'},
+					{
+						"data": 'jobCron',
+						"visible" : true,
+						"width":'10%'
+					},
 	                { 
 	                { 
 	                	"data": 'addTime', 
 	                	"data": 'addTime', 
 	                	"visible" : false, 
 	                	"visible" : false, 
@@ -72,7 +82,6 @@ $(function() {
 	                },
 	                },
 	                { "data": 'author', "visible" : true, "width":'10%'},
 	                { "data": 'author', "visible" : true, "width":'10%'},
 	                { "data": 'alarmEmail', "visible" : false},
 	                { "data": 'alarmEmail', "visible" : false},
-	                { "data": 'glueType', "visible" : false},
 	                { 
 	                { 
 	                	"data": 'jobStatus',
 	                	"data": 'jobStatus',
 						"width":'10%',
 						"width":'10%',
@@ -81,24 +90,24 @@ $(function() {
 	                		if ('NORMAL' == data) {
 	                		if ('NORMAL' == data) {
 	                			return '<small class="label label-success" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
 	                			return '<small class="label label-success" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
 							} else if ('PAUSED' == data){
 							} else if ('PAUSED' == data){
-								return '<small class="label label-default" title="暂停" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
+								return '<small class="label label-default" ><i class="fa fa-clock-o"></i>'+ data +'</small>';
 							} else if ('BLOCKED' == data){
 							} else if ('BLOCKED' == data){
-								return '<small class="label label-default" title="阻塞[串行]" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
+								return '<small class="label label-default" ><i class="fa fa-clock-o"></i>'+ data +'</small>';
 							}
 							}
 	                		return data;
 	                		return data;
 	                	}
 	                	}
 	                },
 	                },
 	                {
 	                {
-						"data": '操作' ,
+						"data": I18n.system_opt ,
 						"width":'15%',
 						"width":'15%',
 	                	"render": function ( data, type, row ) {
 	                	"render": function ( data, type, row ) {
 	                		return function(){
 	                		return function(){
 	                			// status
 	                			// status
 	                			var pause_resume = "";
 	                			var pause_resume = "";
 	                			if ('NORMAL' == row.jobStatus) {
 	                			if ('NORMAL' == row.jobStatus) {
-	                				pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_pause" type="button">暂停</button>  ';
+	                				pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_pause" type="button">'+ I18n.jobinfo_opt_pause +'</button>  ';
 								} else if ('PAUSED' == row.jobStatus){
 								} else if ('PAUSED' == row.jobStatus){
-									pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_resume" type="button">恢复</button>  ';
+									pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_resume" type="button">'+ I18n.jobinfo_opt_resume +'</button>  ';
 								}
 								}
 	                			// log url
 	                			// log url
 	                			var logUrl = base_url +'/joblog?jobId='+ row.id;
 	                			var logUrl = base_url +'/joblog?jobId='+ row.id;
@@ -113,12 +122,12 @@ $(function() {
 								// html
 								// html
                                 tableData['key'+row.id] = row;
                                 tableData['key'+row.id] = row;
 								var html = '<p id="'+ row.id +'" >'+
 								var html = '<p id="'+ row.id +'" >'+
-									'<button class="btn btn-primary btn-xs job_operate" _type="job_trigger" type="button">执行</button>  '+
+									'<button class="btn btn-primary btn-xs job_operate" _type="job_trigger" type="button">'+ I18n.jobinfo_opt_run +'</button>  '+
 									pause_resume +
 									pause_resume +
-									'<button class="btn btn-primary btn-xs" type="job_del" type="button" onclick="javascript:window.open(\'' + logUrl + '\')" >日志</button><br>  '+
-									'<button class="btn btn-warning btn-xs update" type="button">编辑</button>  '+
+									'<button class="btn btn-primary btn-xs" type="job_del" type="button" onclick="javascript:window.open(\'' + logUrl + '\')" >'+ I18n.jobinfo_opt_log +'</button><br>  '+
+									'<button class="btn btn-warning btn-xs update" type="button">'+ I18n.system_opt_edit +'</button>  '+
 									codeBtn +
 									codeBtn +
-									'<button class="btn btn-danger btn-xs job_operate" _type="job_del" type="button">删除</button>  '+
+									'<button class="btn btn-danger btn-xs job_operate" _type="job_del" type="button">'+ I18n.system_opt_del +'</button>  '+
 									'</p>';
 									'</p>';
 
 
 	                			return html;
 	                			return html;
@@ -127,27 +136,27 @@ $(function() {
 	                }
 	                }
 	            ],
 	            ],
 		"language" : {
 		"language" : {
-			"sProcessing" : "处理中...",
-			"sLengthMenu" : "每页 _MENU_ 条记录",
-			"sZeroRecords" : "没有匹配结果",
-			"sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 )",
-			"sInfoEmpty" : "无记录",
-			"sInfoFiltered" : "(由 _MAX_ 项结果过滤)",
+			"sProcessing" : I18n.dataTable_sProcessing ,
+			"sLengthMenu" : I18n.dataTable_sLengthMenu ,
+			"sZeroRecords" : I18n.dataTable_sZeroRecords ,
+			"sInfo" : I18n.dataTable_sInfo ,
+			"sInfoEmpty" : I18n.dataTable_sInfoEmpty ,
+			"sInfoFiltered" : I18n.dataTable_sInfoFiltered ,
 			"sInfoPostFix" : "",
 			"sInfoPostFix" : "",
-			"sSearch" : "搜索:",
+			"sSearch" : I18n.dataTable_sSearch ,
 			"sUrl" : "",
 			"sUrl" : "",
-			"sEmptyTable" : "表中数据为空",
-			"sLoadingRecords" : "载入中...",
+			"sEmptyTable" : I18n.dataTable_sEmptyTable ,
+			"sLoadingRecords" : I18n.dataTable_sLoadingRecords ,
 			"sInfoThousands" : ",",
 			"sInfoThousands" : ",",
 			"oPaginate" : {
 			"oPaginate" : {
-				"sFirst" : "首页",
-				"sPrevious" : "上页",
-				"sNext" : "下页",
-				"sLast" : "末页"
+				"sFirst" : I18n.dataTable_sFirst ,
+				"sPrevious" : I18n.dataTable_sPrevious ,
+				"sNext" : I18n.dataTable_sNext ,
+				"sLast" : I18n.dataTable_sLast
 			},
 			},
 			"oAria" : {
 			"oAria" : {
-				"sSortAscending" : ": 以升序排列此列",
-				"sSortDescending" : ": 以降序排列此列"
+				"sSortAscending" : I18n.dataTable_sSortAscending ,
+				"sSortDescending" : I18n.dataTable_sSortDescending
 			}
 			}
 		}
 		}
 	});
 	});
@@ -155,7 +164,7 @@ $(function() {
     // table data
     // table data
     var tableData = {};
     var tableData = {};
 
 
-	// 搜索按钮
+	// search btn
 	$('#searchBtn').on('click', function(){
 	$('#searchBtn').on('click', function(){
 		jobTable.fnDraw();
 		jobTable.fnDraw();
 	});
 	});
@@ -175,19 +184,19 @@ $(function() {
 
 
 		var type = $(this).attr("_type");
 		var type = $(this).attr("_type");
 		if ("job_pause" == type) {
 		if ("job_pause" == type) {
-			typeName = "暂停";
+			typeName = I18n.jobinfo_opt_pause ;
 			url = base_url + "/jobinfo/pause";
 			url = base_url + "/jobinfo/pause";
 			needFresh = true;
 			needFresh = true;
 		} else if ("job_resume" == type) {
 		} else if ("job_resume" == type) {
-			typeName = "恢复";
+			typeName = I18n.jobinfo_opt_resume ;
 			url = base_url + "/jobinfo/resume";
 			url = base_url + "/jobinfo/resume";
 			needFresh = true;
 			needFresh = true;
 		} else if ("job_del" == type) {
 		} else if ("job_del" == type) {
-			typeName = "删除";
+			typeName = I18n.system_opt_del ;
 			url = base_url + "/jobinfo/remove";
 			url = base_url + "/jobinfo/remove";
 			needFresh = true;
 			needFresh = true;
 		} else if ("job_trigger" == type) {
 		} else if ("job_trigger" == type) {
-			typeName = "执行";
+			typeName = I18n.jobinfo_opt_run ;
 			url = base_url + "/jobinfo/trigger";
 			url = base_url + "/jobinfo/trigger";
 		} else {
 		} else {
 			return;
 			return;
@@ -195,7 +204,11 @@ $(function() {
 		
 		
 		var id = $(this).parent('p').attr("id");
 		var id = $(this).parent('p').attr("id");
 
 
-		layer.confirm('确认' + typeName + '?', {icon: 3, title:'系统提示'}, function(index){
+		layer.confirm( I18n.system_ok + typeName + '?', {
+			icon: 3,
+			title: I18n.system_tips ,
+            btn: [ I18n.system_ok, I18n.system_cancel ]
+		}, function(index){
 			layer.close(index);
 			layer.close(index);
 
 
 			$.ajax({
 			$.ajax({
@@ -209,8 +222,9 @@ $(function() {
 					if (data.code == 200) {
 					if (data.code == 200) {
 
 
 						layer.open({
 						layer.open({
-							title: '系统提示',
-							content: typeName + "成功",
+							title: I18n.system_tips,
+                            btn: [ I18n.system_ok ],
+							content: typeName + I18n.system_success ,
 							icon: '1',
 							icon: '1',
 							end: function(layero, index){
 							end: function(layero, index){
 								if (needFresh) {
 								if (needFresh) {
@@ -221,8 +235,9 @@ $(function() {
 						});
 						});
 					} else {
 					} else {
 						layer.open({
 						layer.open({
-							title: '系统提示',
-							content: (data.msg || typeName + "失败"),
+							title: I18n.system_tips,
+                            btn: [ I18n.system_ok ],
+							content: (data.msg || typeName + I18n.system_fail ),
 							icon: '2'
 							icon: '2'
 						});
 						});
 					}
 					}
@@ -230,15 +245,8 @@ $(function() {
 			});
 			});
 		});
 		});
 	});
 	});
-	
-	// jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线”
-	jQuery.validator.addMethod("myValid01", function(value, element) {
-		var length = value.length;
-		var valid = /^[a-zA-Z][a-zA-Z0-9_]*$/;
-		return this.optional(element) || valid.test(value);
-	}, "只支持英文字母开头,只含有英文字母、数字和下划线");
-	
-	// 新增
+
+	// add
 	$(".add").click(function(){
 	$(".add").click(function(){
 		$('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
 		$('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
 	});
 	});
@@ -260,13 +268,13 @@ $(function() {
         }, 
         }, 
         messages : {  
         messages : {  
             jobDesc : {
             jobDesc : {
-            	required :"请输入“描述”."
+            	required : I18n.system_please_input + I18n.jobinfo_field_jobdesc
             },
             },
             jobCron : {
             jobCron : {
-            	required :"请输入“Cron”."
+            	required : I18n.system_please_input + "Cron"
             },
             },
             author : {
             author : {
-            	required : "请输入“负责人”."
+            	required : I18n.system_please_input + I18n.jobinfo_field_author
             }
             }
         },
         },
 		highlight : function(element) {  
 		highlight : function(element) {  
@@ -284,8 +292,9 @@ $(function() {
     			if (data.code == "200") {
     			if (data.code == "200") {
 					$('#addModal').modal('hide');
 					$('#addModal').modal('hide');
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: '新增任务成功',
+						title: I18n.system_tips ,
+                        btn: [ I18n.system_ok ],
+						content: I18n.system_add_suc ,
 						icon: '1',
 						icon: '1',
 						end: function(layero, index){
 						end: function(layero, index){
 							jobTable.fnDraw();
 							jobTable.fnDraw();
@@ -294,8 +303,9 @@ $(function() {
 					});
 					});
     			} else {
     			} else {
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: (data.msg || "新增失败"),
+						title: I18n.system_tips ,
+                        btn: [ I18n.system_ok ],
+						content: (data.msg || I18n.system_add_fail),
 						icon: '2'
 						icon: '2'
 					});
 					});
     			}
     			}
@@ -312,7 +322,7 @@ $(function() {
 	});
 	});
 
 
 
 
-    // 运行模式
+    // glueType change
     $(".glueType").change(function(){
     $(".glueType").change(function(){
 		// executorHandler
 		// executorHandler
         var $executorHandler = $(this).parents("form").find("input[name='executorHandler']");
         var $executorHandler = $(this).parents("form").find("input[name='executorHandler']");
@@ -339,19 +349,11 @@ $(function() {
 		}
 		}
 	});
 	});
 
 
-	// 更新
+	// update
 	$("#job_list").on('click', '.update',function() {
 	$("#job_list").on('click', '.update',function() {
 
 
         var id = $(this).parent('p').attr("id");
         var id = $(this).parent('p').attr("id");
         var row = tableData['key'+id];
         var row = tableData['key'+id];
-        if (!row) {
-            layer.open({
-                title: '系统提示',
-                content: ("任务信息加载失败,请刷新页面"),
-                icon: '2'
-            });
-            return;
-        }
 
 
 		// base data
 		// base data
 		$("#updateModal .form input[name='id']").val( row.id );
 		$("#updateModal .form input[name='id']").val( row.id );
@@ -392,13 +394,13 @@ $(function() {
 		},
 		},
 		messages : {
 		messages : {
 			jobDesc : {
 			jobDesc : {
-				required :"请输入“描述”."
+                required : I18n.system_please_input + I18n.jobinfo_field_jobdesc
 			},
 			},
 			jobCron : {
 			jobCron : {
-				required :"请输入“Cron”."
+				required : I18n.system_please_input + "Cron"
 			},
 			},
 			author : {
 			author : {
-				required : "请输入“负责人”."
+				required : I18n.system_please_input + I18n.jobinfo_field_author
 			}
 			}
 		},
 		},
 		highlight : function(element) {
 		highlight : function(element) {
@@ -413,12 +415,13 @@ $(function() {
         },
         },
         submitHandler : function(form) {
         submitHandler : function(form) {
 			// post
 			// post
-    		$.post(base_url + "/jobinfo/reschedule", $("#updateModal .form").serialize(), function(data, status) {
+    		$.post(base_url + "/jobinfo/update", $("#updateModal .form").serialize(), function(data, status) {
     			if (data.code == "200") {
     			if (data.code == "200") {
 					$('#updateModal').modal('hide');
 					$('#updateModal').modal('hide');
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: '更新成功',
+						title: I18n.system_tips ,
+                        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();
@@ -427,8 +430,9 @@ $(function() {
 					});
 					});
     			} else {
     			} else {
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: (data.msg || "更新失败"),
+						title: I18n.system_tips ,
+                        btn: [ I18n.system_ok ],
+						content: (data.msg || I18n.system_update_fail ),
 						icon: '2'
 						icon: '2'
 					});
 					});
     			}
     			}
@@ -439,4 +443,20 @@ $(function() {
 		$("#updateModal .form")[0].reset()
 		$("#updateModal .form")[0].reset()
 	});
 	});
 
 
+    /**
+	 * find title by name, GlueType
+     */
+	function findGlueTypeTitle(glueType) {
+		var glueTypeTitle;
+        $("#addModal .form select[name=glueType] option").each(function () {
+            var name = $(this).val();
+            var title = $(this).text();
+            if (glueType == name) {
+                glueTypeTitle = title;
+                return false
+            }
+        });
+        return glueTypeTitle;
+    }
+
 });
 });

+ 2 - 2
xxl-job-admin/src/main/webapp/static/js/joblog.detail.1.js

@@ -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() {
     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;
         }
         }
 
 

+ 102 - 91
xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js

@@ -1,6 +1,6 @@
 $(function() {
 $(function() {
 
 
-	// 任务组列表选中, 任务列表初始化和选中
+	// jobGroup change, job list init and select
 	$("#jobGroup").on("change", function () {
 	$("#jobGroup").on("change", function () {
 		var jobGroup = $(this).children('option:selected').val();
 		var jobGroup = $(this).children('option:selected').val();
 		$.ajax({
 		$.ajax({
@@ -11,7 +11,7 @@ $(function() {
 			dataType : "json",
 			dataType : "json",
 			success : function(data){
 			success : function(data){
 				if (data.code == 200) {
 				if (data.code == 200) {
-					$("#jobId").html('<option value="0" >全部</option>');
+					$("#jobId").html( '<option value="0" >'+ I18n.system_all +'</option>' );
 					$.each(data.content, function (n, value) {
 					$.each(data.content, function (n, value) {
                         $("#jobId").append('<option value="' + value.id + '" >' + value.jobDesc + '</option>');
                         $("#jobId").append('<option value="' + value.id + '" >' + value.jobDesc + '</option>');
                     });
                     });
@@ -20,8 +20,9 @@ $(function() {
                     }
                     }
 				} else {
 				} else {
 					layer.open({
 					layer.open({
-						title: '系统提示',
-						content: (data.msg || "接口异常"),
+						title: I18n.system_tips ,
+                        btn: [ I18n.system_ok ],
+						content: (data.msg || I18n.system_api_error ),
 						icon: '2'
 						icon: '2'
 					});
 					});
 				}
 				}
@@ -33,7 +34,16 @@ $(function() {
         $("#jobGroup").change();
         $("#jobGroup").change();
 	}
 	}
 
 
-	// 过滤时间
+	// filter Time
+    var rangesConf = {};
+    rangesConf[I18n.daterangepicker_ranges_recent_hour] = [moment().subtract(1, 'hours'), 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,
@@ -42,29 +52,21 @@ $(function() {
 		timePickerIncrement: 10, 	// 时间的增量,单位为分钟
 		timePickerIncrement: 10, 	// 时间的增量,单位为分钟
         timePicker24Hour : true,
         timePicker24Hour : true,
         opens : 'left', //日期选择框的弹出位置
         opens : 'left', //日期选择框的弹出位置
-		ranges: {
-			'最近1小时': [moment().subtract(1, 'hours'), moment()],
-			'今日': [moment().startOf('day'), moment().endOf('day')],
-			'昨日': [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')],
-			'最近7日': [moment().subtract(6, 'days'), moment()],
-			'最近30日': [moment().subtract(29, 'days'), moment()],
-			'本月': [moment().startOf('month'), moment().endOf('month')],
-			'上个月': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
-		},
+		ranges: rangesConf,
         locale : {
         locale : {
             format: 'YYYY-MM-DD HH:mm:ss',
             format: 'YYYY-MM-DD HH:mm:ss',
             separator : ' - ',
             separator : ' - ',
-        	customRangeLabel : '自定义',
-            applyLabel : '确定',
-            cancelLabel : '取消',
-            fromLabel : '起始时间',
-            toLabel : '结束时间',
-            daysOfWeek : [ '日', '一', '二', '三', '四', '五', '六' ],
-            monthNames : [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ],
-            firstDay : 1,
-            startDate: moment().startOf('day'),
-            endDate: moment().endOf('day')
-        }
+            customRangeLabel : I18n.daterangepicker_custom_name ,
+            applyLabel : I18n.system_ok ,
+            cancelLabel : I18n.system_cancel ,
+            fromLabel : I18n.daterangepicker_custom_starttime ,
+            toLabel : I18n.daterangepicker_custom_endtime ,
+            daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') ,        // '日', '一', '二', '三', '四', '五', '六'
+            monthNames : I18n.daterangepicker_custom_monthnames.split(',') ,        // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'
+            firstDay : 1
+        },
+        startDate: rangesConf[I18n.daterangepicker_ranges_today][0],
+        endDate: rangesConf[I18n.daterangepicker_ranges_today][1]
 	});
 	});
 
 
 	// init date tables
 	// init date tables
@@ -74,6 +76,7 @@ $(function() {
 	    "serverSide": true,
 	    "serverSide": true,
 		"ajax": {
 		"ajax": {
 	        url: base_url + "/joblog/pageList" ,
 	        url: base_url + "/joblog/pageList" ,
+            type:"post",
 	        data : function ( d ) {
 	        data : function ( d ) {
 	        	var obj = {};
 	        	var obj = {};
 	        	obj.jobGroup = $('#jobGroup').val();
 	        	obj.jobGroup = $('#jobGroup').val();
@@ -92,24 +95,18 @@ $(function() {
 					{
 					{
 						"data": 'jobId',
 						"data": 'jobId',
 						"visible" : true,
 						"visible" : true,
+                        "width":'10%',
 						"render": function ( data, type, row ) {
 						"render": function ( data, type, row ) {
-							var glueTypeTitle = row.glueType;
-							if ('GLUE_GROOVY'==row.glueType) {
-								glueTypeTitle = "GLUE模式(Java)";
-							} else if ('GLUE_SHELL'==row.glueType) {
-								glueTypeTitle = "GLUE模式(Shell)";
-							} else if ('GLUE_PYTHON'==row.glueType) {
-								glueTypeTitle = "GLUE模式(Python)";
-							}else if ('GLUE_NODEJS'==row.glueType) {
-								glueTypeTitle = "GLUE模式(Nodejs)";
-							} else if ('BEAN'==row.glueType) {
-								glueTypeTitle = "BEAN模式:" + row.executorHandler;
-							}
+
+                            var glueTypeTitle = GlueTypeEnum[row.glueType];
+                            if (row.executorHandler) {
+                                glueTypeTitle = glueTypeTitle +":" + row.executorHandler;
+                            }
 
 
 							var temp = '';
 							var temp = '';
-							temp += '执行器地址:' + (row.executorAddress?row.executorAddress:'');
-							temp += '<br>运行模式:' + glueTypeTitle;
-							temp += '<br>任务参数:' + row.executorParam;
+							temp += I18n.joblog_field_executorAddress + ':' + (row.executorAddress?row.executorAddress:'');
+							temp += '<br>'+ I18n.jobinfo_field_gluetype +':' + glueTypeTitle;
+							temp += '<br>'+ I18n.jobinfo_field_executorparam +':' + row.executorParam;
 
 
 							return '<a class="logTips" href="javascript:;" >'+ row.jobId +'<span style="display:none;">'+ temp +'</span></a>';
 							return '<a class="logTips" href="javascript:;" >'+ row.jobId +'<span style="display:none;">'+ temp +'</span></a>';
 						}
 						}
@@ -117,18 +114,20 @@ $(function() {
 					{ "data": 'jobGroup', "visible" : false},
 					{ "data": 'jobGroup', "visible" : false},
 					{
 					{
 						"data": 'triggerTime',
 						"data": 'triggerTime',
+                        "width":'16%',
 						"render": function ( data, type, row ) {
 						"render": function ( data, type, row ) {
 							return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
 							return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
 						}
 						}
 					},
 					},
 					{
 					{
 						"data": 'triggerCode',
 						"data": 'triggerCode',
+                        "width":'12%',
 						"render": function ( data, type, row ) {
 						"render": function ( data, type, row ) {
 							var html = data;
 							var html = data;
 							if (data == 200) {
 							if (data == 200) {
-								html = '<span style="color: green">成功</span>';
+								html = '<span style="color: green">'+ I18n.system_success +'</span>';
 							} else if (data == 500) {
 							} else if (data == 500) {
-								html = '<span style="color: red">失败</span>';
+								html = '<span style="color: red">'+ I18n.system_fail +'</span>';
 							} else if (data == 0) {
 							} else if (data == 0) {
                                 html = '';
                                 html = '';
 							}
 							}
@@ -137,26 +136,29 @@ $(function() {
 					},
 					},
 					{
 					{
 						"data": 'triggerMsg',
 						"data": 'triggerMsg',
+                        "width":'12%',
 						"render": function ( data, type, row ) {
 						"render": function ( data, type, row ) {
-							return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
+							return data?'<a class="logTips" href="javascript:;" >'+ I18n.system_show +'<span style="display:none;">'+ data +'</span></a>':I18n.system_empty;
 						}
 						}
 					},
 					},
 	                { 
 	                { 
 	                	"data": 'handleTime',
 	                	"data": 'handleTime',
+                        "width":'16%',
 	                	"render": function ( data, type, row ) {
 	                	"render": function ( data, type, row ) {
 	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
 	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
 	                	}
 	                	}
 	                },
 	                },
 	                {
 	                {
 						"data": 'handleCode',
 						"data": 'handleCode',
+                        "width":'12%',
 						"render": function ( data, type, row ) {
 						"render": function ( data, type, row ) {
                             var html = data;
                             var html = data;
                             if (data == 200) {
                             if (data == 200) {
-                                html = '<span style="color: green">成功</span>';
+                                html = '<span style="color: green">'+ I18n.joblog_handleCode_200 +'</span>';
                             } else if (data == 500) {
                             } else if (data == 500) {
-                                html = '<span style="color: red">失败</span>';
+                                html = '<span style="color: red">'+ I18n.joblog_handleCode_500 +'</span>';
                             } else if (data == 501) {
                             } else if (data == 501) {
-                                html = '<span style="color: red">失败重试</span>';
+                                html = '<span style="color: red">'+ I18n.joblog_handleCode_501 +'</span>';
                             } else if (data == 0) {
                             } else if (data == 0) {
                                 html = '';
                                 html = '';
                             }
                             }
@@ -165,21 +167,22 @@ $(function() {
 	                },
 	                },
 	                { 
 	                { 
 	                	"data": 'handleMsg',
 	                	"data": 'handleMsg',
+                        "width":'12%',
 	                	"render": function ( data, type, row ) {
 	                	"render": function ( data, type, row ) {
-	                		return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
+	                		return data?'<a class="logTips" href="javascript:;" >'+ I18n.system_show +'<span style="display:none;">'+ data +'</span></a>':I18n.system_empty;
 	                	}
 	                	}
 	                },
 	                },
 	                {
 	                {
 						"data": 'handleMsg' ,
 						"data": 'handleMsg' ,
 						"bSortable": false,
 						"bSortable": false,
-						"width": "8%" ,
+                        "width":'10%',
 	                	"render": function ( data, type, row ) {
 	                	"render": function ( data, type, row ) {
 	                		// better support expression or string, not function
 	                		// better support expression or string, not function
 	                		return function () {
 	                		return function () {
 		                		if (row.triggerCode == 200){
 		                		if (row.triggerCode == 200){
-		                			var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">执行日志</a>';
+		                			var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">'+ I18n.joblog_rolling_log +'</a>';
 		                			if(row.handleCode == 0){
 		                			if(row.handleCode == 0){
-		                				temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'" style="color: red;" >终止任务</a>';
+		                				temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'" style="color: red;" >'+ I18n.joblog_kill_log +'</a>';
 		                			}
 		                			}
 		                			return temp;
 		                			return temp;
 		                		}
 		                		}
@@ -188,44 +191,44 @@ $(function() {
 	                	}
 	                	}
 	                }
 	                }
 	            ],
 	            ],
-		"language" : {
-			"sProcessing" : "处理中...",
-			"sLengthMenu" : "每页 _MENU_ 条记录",
-			"sZeroRecords" : "没有匹配结果",
-			"sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 )",
-			"sInfoEmpty" : "无记录",
-			"sInfoFiltered" : "(由 _MAX_ 项结果过滤)",
-			"sInfoPostFix" : "",
-			"sSearch" : "搜索:",
-			"sUrl" : "",
-			"sEmptyTable" : "表中数据为空",
-			"sLoadingRecords" : "载入中...",
-			"sInfoThousands" : ",",
-			"oPaginate" : {
-				"sFirst" : "首页",
-				"sPrevious" : "上页",
-				"sNext" : "下页",
-				"sLast" : "末页"
-			},
-			"oAria" : {
-				"sSortAscending" : ": 以升序排列此列",
-				"sSortDescending" : ": 以降序排列此列"
-			}
-		}
+        "language" : {
+            "sProcessing" : I18n.dataTable_sProcessing ,
+            "sLengthMenu" : I18n.dataTable_sLengthMenu ,
+            "sZeroRecords" : I18n.dataTable_sZeroRecords ,
+            "sInfo" : I18n.dataTable_sInfo ,
+            "sInfoEmpty" : I18n.dataTable_sInfoEmpty ,
+            "sInfoFiltered" : I18n.dataTable_sInfoFiltered ,
+            "sInfoPostFix" : "",
+            "sSearch" : I18n.dataTable_sSearch ,
+            "sUrl" : "",
+            "sEmptyTable" : I18n.dataTable_sEmptyTable ,
+            "sLoadingRecords" : I18n.dataTable_sLoadingRecords ,
+            "sInfoThousands" : ",",
+            "oPaginate" : {
+                "sFirst" : I18n.dataTable_sFirst ,
+                "sPrevious" : I18n.dataTable_sPrevious ,
+                "sNext" : I18n.dataTable_sNext ,
+                "sLast" : I18n.dataTable_sLast
+            },
+            "oAria" : {
+                "sSortAscending" : I18n.dataTable_sSortAscending ,
+                "sSortDescending" : I18n.dataTable_sSortDescending
+            }
+        }
 	});
 	});
 	
 	
-	// 日志弹框提示
+	// logTips alert
 	$('#joblog_list').on('click', '.logTips', function(){
 	$('#joblog_list').on('click', '.logTips', function(){
 		var msg = $(this).find('span').html();
 		var msg = $(this).find('span').html();
 		ComAlertTec.show(msg);
 		ComAlertTec.show(msg);
 	});
 	});
 	
 	
-	// 搜索按钮
+	// search Btn
 	$('#searchBtn').on('click', function(){
 	$('#searchBtn').on('click', function(){
 		logTable.fnDraw();
 		logTable.fnDraw();
 	});
 	});
 	
 	
-	// 查看执行器详细执行日志
+	// logDetail look
 	$('#joblog_list').on('click', '.logDetail', function(){
 	$('#joblog_list').on('click', '.logDetail', function(){
 		var _id = $(this).attr('_id');
 		var _id = $(this).attr('_id');
 		
 		
@@ -234,12 +237,16 @@ $(function() {
 	});
 	});
 
 
 	/**
 	/**
-	 * 终止任务
+	 * log Kill
 	 */
 	 */
 	$('#joblog_list').on('click', '.logKill', function(){
 	$('#joblog_list').on('click', '.logKill', function(){
 		var _id = $(this).attr('_id');
 		var _id = $(this).attr('_id');
 
 
-        layer.confirm('确认主动终止任务?', {icon: 3, title:'系统提示'}, function(index){
+        layer.confirm( (I18n.system_ok + I18n.joblog_kill_log + '?'), {
+        	icon: 3,
+			title: I18n.system_tips ,
+            btn: [ I18n.system_ok, I18n.system_cancel ]
+		}, function(index){
             layer.close(index);
             layer.close(index);
 
 
             $.ajax({
             $.ajax({
@@ -250,8 +257,9 @@ $(function() {
                 success : function(data){
                 success : function(data){
                     if (data.code == 200) {
                     if (data.code == 200) {
                         layer.open({
                         layer.open({
-                            title: '系统提示',
-                            content: '操作成功',
+                            title: I18n.system_tips,
+                            btn: [ I18n.system_ok ],
+                            content: I18n.system_opt_suc ,
                             icon: '1',
                             icon: '1',
                             end: function(layero, index){
                             end: function(layero, index){
                                 logTable.fnDraw();
                                 logTable.fnDraw();
@@ -259,8 +267,9 @@ $(function() {
                         });
                         });
                     } else {
                     } else {
                         layer.open({
                         layer.open({
-                            title: '系统提示',
-                            content: (data.msg || "操作失败"),
+                            title: I18n.system_tips,
+                            btn: [ I18n.system_ok ],
+                            content: (data.msg || I18n.system_opt_fail ),
                             icon: '2'
                             icon: '2'
                         });
                         });
                     }
                     }
@@ -271,7 +280,7 @@ $(function() {
 	});
 	});
 
 
 	/**
 	/**
-	 * 清理任务Log
+	 * clear Log
 	 */
 	 */
 	$('#clearLog').on('click', function(){
 	$('#clearLog').on('click', function(){
 
 
@@ -295,8 +304,9 @@ $(function() {
 			if (data.code == "200") {
 			if (data.code == "200") {
 				$('#clearLogModal').modal('hide');
 				$('#clearLogModal').modal('hide');
 				layer.open({
 				layer.open({
-					title: '系统提示',
-					content: '日志清理成功',
+					title: I18n.system_tips ,
+                    btn: [ I18n.system_ok ],
+					content: (I18n.joblog_clean_log + I18n.system_success) ,
 					icon: '1',
 					icon: '1',
 					end: function(layero, index){
 					end: function(layero, index){
 						logTable.fnDraw();
 						logTable.fnDraw();
@@ -304,8 +314,9 @@ $(function() {
 				});
 				});
 			} else {
 			} else {
 				layer.open({
 				layer.open({
-					title: '系统提示',
-					content: (data.msg || "日志清理失败"),
+					title: I18n.system_tips ,
+                    btn: [ I18n.system_ok ],
+					content: (data.msg || (I18n.joblog_clean_log + I18n.system_fail) ),
 					icon: '2'
 					icon: '2'
 				});
 				});
 			}
 			}
@@ -318,7 +329,7 @@ $(function() {
 });
 });
 
 
 
 
-// 提示-科技主题
+// Com Alert by Tec theme
 var ComAlertTec = {
 var ComAlertTec = {
 	html:function(){
 	html:function(){
 		var html =
 		var html =
@@ -328,7 +339,7 @@ var ComAlertTec = {
 			'<div class="modal-body"><div class="alert" style="color:#fff;"></div></div>' +
 			'<div class="modal-body"><div class="alert" style="color:#fff;"></div></div>' +
 			'<div class="modal-footer">' +
 			'<div class="modal-footer">' +
 			'<div class="text-center" >' +
 			'<div class="text-center" >' +
-			'<button type="button" class="btn btn-info ok" data-dismiss="modal" >确认</button>' +
+			'<button type="button" class="btn btn-info ok" data-dismiss="modal" >'+ I18n.system_ok +'</button>' +
 			'</div>' +
 			'</div>' +
 			'</div>' +
 			'</div>' +
 			'</div>' +
 			'</div>' +
@@ -342,7 +353,7 @@ var ComAlertTec = {
 			$('body').append(ComAlertTec.html());
 			$('body').append(ComAlertTec.html());
 		}
 		}
 
 
-		// 弹框初始
+		// init com alert
 		$('#ComAlertTec .alert').html(msg);
 		$('#ComAlertTec .alert').html(msg);
 		$('#ComAlertTec').modal('show');
 		$('#ComAlertTec').modal('show');
 
 

+ 13 - 20
xxl-job-admin/src/main/webapp/static/js/login.1.js

@@ -1,12 +1,13 @@
 $(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(){
         }, 
         }, 
         messages : {  
         messages : {  
         	userName : {  
         	userName : {  
-                required :"请输入登录账号."  ,
-                minlength:"登录账号不应低于5位",
-                maxlength:"登录账号不应超过18位"
-            },  
+                required  : I18n.login_username_empty,
+                minlength : I18n.login_username_lt_5
+            },
             password : {
             password : {
-            	required :"请输入登录密码."  ,
-                minlength:"登录密码不应低于5位",
-                maxlength:"登录密码不应超过18位"
+            	required  : I18n.login_password_empty  ,
+                minlength : I18n.login_password_lt_5
+                /*,maxlength:"登录密码不应超过18位"*/
             }
             }
         }, 
         }, 
 		highlight : function(element) {  
 		highlight : function(element) {  
@@ -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: '系统提示',
-                        content: (data.msg || "登录失败"),
+                        title: I18n.system_tips,
+                        btn: [ I18n.system_ok ],
+                        content: (data.msg || I18n.login_fail ),
                         icon: '2'
                         icon: '2'
                     });
                     });
 				}
 				}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 1
xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/layer.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 0 - 0
xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/need/layer.css


+ 3 - 3
xxl-job-admin/src/test/java/com/xxl/job/admin/controller/JobInfoControllerTest.java

@@ -1,7 +1,7 @@
 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 {
     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("password", PropertiesUtil.getString("xxl.job.login.password"))
+            .param("userName", XxlJobAdminConfig.getAdminConfig().getLoginUsername())
+            .param("password", XxlJobAdminConfig.getAdminConfig().getLoginPassword())
     ).andReturn();
     ).andReturn();
     cookie = ret.getResponse().getCookie(PermissionInterceptor.LOGIN_IDENTITY_KEY);
     cookie = ret.getResponse().getCookie(PermissionInterceptor.LOGIN_IDENTITY_KEY);
   }
   }

+ 2 - 2
xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobInfoDaoTest.java

@@ -20,8 +20,8 @@ public class XxlJobInfoDaoTest {
 	
 	
 	@Test
 	@Test
 	public void pageList(){
 	public void pageList(){
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, 0, null);
-		int list_count = xxlJobInfoDao.pageListCount(0, 20, 0, null);
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, 0, null, 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);

+ 1 - 1
xxl-job-admin/src/test/java/com/xxl/job/admin/dao/XxlJobLogDaoTest.java

@@ -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);
 
 

+ 25 - 0
xxl-job-admin/src/test/java/com/xxl/job/admin/util/I18nUtilTest.java

@@ -0,0 +1,25 @@
+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());
+    }
+
+}

+ 5 - 0
xxl-job-admin/src/test/java/com/xxl/job/admin/util/MailUtilTest.java

@@ -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;
  *
  *
  * @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

+ 0 - 18
xxl-job-admin/src/test/java/com/xxl/job/admin/util/PropertiesUtilTest.java

@@ -1,18 +0,0 @@
-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"));
-    }
-
-}

+ 1 - 1
xxl-job-core/pom.xml

@@ -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>

+ 19 - 9
xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java

@@ -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 {
     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 {
 
 
         // 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 {
 
 
         // destory executor-server
         // destory executor-server
         stopExecutorServer();
         stopExecutorServer();
+
+        // destory JobLogFileCleanThread
+        JobLogFileCleanThread.getInstance().toStop();
     }
     }
 
 
 
 

+ 2 - 2
xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java

@@ -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()
-                .concat("/gluesource/")
+        String scriptFileName = XxlJobFileAppender.getGlueSrcPath()
+                .concat("/")
                 .concat(String.valueOf(jobId))
                 .concat(String.valueOf(jobId))
                 .concat("_")
                 .concat("_")
                 .concat(String.valueOf(glueUpdatetime))
                 .concat(String.valueOf(glueUpdatetime))

+ 18 - 2
xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java

@@ -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 {
 		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"

+ 118 - 0
xxl-job-core/src/main/java/com/xxl/job/core/thread/JobLogFileCleanThread.java

@@ -0,0 +1,118 @@
+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);
+        }
+    }
+
+}

+ 27 - 0
xxl-job-core/src/main/java/com/xxl/job/core/util/FileUtil.java

@@ -0,0 +1,27 @@
+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;
+    }
+
+}

+ 15 - 14
xxl-job-core/src/main/java/com/xxl/job/core/util/ScriptUtil.java

@@ -59,22 +59,23 @@ 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);
-        PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
+        try (FileOutputStream fileOutputStream = new FileOutputStream(logFile, true)) {
+            PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
 
 
-        // command
-        CommandLine commandline = new CommandLine(command);
-        commandline.addArgument(scriptFile);
-        if (params!=null && params.length>0) {
-            commandline.addArguments(params);
-        }
+            // command
+            CommandLine commandline = new CommandLine(command);
+            commandline.addArgument(scriptFile);
+            if (params!=null && params.length>0) {
+                commandline.addArguments(params);
+            }
 
 
-        // exec
-        DefaultExecutor exec = new DefaultExecutor();
-        exec.setExitValues(null);
-        exec.setStreamHandler(streamHandler);
-        int exitValue = exec.execute(commandline);  // exit code: 0=success, 1=error
-        return exitValue;
+            // exec
+            DefaultExecutor exec = new DefaultExecutor();
+            exec.setExitValues(null);
+            exec.setStreamHandler(streamHandler);
+            int exitValue = exec.execute(commandline);  // exit code: 0=success, 1=error
+            return exitValue;
+        }
     }
     }
 
 
 }
 }

+ 1 - 1
xxl-job-executor-samples/pom.xml

@@ -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>

+ 1 - 1
xxl-job-executor-samples/xxl-job-executor-sample-jfinal/pom.xml

@@ -5,7 +5,7 @@
     <parent>
     <parent>
         <artifactId>xxl-job-executor-samples</artifactId>
         <artifactId>xxl-job-executor-samples</artifactId>
         <groupId>com.xuxueli</groupId>
         <groupId>com.xuxueli</groupId>
-        <version>1.9.0-SNAPSHOT</version>
+        <version>1.9.2-SNAPSHOT</version>
     </parent>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>xxl-job-executor-sample-jfinal</artifactId>
     <artifactId>xxl-job-executor-sample-jfinal</artifactId>

+ 4 - 3
xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/java/com/xuxueli/executor/sample/jfinal/config/JFinalCoreConfig.java

@@ -29,12 +29,13 @@ public class JFinalCoreConfig extends JFinalConfig {
 
 
 		// init executor
 		// init executor
 		xxlJobExecutor = new XxlJobExecutor();
 		xxlJobExecutor = new XxlJobExecutor();
+		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
+		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
 		xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip"));
 		xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip"));
 		xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port"));
 		xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port"));
-		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
-		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
-		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
 		xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken"));
 		xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken"));
+		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
+		xxlJobExecutor.setLogRetentionDays(xxlJobProp.getInt("xxl.job.executor.logretentiondays"));
 
 
 		// start executor
 		// start executor
 		try {
 		try {

+ 5 - 3
xxl-job-executor-samples/xxl-job-executor-sample-jfinal/src/main/resources/xxl-job-executor.properties

@@ -6,8 +6,10 @@ xxl.job.executor.appname=xxl-job-executor-sample
 xxl.job.executor.ip=
 xxl.job.executor.ip=
 xxl.job.executor.port=9996
 xxl.job.executor.port=9996
 
 
+### xxl-job, access token
+xxl.job.accessToken=
+
 ### xxl-job log path
 ### xxl-job log path
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
-
-### xxl-job, access token
-xxl.job.accessToken=
+### xxl-job log retention days
+xxl.job.executor.logretentiondays=-1

+ 1 - 1
xxl-job-executor-samples/xxl-job-executor-sample-nutz/pom.xml

@@ -5,7 +5,7 @@
     <parent>
     <parent>
         <groupId>com.xuxueli</groupId>
         <groupId>com.xuxueli</groupId>
         <artifactId>xxl-job-executor-samples</artifactId>
         <artifactId>xxl-job-executor-samples</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
+        <version>1.9.2-SNAPSHOT</version>
     </parent>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>xxl-job-executor-sample-nutz</artifactId>
     <artifactId>xxl-job-executor-sample-nutz</artifactId>

+ 4 - 3
xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/java/com/xuxueli/executor/sample/nutz/config/NutzSetup.java

@@ -39,12 +39,13 @@ public class NutzSetup implements Setup {
 
 
 		// init executor
 		// init executor
 		xxlJobExecutor = new XxlJobExecutor();
 		xxlJobExecutor = new XxlJobExecutor();
+		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
+		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
 		xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip"));
 		xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip"));
 		xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port"));
 		xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port"));
-		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
-		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
-		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
 		xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken"));
 		xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken"));
+		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
+		xxlJobExecutor.setLogRetentionDays(xxlJobProp.getInt("xxl.job.executor.logretentiondays"));
 
 
 		// start executor
 		// start executor
 		try {
 		try {

+ 5 - 3
xxl-job-executor-samples/xxl-job-executor-sample-nutz/src/main/resources/xxl-job-executor.properties

@@ -6,8 +6,10 @@ xxl.job.executor.appname=xxl-job-executor-sample
 xxl.job.executor.ip=
 xxl.job.executor.ip=
 xxl.job.executor.port=9997
 xxl.job.executor.port=9997
 
 
+### xxl-job, access token
+xxl.job.accessToken=
+
 ### xxl-job log path
 ### xxl-job log path
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
-
-### xxl-job, access token
-xxl.job.accessToken=
+### xxl-job log retention days
+xxl.job.executor.logretentiondays=-1

+ 1 - 1
xxl-job-executor-samples/xxl-job-executor-sample-spring/pom.xml

@@ -4,7 +4,7 @@
 	<parent>
 	<parent>
 		<groupId>com.xuxueli</groupId>
 		<groupId>com.xuxueli</groupId>
 		<artifactId>xxl-job-executor-samples</artifactId>
 		<artifactId>xxl-job-executor-samples</artifactId>
-		<version>1.9.0-SNAPSHOT</version>
+		<version>1.9.2-SNAPSHOT</version>
 	</parent>
 	</parent>
 	<artifactId>xxl-job-executor-sample-spring</artifactId>
 	<artifactId>xxl-job-executor-sample-spring</artifactId>
 	<packaging>war</packaging>
 	<packaging>war</packaging>

+ 8 - 6
xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml

@@ -23,18 +23,20 @@
 
 
 	<!-- 配置02、执行器 -->
 	<!-- 配置02、执行器 -->
 	<bean id="xxlJobExecutor" class="com.xxl.job.core.executor.XxlJobExecutor" init-method="start" destroy-method="destroy" >
 	<bean id="xxlJobExecutor" class="com.xxl.job.core.executor.XxlJobExecutor" init-method="start" destroy-method="destroy" >
+		<!-- 执行器注册中心地址[选填],为空则关闭自动注册 -->
+		<property name="adminAddresses" value="${xxl.job.admin.addresses}" />
+		<!-- 执行器AppName[选填],为空则关闭自动注册 -->
+		<property name="appName" value="${xxl.job.executor.appname}" />
 		<!-- 执行器IP[选填],为空则自动获取 -->
 		<!-- 执行器IP[选填],为空则自动获取 -->
 		<property name="ip" value="${xxl.job.executor.ip}" />
 		<property name="ip" value="${xxl.job.executor.ip}" />
 		<!-- 执行器端口号[选填],为空则自动获取 -->
 		<!-- 执行器端口号[选填],为空则自动获取 -->
 		<property name="port" value="${xxl.job.executor.port}" />
 		<property name="port" value="${xxl.job.executor.port}" />
-		<!-- 执行器AppName[选填],为空则关闭自动注册 -->
-        <property name="appName" value="${xxl.job.executor.appname}" />
-        <!-- 执行器注册中心地址[选填],为空则关闭自动注册 -->
-		<property name="adminAddresses" value="${xxl.job.admin.addresses}" />
-		<!-- 执行器日志路径[选填],为空则使用默认路径 -->
-		<property name="logPath" value="${xxl.job.executor.logpath}" />
 		<!-- 访问令牌[选填],非空则进行匹配校验 -->
 		<!-- 访问令牌[选填],非空则进行匹配校验 -->
 		<property name="accessToken" value="${xxl.job.accessToken}" />
 		<property name="accessToken" value="${xxl.job.accessToken}" />
+		<!-- 执行器日志路径[选填],为空则使用默认路径 -->
+		<property name="logPath" value="${xxl.job.executor.logpath}" />
+		<!-- 日志保存天数[选填],值大于3时生效 -->
+		<property name="logRetentionDays" value="${xxl.job.executor.logretentiondays}" />
 	</bean>
 	</bean>
 
 
 
 

+ 6 - 4
xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties

@@ -4,10 +4,12 @@ xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
 ### xxl-job executor address
 ### xxl-job executor address
 xxl.job.executor.appname=xxl-job-executor-sample
 xxl.job.executor.appname=xxl-job-executor-sample
 xxl.job.executor.ip=
 xxl.job.executor.ip=
-xxl.job.executor.port=9999
+xxl.job.executor.port=9998
+
+### xxl-job, access token
+xxl.job.accessToken=
 
 
 ### xxl-job log path
 ### xxl-job log path
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
-
-### xxl-job, access token
-xxl.job.accessToken=
+### xxl-job log retention days
+xxl.job.executor.logretentiondays=-1

+ 1 - 1
xxl-job-executor-samples/xxl-job-executor-sample-springboot/pom.xml

@@ -6,7 +6,7 @@
     <parent>
     <parent>
         <groupId>com.xuxueli</groupId>
         <groupId>com.xuxueli</groupId>
         <artifactId>xxl-job-executor-samples</artifactId>
         <artifactId>xxl-job-executor-samples</artifactId>
-        <version>1.9.0-SNAPSHOT</version>
+        <version>1.9.2-SNAPSHOT</version>
     </parent>
     </parent>
     <artifactId>xxl-job-executor-sample-springboot</artifactId>
     <artifactId>xxl-job-executor-sample-springboot</artifactId>
     <packaging>jar</packaging>
     <packaging>jar</packaging>

+ 14 - 9
xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/java/com/xxl/job/executor/core/config/XxlJobConfig.java

@@ -18,12 +18,11 @@ import org.springframework.context.annotation.Configuration;
 public class XxlJobConfig {
 public class XxlJobConfig {
     private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
     private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
 
 
-
     @Value("${xxl.job.admin.addresses}")
     @Value("${xxl.job.admin.addresses}")
-    private String addresses;
+    private String adminAddresses;
 
 
     @Value("${xxl.job.executor.appname}")
     @Value("${xxl.job.executor.appname}")
-    private String appname;
+    private String appName;
 
 
     @Value("${xxl.job.executor.ip}")
     @Value("${xxl.job.executor.ip}")
     private String ip;
     private String ip;
@@ -31,22 +30,28 @@ public class XxlJobConfig {
     @Value("${xxl.job.executor.port}")
     @Value("${xxl.job.executor.port}")
     private int port;
     private int port;
 
 
-    @Value("${xxl.job.executor.logpath}")
-    private String logpath;
-
     @Value("${xxl.job.accessToken}")
     @Value("${xxl.job.accessToken}")
     private String accessToken;
     private String accessToken;
 
 
+    @Value("${xxl.job.executor.logpath}")
+    private String logPath;
+
+    @Value("${xxl.job.executor.logretentiondays}")
+    private int logRetentionDays;
+
+
     @Bean(initMethod = "start", destroyMethod = "destroy")
     @Bean(initMethod = "start", destroyMethod = "destroy")
     public XxlJobExecutor xxlJobExecutor() {
     public XxlJobExecutor xxlJobExecutor() {
         logger.info(">>>>>>>>>>> xxl-job config init.");
         logger.info(">>>>>>>>>>> xxl-job config init.");
         XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
         XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
+        xxlJobExecutor.setAdminAddresses(adminAddresses);
+        xxlJobExecutor.setAppName(appName);
         xxlJobExecutor.setIp(ip);
         xxlJobExecutor.setIp(ip);
         xxlJobExecutor.setPort(port);
         xxlJobExecutor.setPort(port);
-        xxlJobExecutor.setAppName(appname);
-        xxlJobExecutor.setAdminAddresses(addresses);
-        xxlJobExecutor.setLogPath(logpath);
         xxlJobExecutor.setAccessToken(accessToken);
         xxlJobExecutor.setAccessToken(accessToken);
+        xxlJobExecutor.setLogPath(logPath);
+        xxlJobExecutor.setLogRetentionDays(logRetentionDays);
+
         return xxlJobExecutor;
         return xxlJobExecutor;
     }
     }
 
 

+ 7 - 5
xxl-job-executor-samples/xxl-job-executor-sample-springboot/src/main/resources/application.properties

@@ -4,17 +4,19 @@ server.port=8081
 # log config
 # log config
 logging.config=classpath:logback.xml
 logging.config=classpath:logback.xml
 
 
-# xxl-job
+
 ### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
 ### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
 xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
 xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
 
 
 ### xxl-job executor address
 ### xxl-job executor address
 xxl.job.executor.appname=xxl-job-executor-sample
 xxl.job.executor.appname=xxl-job-executor-sample
 xxl.job.executor.ip=
 xxl.job.executor.ip=
-xxl.job.executor.port=9998
-
-### xxl-job log path
-xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
+xxl.job.executor.port=9999
 
 
 ### xxl-job, access token
 ### xxl-job, access token
 xxl.job.accessToken=
 xxl.job.accessToken=
+
+### xxl-job log path
+xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
+### xxl-job log retention days
+xxl.job.executor.logretentiondays=-1

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels