Bläddra i källkod

Merge branch 'master' into dev

thinking_fioa 7 år sedan
förälder
incheckning
94eeade64c
86 ändrade filer med 2098 tillägg och 901 borttagningar
  1. 13 7
      README.md
  2. 20 1
      doc/XXL-JOB-English-Documentation.md
  3. 91 31
      doc/XXL-JOB官方文档.md
  4. Binär
      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 2
      xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/layer.js
  60. 0 1
      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 Visa fil

@@ -1,12 +1,10 @@
1 1
 <p align="center">
2
-    <a href="http://www.xuxueli.com/xxl-job/">
3
-        <img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150">
4
-    </a>
2
+    <img src="https://raw.githubusercontent.com/xuxueli/xxl-job/master/doc/images/xxl-logo.jpg" width="150">
5 3
     <h3 align="center">XXL-JOB</h3>
6 4
     <p align="center">
7 5
         XXL-JOB, a lightweight distributed task scheduling framework.
8 6
         <br>
9
-        <a href="http://www.xuxueli.com/xxl-job/"><strong>-- Browse website. --</strong></a>
7
+        <a href="http://www.xuxueli.com/xxl-job/"><strong>-- Home Page --</strong></a>
10 8
         <br>
11 9
         <br>
12 10
         <a href="https://travis-ci.org/xuxueli/xxl-job">
@@ -71,7 +69,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
71 69
 - 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
72 70
 - 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
73 71
 - 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
74
-
72
+- 27、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
73
+- 28、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
75 74
 
76 75
 ## Development
77 76
 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
@@ -150,6 +149,13 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
150 149
     - 57、华夏票联(北京)科技有限公司
151 150
     - 58、拍拍贷
152 151
     - 59、北京尚德机构在线教育有限公司
152
+    - 60、任子行股份有限公司
153
+    - 61、北京时态电子商务有限公司
154
+    - 62、深圳卷皮网络科技有限公司
155
+    - 63、北京安博通科技股份有限公司
156
+    - 64、未来无线网
157
+    - 65、厦门瓷禧网络有限公司
158
+    - 66、北京递蓝科软件股份有限公司
153 159
 	- ……
154 160
 
155 161
 > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
@@ -179,6 +185,6 @@ This product is open source and free, and will continue to provide free communit
179 185
 
180 186
 
181 187
 ## Donate
182
-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 )
188
+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 )
183 189
 
184
-无论金额多少都足够表达您这份心意,非常感谢 :)      [前往捐赠](http://www.xuxueli.com/page/donate.html )
190
+无论捐赠金额多少都足够表达您这份心意,非常感谢 :)      [前往捐赠](http://www.xuxueli.com/page/donate.html )

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

@@ -12,6 +12,9 @@
12 12
 
13 13
 ### 1.1 Overview
14 14
 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.
15
+
16
+> English document update slightly delayed, Please check the Chinese version for the latest document.
17
+
15 18
 ### 1.2 Features
16 19
 - 1.Simple: support through the Web page on the task CRUD operation, simple operation, a minute to get started;
17 20
 - 2.Dynamic: support dynamic modification of task status, pause / resume tasks, and termination of running tasks,immediate effect;
@@ -105,6 +108,19 @@ So far, XXL-JOB has access to a number of companies online product line, access
105 108
     - 52、聚金资本
106 109
     - 53、北京父母邦网络科技有限公司
107 110
     - 54、中山元赫软件科技有限公司
111
+    - 55、中商惠民(北京)电子商务有限公司
112
+    - 56、凯京集团
113
+    - 57、华夏票联(北京)科技有限公司
114
+    - 58、拍拍贷
115
+    - 59、北京尚德机构在线教育有限公司
116
+    - 60、任子行股份有限公司
117
+    - 61、北京时态电子商务有限公司
118
+    - 62、深圳卷皮网络科技有限公司
119
+    - 63、北京安博通科技股份有限公司
120
+    - 64、未来无线网
121
+    - 65、厦门瓷禧网络有限公司
122
+    - 66、北京递蓝科软件股份有限公司
123
+    - 67、郑州创海软件科技公司
108 124
 	- ……
109 125
 
110 126
 > The company that access and use this product is welcome to register at the [address](https://github.com/xuxueli/xxl-job/issues/1 ), only for product promotion. 
@@ -122,7 +138,7 @@ Welcome everyone's attention and use, XXL-JOB will also embrace changes, sustain
122 138
 Source repository address | Release Download
123 139
 --- | ---
124 140
 [https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases)  
125
-[http://git.oschina.net/xuxueli0323/xxl-job](http://git.oschina.net/xuxueli0323/xxl-job) | [Download](http://git.oschina.net/xuxueli0323/xxl-job/releases)
141
+[http://gitee.com/xuxueli0323/xxl-job](http://gitee.com/xuxueli0323/xxl-job) | [Download](http://gitee.com/xuxueli0323/xxl-job/releases)
126 142
 
127 143
 #### Center repository address (The latest Release version:1.8.1)
128 144
 ```
@@ -203,6 +219,9 @@ The concrete contet describe as follows:
203 219
     
204 220
     ### TOKEN used for communication between the executor and schedule center, enabled if it’s not null
205 221
     xxl.job.accessToken=
222
+    
223
+    ### Internationalized Settings, the default is Chinese version,Switch to English when the value is "en".
224
+    xxl.job.i18n=en
206 225
 
207 226
 #### Step 2:Deploy:
208 227
 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 Visa fil

@@ -40,6 +40,8 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
40 40
 - 24、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
41 41
 - 25、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
42 42
 - 26、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
43
+- 27、全异步:系统底层实现全部异步化,针对密集调度进行流量削峰,理论上支持任意时长任务的运行;
44
+- 28、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
43 45
 
44 46
 ### 1.3 发展
45 47
 于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
@@ -52,12 +54,18 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
52 54
 
53 55
 于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。
54 56
 
57
+于2017-10-22,又拍云 Open Talk 联合 Spring Cloud 中国社区举办的 "[进击的微服务实战派上海站](https://opentalk.upyun.com/303.html)",我登台对XXL-JOB做了演讲,现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流
58
+
55 59
 于2017-12-11,XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》,并被拍拍贷架构总监"杨波老师"在专题 "[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)" 中现场介绍。
56 60
 
61
+于2017-12-18,XXL-JOB参与"[2017年度最受欢迎中国开源软件](http://www.oschina.net/project/top_cn_2017?sort=1)"评比,在当时已录入的约九千个国产开源项目中角逐,最终进入了前30强。
62
+
63
+于2018-01-15,XXL-JOB参与"[2017码云最火开源项目](https://www.oschina.net/news/92438/2017-mayun-top-50)"评比,在当时已录入的约六千五百个码云项目中角逐,最终进去了前20强。
64
+
57 65
 > 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。
58 66
 据最新统计, 自2016-01-21接入至2017-12-01期间,该系统已调度约100万次,表现优异。新接入应用推荐使用最新版本,因为经过数个大版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。
59 67
 
60
-至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止2016-07-19为止,XXL-JOB已接入的公司包括不限于:
68
+至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止最新统计时间为止,XXL-JOB已接入的公司包括不限于:
61 69
     
62 70
 	- 1、大众点评;
63 71
 	- 2、山东学而网络科技有限公司;
@@ -118,6 +126,14 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
118 126
     - 57、华夏票联(北京)科技有限公司
119 127
     - 58、拍拍贷
120 128
     - 59、北京尚德机构在线教育有限公司
129
+    - 60、任子行股份有限公司
130
+    - 61、北京时态电子商务有限公司
131
+    - 62、深圳卷皮网络科技有限公司
132
+    - 63、北京安博通科技股份有限公司
133
+    - 64、未来无线网
134
+    - 65、厦门瓷禧网络有限公司
135
+    - 66、北京递蓝科软件股份有限公司
136
+    - 67、郑州创海软件科技公司
121 137
 	- ……
122 138
 
123 139
 > 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
@@ -137,7 +153,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
137 153
 源码仓库地址 | Release Download
138 154
 --- | ---
139 155
 [https://github.com/xuxueli/xxl-job](https://github.com/xuxueli/xxl-job) | [Download](https://github.com/xuxueli/xxl-job/releases)  
140
-[http://git.oschina.net/xuxueli0323/xxl-job](http://git.oschina.net/xuxueli0323/xxl-job) | [Download](http://git.oschina.net/xuxueli0323/xxl-job/releases)
156
+[http://gitee.com/xuxueli0323/xxl-job](http://gitee.com/xuxueli0323/xxl-job) | [Download](http://gitee.com/xuxueli0323/xxl-job/releases)
141 157
 
142 158
 
143 159
 #### 中央仓库地址
@@ -147,7 +163,7 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
147 163
 <dependency>
148 164
     <groupId>com.xuxueli</groupId>
149 165
     <artifactId>xxl-job-core</artifactId>
150
-    <version>1.8.2</version>
166
+    <version>${最新稳定版本}</version>
151 167
 </dependency>
152 168
 ```
153 169
 
@@ -222,6 +238,9 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
222 238
     
223 239
     ### 调度中心通讯TOKEN,非空时启用
224 240
     xxl.job.accessToken=
241
+    
242
+    ### 调度中心国际化设置,默认为中文版本,值设置为“en”时切换为英文版本
243
+    xxl.job.i18n=
225 244
 
226 245
 #### 步骤二:部署项目:
227 246
 如果已经正确进行上述配置,可将项目编译打war包并部署到tomcat中。
@@ -263,12 +282,15 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
263 282
     xxl.job.executor.ip=
264 283
     xxl.job.executor.port=9999
265 284
     
285
+    ### xxl-job, access token:执行器通讯TOKEN,非空时启用
286
+    xxl.job.accessToken=
287
+        
266 288
     ### xxl-job log path:执行器运行日志文件存储的磁盘位置,需要对该路径拥有读写权限
267 289
     xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler/
268 290
     
269
-    ### xxl-job, access token:执行器通讯TOKEN,非空时启用
270
-    xxl.job.accessToken=
271
-
291
+    ### xxl-job log retention days:执行器Log文件定期清理功能,指定日志保存天数,日志文件过期自动删除。限制至少保持3天,否则功能不生效;
292
+    xxl.job.executor.logretentiondays=-1
293
+    
272 294
 
273 295
 #### 步骤三:执行器组件配置
274 296
 
@@ -282,35 +304,42 @@ XXL-JOB是一个轻量级分布式任务调度框架,其核心设计目标是
282 304
 <!-- 配置01、JobHandler 扫描路径:自动扫描容器中JobHandler -->
283 305
 <context:component-scan base-package="com.xxl.job.executor.service.jobhandler" />
284 306
 
285
-<!-- 配置02、执行器Excutor配置:执行器核心配置 -->
307
+<!-- 配置02、执行器 -->
286 308
 <bean id="xxlJobExecutor" class="com.xxl.job.core.executor.XxlJobExecutor" init-method="start" destroy-method="destroy" >
309
+    <!-- 执行器注册中心地址[选填],为空则关闭自动注册 -->
310
+    <property name="adminAddresses" value="${xxl.job.admin.addresses}" />
311
+    <!-- 执行器AppName[选填],为空则关闭自动注册 -->
312
+    <property name="appName" value="${xxl.job.executor.appname}" />
287 313
     <!-- 执行器IP[选填],为空则自动获取 -->
288 314
     <property name="ip" value="${xxl.job.executor.ip}" />
289 315
     <!-- 执行器端口号[选填],为空则自动获取 -->
290 316
     <property name="port" value="${xxl.job.executor.port}" />
291
-    <!-- 执行器AppName[选填],为空则关闭自动注册 -->
292
-    <property name="appName" value="${xxl.job.executor.appname}" />
293
-    <!-- 执行器注册中心地址[选填],为空则关闭自动注册 -->
294
-    <property name="adminAddresses" value="${xxl.job.admin.addresses}" />
295
-    <!-- 执行器日志路径[选填],为空则使用默认路径 -->
296
-    <property name="logPath" value="${xxl.job.executor.logpath}" />
297 317
     <!-- 访问令牌[选填],非空则进行匹配校验 -->
298 318
     <property name="accessToken" value="${xxl.job.accessToken}" />
319
+    <!-- 执行器日志路径[选填],为空则使用默认路径 -->
320
+    <property name="logPath" value="${xxl.job.executor.logpath}" />
321
+    <!-- 日志保存天数[选填],值大于3时生效 -->
322
+    <property name="logRetentionDays" value="${xxl.job.executor.logretentiondays}" />
299 323
 </bean>
300 324
 ```
301 325
 
302 326
 #### 步骤四:部署执行器项目:
303
-如果已经正确进行上述配置,可将执行器项目编译打部署,系统提供三个执行器Sample示例项目,选择其中一个即可,各自的部署方式如下。
327
+如果已经正确进行上述配置,可将执行器项目编译打部署,系统提供多种执行器Sample示例项目,选择其中一个即可,各自的部署方式如下。
304 328
 
305
-    xxl-job-executor-sample-spring:项目编译打包成WAR包,并部署到tomcat中。
306 329
     xxl-job-executor-sample-springboot:项目编译打包成springboot类型的可执行JAR包,命令启动即可;
330
+    xxl-job-executor-sample-spring:项目编译打包成WAR包,并部署到tomcat中。
331
+    xxl-job-executor-sample-jfinal:同上
332
+    xxl-job-executor-sample-nutz:同上
333
+    
307 334
 
308 335
 至此“执行器”项目已经部署结束。
309 336
 
310 337
 #### 步骤五:执行器集群(可选):
311 338
 执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。
312 339
 
313
-集群部署唯一要求为:保证集群中每个执行器的配置项 "xxl.job.admin.addresses/调度中心地址" 保持一致,执行器根据该配置进行执行器自动注册等操作。 
340
+执行器集群部署时,几点要求和建议:
341
+- 执行器回调地址(xxl.job.admin.addresses)需要保持一致;执行器根据该配置进行执行器自动注册等操作。 
342
+- 同一个执行器集群内AppName(xxl.job.executor.appname)需要保持一致;调度中心根据该配置动态发现不同集群的在线执行器列表。
314 343
 
315 344
 
316 345
 ### 2.5 开发第一个任务“Hello World”       
@@ -602,7 +631,7 @@ XXL-JOB首先定制了Quartz原生表结构前缀(XXL_JOB_QRTZ_)。
602 631
 
603 632
 #### 5.3.3 架构图
604 633
 
605
-![输入图片说明](https://static.oschina.net/uploads/img/201707/17190028_aEE2.png "在这里输入图片标题")
634
+![输入图片说明](https://static.oschina.net/uploads/img/201801/03103007_Qohm.png "在这里输入图片标题")
606 635
 
607 636
 ### 5.4 调度模块剖析
608 637
 #### 5.4.1 quartz的不足
@@ -639,15 +668,22 @@ org.quartz.threadPool.threadPriority: 5
639 668
 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
640 669
 ```
641 670
 
642
-XXL-JOB系统中业务逻辑在远程执行器执行,调度中心每次触发调度时仅发送一次调度请求,执行器会将请求存入执行队列并且立即响应调度中心;相比直接在quartz的QuartzJobBean中执行业务逻辑,极大的降低了调度线程占用;
671
+XXL-JOB系统中业务逻辑在远程执行器执行,全异步化设计,调度中心每次触发调度时仅发送一次调度请求,执行器会将请求存入执行队列并且立即响应调度中心,异步运行;相比直接在quartz的QuartzJobBean中执行业务逻辑,极大的降低了调度线程占用时间
643 672
 
644 673
 XXL-JOB调度中心中每个JOB逻辑非常 “轻”,单个JOB一次运行平均耗时基本在 "10ms" 之内(基本为一次请求的网络开销);因此,可以保证使用有限的线程支撑大量的JOB并发运行;
645 674
 
646
-理论上采用推荐机器配置 "4核4G内存"情况下,单线程可以承担 100(quartz最小时间粒度1000ms/触发一次任务耗时10ms)个密集任务(每秒执行一次)的正常调度触发。因此,默认配置的15个线程理论上可以承担起1500个密集任务的正常运行。
675
+理论支撑任务量公式如下:
676
+
677
+    理论支撑任务量 = 线程数配置 / 平均调度频率(每秒) * 平均触发耗时(单位s)
678
+
679
+理论上采用推荐机器配置 "4核4G内存" + "配置1s运行1次密集任务" + "调度中心与执行器ping延迟10ms(0.01s)" 的情况下,
680
+
681
+    - 单线程支撑任务量  :1 / 1 * 0.01 = 100个任务
682
+    - 15个线程支撑任务量:15 / 1 * 0.01 = 1500个任务
647 683
 
648
-实际场景中,调度请求网络耗时不同、DB读写耗时不同、任务密集或稀疏调度情况不同,会导致任务量上限会上下波动。
684
+实际场景中,由于调度中心与执行器ping延迟不同、DB读写耗时不同、任务调度密集程度不同,会导致任务量上限会上下波动。
649 685
 
650
-如若需要支撑更多的任务量,可以通过 "调大调度线程数" 和 "提升机器配置" 两种方式实现。
686
+如若需要支撑更多的任务量,可以通过 "调大调度线程数" 、"降低调度中心与执行器ping延迟" 和 "提升机器配置" 几种方式实现。
651 687
 
652 688
 #### 5.4.5 @DisallowConcurrentExecution
653 689
 XXL-JOB调度模块的“调度中心”默认不使用该注解,即默认开启并行机制,因为RemoteHttpJobBean为公共QuartzJobBean,这样在多线程调度的情况下,调度模块被阻塞的几率很低,大大提高了调度系统的承载量。
@@ -1074,7 +1110,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
1074 1110
 - 9、调度中心任务监控线程销毁时,批量对失败任务告警,防止告警信息丢失;
1075 1111
 - 10、任务日志文件路径时间戳格式化时SimpleDateFormat并发问题解决;
1076 1112
 
1077
-### 6.20 版本 V1.9.0 特性[迭代中]
1113
+### 6.20 版本 V1.9.0 特性[2017-12-29]
1078 1114
 - 1、新增Nutz执行器Sample示例项目;
1079 1115
 - 2、新增任务运行模式 "GLUE模式(NodeJS) ",支持NodeJS脚本任务;
1080 1116
 - 3、脚本任务Shell、Python和Nodejs等支持获取分片参数;
@@ -1084,13 +1120,13 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
1084 1120
 - 7、调度报表优化,支持时间区间筛选;
1085 1121
 - 8、Log组件支持输出异常栈信息,底层实现优化;
1086 1122
 - 9、告警邮件样式优化,调整为表格形式,邮件组件调整为commons-email简化邮件操作;
1087
-- 10、项目依赖升级,如spring、jackson等;
1123
+- 10、项目依赖全量升级至较新稳定版本,如spring、jackson等;
1088 1124
 - 11、任务日志,记录发起调度的机器信息;
1089 1125
 - 12、交互优化,如登陆注销;
1090 1126
 - 13、任务Cron长度扩展支持至128位,支持负责类型Cron设置;
1091 1127
 - 14、执行器地址录入交互优化,地址长度扩展支持至512位,支持大规模执行器集群配置;
1092 1128
 - 15、任务参数“IJobHandler.execute”入参改为“String params”,增强入参通用性。
1093
-- 16、JobHandler提供init/destroy方法,支持在JobHandler初始化和销毁时进行附加操作;
1129
+- 16、IJobHandler提供init/destroy方法,支持在相应任务线程初始化和销毁时进行附加操作;
1094 1130
 - 17、任务注解调整为 “@JobHandler”,与任务抽象接口统一;
1095 1131
 - 18、修复任务监控线程被耗时任务阻塞的问题;
1096 1132
 - 19、修复任务监控线程无法监控任务触发和执行状态均未0的问题;
@@ -1104,6 +1140,24 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
1104 1140
 - 27、系统安全性优化,登陆Token写Cookie时进行MD5加密,同时Cookie启用HttpOnly;
1105 1141
 - 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。
1106 1142
 - 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环;
1143
+- 30、任务列表新增筛选条件 "任务描述",快速检索任务;
1144
+- 31、执行器Log文件定期清理功能:执行器新增配置项("xxl.job.executor.logretentiondays")日志保存天数,日志文件过期自动删除。
1145
+
1146
+### 6.21 版本 V1.9.1 特性[2018-02-22]
1147
+- 1、国际化:调度中心实现国际化,支持中文、英文两种语言,默认为中文。
1148
+- 2、调度报表新增"运行中"中状态项;
1149
+- 3、调度报表优化,报表SQL调优并且新增LocalCache缓存(缓存时间60s),提高大数据量下报表加载速度;
1150
+- 4、修复打包部署时资源文件乱码问题;
1151
+- 5、修复新版本chrome滚动到顶部失效问题;
1152
+- 6、调度中心配置加载优化,取消对配置文件名的强依赖,支持加载磁盘配置;
1153
+- 7、修复脚本任务Log文件未正常close的问题;
1154
+- 8、项目依赖全量升级至较新稳定版本,如spring、jackson等等;
1155
+
1156
+### 6.22 版本 V1.9.2 特性[迭代中]
1157
+- 1、[迭代中]支持通过API服务操作任务信息;
1158
+- 2、[迭代中]任务告警逻辑调整:任务调度,以及任务回调失败时,均推送监控队列。后期考虑通过任务Log字段控制告警状态;
1159
+- 3、[迭代中]任务超时设置,超时任务主动终止;
1160
+
1107 1161
 
1108 1162
 ### TODO LIST
1109 1163
 - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限;
@@ -1114,12 +1168,18 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
1114 1168
 - 6、调度任务优先级;
1115 1169
 - 7、移除quartz依赖,重写调度模块:新增或恢复任务时将下次执行记录插入delayqueue,调度中心集群竞争分布式锁,成功节点批量加载到期delayqueue数据,批量执行。
1116 1170
 - 8、springboot 和 docker镜像,并且推送docker镜像到中央仓库,更进一步实现产品开箱即用;
1117
-- 9、国际化:调度中心界面。
1118
-- 10、任务告警逻辑调整:任务调度,以及任务回调失败时,均推送监控队列。后期考虑通过任务Log字段控制告警状态;
1119
-- 11、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件;
1120
-- 12、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性;
1121
-- 13、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发;
1122
-- 14、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题;
1171
+- 9、多数据库支持;
1172
+- 10、执行器Log清理功能:调度中心Log删除时同步删除执行器中的Log文件;
1173
+- 11、Bean模式任务,JobHandler自动从执行器中查询展示为下拉框,选择后自动填充任务名称等属性;
1174
+- 12、API事件触发类型任务(更类似MQ消息)支持"动态传参、延时消费";该类型任务不走Quartz,单独建立MQ消息表,调度中心竞争触发;
1175
+- 13、任务依赖增强,新增任务类型 "流程任务",流程节点可挂载普通类型任务,承担任务依赖功能。现有子任务模型取消;需要考虑任务依赖死循环问题;
1176
+- 14、分片任务某一分片失败,支持分片转移;
1177
+- 15、调度中心触发任务后,先推送触发队列,异步触发,然后立即返回。降低quartz线程占用时长。
1178
+- 16、新增API服务 "XxlJobService" ,支持通过API服务来维护管理任务信息;
1179
+- 17、新增任务默认运行状态,任务更新时运行状态保持不变;
1180
+- 18、告警邮件中展示失败告警信息;
1181
+- 19、提供多版本执行器:不依赖容器版本、不内嵌Jetty版本(通过配置executoraddress替换jetty通讯)等;
1182
+
1123 1183
 
1124 1184
 
1125 1185
 ## 七、其他
@@ -1138,4 +1198,4 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
1138 1198
 
1139 1199
 ---
1140 1200
 ### 捐赠
1141
-无论金额多少都足够表达您这份心意,非常感谢 :)      [前往捐赠](http://www.xuxueli.com/page/donate.html )
1201
+无论捐赠金额多少都足够表达您这份心意,非常感谢 :)      [前往捐赠](http://www.xuxueli.com/page/donate.html )

Binär
doc/XXL-JOB架构图.pptx Visa fil


+ 14 - 6
pom.xml Visa fil

@@ -3,7 +3,7 @@
3 3
 	<modelVersion>4.0.0</modelVersion>
4 4
 	<groupId>com.xuxueli</groupId>
5 5
 	<artifactId>xxl-job</artifactId>
6
-	<version>1.9.0-SNAPSHOT</version>
6
+	<version>1.9.2-SNAPSHOT</version>
7 7
 	<packaging>pom</packaging>
8 8
 
9 9
 	<name>${project.artifactId}</name>
@@ -20,16 +20,16 @@
20 20
 		<javax.servlet-api.version>3.0.1</javax.servlet-api.version>
21 21
 		<jsp-api.version>2.2</jsp-api.version>
22 22
 
23
-		<spring.version>4.3.13.RELEASE</spring.version>
24
-		<jackson.version>2.9.3</jackson.version>
23
+		<spring.version>4.3.14.RELEASE</spring.version>
24
+		<jackson.version>2.9.4</jackson.version>
25 25
 		<aspectjweaver.version>1.8.13</aspectjweaver.version>
26 26
 		<slf4j-api.version>1.7.25</slf4j-api.version>
27 27
 		<freemarker.version>2.3.23</freemarker.version>
28 28
 		<junit.version>4.12</junit.version>
29 29
 
30
-		<jetty-server.version>9.2.22.v20170606</jetty-server.version>
30
+		<jetty-server.version>9.2.24.v20180105</jetty-server.version>
31 31
 		<hessian.version>4.0.51</hessian.version>
32
-		<httpclient.version>4.5.4</httpclient.version>
32
+		<httpclient.version>4.5.5</httpclient.version>
33 33
 		
34 34
 		<commons-exec.version>1.3</commons-exec.version>
35 35
 		<commons-collections4.version>4.1</commons-collections4.version>
@@ -44,7 +44,7 @@
44 44
 		<groovy-all.version>2.4.13</groovy-all.version>
45 45
 		<quartz.version>2.3.0</quartz.version>
46 46
 
47
-		<spring-boot.version>1.5.9.RELEASE</spring-boot.version>
47
+		<spring-boot.version>1.5.10.RELEASE</spring-boot.version>
48 48
 	</properties>
49 49
 
50 50
 	<build>
@@ -61,6 +61,14 @@
61 61
 			</plugin>
62 62
 			<plugin>
63 63
 				<groupId>org.apache.maven.plugins</groupId>
64
+				<artifactId>maven-resources-plugin</artifactId>
65
+				<version>2.6</version>
66
+				<configuration>
67
+					<encoding>UTF-8</encoding>
68
+				</configuration>
69
+			</plugin>
70
+			<plugin>
71
+				<groupId>org.apache.maven.plugins</groupId>
64 72
 				<artifactId>maven-war-plugin</artifactId>
65 73
 				<version>2.2</version>
66 74
 				<configuration>

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

@@ -4,7 +4,7 @@
4 4
 	<parent>
5 5
 		<groupId>com.xuxueli</groupId>
6 6
 		<artifactId>xxl-job</artifactId>
7
-		<version>1.9.0-SNAPSHOT</version>
7
+		<version>1.9.2-SNAPSHOT</version>
8 8
 	</parent>
9 9
 	<artifactId>xxl-job-admin</artifactId>
10 10
 	<packaging>war</packaging>

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

@@ -2,6 +2,7 @@ package com.xxl.job.admin.controller;
2 2
 
3 3
 import com.xxl.job.admin.controller.annotation.PermessionLimit;
4 4
 import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
5
+import com.xxl.job.admin.core.util.I18nUtil;
5 6
 import com.xxl.job.admin.service.XxlJobService;
6 7
 import com.xxl.job.core.biz.model.ReturnT;
7 8
 import org.apache.commons.lang3.StringUtils;
@@ -40,11 +41,11 @@ public class IndexController {
40 41
 		return "index";
41 42
 	}
42 43
 
43
-    @RequestMapping("/triggerChartDate")
44
+    @RequestMapping("/chartInfo")
44 45
 	@ResponseBody
45
-	public ReturnT<Map<String, Object>> triggerChartDate(Date startDate, Date endDate) {
46
-        ReturnT<Map<String, Object>> triggerChartDate = xxlJobService.triggerChartDate(startDate, endDate);
47
-        return triggerChartDate;
46
+	public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
47
+        ReturnT<Map<String, Object>> chartInfo = xxlJobService.chartInfo(startDate, endDate);
48
+        return chartInfo;
48 49
     }
49 50
 	
50 51
 	@RequestMapping("/toLogin")
@@ -67,14 +68,14 @@ public class IndexController {
67 68
 
68 69
 		// param
69 70
 		if (StringUtils.isBlank(userName) || StringUtils.isBlank(password)){
70
-			return new ReturnT<String>(500, "账号或密码为空");
71
+			return new ReturnT<String>(500, I18nUtil.getString("login_param_empty"));
71 72
 		}
72 73
 		boolean ifRem = (StringUtils.isNotBlank(ifRemember) && "on".equals(ifRemember))?true:false;
73 74
 
74 75
 		// do login
75 76
 		boolean loginRet = PermissionInterceptor.login(response, userName, password, ifRem);
76 77
 		if (!loginRet) {
77
-			return new ReturnT<String>(500, "账号或密码错误");
78
+			return new ReturnT<String>(500, I18nUtil.getString("login_param_unvalid"));
78 79
 		}
79 80
 		return ReturnT.SUCCESS;
80 81
 	}

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

@@ -2,6 +2,7 @@ package com.xxl.job.admin.controller;
2 2
 
3 3
 import com.xxl.job.admin.core.model.XxlJobInfo;
4 4
 import com.xxl.job.admin.core.model.XxlJobLogGlue;
5
+import com.xxl.job.admin.core.util.I18nUtil;
5 6
 import com.xxl.job.admin.dao.XxlJobInfoDao;
6 7
 import com.xxl.job.admin.dao.XxlJobLogGlueDao;
7 8
 import com.xxl.job.core.biz.model.ReturnT;
@@ -34,10 +35,10 @@ public class JobCodeController {
34 35
 		List<XxlJobLogGlue> jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId);
35 36
 
36 37
 		if (jobInfo == null) {
37
-			throw new RuntimeException("抱歉,任务不存在.");
38
+			throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
38 39
 		}
39 40
 		if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) {
40
-			throw new RuntimeException("该任务非GLUE模式.");
41
+			throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid"));
41 42
 		}
42 43
 
43 44
 		// Glue类型-字典
@@ -53,14 +54,14 @@ public class JobCodeController {
53 54
 	public ReturnT<String> save(Model model, int id, String glueSource, String glueRemark) {
54 55
 		// valid
55 56
 		if (glueRemark==null) {
56
-			return new ReturnT<String>(500, "请输入备注");
57
+			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")) );
57 58
 		}
58 59
 		if (glueRemark.length()<4 || glueRemark.length()>100) {
59
-			return new ReturnT<String>(500, "备注长度应该在4至100之间");
60
+			return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_remark_limit"));
60 61
 		}
61 62
 		XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(id);
62 63
 		if (exists_jobInfo == null) {
63
-			return new ReturnT<String>(500, "参数异常");
64
+			return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
64 65
 		}
65 66
 		
66 67
 		// update new code

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

@@ -1,6 +1,7 @@
1 1
 package com.xxl.job.admin.controller;
2 2
 
3 3
 import com.xxl.job.admin.core.model.XxlJobGroup;
4
+import com.xxl.job.admin.core.util.I18nUtil;
4 5
 import com.xxl.job.admin.dao.XxlJobGroupDao;
5 6
 import com.xxl.job.admin.dao.XxlJobInfoDao;
6 7
 import com.xxl.job.core.biz.model.ReturnT;
@@ -42,22 +43,22 @@ public class JobGroupController {
42 43
 
43 44
 		// valid
44 45
 		if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) {
45
-			return new ReturnT<String>(500, "请输入AppName");
46
+			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
46 47
 		}
47
-		if (xxlJobGroup.getAppName().length()>64) {
48
-			return new ReturnT<String>(500, "AppName长度限制为4~64");
48
+		if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>64) {
49
+			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appName_length") );
49 50
 		}
50 51
 		if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
51
-			return new ReturnT<String>(500, "请输入名称");
52
+			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
52 53
 		}
53 54
 		if (xxlJobGroup.getAddressType()!=0) {
54 55
 			if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
55
-				return new ReturnT<String>(500, "手动录入注册方式,机器地址不可为空");
56
+				return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
56 57
 			}
57 58
 			String[] addresss = xxlJobGroup.getAddressList().split(",");
58 59
 			for (String item: addresss) {
59 60
 				if (StringUtils.isBlank(item)) {
60
-					return new ReturnT<String>(500, "机器地址非法");
61
+					return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
61 62
 				}
62 63
 			}
63 64
 		}
@@ -71,22 +72,22 @@ public class JobGroupController {
71 72
 	public ReturnT<String> update(XxlJobGroup xxlJobGroup){
72 73
 		// valid
73 74
 		if (xxlJobGroup.getAppName()==null || StringUtils.isBlank(xxlJobGroup.getAppName())) {
74
-			return new ReturnT<String>(500, "请输入AppName");
75
+			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input")+"AppName") );
75 76
 		}
76
-		if (xxlJobGroup.getAppName().length()>64) {
77
-			return new ReturnT<String>(500, "AppName长度限制为4~64");
77
+		if (xxlJobGroup.getAppName().length()<4 || xxlJobGroup.getAppName().length()>64) {
78
+			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appName_length") );
78 79
 		}
79 80
 		if (xxlJobGroup.getTitle()==null || StringUtils.isBlank(xxlJobGroup.getTitle())) {
80
-			return new ReturnT<String>(500, "请输入名称");
81
+			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
81 82
 		}
82 83
 		if (xxlJobGroup.getAddressType()!=0) {
83 84
 			if (StringUtils.isBlank(xxlJobGroup.getAddressList())) {
84
-				return new ReturnT<String>(500, "手动录入注册方式,机器地址不可为空");
85
+				return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
85 86
 			}
86 87
 			String[] addresss = xxlJobGroup.getAddressList().split(",");
87 88
 			for (String item: addresss) {
88 89
 				if (StringUtils.isBlank(item)) {
89
-					return new ReturnT<String>(500, "机器地址非法");
90
+					return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList_unvalid") );
90 91
 				}
91 92
 			}
92 93
 		}
@@ -100,14 +101,14 @@ public class JobGroupController {
100 101
 	public ReturnT<String> remove(int id){
101 102
 
102 103
 		// valid
103
-		int count = xxlJobInfoDao.pageListCount(0, 10, id, null);
104
+		int count = xxlJobInfoDao.pageListCount(0, 10, id, null, null);
104 105
 		if (count > 0) {
105
-			return new ReturnT<String>(500, "该分组使用中, 不可删除");
106
+			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_0") );
106 107
 		}
107 108
 
108 109
 		List<XxlJobGroup> allList = xxlJobGroupDao.findAll();
109 110
 		if (allList.size() == 1) {
110
-			return new ReturnT<String>(500, "删除失败, 系统需要至少预留一个默认分组");
111
+			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_del_limit_1") );
111 112
 		}
112 113
 
113 114
 		int ret = xxlJobGroupDao.remove(id);

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

@@ -53,9 +53,9 @@ public class JobInfoController {
53 53
 	@ResponseBody
54 54
 	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
55 55
 			@RequestParam(required = false, defaultValue = "10") int length,
56
-			int jobGroup, String executorHandler, String filterTime) {
56
+			int jobGroup, String jobDesc, String executorHandler, String filterTime) {
57 57
 		
58
-		return xxlJobService.pageList(start, length, jobGroup, executorHandler, filterTime);
58
+		return xxlJobService.pageList(start, length, jobGroup, jobDesc, executorHandler, filterTime);
59 59
 	}
60 60
 	
61 61
 	@RequestMapping("/add")
@@ -64,10 +64,10 @@ public class JobInfoController {
64 64
 		return xxlJobService.add(jobInfo);
65 65
 	}
66 66
 	
67
-	@RequestMapping("/reschedule")
67
+	@RequestMapping("/update")
68 68
 	@ResponseBody
69
-	public ReturnT<String> reschedule(XxlJobInfo jobInfo) {
70
-		return xxlJobService.reschedule(jobInfo);
69
+	public ReturnT<String> update(XxlJobInfo jobInfo) {
70
+		return xxlJobService.update(jobInfo);
71 71
 	}
72 72
 	
73 73
 	@RequestMapping("/remove")

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

@@ -4,12 +4,14 @@ import com.xxl.job.admin.core.model.XxlJobGroup;
4 4
 import com.xxl.job.admin.core.model.XxlJobInfo;
5 5
 import com.xxl.job.admin.core.model.XxlJobLog;
6 6
 import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
7
+import com.xxl.job.admin.core.util.I18nUtil;
7 8
 import com.xxl.job.admin.dao.XxlJobGroupDao;
8 9
 import com.xxl.job.admin.dao.XxlJobInfoDao;
9 10
 import com.xxl.job.admin.dao.XxlJobLogDao;
10 11
 import com.xxl.job.core.biz.ExecutorBiz;
11 12
 import com.xxl.job.core.biz.model.LogResult;
12 13
 import com.xxl.job.core.biz.model.ReturnT;
14
+import com.xxl.job.core.glue.GlueTypeEnum;
13 15
 import com.xxl.job.core.rpc.netcom.NetComClientProxy;
14 16
 import org.apache.commons.lang3.StringUtils;
15 17
 import org.apache.commons.lang3.time.DateUtils;
@@ -50,6 +52,7 @@ public class JobLogController {
50 52
 		// 执行器列表
51 53
 		List<XxlJobGroup> jobGroupList =  xxlJobGroupDao.findAll();
52 54
 		model.addAttribute("JobGroupList", jobGroupList);
55
+		model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());
53 56
 
54 57
 		// 任务
55 58
 		if (jobId > 0) {
@@ -105,7 +108,7 @@ public class JobLogController {
105 108
 		ReturnT<String> logStatue = ReturnT.SUCCESS;
106 109
 		XxlJobLog jobLog = xxlJobLogDao.load(id);
107 110
 		if (jobLog == null) {
108
-            throw new RuntimeException("抱歉,日志ID非法.");
111
+            throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
109 112
 		}
110 113
 
111 114
         model.addAttribute("triggerCode", jobLog.getTriggerCode());
@@ -145,10 +148,10 @@ public class JobLogController {
145 148
 		XxlJobLog log = xxlJobLogDao.load(id);
146 149
 		XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
147 150
 		if (jobInfo==null) {
148
-			return new ReturnT<String>(500, "参数异常");
151
+			return new ReturnT<String>(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
149 152
 		}
150 153
 		if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
151
-			return new ReturnT<String>(500, "调度失败,无法终止日志");
154
+			return new ReturnT<String>(500, I18nUtil.getString("joblog_kill_log_limit"));
152 155
 		}
153 156
 
154 157
 		// request of kill
@@ -163,7 +166,7 @@ public class JobLogController {
163 166
 
164 167
 		if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
165 168
 			log.setHandleCode(ReturnT.FAIL_CODE);
166
-			log.setHandleMsg("人为操作主动终止:" + (runResult.getMsg()!=null?runResult.getMsg():""));
169
+			log.setHandleMsg( I18nUtil.getString("joblog_kill_log_byman")+":" + (runResult.getMsg()!=null?runResult.getMsg():""));
167 170
 			log.setHandleTime(new Date());
168 171
 			xxlJobLogDao.updateHandleInfo(log);
169 172
 			return new ReturnT<String>(runResult.getMsg());
@@ -197,7 +200,7 @@ public class JobLogController {
197 200
 		} else if (type == 9) {
198 201
 			clearBeforeNum = 0;			// 清理所有日志数据
199 202
 		} else {
200
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "清理类型参数异常");
203
+			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid"));
201 204
 		}
202 205
 
203 206
 		xxlJobLogDao.clearLog(jobGroup, jobId, clearBeforeTime, clearBeforeNum);

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

@@ -1,5 +1,7 @@
1 1
 package com.xxl.job.admin.controller.interceptor;
2 2
 
3
+import com.xxl.job.admin.core.util.FtlUtil;
4
+import com.xxl.job.admin.core.util.I18nUtil;
3 5
 import org.apache.commons.lang3.ArrayUtils;
4 6
 import org.springframework.web.servlet.ModelAndView;
5 7
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -19,7 +21,8 @@ public class CookieInterceptor extends HandlerInterceptorAdapter {
19 21
 	@Override
20 22
 	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
21 23
 			ModelAndView modelAndView) throws Exception {
22
-		
24
+
25
+		// cookie
23 26
 		if (modelAndView!=null && ArrayUtils.isNotEmpty(request.getCookies())) {
24 27
 			HashMap<String, Cookie> cookieMap = new HashMap<String, Cookie>();
25 28
 			for (Cookie ck : request.getCookies()) {
@@ -27,6 +30,11 @@ public class CookieInterceptor extends HandlerInterceptorAdapter {
27 30
 			}
28 31
 			modelAndView.addObject("cookieMap", cookieMap);
29 32
 		}
33
+
34
+		// static method
35
+		if (modelAndView != null) {
36
+			modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
37
+		}
30 38
 		
31 39
 		super.postHandle(request, response, handler, modelAndView);
32 40
 	}

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

@@ -1,8 +1,8 @@
1 1
 package com.xxl.job.admin.controller.interceptor;
2 2
 
3 3
 import com.xxl.job.admin.controller.annotation.PermessionLimit;
4
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
4 5
 import com.xxl.job.admin.core.util.CookieUtil;
5
-import com.xxl.job.admin.core.util.PropertiesUtil;
6 6
 import org.apache.commons.codec.digest.DigestUtils;
7 7
 import org.springframework.web.method.HandlerMethod;
8 8
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -22,8 +22,8 @@ public class PermissionInterceptor extends HandlerInterceptorAdapter {
22 22
 	public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
23 23
 	public static final String LOGIN_IDENTITY_TOKEN;
24 24
     static {
25
-        String username = PropertiesUtil.getString("xxl.job.login.username");
26
-        String password = PropertiesUtil.getString("xxl.job.login.password");
25
+        String username = XxlJobAdminConfig.getAdminConfig().getLoginUsername();
26
+        String password = XxlJobAdminConfig.getAdminConfig().getLoginPassword();
27 27
 
28 28
         // login token
29 29
         String tokenTmp = DigestUtils.md5Hex(username + "_" + password);

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

@@ -11,6 +11,7 @@ import org.springframework.web.servlet.ModelAndView;
11 11
 
12 12
 import javax.servlet.http.HttpServletRequest;
13 13
 import javax.servlet.http.HttpServletResponse;
14
+import java.io.IOException;
14 15
 
15 16
 /**
16 17
  * common exception resolver
@@ -23,19 +24,34 @@ public class WebExceptionResolver implements HandlerExceptionResolver {
23 24
 	public ModelAndView resolveException(HttpServletRequest request,
24 25
 			HttpServletResponse response, Object handler, Exception ex) {
25 26
 		logger.error("WebExceptionResolver:{}", ex);
26
-		
27
-		ModelAndView mv = new ModelAndView();
27
+
28
+		// if json
29
+		boolean isJson = false;
28 30
 		HandlerMethod method = (HandlerMethod)handler;
29 31
 		ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
30 32
 		if (responseBody != null) {
31
-			response.setContentType("application/json;charset=UTF-8");
32
-			mv.addObject("result", JacksonUtil.writeValueAsString(new ReturnT<String>(500, ex.toString().replaceAll("\n", "<br/>"))));
33
-			mv.setViewName("/common/common.result");
33
+			isJson = true;
34
+		}
35
+
36
+		// error result
37
+		ReturnT<String> errorResult = new ReturnT<String>(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", "<br/>"));
38
+
39
+		// response
40
+		ModelAndView mv = new ModelAndView();
41
+		if (isJson) {
42
+			try {
43
+				response.setContentType("application/json;charset=utf-8");
44
+				response.getWriter().print(JacksonUtil.writeValueAsString(errorResult));
45
+			} catch (IOException e) {
46
+				logger.error(e.getMessage(), e);
47
+			}
48
+			return mv;
34 49
 		} else {
35
-			mv.addObject("exceptionMsg", ex.toString().replaceAll("\n", "<br/>"));	
50
+
51
+			mv.addObject("exceptionMsg", errorResult.getMsg());
36 52
 			mv.setViewName("/common/common.exception");
53
+			return mv;
37 54
 		}
38
-		return mv;
39 55
 	}
40 56
 	
41 57
 }

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

@@ -0,0 +1,81 @@
1
+package com.xxl.job.admin.core.conf;
2
+
3
+import org.springframework.beans.factory.InitializingBean;
4
+import org.springframework.beans.factory.annotation.Value;
5
+import org.springframework.context.annotation.Configuration;
6
+
7
+/**
8
+ * xxl-job config
9
+ *
10
+ * @author xuxueli 2017-04-28
11
+ */
12
+@Configuration
13
+public class XxlJobAdminConfig implements InitializingBean{
14
+    private static XxlJobAdminConfig adminConfig = null;
15
+    public static XxlJobAdminConfig getAdminConfig() {
16
+        return adminConfig;
17
+    }
18
+
19
+    @Override
20
+    public void afterPropertiesSet() throws Exception {
21
+        adminConfig = this;
22
+    }
23
+
24
+    @Value("${xxl.job.mail.host}")
25
+    private String mailHost;
26
+
27
+    @Value("${xxl.job.mail.port}")
28
+    private String mailPort;
29
+
30
+    @Value("${xxl.job.mail.username}")
31
+    private String mailUsername;
32
+
33
+    @Value("${xxl.job.mail.password}")
34
+    private String mailPassword;
35
+
36
+    @Value("${xxl.job.mail.sendNick}")
37
+    private String mailSendNick;
38
+
39
+    @Value("${xxl.job.login.username}")
40
+    private String loginUsername;
41
+
42
+    @Value("${xxl.job.login.password}")
43
+    private String loginPassword;
44
+
45
+    @Value("${xxl.job.i18n}")
46
+    private String i18n;
47
+
48
+
49
+    public String getMailHost() {
50
+        return mailHost;
51
+    }
52
+
53
+    public String getMailPort() {
54
+        return mailPort;
55
+    }
56
+
57
+    public String getMailUsername() {
58
+        return mailUsername;
59
+    }
60
+
61
+    public String getMailPassword() {
62
+        return mailPassword;
63
+    }
64
+
65
+    public String getMailSendNick() {
66
+        return mailSendNick;
67
+    }
68
+
69
+    public String getLoginUsername() {
70
+        return loginUsername;
71
+    }
72
+
73
+    public String getLoginPassword() {
74
+        return loginPassword;
75
+    }
76
+
77
+    public String getI18n() {
78
+        return i18n;
79
+    }
80
+
81
+}

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

@@ -1,13 +1,15 @@
1 1
 package com.xxl.job.admin.core.enums;
2 2
 
3
+import com.xxl.job.admin.core.util.I18nUtil;
4
+
3 5
 /**
4 6
  * Created by xuxueli on 17/5/9.
5 7
  */
6 8
 public enum ExecutorFailStrategyEnum {
7 9
 
8
-    FAIL_ALARM("失败告警"),
10
+    FAIL_ALARM(I18nUtil.getString("jobconf_fail_alarm")),
9 11
 
10
-    FAIL_RETRY("失败重试");
12
+    FAIL_RETRY(I18nUtil.getString("jobconf_fail_retry"));
11 13
 
12 14
     private final String title;
13 15
     private ExecutorFailStrategyEnum(String title) {

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

@@ -1,22 +1,23 @@
1 1
 package com.xxl.job.admin.core.route;
2 2
 
3 3
 import com.xxl.job.admin.core.route.strategy.*;
4
+import com.xxl.job.admin.core.util.I18nUtil;
4 5
 
5 6
 /**
6 7
  * Created by xuxueli on 17/3/10.
7 8
  */
8 9
 public enum ExecutorRouteStrategyEnum {
9 10
 
10
-    FIRST("第一个", new ExecutorRouteFirst()),
11
-    LAST("最后一个", new ExecutorRouteLast()),
12
-    ROUND("轮询", new ExecutorRouteRound()),
13
-    RANDOM("随机", new ExecutorRouteRandom()),
14
-    CONSISTENT_HASH("一致性HASH", new ExecutorRouteConsistentHash()),
15
-    LEAST_FREQUENTLY_USED("最不经常使用", new ExecutorRouteLFU()),
16
-    LEAST_RECENTLY_USED("最近最久未使用", new ExecutorRouteLRU()),
17
-    FAILOVER("故障转移", new ExecutorRouteFailover()),
18
-    BUSYOVER("忙碌转移", new ExecutorRouteBusyover()),
19
-    SHARDING_BROADCAST("分片广播", null);
11
+    FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()),
12
+    LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()),
13
+    ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()),
14
+    RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()),
15
+    CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()),
16
+    LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()),
17
+    LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()),
18
+    FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()),
19
+    BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()),
20
+    SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null);
20 21
 
21 22
     ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
22 23
         this.title = title;

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

@@ -3,6 +3,7 @@ package com.xxl.job.admin.core.route.strategy;
3 3
 import com.xxl.job.admin.core.route.ExecutorRouter;
4 4
 import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
5 5
 import com.xxl.job.admin.core.trigger.XxlJobTrigger;
6
+import com.xxl.job.admin.core.util.I18nUtil;
6 7
 import com.xxl.job.core.biz.ExecutorBiz;
7 8
 import com.xxl.job.core.biz.model.ReturnT;
8 9
 import com.xxl.job.core.biz.model.TriggerParam;
@@ -33,7 +34,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
33 34
                 idleBeatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
34 35
             }
35 36
             idleBeatResultSB.append( (idleBeatResultSB.length()>0)?"<br><br>":"")
36
-                    .append("空闲检测:")
37
+                    .append(I18nUtil.getString("jobconf_idleBeat") + ":")
37 38
                     .append("<br>address:").append(address)
38 39
                     .append("<br>code:").append(idleBeatResult.getCode())
39 40
                     .append("<br>msg:").append(idleBeatResult.getMsg());

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

@@ -3,6 +3,7 @@ package com.xxl.job.admin.core.route.strategy;
3 3
 import com.xxl.job.admin.core.route.ExecutorRouter;
4 4
 import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
5 5
 import com.xxl.job.admin.core.trigger.XxlJobTrigger;
6
+import com.xxl.job.admin.core.util.I18nUtil;
6 7
 import com.xxl.job.core.biz.ExecutorBiz;
7 8
 import com.xxl.job.core.biz.model.ReturnT;
8 9
 import com.xxl.job.core.biz.model.TriggerParam;
@@ -33,7 +34,7 @@ public class ExecutorRouteFailover extends ExecutorRouter {
33 34
                 beatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
34 35
             }
35 36
             beatResultSB.append( (beatResultSB.length()>0)?"<br><br>":"")
36
-                    .append("心跳检测:")
37
+                    .append(I18nUtil.getString("jobconf_beat") + ":")
37 38
                     .append("<br>address:").append(address)
38 39
                     .append("<br>code:").append(beatResult.getCode())
39 40
                     .append("<br>msg:").append(beatResult.getMsg());

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

@@ -4,6 +4,7 @@ import com.xxl.job.admin.core.model.XxlJobGroup;
4 4
 import com.xxl.job.admin.core.model.XxlJobInfo;
5 5
 import com.xxl.job.admin.core.model.XxlJobLog;
6 6
 import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
7
+import com.xxl.job.admin.core.util.I18nUtil;
7 8
 import com.xxl.job.admin.core.util.MailUtil;
8 9
 import com.xxl.job.core.biz.model.ReturnT;
9 10
 import com.xxl.job.core.handler.IJobHandler;
@@ -119,14 +120,14 @@ public class JobFailMonitorHelper {
119 120
 	// ---------------------- alarm ----------------------
120 121
 
121 122
 	// email alarm template
122
-	private static final String mailBodyTemplate = "<h5>监控告警明细:</span>" +
123
+	private static final String mailBodyTemplate = "<h5>" + I18nUtil.getString("jobconf_monitor_detail") + ":</span>" +
123 124
 			"<table border=\"1\" cellpadding=\"3\" style=\"border-collapse:collapse; width:80%;\" >\n" +
124 125
 			"   <thead style=\"font-weight: bold;color: #ffffff;background-color: #ff8c00;\" >" +
125 126
 			"      <tr>\n" +
126
-			"         <td>执行器</td>\n" +
127
-			"         <td>任务ID</td>\n" +
128
-			"         <td>任务描述</td>\n" +
129
-			"         <td>告警类型</td>\n" +
127
+			"         <td>"+ I18nUtil.getString("jobinfo_field_jobgroup") +"</td>\n" +
128
+			"         <td>"+ I18nUtil.getString("jobinfo_field_id") +"</td>\n" +
129
+			"         <td>"+ I18nUtil.getString("jobinfo_field_jobdesc") +"</td>\n" +
130
+			"         <td>"+ I18nUtil.getString("jobconf_monitor_alarm_title") +"</td>\n" +
130 131
 			"      </tr>\n" +
131 132
 			"   <thead/>\n" +
132 133
 			"   <tbody>\n" +
@@ -134,7 +135,7 @@ public class JobFailMonitorHelper {
134 135
 			"         <td>{0}</td>\n" +
135 136
 			"         <td>{1}</td>\n" +
136 137
 			"         <td>{2}</td>\n" +
137
-			"         <td>调度失败</td>\n" +
138
+			"         <td>"+ I18nUtil.getString("jobconf_monitor_alarm_type") +"</td>\n" +
138 139
 			"      </tr>\n" +
139 140
 			"   <tbody>\n" +
140 141
 			"</table>";
@@ -154,7 +155,7 @@ public class JobFailMonitorHelper {
154 155
 			for (String email: emailSet) {
155 156
 				XxlJobGroup group = XxlJobDynamicScheduler.xxlJobGroupDao.load(Integer.valueOf(info.getJobGroup()));
156 157
 
157
-				String title = "调度中心监控报警";
158
+				String title = I18nUtil.getString("jobconf_monitor");
158 159
 				String content = MessageFormat.format(mailBodyTemplate, group!=null?group.getTitle():"null", info.getId(), info.getJobDesc());
159 160
 
160 161
 				MailUtil.sendMail(email, title, content);

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

@@ -7,6 +7,7 @@ import com.xxl.job.admin.core.model.XxlJobLog;
7 7
 import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
8 8
 import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
9 9
 import com.xxl.job.admin.core.thread.JobFailMonitorHelper;
10
+import com.xxl.job.admin.core.util.I18nUtil;
10 11
 import com.xxl.job.core.biz.ExecutorBiz;
11 12
 import com.xxl.job.core.biz.model.ReturnT;
12 13
 import com.xxl.job.core.biz.model.TriggerParam;
@@ -67,17 +68,18 @@ public class XxlJobTrigger {
67 68
 
68 69
                 ReturnT<String> triggerResult = new ReturnT<String>(null);
69 70
                 StringBuffer triggerMsgSb = new StringBuffer();
70
-                triggerMsgSb.append("调度机器:").append(IpUtil.getIp());
71
-                triggerMsgSb.append("<br>执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" );
72
-                triggerMsgSb.append("<br>执行器-地址列表:").append(group.getRegistryList());
73
-                triggerMsgSb.append("<br>路由策略:").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01
74
-                triggerMsgSb.append("<br>阻塞处理策略:").append(blockStrategy.getTitle());
75
-                triggerMsgSb.append("<br>失败处理策略:").append(failStrategy.getTitle());
71
+                triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
72
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
73
+                        .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
74
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
75
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle()).append("("+i+"/"+addressList.size()+")"); // update01
76
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
77
+                triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailStrategy")).append(":").append(failStrategy.getTitle());
76 78
 
77 79
                 // 3、trigger-valid
78 80
                 if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
79 81
                     triggerResult.setCode(ReturnT.FAIL_CODE);
80
-                    triggerMsgSb.append("<br>----------------------<br>").append("调度失败:").append("执行器地址为空");
82
+                    triggerMsgSb.append("<br>----------------------<br>").append(I18nUtil.getString("jobconf_trigger_address_empty"));
81 83
                 }
82 84
 
83 85
                 if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) {
@@ -97,12 +99,12 @@ public class XxlJobTrigger {
97 99
 
98 100
                     // 4.2、trigger-run (route run / trigger remote executor)
99 101
                     triggerResult = runExecutor(triggerParam, address);     // update03
100
-                    triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
102
+                    triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
101 103
 
102 104
                     // 4.3、trigger (fail retry)
103 105
                     if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
104 106
                         triggerResult = runExecutor(triggerParam, address);  // update04
105
-                        triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
107
+                        triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_fail_retry") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
106 108
                     }
107 109
                 }
108 110
 
@@ -112,7 +114,7 @@ public class XxlJobTrigger {
112 114
                 jobLog.setTriggerMsg(triggerMsgSb.toString());
113 115
                 XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog);
114 116
 
115
-                // 6、monitor triger
117
+                // 6、monitor trigger
116 118
                 JobFailMonitorHelper.monitor(jobLog.getId());
117 119
                 logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
118 120
 
@@ -134,17 +136,18 @@ public class XxlJobTrigger {
134 136
 
135 137
             ReturnT<String> triggerResult = new ReturnT<String>(null);
136 138
             StringBuffer triggerMsgSb = new StringBuffer();
137
-            triggerMsgSb.append("调度机器:").append(IpUtil.getIp());
138
-            triggerMsgSb.append("<br>执行器-注册方式:").append( (group.getAddressType() == 0)?"自动注册":"手动录入" );
139
-            triggerMsgSb.append("<br>执行器-地址列表:").append(group.getRegistryList());
140
-            triggerMsgSb.append("<br>路由策略:").append(executorRouteStrategyEnum.getTitle());
141
-            triggerMsgSb.append("<br>阻塞处理策略:").append(blockStrategy.getTitle());
142
-            triggerMsgSb.append("<br>失败处理策略:").append(failStrategy.getTitle());
139
+            triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
140
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
141
+                    .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
142
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
143
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle());
144
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
145
+            triggerMsgSb.append("<br>").append(I18nUtil.getString("jobinfo_field_executorFailStrategy")).append(":").append(failStrategy.getTitle());
143 146
 
144 147
             // 3、trigger-valid
145 148
             if (triggerResult.getCode()==ReturnT.SUCCESS_CODE && CollectionUtils.isEmpty(addressList)) {
146 149
                 triggerResult.setCode(ReturnT.FAIL_CODE);
147
-                triggerMsgSb.append("<br>----------------------<br>").append("调度失败:").append("执行器地址为空");
150
+                triggerMsgSb.append("<br>----------------------<br>").append(I18nUtil.getString("jobconf_trigger_address_empty"));
148 151
             }
149 152
 
150 153
             if (triggerResult.getCode() == ReturnT.SUCCESS_CODE) {
@@ -164,12 +167,12 @@ public class XxlJobTrigger {
164 167
 
165 168
                 // 4.2、trigger-run (route run / trigger remote executor)
166 169
                 triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
167
-                triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发调度<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
170
+                triggerMsgSb.append("<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
168 171
 
169 172
                 // 4.3、trigger (fail retry)
170 173
                 if (triggerResult.getCode()!=ReturnT.SUCCESS_CODE && failStrategy == ExecutorFailStrategyEnum.FAIL_RETRY) {
171 174
                     triggerResult = executorRouteStrategyEnum.getRouter().routeRun(triggerParam, addressList);
172
-                    triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>调度失败重试<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
175
+                    triggerMsgSb.append("<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_fail_retry") +"<<<<<<<<<<< </span><br>").append(triggerResult.getMsg());
173 176
                 }
174 177
             }
175 178
 
@@ -179,7 +182,7 @@ public class XxlJobTrigger {
179 182
             jobLog.setTriggerMsg(triggerMsgSb.toString());
180 183
             XxlJobDynamicScheduler.xxlJobLogDao.updateTriggerInfo(jobLog);
181 184
 
182
-            // 6、monitor triger
185
+            // 6、monitor trigger
183 186
             JobFailMonitorHelper.monitor(jobLog.getId());
184 187
             logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
185 188
         }
@@ -202,7 +205,7 @@ public class XxlJobTrigger {
202 205
             runResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );
203 206
         }
204 207
 
205
-        StringBuffer runResultSB = new StringBuffer("触发调度:");
208
+        StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":");
206 209
         runResultSB.append("<br>address:").append(address);
207 210
         runResultSB.append("<br>code:").append(runResult.getCode());
208 211
         runResultSB.append("<br>msg:").append(runResult.getMsg());

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

@@ -0,0 +1,25 @@
1
+package com.xxl.job.admin.core.util;
2
+
3
+import freemarker.ext.beans.BeansWrapper;
4
+import freemarker.template.TemplateHashModel;
5
+
6
+/**
7
+ * ftl util
8
+ *
9
+ * @author xuxueli 2018-01-17 20:37:48
10
+ */
11
+public class FtlUtil {
12
+
13
+    public static TemplateHashModel generateStaticModel(String packageName) {
14
+        try {
15
+            BeansWrapper wrapper = BeansWrapper.getDefaultInstance();
16
+            TemplateHashModel staticModels = wrapper.getStaticModels();
17
+            TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName);
18
+            return fileStatics;
19
+        } catch (Exception e) {
20
+            e.printStackTrace();
21
+        }
22
+        return null;
23
+    }
24
+
25
+}

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

@@ -0,0 +1,82 @@
1
+package com.xxl.job.admin.core.util;
2
+
3
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
4
+import com.xxl.job.core.util.JacksonUtil;
5
+import org.apache.commons.lang3.StringUtils;
6
+import org.slf4j.Logger;
7
+import org.slf4j.LoggerFactory;
8
+import org.springframework.core.io.ClassPathResource;
9
+import org.springframework.core.io.Resource;
10
+import org.springframework.core.io.support.EncodedResource;
11
+import org.springframework.core.io.support.PropertiesLoaderUtils;
12
+
13
+import java.io.IOException;
14
+import java.text.MessageFormat;
15
+import java.util.HashMap;
16
+import java.util.Map;
17
+import java.util.Properties;
18
+
19
+/**
20
+ * i18n util
21
+ *
22
+ * @author xuxueli 2018-01-17 20:39:06
23
+ */
24
+public class I18nUtil {
25
+    private static Logger logger = LoggerFactory.getLogger(I18nUtil.class);
26
+
27
+    private static Properties prop = null;
28
+    public static Properties loadI18nProp(){
29
+        if (prop != null) {
30
+            return prop;
31
+        }
32
+        try {
33
+            // bild i18n prop
34
+            String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
35
+            i18n = StringUtils.isNotBlank(i18n)?("_"+i18n):i18n;
36
+            String i18nFile = MessageFormat.format("i18n/message{0}.properties", i18n);
37
+
38
+            // load prop
39
+            Resource resource = new ClassPathResource(i18nFile);
40
+            EncodedResource encodedResource = new EncodedResource(resource,"UTF-8");
41
+            prop = PropertiesLoaderUtils.loadProperties(encodedResource);
42
+        } catch (IOException e) {
43
+            logger.error(e.getMessage(), e);
44
+        }
45
+        return prop;
46
+    }
47
+
48
+    /**
49
+     * get val of i18n key
50
+     *
51
+     * @param key
52
+     * @return
53
+     */
54
+    public static String getString(String key) {
55
+        return loadI18nProp().getProperty(key);
56
+    }
57
+
58
+    /**
59
+     * get mult val of i18n mult key, as json
60
+     *
61
+     * @param keys
62
+     * @return
63
+     */
64
+    public static String getMultString(String... keys) {
65
+        Map<String, String> map = new HashMap<>();
66
+
67
+        Properties prop = loadI18nProp();
68
+        if (keys!=null && keys.length>0) {
69
+            for (String key: keys) {
70
+                map.put(key, prop.getProperty(key));
71
+            }
72
+        } else {
73
+            for (String key: prop.stringPropertyNames()) {
74
+                map.put(key, prop.getProperty(key));
75
+            }
76
+        }
77
+
78
+        String json = JacksonUtil.writeValueAsString(map);
79
+        return json;
80
+    }
81
+
82
+}

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

@@ -0,0 +1,134 @@
1
+package com.xxl.job.admin.core.util;
2
+
3
+import org.apache.commons.lang3.StringUtils;
4
+
5
+import java.util.concurrent.ConcurrentHashMap;
6
+
7
+/**
8
+ * local cache tool
9
+ *
10
+ * @author xuxueli 2018-01-22 21:37:34
11
+ */
12
+public class LocalCacheUtil {
13
+
14
+    private static ConcurrentHashMap<String, LocalCacheData> cacheRepository = new ConcurrentHashMap<>();
15
+    private static class LocalCacheData{
16
+        private String key;
17
+        private Object val;
18
+        private long timeoutTime;
19
+
20
+        public LocalCacheData() {
21
+        }
22
+
23
+        public LocalCacheData(String key, Object val, long timeoutTime) {
24
+            this.key = key;
25
+            this.val = val;
26
+            this.timeoutTime = timeoutTime;
27
+        }
28
+
29
+        public String getKey() {
30
+            return key;
31
+        }
32
+
33
+        public void setKey(String key) {
34
+            this.key = key;
35
+        }
36
+
37
+        public Object getVal() {
38
+            return val;
39
+        }
40
+
41
+        public void setVal(Object val) {
42
+            this.val = val;
43
+        }
44
+
45
+        public long getTimeoutTime() {
46
+            return timeoutTime;
47
+        }
48
+
49
+        public void setTimeoutTime(long timeoutTime) {
50
+            this.timeoutTime = timeoutTime;
51
+        }
52
+    }
53
+
54
+
55
+    /**
56
+     * set cache
57
+     *
58
+     * @param key
59
+     * @param val
60
+     * @param cacheTime
61
+     * @return
62
+     */
63
+    public static boolean set(String key, Object val, long cacheTime){
64
+
65
+        // clean timeout cache, before set new cache (avoid cache too much)
66
+        cleanTimeutCache();
67
+
68
+        // set new cache
69
+        if (StringUtils.isBlank(key)) {
70
+            return false;
71
+        }
72
+        if (val == null) {
73
+            remove(key);
74
+        }
75
+        if (cacheTime <= 0) {
76
+            remove(key);
77
+        }
78
+        long timeoutTime = System.currentTimeMillis() + cacheTime;
79
+        LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime);
80
+        cacheRepository.put(localCacheData.getKey(), localCacheData);
81
+        return true;
82
+    }
83
+
84
+    /**
85
+     * remove cache
86
+     *
87
+     * @param key
88
+     * @return
89
+     */
90
+    public static boolean remove(String key){
91
+        if (StringUtils.isBlank(key)) {
92
+            return false;
93
+        }
94
+        cacheRepository.remove(key);
95
+        return true;
96
+    }
97
+
98
+    /**
99
+     * get cache
100
+     *
101
+     * @param key
102
+     * @return
103
+     */
104
+    public static Object get(String key){
105
+        if (StringUtils.isBlank(key)) {
106
+            return null;
107
+        }
108
+        LocalCacheData localCacheData = cacheRepository.get(key);
109
+        if (localCacheData!=null && System.currentTimeMillis()<localCacheData.getTimeoutTime()) {
110
+            return localCacheData.getVal();
111
+        } else {
112
+            remove(key);
113
+            return null;
114
+        }
115
+    }
116
+
117
+    /**
118
+     * clean timeout cache
119
+     *
120
+     * @return
121
+     */
122
+    public static boolean cleanTimeutCache(){
123
+        if (!cacheRepository.keySet().isEmpty()) {
124
+            for (String key: cacheRepository.keySet()) {
125
+                LocalCacheData localCacheData = cacheRepository.get(key);
126
+                if (localCacheData!=null && System.currentTimeMillis()>=localCacheData.getTimeoutTime()) {
127
+                    cacheRepository.remove(key);
128
+                }
129
+            }
130
+        }
131
+        return true;
132
+    }
133
+
134
+}

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

@@ -1,5 +1,6 @@
1 1
 package com.xxl.job.admin.core.util;
2 2
 
3
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
3 4
 import org.apache.commons.mail.DefaultAuthenticator;
4 5
 import org.apache.commons.mail.EmailException;
5 6
 import org.apache.commons.mail.HtmlEmail;
@@ -16,19 +17,6 @@ import java.nio.charset.Charset;
16 17
 public class MailUtil {
17 18
 	private static Logger logger = LoggerFactory.getLogger(MailUtil.class);
18 19
 	
19
-	private static String host;
20
-	private static String port;
21
-	private static String username;
22
-	private static String password;
23
-	private static String sendNick;
24
-	static{
25
-		host = PropertiesUtil.getString("xxl.job.mail.host");
26
-		port = PropertiesUtil.getString("xxl.job.mail.port");
27
-		username = PropertiesUtil.getString("xxl.job.mail.username");
28
-		password = PropertiesUtil.getString("xxl.job.mail.password");
29
-		sendNick = PropertiesUtil.getString("xxl.job.mail.sendNick");
30
-	}
31
-
32 20
 	/**
33 21
 	 *
34 22
 	 * @param toAddress		收件人邮箱
@@ -46,13 +34,13 @@ public class MailUtil {
46 34
 			//email.setTLS(true);		// 是否TLS校验,,某些邮箱需要TLS安全校验,同理有SSL校验
47 35
 			//email.setSSL(true);
48 36
 
49
-			email.setHostName(host);
50
-			email.setSmtpPort(Integer.valueOf(port));
37
+			email.setHostName(XxlJobAdminConfig.getAdminConfig().getMailHost());
38
+			email.setSmtpPort(Integer.valueOf(XxlJobAdminConfig.getAdminConfig().getMailPort()));
51 39
 			//email.setSslSmtpPort(port);
52
-			email.setAuthenticator(new DefaultAuthenticator(username, password));
40
+			email.setAuthenticator(new DefaultAuthenticator(XxlJobAdminConfig.getAdminConfig().getMailUsername(), XxlJobAdminConfig.getAdminConfig().getMailPassword()));
53 41
 			email.setCharset(Charset.defaultCharset().name());
54 42
 
55
-			email.setFrom(username, sendNick);
43
+			email.setFrom(XxlJobAdminConfig.getAdminConfig().getMailUsername(), XxlJobAdminConfig.getAdminConfig().getMailSendNick());
56 44
 			email.addTo(toAddress);
57 45
 			email.setSubject(mailSubject);
58 46
 			email.setMsg(mailBody);

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

@@ -1,38 +0,0 @@
1
-package com.xxl.job.admin.core.util;
2
-
3
-import org.slf4j.Logger;
4
-import org.slf4j.LoggerFactory;
5
-import org.springframework.core.io.ClassPathResource;
6
-import org.springframework.core.io.Resource;
7
-import org.springframework.core.io.support.EncodedResource;
8
-import org.springframework.core.io.support.PropertiesLoaderUtils;
9
-
10
-import java.io.IOException;
11
-import java.util.Properties;
12
-
13
-/**
14
- * properties util
15
- *
16
- * @author xuxueli 2015-8-28 10:35:53
17
- */
18
-public class PropertiesUtil {
19
-	private static Logger logger = LoggerFactory.getLogger(PropertiesUtil.class);
20
-	private static final String file_name = "xxl-job-admin.properties";
21
-
22
-
23
-	public static String getString(String key) {
24
-		Properties prop = null;
25
-		try {
26
-			Resource resource = new ClassPathResource(file_name);
27
-			EncodedResource encodedResource = new EncodedResource(resource,"UTF-8");
28
-			prop = PropertiesLoaderUtils.loadProperties(encodedResource);
29
-		} catch (IOException e) {
30
-			logger.error(e.getMessage(), e);
31
-		}
32
-		if (prop!=null) {
33
-			return prop.getProperty(key);
34
-		}
35
-		return null;
36
-	}
37
-
38
-}

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

@@ -12,8 +12,16 @@ import java.util.List;
12 12
  */
13 13
 public interface XxlJobInfoDao {
14 14
 
15
-	public List<XxlJobInfo> pageList(@Param("offset") int offset, @Param("pagesize") int pagesize, @Param("jobGroup") int jobGroup, @Param("executorHandler") String executorHandler);
16
-	public int pageListCount(@Param("offset") int offset, @Param("pagesize") int pagesize, @Param("jobGroup") int jobGroup, @Param("executorHandler") String executorHandler);
15
+	public List<XxlJobInfo> pageList(@Param("offset") int offset,
16
+									 @Param("pagesize") int pagesize,
17
+									 @Param("jobGroup") int jobGroup,
18
+									 @Param("jobDesc") String jobDesc,
19
+									 @Param("executorHandler") String executorHandler);
20
+	public int pageListCount(@Param("offset") int offset,
21
+							 @Param("pagesize") int pagesize,
22
+							 @Param("jobGroup") int jobGroup,
23
+							 @Param("jobDesc") String jobDesc,
24
+							 @Param("executorHandler") String executorHandler);
17 25
 	
18 26
 	public int save(XxlJobInfo info);
19 27
 

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

@@ -41,8 +41,7 @@ public interface XxlJobLogDao {
41 41
 	public int triggerCountByHandleCode(@Param("handleCode") int handleCode);
42 42
 
43 43
 	public List<Map<String, Object>> triggerCountByDay(@Param("from") Date from,
44
-													   @Param("to") Date to,
45
-													   @Param("handleCode") int handleCode);
44
+													   @Param("to") Date to);
46 45
 
47 46
 	public int clearLog(@Param("jobGroup") int jobGroup,
48 47
 						@Param("jobId") int jobId,

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

@@ -13,23 +13,82 @@ import java.util.Map;
13 13
  * @author xuxueli 2016-5-28 15:30:33
14 14
  */
15 15
 public interface XxlJobService {
16
-	
17
-	public Map<String, Object> pageList(int start, int length, int jobGroup, String executorHandler, String filterTime);
18
-	
16
+
17
+	/**
18
+	 * page list
19
+	 *
20
+	 * @param start
21
+	 * @param length
22
+	 * @param jobGroup
23
+	 * @param jobDesc
24
+	 * @param executorHandler
25
+	 * @param filterTime
26
+	 * @return
27
+	 */
28
+	public Map<String, Object> pageList(int start, int length, int jobGroup, String jobDesc, String executorHandler, String filterTime);
29
+
30
+	/**
31
+	 * add job
32
+	 *
33
+	 * @param jobInfo
34
+	 * @return
35
+	 */
19 36
 	public ReturnT<String> add(XxlJobInfo jobInfo);
20
-	
21
-	public ReturnT<String> reschedule(XxlJobInfo jobInfo);
22
-	
37
+
38
+	/**
39
+	 * update job
40
+	 *
41
+	 * @param jobInfo
42
+	 * @return
43
+	 */
44
+	public ReturnT<String> update(XxlJobInfo jobInfo);
45
+
46
+	/**
47
+	 * remove job
48
+	 *
49
+	 * @param id
50
+	 * @return
51
+	 */
23 52
 	public ReturnT<String> remove(int id);
24
-	
53
+
54
+	/**
55
+	 * pause job
56
+	 *
57
+	 * @param id
58
+	 * @return
59
+	 */
25 60
 	public ReturnT<String> pause(int id);
26
-	
61
+
62
+	/**
63
+	 * resume job
64
+	 *
65
+	 * @param id
66
+	 * @return
67
+	 */
27 68
 	public ReturnT<String> resume(int id);
28
-	
69
+
70
+	/**
71
+	 * trigger job
72
+	 *
73
+	 * @param id
74
+	 * @return
75
+	 */
29 76
 	public ReturnT<String> triggerJob(int id);
30 77
 
78
+	/**
79
+	 * dashboard info
80
+	 *
81
+	 * @return
82
+	 */
31 83
 	public Map<String,Object> dashboardInfo();
32 84
 
33
-	public ReturnT<Map<String,Object>> triggerChartDate(Date startDate, Date endDate);
85
+	/**
86
+	 * chart info
87
+	 *
88
+	 * @param startDate
89
+	 * @param endDate
90
+	 * @return
91
+	 */
92
+	public ReturnT<Map<String,Object>> chartInfo(Date startDate, Date endDate);
34 93
 
35 94
 }

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

@@ -2,6 +2,7 @@ package com.xxl.job.admin.service.impl;
2 2
 
3 3
 import com.xxl.job.admin.core.model.XxlJobInfo;
4 4
 import com.xxl.job.admin.core.model.XxlJobLog;
5
+import com.xxl.job.admin.core.util.I18nUtil;
5 6
 import com.xxl.job.admin.dao.XxlJobInfoDao;
6 7
 import com.xxl.job.admin.dao.XxlJobLogDao;
7 8
 import com.xxl.job.admin.dao.XxlJobRegistryDao;
@@ -64,7 +65,7 @@ public class AdminBizImpl implements AdminBiz {
64 65
         if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
65 66
             XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId());
66 67
             if (xxlJobInfo!=null && StringUtils.isNotBlank(xxlJobInfo.getChildJobId())) {
67
-                callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>触发子任务<<<<<<<<<<< </span><br>";
68
+                callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";
68 69
 
69 70
                 String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
70 71
                 for (int i = 0; i < childJobIds.length; i++) {
@@ -73,21 +74,27 @@ public class AdminBizImpl implements AdminBiz {
73 74
                         ReturnT<String> triggerChildResult = xxlJobService.triggerJob(childJobId);
74 75
 
75 76
                         // add msg
76
-                        callbackMsg += MessageFormat.format("{0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>",
77
-                                (i+1), childJobIds.length, childJobIds[i], (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), triggerChildResult.getMsg());
77
+                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
78
+                                (i+1),
79
+                                childJobIds.length,
80
+                                childJobIds[i],
81
+                                (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")),
82
+                                triggerChildResult.getMsg());
78 83
                     } else {
79
-                        callbackMsg += MessageFormat.format(" {0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>",
80
-                                (i+1), childJobIds.length, childJobIds[i]);
84
+                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
85
+                                (i+1),
86
+                                childJobIds.length,
87
+                                childJobIds[i]);
81 88
                     }
82 89
                 }
83 90
 
84 91
             }
85 92
         } else if (IJobHandler.FAIL_RETRY.getCode() == handleCallbackParam.getExecuteResult().getCode()){
86 93
             ReturnT<String> retryTriggerResult = xxlJobService.triggerJob(log.getJobId());
87
-            callbackMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>执行失败重试<<<<<<<<<<< </span><br>";
94
+            callbackMsg = "<br><br><span style=\"color:#F39C12;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_exe_fail_retry") +"<<<<<<<<<<< </span><br>";
88 95
 
89
-            callbackMsg += MessageFormat.format("触发{0}, 触发备注: {1}",
90
-                   (retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?"成功":"失败"), retryTriggerResult.getMsg());
96
+            callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_msg1"),
97
+                   (retryTriggerResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")), retryTriggerResult.getMsg());
91 98
         }
92 99
 
93 100
         // handle msg

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

@@ -5,6 +5,8 @@ import com.xxl.job.admin.core.model.XxlJobGroup;
5 5
 import com.xxl.job.admin.core.model.XxlJobInfo;
6 6
 import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
7 7
 import com.xxl.job.admin.core.schedule.XxlJobDynamicScheduler;
8
+import com.xxl.job.admin.core.util.I18nUtil;
9
+import com.xxl.job.admin.core.util.LocalCacheUtil;
8 10
 import com.xxl.job.admin.dao.XxlJobGroupDao;
9 11
 import com.xxl.job.admin.dao.XxlJobInfoDao;
10 12
 import com.xxl.job.admin.dao.XxlJobLogDao;
@@ -45,11 +47,11 @@ public class XxlJobServiceImpl implements XxlJobService {
45 47
 	private XxlJobLogGlueDao xxlJobLogGlueDao;
46 48
 	
47 49
 	@Override
48
-	public Map<String, Object> pageList(int start, int length, int jobGroup, String executorHandler, String filterTime) {
50
+	public Map<String, Object> pageList(int start, int length, int jobGroup, String jobDesc, String executorHandler, String filterTime) {
49 51
 
50 52
 		// page list
51
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, executorHandler);
52
-		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, executorHandler);
53
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(start, length, jobGroup, jobDesc, executorHandler);
54
+		int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, jobDesc, executorHandler);
53 55
 		
54 56
 		// fill job info
55 57
 		if (list!=null && list.size()>0) {
@@ -71,31 +73,31 @@ public class XxlJobServiceImpl implements XxlJobService {
71 73
 		// valid
72 74
 		XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
73 75
 		if (group == null) {
74
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请选择“执行器”");
76
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")) );
75 77
 		}
76 78
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
77
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入格式正确的“Cron”");
79
+			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
78 80
 		}
79 81
 		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
80
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“任务描述”");
82
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
81 83
 		}
82 84
 		if (StringUtils.isBlank(jobInfo.getAuthor())) {
83
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“负责人”");
85
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
84 86
 		}
85 87
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
86
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "路由策略非法");
88
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
87 89
 		}
88 90
 		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
89
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "阻塞处理策略非法");
91
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
90 92
 		}
91 93
 		if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) {
92
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "失败处理策略非法");
94
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorFailStrategy")+I18nUtil.getString("system_unvalid")) );
93 95
 		}
94 96
 		if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
95
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "运行模式非法非法");
97
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
96 98
 		}
97 99
 		if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && StringUtils.isBlank(jobInfo.getExecutorHandler())) {
98
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“JobHandler”");
100
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
99 101
 		}
100 102
 
101 103
 		// fix "\r" in shell
@@ -110,10 +112,12 @@ public class XxlJobServiceImpl implements XxlJobService {
110 112
 				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
111 113
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
112 114
 					if (childJobInfo==null) {
113
-						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem));
115
+						return new ReturnT<String>(ReturnT.FAIL_CODE,
116
+								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
114 117
 					}
115 118
 				} else {
116
-					return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem));
119
+					return new ReturnT<String>(ReturnT.FAIL_CODE,
120
+							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
117 121
 				}
118 122
 			}
119 123
 			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
@@ -122,7 +126,7 @@ public class XxlJobServiceImpl implements XxlJobService {
122 126
 		// add in db
123 127
 		xxlJobInfoDao.save(jobInfo);
124 128
 		if (jobInfo.getId() < 1) {
125
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "新增任务失败");
129
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
126 130
 		}
127 131
 
128 132
 		// add in quartz
@@ -140,31 +144,31 @@ public class XxlJobServiceImpl implements XxlJobService {
140 144
             } catch (SchedulerException e1) {
141 145
                 logger.error(e.getMessage(), e1);
142 146
             }
143
-            return new ReturnT<String>(ReturnT.FAIL_CODE, "新增任务失败:" + e.getMessage());
147
+            return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail"))+":" + e.getMessage());
144 148
         }
145 149
 	}
146 150
 
147 151
 	@Override
148
-	public ReturnT<String> reschedule(XxlJobInfo jobInfo) {
152
+	public ReturnT<String> update(XxlJobInfo jobInfo) {
149 153
 
150 154
 		// valid
151 155
 		if (!CronExpression.isValidExpression(jobInfo.getJobCron())) {
152
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入格式正确的“Cron”");
156
+			return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid") );
153 157
 		}
154 158
 		if (StringUtils.isBlank(jobInfo.getJobDesc())) {
155
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“任务描述”");
159
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
156 160
 		}
157 161
 		if (StringUtils.isBlank(jobInfo.getAuthor())) {
158
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "请输入“负责人”");
162
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
159 163
 		}
160 164
 		if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
161
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "路由策略非法");
165
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
162 166
 		}
163 167
 		if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
164
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "阻塞处理策略非法");
168
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
165 169
 		}
166 170
 		if (ExecutorFailStrategyEnum.match(jobInfo.getExecutorFailStrategy(), null) == null) {
167
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "失败处理策略非法");
171
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorFailStrategy")+I18nUtil.getString("system_unvalid")));
168 172
 		}
169 173
 
170 174
 		// ChildJobId valid
@@ -174,14 +178,16 @@ public class XxlJobServiceImpl implements XxlJobService {
174 178
 				if (StringUtils.isNotBlank(childJobIdItem) && StringUtils.isNumeric(childJobIdItem)) {
175 179
 					XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.valueOf(childJobIdItem));
176 180
 					if (childJobInfo==null) {
177
-						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})无效", childJobIdItem));
181
+						return new ReturnT<String>(ReturnT.FAIL_CODE,
182
+								MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
178 183
 					}
179 184
 					// avoid cycle relate
180 185
 					if (childJobInfo.getId() == jobInfo.getId()) {
181
-						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})不可与父任务重复", childJobIdItem));
186
+						return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format(I18nUtil.getString("jobinfo_field_childJobId_limit"), childJobIdItem));
182 187
 					}
183 188
 				} else {
184
-					return new ReturnT<String>(ReturnT.FAIL_CODE, MessageFormat.format("子任务ID({0})格式错误", childJobIdItem));
189
+					return new ReturnT<String>(ReturnT.FAIL_CODE,
190
+							MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
185 191
 				}
186 192
 			}
187 193
 			jobInfo.setChildJobId(StringUtils.join(childJobIds, ","));
@@ -190,7 +196,7 @@ public class XxlJobServiceImpl implements XxlJobService {
190 196
 		// stage job info
191 197
 		XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
192 198
 		if (exists_jobInfo == null) {
193
-			return new ReturnT<String>(ReturnT.FAIL_CODE, "参数异常");
199
+			return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_not_found")) );
194 200
 		}
195 201
 		//String old_cron = exists_jobInfo.getJobCron();
196 202
 
@@ -271,7 +277,7 @@ public class XxlJobServiceImpl implements XxlJobService {
271 277
 	public ReturnT<String> triggerJob(int id) {
272 278
         XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
273 279
         if (xxlJobInfo == null) {
274
-        	return new ReturnT<String>(ReturnT.FAIL_CODE, "任务ID非法");
280
+        	return new ReturnT<String>(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id")+I18nUtil.getString("system_unvalid")) );
275 281
 		}
276 282
 
277 283
         String group = String.valueOf(xxlJobInfo.getJobGroup());
@@ -315,38 +321,42 @@ public class XxlJobServiceImpl implements XxlJobService {
315 321
 		return dashboardMap;
316 322
 	}
317 323
 
324
+	private static final String TRIGGER_CHART_DATA_CACHE = "trigger_chart_data_cache";
318 325
 	@Override
319
-	public ReturnT<Map<String, Object>> triggerChartDate(Date startDate, Date endDate) {
326
+	public ReturnT<Map<String, Object>> chartInfo(Date startDate, Date endDate) {
327
+		// get cache
328
+		String cacheKey = TRIGGER_CHART_DATA_CACHE + "_" + startDate.getTime() + "_" + endDate.getTime();
329
+		Map<String, Object> chartInfo = (Map<String, Object>) LocalCacheUtil.get(cacheKey);
330
+		if (chartInfo != null) {
331
+			return new ReturnT<Map<String, Object>>(chartInfo);
332
+		}
333
+
334
+		// process
320 335
 		List<String> triggerDayList = new ArrayList<String>();
336
+		List<Integer> triggerDayCountRunningList = new ArrayList<Integer>();
321 337
 		List<Integer> triggerDayCountSucList = new ArrayList<Integer>();
322 338
 		List<Integer> triggerDayCountFailList = new ArrayList<Integer>();
339
+		int triggerCountRunningTotal = 0;
323 340
 		int triggerCountSucTotal = 0;
324 341
 		int triggerCountFailTotal = 0;
325 342
 
326
-		List<Map<String, Object>> triggerCountMapAll = xxlJobLogDao.triggerCountByDay(startDate, endDate, -1);
327
-		List<Map<String, Object>> triggerCountMapSuc = xxlJobLogDao.triggerCountByDay(startDate, endDate, ReturnT.SUCCESS_CODE);
343
+		List<Map<String, Object>> triggerCountMapAll = xxlJobLogDao.triggerCountByDay(startDate, endDate);
328 344
 		if (CollectionUtils.isNotEmpty(triggerCountMapAll)) {
329 345
 			for (Map<String, Object> item: triggerCountMapAll) {
330 346
 				String day = String.valueOf(item.get("triggerDay"));
331
-				int dayAllCount = Integer.valueOf(String.valueOf(item.get("triggerCount")));
332
-				int daySucCount = 0;
333
-				int dayFailCount = dayAllCount - daySucCount;
334
-
335
-				if (CollectionUtils.isNotEmpty(triggerCountMapSuc)) {
336
-					for (Map<String, Object> sucItem: triggerCountMapSuc) {
337
-						String daySuc = String.valueOf(sucItem.get("triggerDay"));
338
-						if (day.equals(daySuc)) {
339
-							daySucCount = Integer.valueOf(String.valueOf(sucItem.get("triggerCount")));
340
-							dayFailCount = dayAllCount - daySucCount;
341
-						}
342
-					}
343
-				}
347
+				int triggerDayCount = Integer.valueOf(String.valueOf(item.get("triggerDayCount")));
348
+				int triggerDayCountRunning = Integer.valueOf(String.valueOf(item.get("triggerDayCountRunning")));
349
+				int triggerDayCountSuc = Integer.valueOf(String.valueOf(item.get("triggerDayCountSuc")));
350
+				int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;
344 351
 
345 352
 				triggerDayList.add(day);
346
-				triggerDayCountSucList.add(daySucCount);
347
-				triggerDayCountFailList.add(dayFailCount);
348
-				triggerCountSucTotal += daySucCount;
349
-				triggerCountFailTotal += dayFailCount;
353
+				triggerDayCountRunningList.add(triggerDayCountRunning);
354
+				triggerDayCountSucList.add(triggerDayCountSuc);
355
+				triggerDayCountFailList.add(triggerDayCountFail);
356
+
357
+				triggerCountRunningTotal += triggerDayCountRunning;
358
+				triggerCountSucTotal += triggerDayCountSuc;
359
+				triggerCountFailTotal += triggerDayCountFail;
350 360
 			}
351 361
 		} else {
352 362
             for (int i = 4; i > -1; i--) {
@@ -358,10 +368,17 @@ public class XxlJobServiceImpl implements XxlJobService {
358 368
 
359 369
 		Map<String, Object> result = new HashMap<String, Object>();
360 370
 		result.put("triggerDayList", triggerDayList);
371
+		result.put("triggerDayCountRunningList", triggerDayCountRunningList);
361 372
 		result.put("triggerDayCountSucList", triggerDayCountSucList);
362 373
 		result.put("triggerDayCountFailList", triggerDayCountFailList);
374
+
375
+		result.put("triggerCountRunningTotal", triggerCountRunningTotal);
363 376
 		result.put("triggerCountSucTotal", triggerCountSucTotal);
364 377
 		result.put("triggerCountFailTotal", triggerCountFailTotal);
378
+
379
+		// set cache
380
+		LocalCacheUtil.set(cacheKey, result, 60*1000);     // cache 60s
381
+
365 382
 		return new ReturnT<Map<String, Object>>(result);
366 383
 	}
367 384
 

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

@@ -0,0 +1,226 @@
1
+admin_name=任务调度中心
2
+admin_name_full=分布式任务调度平台XXL-JOB
3
+admin_version=1.9.2 (快照版)
4
+
5
+## system
6
+system_tips=系统提示
7
+system_ok=确定
8
+system_close=关闭
9
+system_save=保存
10
+system_cancel=取消
11
+system_search=搜索
12
+system_status=状态
13
+system_opt=操作
14
+system_please_input=请输入
15
+system_please_choose=请选择
16
+system_success=成功
17
+system_fail=失败
18
+system_add_suc=新增成功
19
+system_add_fail=新增失败
20
+system_update_suc=更新成功
21
+system_update_fail=更新失败
22
+system_all=全部
23
+system_api_error=接口异常
24
+system_show=查看
25
+system_empty=无
26
+system_opt_suc=操作成功
27
+system_opt_fail=操作失败
28
+system_opt_edit=编辑
29
+system_opt_del=删除
30
+system_unvalid=非法
31
+system_not_found=不存在
32
+system_nav=导航
33
+
34
+## daterangepicker
35
+daterangepicker_ranges_recent_hour=最近一小时
36
+daterangepicker_ranges_today=今日
37
+daterangepicker_ranges_yesterday=昨日
38
+daterangepicker_ranges_this_month=本月
39
+daterangepicker_ranges_last_month=上个月
40
+daterangepicker_ranges_recent_week=最近一周
41
+daterangepicker_ranges_recent_month=最近一月
42
+daterangepicker_custom_name=自定义
43
+daterangepicker_custom_starttime=起始时间
44
+daterangepicker_custom_endtime=结束时间
45
+daterangepicker_custom_daysofweek=日,一,二,三,四,五,六
46
+daterangepicker_custom_monthnames=一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月
47
+
48
+## dataTable
49
+dataTable_sProcessing=处理中...
50
+dataTable_sLengthMenu=每页 _MENU_ 条记录
51
+dataTable_sZeroRecords=没有匹配结果
52
+dataTable_sInfo=第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 )
53
+dataTable_sInfoEmpty=无记录
54
+dataTable_sInfoFiltered=(由 _MAX_ 项结果过滤)
55
+dataTable_sSearch=搜索
56
+dataTable_sEmptyTable=表中数据为空
57
+dataTable_sLoadingRecords=载入中...
58
+dataTable_sFirst=首页
59
+dataTable_sPrevious=上页
60
+dataTable_sNext=下页
61
+dataTable_sLast=末页
62
+dataTable_sSortAscending=: 以升序排列此列
63
+dataTable_sSortDescending=: 以降序排列此列
64
+
65
+## login
66
+login_btn=登录
67
+login_remember_me=记住密码
68
+login_username_placeholder=请输入登录账号
69
+login_password_placeholder=请输入登录密码
70
+login_username_empty=请输入登录账号
71
+login_username_lt_5=登录账号不应低于5位
72
+login_password_empty=请输入登录密码
73
+login_password_lt_5=登录密码不应低于5位
74
+login_success=登录成功
75
+login_fail=登录失败
76
+login_param_empty=账号或密码为空
77
+login_param_unvalid=账号或密码错误
78
+
79
+## logout
80
+logout_btn=注销
81
+logout_confirm=确认注销登录?
82
+logout_success=注销成功
83
+logout_fail=注销失败
84
+
85
+## dashboard
86
+job_dashboard_name=运行报表
87
+job_dashboard_job_num=任务数量
88
+job_dashboard_job_num_tip=调度中心运行的任务数量
89
+job_dashboard_trigger_num=调度次数
90
+job_dashboard_trigger_num_tip=调度中心触发的调度次数
91
+job_dashboard_jobgroup_num=执行器数量
92
+job_dashboard_jobgroup_num_tip=调度中心在线的执行器机器数量
93
+job_dashboard_report=调度报表
94
+job_dashboard_report_loaddata_fail=调度报表数据加载异常
95
+job_dashboard_date_report=日期分布图
96
+job_dashboard_rate_report=成功比例图
97
+
98
+## job info
99
+jobinfo_name=任务管理
100
+jobinfo_job=任务
101
+jobinfo_field_add=新增任务
102
+jobinfo_field_update=更新任务
103
+jobinfo_field_id=任务ID
104
+jobinfo_field_jobgroup=执行器
105
+jobinfo_field_jobdesc=任务描述
106
+jobinfo_field_gluetype=运行模式
107
+jobinfo_field_executorparam=任务参数
108
+jobinfo_field_cron_unvalid=Cron格式非法
109
+jobinfo_field_author=负责人
110
+jobinfo_field_alarmemail=报警邮件
111
+jobinfo_field_alarmemail_placeholder=请输入报警邮件,多个邮件地址则逗号分隔
112
+jobinfo_field_executorRouteStrategy=路由策略
113
+jobinfo_field_childJobId=子任务ID
114
+jobinfo_field_childJobId_limit=子任务ID({0})不可与父任务重复
115
+jobinfo_field_childJobId_placeholder=请输入子任务的任务ID,如存在多个则逗号分隔
116
+jobinfo_field_executorBlockStrategy=阻塞处理策略
117
+jobinfo_field_executorFailStrategy=失败处理策略
118
+jobinfo_script_location=脚本位置
119
+jobinfo_shard_index=分片序号
120
+jobinfo_shard_total=分片总数
121
+jobinfo_opt_pause=暂停
122
+jobinfo_opt_resume=恢复
123
+jobinfo_opt_log=日志
124
+jobinfo_opt_run=执行
125
+jobinfo_glue_remark=源码备注
126
+jobinfo_glue_remark_limit=源码备注长度限制为4~100
127
+jobinfo_glue_rollback=版本回溯
128
+jobinfo_glue_jobid_unvalid=任务ID非法
129
+jobinfo_glue_gluetype_unvalid=该任务非GLUE模式
130
+
131
+## job log
132
+joblog_name=调度日志
133
+joblog_status=状态
134
+joblog_status_all=全部
135
+joblog_status_suc=成功
136
+joblog_status_fail=失败
137
+joblog_status_running=进行中
138
+joblog_field_triggerTime=调度时间
139
+joblog_field_triggerCode=调度结果
140
+joblog_field_triggerMsg=调度备注
141
+joblog_field_handleTime=执行时间
142
+joblog_field_handleCode=执行结果
143
+joblog_field_handleMsg=执行备注
144
+joblog_field_executorAddress=执行器地址
145
+joblog_clean=清理
146
+joblog_clean_log=日志清理
147
+joblog_clean_type=清理方式
148
+joblog_clean_type_1=清理一个月之前日志数据
149
+joblog_clean_type_2=清理三个月之前日志数据
150
+joblog_clean_type_3=清理六个月之前日志数据
151
+joblog_clean_type_4=清理一年之前日志数据
152
+joblog_clean_type_5=清理一千条以前日志数据
153
+joblog_clean_type_6=清理一万条以前日志数据
154
+joblog_clean_type_7=清理三万条以前日志数据
155
+joblog_clean_type_8=清理十万条以前日志数据
156
+joblog_clean_type_9=清理所有日志数据
157
+joblog_clean_type_unvalid=清理类型参数异常
158
+joblog_handleCode_200=成功
159
+joblog_handleCode_500=失败
160
+joblog_handleCode_501=失败重试
161
+joblog_kill_log=终止任务
162
+joblog_kill_log_limit=调度失败,无法终止日志
163
+joblog_kill_log_byman=人为操作主动终止
164
+joblog_rolling_log=执行日志
165
+joblog_rolling_log_refresh=刷新
166
+joblog_rolling_log_triggerfail=任务发起调度失败,无法查看执行日志
167
+joblog_rolling_log_failoften=终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志
168
+joblog_logid_unvalid=日志ID非法
169
+
170
+## job group
171
+jobgroup_name=执行器管理
172
+jobgroup_list=执行器列表
173
+jobgroup_add=新增执行器
174
+jobgroup_edit=编辑执行器
175
+jobgroup_del=删除执行器
176
+jobgroup_field_order=排序
177
+jobgroup_field_title=名称
178
+jobgroup_field_addressType=注册方式
179
+jobgroup_field_addressType_0=自动注册
180
+jobgroup_field_addressType_1=手动录入
181
+jobgroup_field_addressType_limit=手动录入注册方式,机器地址不可为空
182
+jobgroup_field_registryList=机器地址
183
+jobgroup_field_registryList_unvalid=机器地址格式非法
184
+jobgroup_field_registryList_placeholder=请输入执行器地址列表,多地址逗号分隔
185
+jobgroup_field_appName_limit=限制以小写字母开头,由小写字母、数字和中划线组成
186
+jobgroup_field_appName_length=AppName长度限制为4~64
187
+jobgroup_field_title_length=名称长度限制为4~12
188
+jobgroup_field_order_digits=请输入整数
189
+jobgroup_field_orderrange=取值范围为1~1000
190
+jobgroup_del_limit_0=拒绝删除,该执行器使用中
191
+jobgroup_del_limit_1=拒绝删除, 系统至少保留一个执行器
192
+
193
+## job conf
194
+jobconf_fail_alarm=失败告警
195
+jobconf_fail_retry=失败重试
196
+jobconf_route_first=第一个
197
+jobconf_route_last=最后一个
198
+jobconf_route_round=轮询
199
+jobconf_route_random=随机
200
+jobconf_route_consistenthash=一致性HASH
201
+jobconf_route_lfu=最不经常使用
202
+jobconf_route_lru=最近最久未使用
203
+jobconf_route_failover=故障转移
204
+jobconf_route_busyover=忙碌转移
205
+jobconf_route_shard=分片广播
206
+jobconf_idleBeat=空闲检测
207
+jobconf_beat=心跳检测
208
+jobconf_monitor=调度中心监控报警
209
+jobconf_monitor_detail=监控告警明细
210
+jobconf_monitor_alarm_title=告警类型
211
+jobconf_monitor_alarm_type=调度失败
212
+jobconf_trigger_admin_adress=调度机器
213
+jobconf_trigger_exe_regtype=执行器-注册方式
214
+jobconf_trigger_exe_regaddress=执行器-地址列表
215
+jobconf_trigger_address_empty=调度失败:执行器地址为空
216
+jobconf_trigger_run=触发调度
217
+jobconf_trigger_child_run=触发子任务
218
+jobconf_trigger_fail_retry=调度失败重试
219
+jobconf_exe_fail_retry=执行失败重试
220
+jobconf_callback_child_msg1={0}/{1} [任务ID={2}], 触发{3}, 触发备注: {4} <br>
221
+jobconf_callback_child_msg2={0}/{1} [任务ID={2}], 触发失败, 触发备注: 任务ID格式错误 <br>
222
+jobconf_callback_msg1=触发{0}, 触发备注: {1} <br>
223
+
224
+## help
225
+job_help=使用教程
226
+job_help_document=官方文档

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

@@ -0,0 +1,226 @@
1
+admin_name=Scheduling Center
2
+admin_name_full=Distributed Task Scheduling Platform XXL-JOB
3
+admin_version=1.9.2 (SNAPSHOT)
4
+
5
+## system
6
+system_tips=System message
7
+system_ok=Confirm 
8
+system_close=Close
9
+system_save=Save 
10
+system_cancel=Cancel
11
+system_search=Search
12
+system_status=Status
13
+system_opt=Operate
14
+system_please_input=please input 
15
+system_please_choose=please choose 
16
+system_success=success
17
+system_fail=fail
18
+system_add_suc=add success
19
+system_add_fail=add fail
20
+system_update_suc=update success
21
+system_update_fail=update fail
22
+system_all=All
23
+system_api_error=net error
24
+system_show=Show
25
+system_empty=Empty
26
+system_opt_suc=operate success
27
+system_opt_fail=operate fail
28
+system_opt_edit=Edit 
29
+system_opt_del=Delete 
30
+system_unvalid=illegal
31
+system_not_found=not exist
32
+system_nav=Navigation
33
+
34
+## daterangepicker
35
+daterangepicker_ranges_recent_hour=recent one hour
36
+daterangepicker_ranges_today=today
37
+daterangepicker_ranges_yesterday=yesterday
38
+daterangepicker_ranges_this_month=this month
39
+daterangepicker_ranges_last_month=last month
40
+daterangepicker_ranges_recent_week=recent one week
41
+daterangepicker_ranges_recent_month=recent one month
42
+daterangepicker_custom_name=custom
43
+daterangepicker_custom_starttime=start time
44
+daterangepicker_custom_endtime=end time
45
+daterangepicker_custom_daysofweek=Sun,Mon,Tue,Wed,Thu,Fri,Sat
46
+daterangepicker_custom_monthnames=Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
47
+
48
+## dataTable
49
+dataTable_sProcessing=processing...
50
+dataTable_sLengthMenu= _MENU_ records per page
51
+dataTable_sZeroRecords=No matching results
52
+dataTable_sInfo=page _PAGE_  ( Total _PAGES_ pages,_TOTAL_ records )
53
+dataTable_sInfoEmpty=No Record
54
+dataTable_sInfoFiltered=(Filtered by _MAX_ results)
55
+dataTable_sSearch=Search
56
+dataTable_sEmptyTable=Table data is empty
57
+dataTable_sLoadingRecords=Loading...
58
+dataTable_sFirst=FIRST PAGE
59
+dataTable_sPrevious=Previous Page
60
+dataTable_sNext=Next Page
61
+dataTable_sLast=LAST PAGE
62
+dataTable_sSortAscending=: Rank this column in ascending order
63
+dataTable_sSortDescending=: Rank this column in descending order
64
+
65
+## login
66
+login_btn=Login
67
+login_remember_me=Remember Me
68
+login_username_placeholder=Please enter username
69
+login_password_placeholder=Please enter password
70
+login_username_empty=Please enter username
71
+login_username_lt_5=Username length should not be less than 5
72
+login_password_empty=Please enter password
73
+login_password_lt_5=Password length should not be less than 5
74
+login_success=Login success
75
+login_fail=Login fail
76
+login_param_empty=Username or password is empty
77
+login_param_unvalid=Username or password error
78
+
79
+## logout
80
+logout_btn=Logout
81
+logout_confirm=Confirm logout?
82
+logout_success=Logout success
83
+logout_fail=Logout fail
84
+
85
+## dashboard
86
+job_dashboard_name=Run report
87
+job_dashboard_job_num=Job number
88
+job_dashboard_job_num_tip=The number of tasks running in the scheduling center
89
+job_dashboard_trigger_num=trigger number
90
+job_dashboard_trigger_num_tip=The number of trigger record scheduled by the scheduling center
91
+job_dashboard_jobgroup_num=Executor number
92
+job_dashboard_jobgroup_num_tip=The number of online executor machines perceived by the scheduling center
93
+job_dashboard_report=Scheduling report
94
+job_dashboard_report_loaddata_fail=Scheduling report load data error
95
+job_dashboard_date_report=Date distribution
96
+job_dashboard_rate_report=Percentage distribution
97
+
98
+## job info
99
+jobinfo_name=Job Manage
100
+jobinfo_job=Job
101
+jobinfo_field_add=Add Job
102
+jobinfo_field_update=Edit Job
103
+jobinfo_field_id=Job ID
104
+jobinfo_field_jobgroup=Executor
105
+jobinfo_field_jobdesc=Job description
106
+jobinfo_field_gluetype=GLUE Type
107
+jobinfo_field_executorparam=Param
108
+jobinfo_field_cron_unvalid=The Cron is illegal
109
+jobinfo_field_author=Author
110
+jobinfo_field_alarmemail=Alarm email
111
+jobinfo_field_alarmemail_placeholder=Please enter alarm mail, if there are more than one comma separated
112
+jobinfo_field_executorRouteStrategy=Route Strategy
113
+jobinfo_field_childJobId=Child Job ID
114
+jobinfo_field_childJobId_limit=Child job ID({0}) cannot be duplicated with the parent job.
115
+jobinfo_field_childJobId_placeholder=Please enter the Child job ID, if there are more than one comma separated
116
+jobinfo_field_executorBlockStrategy=Block Strategy
117
+jobinfo_field_executorFailStrategy=Fail Strategy
118
+jobinfo_script_location=Script location
119
+jobinfo_shard_index=Shard index
120
+jobinfo_shard_total=Shard total
121
+jobinfo_opt_pause=Pause
122
+jobinfo_opt_resume=Resume
123
+jobinfo_opt_log=Log
124
+jobinfo_opt_run=Run
125
+jobinfo_glue_remark=Resource Remark
126
+jobinfo_glue_remark_limit=Resource Remark length is limited to 4~100
127
+jobinfo_glue_rollback=Version Backtrack
128
+jobinfo_glue_jobid_unvalid=Job ID is illegal
129
+jobinfo_glue_gluetype_unvalid=The job is not GLUE Type
130
+
131
+## job log
132
+joblog_name=Trigger Log
133
+joblog_status=Status
134
+joblog_status_all=All
135
+joblog_status_suc=Success
136
+joblog_status_fail=Fail
137
+joblog_status_running=Running
138
+joblog_field_triggerTime=Trigger Time
139
+joblog_field_triggerCode=Trigger Result
140
+joblog_field_triggerMsg=Trigger Msg
141
+joblog_field_handleTime=Handle Time
142
+joblog_field_handleCode=Handle Result
143
+joblog_field_handleMsg=Trigger Msg
144
+joblog_field_executorAddress=Executor Address
145
+joblog_clean=Clean
146
+joblog_clean_log=Clean Log
147
+joblog_clean_type=Clean Type
148
+joblog_clean_type_1=Clean up log data a month ago
149
+joblog_clean_type_2=Clean up log data three month ago
150
+joblog_clean_type_3=Clean up log data six month ago
151
+joblog_clean_type_4=Clean up log data a year ago
152
+joblog_clean_type_5=Clean up log data a thousand record ago
153
+joblog_clean_type_6=Clean up log data ten thousand record ago
154
+joblog_clean_type_7=Clean up log data thirty thousand record ago
155
+joblog_clean_type_8=Clean up log data hundred thousand record ago
156
+joblog_clean_type_9=Clean up all log data
157
+joblog_clean_type_unvalid=Clean type is illegal
158
+joblog_handleCode_200=Success
159
+joblog_handleCode_500=Fail
160
+joblog_handleCode_501=Fail retry
161
+joblog_kill_log=Kill Job
162
+joblog_kill_log_limit=Trigger Fail, can not kill job
163
+joblog_kill_log_byman=Manual operation to active kill job
164
+joblog_rolling_log=Rolling log
165
+joblog_rolling_log_refresh=Refresh 
166
+joblog_rolling_log_triggerfail=The job trigger fail, can not view the rolling log
167
+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
168
+joblog_logid_unvalid=Log ID is illegal
169
+
170
+## job group
171
+jobgroup_name=Executor Manage
172
+jobgroup_list=Executor List
173
+jobgroup_add=Add Executor
174
+jobgroup_edit=Edit Executor
175
+jobgroup_del=Delete Executor
176
+jobgroup_field_order=Order
177
+jobgroup_field_title=Title
178
+jobgroup_field_addressType=Registry Type
179
+jobgroup_field_addressType_0=Automatic registration
180
+jobgroup_field_addressType_1=Manual registration
181
+jobgroup_field_addressType_limit=Manually registration type, the machine address must not be empty
182
+jobgroup_field_registryList=machine address
183
+jobgroup_field_registryList_unvalid=registry machine address is illegal
184
+jobgroup_field_registryList_placeholder=Please enter the machine address, if there are more than one comma separated
185
+jobgroup_field_appName_limit=Limit the beginning of a lowercase letter, consists of lowercase letters、number and underscores.
186
+jobgroup_field_appName_length=AppName length is limited to 4~64
187
+jobgroup_field_title_length=Title length is limited to 4~12
188
+jobgroup_field_order_digits=Please enter a positive integer
189
+jobgroup_field_orderrange=Order is limited to 1~1000
190
+jobgroup_del_limit_0=Refuse to delete, the executor is being used
191
+jobgroup_del_limit_1=Refuses to delete, the system retains at least one executor
192
+
193
+## job conf
194
+jobconf_fail_alarm=Fail Alarm
195
+jobconf_fail_retry=Fail Retry
196
+jobconf_route_first=First
197
+jobconf_route_last=Last
198
+jobconf_route_round=Round
199
+jobconf_route_random=Random
200
+jobconf_route_consistenthash=Consistent Hash
201
+jobconf_route_lfu=Least Frequently Used
202
+jobconf_route_lru=Least Recently Used
203
+jobconf_route_failover=Failover
204
+jobconf_route_busyover=Busyover
205
+jobconf_route_shard=Sharding Broadcast
206
+jobconf_idleBeat=Idle check
207
+jobconf_beat=Heartbeats
208
+jobconf_monitor=Scheduling Center monitor alarm
209
+jobconf_monitor_detail=monitor alarm details
210
+jobconf_monitor_alarm_title=Alarm Type
211
+jobconf_monitor_alarm_type=Trigger Fail
212
+jobconf_trigger_admin_adress=Trigger machine address
213
+jobconf_trigger_exe_regtype=Execotor-Registry Type
214
+jobconf_trigger_exe_regaddress=Execotor-Registry Address
215
+jobconf_trigger_address_empty=Trigger Fail:registry address is empty
216
+jobconf_trigger_run=Trigger Job
217
+jobconf_trigger_child_run=Trigger child job
218
+jobconf_trigger_fail_retry=Trigger fail retry
219
+jobconf_exe_fail_retry=Handle fail retry
220
+jobconf_callback_child_msg1={0}/{1} [Job ID={2}], Trigger {3}, Trigger msg: {4} <br>
221
+jobconf_callback_child_msg2={0}/{1} [Job ID={2}], Trigger Fail, Trigger msg: Job ID is illegal <br>
222
+jobconf_callback_msg1=Trigger {0}, Trigger msg: {1} <br>
223
+
224
+## help
225
+job_help=Tutorial
226
+job_help_document=Official Document

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

@@ -58,6 +58,9 @@
58 58
 			<if test="jobGroup gt 0">
59 59
 				AND t.job_group = #{jobGroup}
60 60
 			</if>
61
+			<if test="jobDesc != null and jobDesc != ''">
62
+				AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
63
+			</if>
61 64
 			<if test="executorHandler != null and executorHandler != ''">
62 65
 				AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
63 66
 			</if>
@@ -73,6 +76,9 @@
73 76
 			<if test="jobGroup gt 0">
74 77
 				AND t.job_group = #{jobGroup}
75 78
 			</if>
79
+			<if test="jobDesc != null and jobDesc != ''">
80
+				AND t.job_desc like CONCAT(CONCAT('%', #{jobDesc}), '%')
81
+			</if>
76 82
 			<if test="executorHandler != null and executorHandler != ''">
77 83
 				AND t.executor_handler like CONCAT(CONCAT('%', #{executorHandler}), '%')
78 84
 			</if>

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

@@ -163,13 +163,14 @@
163 163
 	</select>
164 164
 
165 165
     <select id="triggerCountByDay" resultType="java.util.Map" >
166
-        SELECT DATE_FORMAT(trigger_time,'%Y-%m-%d') triggerDay, COUNT(id) triggerCount
167
-        FROM XXL_JOB_QRTZ_TRIGGER_LOG
168
-        WHERE trigger_time BETWEEN #{from} and #{to}
169
-		<if test="handleCode gt 0">
170
-			AND handle_code = #{handleCode}
171
-		</if>
172
-        GROUP BY triggerDay;
166
+		SELECT
167
+			DATE_FORMAT(trigger_time,'%Y-%m-%d') triggerDay,
168
+			COUNT(handle_code) triggerDayCount,
169
+			SUM(CASE WHEN handle_code = 0 then 1 else 0 end) as triggerDayCountRunning,
170
+			SUM(CASE WHEN handle_code = 200 then 1 else 0 end) as triggerDayCountSuc
171
+		FROM XXL_JOB_QRTZ_TRIGGER_LOG
172
+		WHERE trigger_time BETWEEN #{from} and #{to}
173
+		GROUP BY triggerDay;
173 174
     </select>
174 175
 
175 176
 	<delete id="clearLog" >

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

@@ -20,7 +20,7 @@ org.quartz.jobStore.maxMisfiresToHandleAtATime: 1
20 20
 #org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
21 21
 
22 22
 # for cluster
23
-org.quartz.jobStore.tablePrefix = XXL_JOB_QRTZ_
23
+org.quartz.jobStore.tablePrefix: XXL_JOB_QRTZ_
24 24
 org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
25 25
 org.quartz.jobStore.isClustered: true
26 26
 org.quartz.jobStore.clusterCheckinInterval: 5000

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

@@ -7,7 +7,7 @@
7 7
            http://www.springframework.org/schema/context
8 8
            http://www.springframework.org/schema/context/spring-context.xsd">
9 9
 
10
-	<context:component-scan base-package="com.xxl.job.admin.service, com.xxl.job.admin.dao" />
10
+	<context:component-scan base-package="com.xxl.job.admin.core.conf, com.xxl.job.admin.service, com.xxl.job.admin.dao" />
11 11
 
12 12
 	<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
13 13
 		<property name="templateLoaderPath" value="/WEB-INF/template/" />

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

@@ -16,4 +16,7 @@ xxl.job.login.username=admin
16 16
 xxl.job.login.password=123456
17 17
 
18 18
 ### xxl-job, access token
19
-xxl.job.accessToken=
19
+xxl.job.accessToken=
20
+
21
+### xxl-job, i18n (default empty as chinese, "en" as english)
22
+xxl.job.i18n=

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

@@ -2,7 +2,7 @@
2 2
 <html>
3 3
 <head>
4 4
 	<meta charset="UTF-8">
5
-	<title>应用程序异常 (500)</title> 
5
+	<title>Error</title>
6 6
     <style type="text/css"> 
7 7
         body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
8 8
         div.dialog {
@@ -21,8 +21,9 @@
21 21
 <body> 
22 22
 
23 23
 	<div class="dialog"> 
24
-	    <h1>应用程序异常</h1> 
25
-	    <p>抱歉!您访问的页面出现异常,请稍后重试或联系管理员。</p> 
24
+	    <h1>System Error</h1>
25
+	    <p>Oops! Page not found.</p>
26
+		<a href="javascript:window.location.href='${request.contextPath}/'">Back</a>
26 27
 	</div>
27 28
 
28 29
 </body>

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

@@ -2,7 +2,7 @@
2 2
 <html>
3 3
 <head>
4 4
 	<meta charset="UTF-8">
5
-	<title>应用程序异常 (error)</title> 
5
+	<title>Error</title>
6 6
     <style type="text/css"> 
7 7
         body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
8 8
         div.dialog {
@@ -21,9 +21,9 @@
21 21
 <body> 
22 22
 
23 23
 	<div class="dialog"> 
24
-	    <h1>应用程序异常</h1> 
24
+	    <h1>System Error</h1>
25 25
 	    <p>${exceptionMsg}</p>
26
-		<a href="javascript:window.location.href='${request.contextPath}/'">返 回</a>
26
+		<a href="javascript:window.location.href='${request.contextPath}/'">Back</a>
27 27
 	    </p> 
28 28
 	</div>
29 29
 

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

@@ -29,6 +29,10 @@
29 29
 
30 30
 	<!-- pace -->
31 31
 	<link rel="stylesheet" href="${request.contextPath}/static/plugins/pace/themes/pace-theme-flash.css">
32
+
33
+	<#-- i18n -->
34
+	<#global I18n = I18nUtil.getMultString()?eval />
35
+
32 36
 </#macro>
33 37
 
34 38
 <#macro commonScript>
@@ -53,7 +57,10 @@
53 57
 
54 58
 	<#-- common -->
55 59
     <script src="${request.contextPath}/static/js/common.1.js"></script>
56
-    <script>var base_url = '${request.contextPath}';</script>
60
+    <script>
61
+		var base_url = '${request.contextPath}';
62
+        var I18n = ${I18nUtil.getMultString()};
63
+	</script>
57 64
 
58 65
 </#macro>
59 66
 
@@ -61,7 +68,7 @@
61 68
 	<header class="main-header">
62 69
 		<a href="${request.contextPath}/" class="logo">
63 70
 			<span class="logo-mini"><b>XXL</b></span>
64
-			<span class="logo-lg"><b>任务调度中心</b></span>
71
+			<span class="logo-lg"><b>${I18n.admin_name}</b></span>
65 72
 		</a>
66 73
 		<nav class="navbar navbar-static-top" role="navigation">
67 74
 			<a href="#" class="sidebar-toggle" data-toggle="offcanvas" role="button"><span class="sr-only">切换导航</span></a>
@@ -69,7 +76,7 @@
69 76
 				<ul class="nav navbar-nav">
70 77
 					<li class="dropdown user user-menu">
71 78
 	                    <a href=";" id="logoutBtn" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
72
-                      		<span class="hidden-xs">注销</span>
79
+                      		<span class="hidden-xs">${I18n.logout_btn}</span>
73 80
 	                    </a>
74 81
 					</li>
75 82
 				</ul>
@@ -85,11 +92,11 @@
85 92
 		<section class="sidebar">
86 93
 			<!-- sidebar menu: : style can be found in sidebar.less -->
87 94
 			<ul class="sidebar-menu">
88
-				<li class="header">常用模块</li>
89
-				<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>
90
-				<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>
91
-                <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>
92
-				<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>
95
+                <li class="header">${I18n.system_nav}</li>
96
+				<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>
97
+				<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>
98
+                <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>
99
+				<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>
93 100
 			</ul>
94 101
 		</section>
95 102
 		<!-- /.sidebar -->
@@ -175,7 +182,7 @@
175 182
 
176 183
 <#macro commonFooter >
177 184
 	<footer class="main-footer">
178
-        Powered by <b>XXL-JOB</b> 1.9.0(快照版本)
185
+        Powered by <b>XXL-JOB</b> ${I18n.admin_version}
179 186
 		<div class="pull-right hidden-xs">
180 187
             <strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;
181 188
                 <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 Visa fil

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

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

@@ -1,9 +1,9 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-  	<title>任务调度中心</title>
5 4
   	<#import "/common/common.macro.ftl" as netCommon>
6 5
 	<@netCommon.commonStyle />
6
+	<title>${I18n.admin_name}</title>
7 7
 </head>
8 8
 <body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
9 9
 <div class="wrapper">
@@ -16,25 +16,19 @@
16 16
 	<div class="content-wrapper">
17 17
 		<!-- Content Header (Page header) -->
18 18
 		<section class="content-header">
19
-			<h1>使用教程<small>任务调度中心</small></h1>
20
-			<!--
21
-			<ol class="breadcrumb">
22
-				<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
23
-				<li class="active">使用教程</li>
24
-			</ol>
25
-			-->
19
+			<h1>${I18n.job_help}</h1>
26 20
 		</section>
27 21
 
28 22
 		<!-- Main content -->
29 23
 		<section class="content">
30 24
 			<div class="callout callout-info">
31
-				<h4>分布式任务调度平台XXL-JOB</h4>
25
+				<h4>${I18n.admin_name_full}</h4>
32 26
 				<br>
33 27
 				<p>
34
-					<a target="_blank" href="https://github.com/xuxueli/xxl-job">github</a>&nbsp;&nbsp;&nbsp;&nbsp;
28
+					<a target="_blank" href="https://github.com/xuxueli/xxl-job">Github</a>&nbsp;&nbsp;&nbsp;&nbsp;
35 29
 					<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> 
36 30
 					<br><br>
37
-                    <a target="_blank" href="http://www.xuxueli.com/xxl-job/">文档地址</a>
31
+                    <a target="_blank" href="http://www.xuxueli.com/xxl-job/">${I18n.job_help_document}</a>
38 32
                     <br><br>
39 33
 
40 34
 				</p>

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

@@ -1,11 +1,11 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-  	<title>任务调度中心</title>
5 4
   	<#import "/common/common.macro.ftl" as netCommon>
6 5
 	<@netCommon.commonStyle />
7 6
     <!-- daterangepicker -->
8 7
     <link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/daterangepicker/daterangepicker.css">
8
+    <title>${I18n.admin_name}</title>
9 9
 </head>
10 10
 <body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
11 11
 <div class="wrapper">
@@ -18,8 +18,9 @@
18 18
 	<div class="content-wrapper">
19 19
 		<!-- Content Header (Page header) -->
20 20
 		<section class="content-header">
21
-			<h1>运行报表<small>任务调度中心</small></h1>
21
+			<h1>${I18n.job_dashboard_name}</h1>
22 22
 			<!--
23
+			<h1>运行报表<small>任务调度中心</small></h1>
23 24
 			<ol class="breadcrumb">
24 25
 				<li><a><i class="fa fa-dashboard"></i>调度中心</a></li>
25 26
 				<li class="active">使用教程</li>
@@ -39,13 +40,13 @@
39 40
                         <span class="info-box-icon"><i class="fa fa-flag-o"></i></span>
40 41
 
41 42
                         <div class="info-box-content">
42
-                            <span class="info-box-text">任务数量</span>
43
+                            <span class="info-box-text">${I18n.job_dashboard_job_num}</span>
43 44
                             <span class="info-box-number">${jobInfoCount}</span>
44 45
 
45 46
                             <div class="progress">
46 47
                                 <div class="progress-bar" style="width: 100%"></div>
47 48
                             </div>
48
-                            <span class="progress-description">调度中心运行的任务数量</span>
49
+                            <span class="progress-description">${I18n.job_dashboard_job_num_tip}</span>
49 50
                         </div>
50 51
                     </div>
51 52
                 </div>
@@ -56,14 +57,14 @@
56 57
                         <span class="info-box-icon"><i class="fa fa-calendar"></i></span>
57 58
 
58 59
                         <div class="info-box-content">
59
-                            <span class="info-box-text">调度次数</span>
60
+                            <span class="info-box-text">${I18n.job_dashboard_trigger_num}</span>
60 61
                             <span class="info-box-number">${jobLogCount}</span>
61 62
 
62 63
                             <div class="progress">
63 64
                                 <div class="progress-bar" style="width: 100%" ></div>
64 65
                             </div>
65 66
                             <span class="progress-description">
66
-                                调度中心触发的调度次数
67
+                                ${I18n.job_dashboard_trigger_num_tip}
67 68
                                 <#--<#if jobLogCount gt 0>
68 69
                                     调度成功率:${(jobLogSuccessCount*100/jobLogCount)?string("0.00")}<small>%</small>
69 70
                                 </#if>-->
@@ -78,13 +79,13 @@
78 79
                         <span class="info-box-icon"><i class="fa ion-ios-settings-strong"></i></span>
79 80
 
80 81
                         <div class="info-box-content">
81
-                            <span class="info-box-text">执行器数量</span>
82
+                            <span class="info-box-text">${I18n.job_dashboard_jobgroup_num}</span>
82 83
                             <span class="info-box-number">${executorCount}</span>
83 84
 
84 85
                             <div class="progress">
85 86
                                 <div class="progress-bar" style="width: 100%"></div>
86 87
                             </div>
87
-                            <span class="progress-description">调度中心在线的执行器机器数量</span>
88
+                            <span class="progress-description">${I18n.job_dashboard_jobgroup_num_tip}</span>
88 89
                         </div>
89 90
                     </div>
90 91
                 </div>
@@ -96,7 +97,7 @@
96 97
                 <div class="col-md-12">
97 98
                     <div class="box">
98 99
                         <div class="box-header with-border">
99
-                            <h3 class="box-title">调度报表</h3>
100
+                            <h3 class="box-title">${I18n.job_dashboard_report}</h3>
100 101
                             <#--<input type="text" class="form-control" id="filterTime" readonly >-->
101 102
 
102 103
                             <!-- tools box -->

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

@@ -1,11 +1,11 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-  	<title>任务调度中心</title>
5 4
   	<#import "/common/common.macro.ftl" as netCommon>
6 5
 	<@netCommon.commonStyle />
7 6
 	<link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/lib/codemirror.css">
8 7
 	<link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/addon/hint/show-hint.css">
8
+    <title>${I18n.admin_name}</title>
9 9
 	<style type="text/css">
10 10
 		.CodeMirror {
11 11
       		font-size:16px;
@@ -35,7 +35,11 @@
35 35
                     <#-- left nav -->
36 36
                     <div class="collapse navbar-collapse pull-left" id="navbar-collapse">
37 37
                         <ul class="nav navbar-nav">
38
-                            <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>
38
+                            <li class="active" ><a href="javascript:;">
39
+                                <span class="sr-only">(current)</span>
40
+                                【<#list GlueTypeEnum as item><#if item == jobInfo.glueType>${item.desc}</#if></#list>】
41
+                                ${jobInfo.jobDesc}
42
+                            </a></li>
39 43
                         </ul>
40 44
                     </div>
41 45
 
@@ -43,7 +47,7 @@
43 47
                     <div class="navbar-custom-menu">
44 48
                         <ul class="nav navbar-nav">
45 49
                             <li class="dropdown">
46
-                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">版本回溯 <span class="caret"></span></a>
50
+                                <a href="#" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">${I18n.jobinfo_glue_rollback} <span class="caret"></span></a>
47 51
                                 <ul class="dropdown-menu" role="menu">
48 52
                                     <li <#if jobLogGlues?exists && jobLogGlues?size gt 0 >style="display: none;"</#if> >
49 53
                                         <a href="javascript:;" class="source_version" version="version_now" glueType="${jobInfo.glueType}" >
@@ -66,7 +70,7 @@
66 70
                             <li id="save" >
67 71
 								<a href="javascript:;" >
68 72
 									<i class="fa fa-fw fa-save" ></i>
69
-                                    保存
73
+                                    ${I18n.system_save}
70 74
 								</a>
71 75
 							</li>
72 76
                         </ul>
@@ -87,19 +91,19 @@
87 91
         <div class="modal-dialog ">
88 92
             <div class="modal-content">
89 93
                 <div class="modal-header">
90
-                    <h4 class="modal-title" ><i class="fa fa-fw fa-save"></i>保存</h4>
94
+                    <h4 class="modal-title" ><i class="fa fa-fw fa-save"></i>${I18n.system_save}</h4>
91 95
                 </div>
92 96
                 <div class="modal-body">
93 97
                     <form class="form-horizontal form" role="form" >
94 98
                         <div class="form-group">
95
-                            <label for="lastname" class="col-sm-2 control-label">源码备注<font color="red">*</font></label>
96
-                            <div class="col-sm-10"><input type="text" class="form-control" id="glueRemark" placeholder="请输入备注信息" maxlength="64" ></div>
99
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_glue_remark}<font color="red">*</font></label>
100
+                            <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>
97 101
                         </div>
98 102
                         <hr>
99 103
                         <div class="form-group">
100 104
                             <div class="col-sm-offset-3 col-sm-6">
101
-                                <button type="button" class="btn btn-primary ok" >保存</button>
102
-                                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
105
+                                <button type="button" class="btn btn-primary ok" >${I18n.system_save}</button>
106
+                                <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
103 107
                             </div>
104 108
                         </div>
105 109
                     </form>

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

@@ -1,11 +1,11 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-  	<title>任务调度中心</title>
5 4
   	<#import "/common/common.macro.ftl" as netCommon>
6 5
 	<@netCommon.commonStyle />
7 6
 	<!-- DataTables -->
8 7
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
8
+    <title>${I18n.admin_name}</title>
9 9
 </head>
10 10
 <body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
11 11
 <div class="wrapper">
@@ -18,7 +18,7 @@
18 18
 	<div class="content-wrapper">
19 19
 		<!-- Content Header (Page header) -->
20 20
 		<section class="content-header">
21
-			<h1>执行器管理<small>任务调度中心</small></h1>
21
+			<h1>${I18n.jobgroup_name}</h1>
22 22
 		</section>
23 23
 
24 24
 		<!-- Main content -->
@@ -28,20 +28,20 @@
28 28
 				<div class="col-xs-12">
29 29
 					<div class="box">
30 30
 			            <div class="box-header">
31
-							<h3 class="box-title">执行器列表</h3>&nbsp;&nbsp;
32
-                            <button class="btn btn-info btn-xs pull-left2 add" >+新增执行器</button>
31
+							<h3 class="box-title">${I18n.jobgroup_list}</h3>&nbsp;&nbsp;
32
+                            <button class="btn btn-info btn-xs pull-left2 add" >${I18n.jobgroup_add}</button>
33 33
 						</div>
34 34
 			            <div class="box-body">
35 35
 			              	<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
36 36
 				                <thead>
37 37
 					            	<tr>
38 38
                                         <#--<th name="id" >ID</th>-->
39
-                                        <th name="order" >排序</th>
39
+                                        <th name="order" >${I18n.jobgroup_field_order}</th>
40 40
                                         <th name="appName" >AppName</th>
41
-                                        <th name="title" >名称</th>
42
-                                        <th name="addressType" >注册方式</th>
43
-                                        <th name="registryList" >OnLine 机器</th>
44
-                                        <th name="operate" >操作</th>
41
+                                        <th name="title" >${I18n.jobgroup_field_title}</th>
42
+                                        <th name="addressType" >${I18n.jobgroup_field_addressType}</th>
43
+                                        <th name="registryList" >OnLine ${I18n.jobgroup_field_registryList}</th>
44
+                                        <th name="operate" >${I18n.system_opt}</th>
45 45
 					                </tr>
46 46
 				                </thead>
47 47
                                 <tbody>
@@ -52,7 +52,7 @@
52 52
                                         <td>${group.order}</td>
53 53
                                         <td>${group.appName}</td>
54 54
                                         <td>${group.title}</td>
55
-                                        <td><#if group.addressType==0>自动注册<#else>手动录入</#if></td>
55
+                                        <td><#if group.addressType==0>${I18n.jobgroup_field_addressType_0}<#else>${I18n.jobgroup_field_addressType_1}</#if></td>
56 56
                                         <td>
57 57
                                             <#if group.registryList?exists>
58 58
                                                 <#list group.registryList as item>
@@ -74,8 +74,8 @@
74 74
                                                     title="${group.title}"
75 75
                                                     order="${group.order}"
76 76
                                                     addressType="${group.addressType}"
77
-                                                    addressList="${group.addressList}" >编辑</button>
78
-                                            <button class="btn btn-danger btn-xs remove" id="${group.id}" >删除</button>
77
+                                                    addressList="${group.addressList}" >${I18n.system_opt_edit}</button>
78
+                                            <button class="btn btn-danger btn-xs remove" id="${group.id}" >${I18n.system_opt_del}</button>
79 79
 										</td>
80 80
 									</tr>
81 81
 								</#list>
@@ -94,41 +94,41 @@
94 94
         <div class="modal-dialog ">
95 95
             <div class="modal-content">
96 96
                 <div class="modal-header">
97
-                    <h4 class="modal-title" >新增执行器</h4>
97
+                    <h4 class="modal-title" >${I18n.jobgroup_add}</h4>
98 98
                 </div>
99 99
                 <div class="modal-body">
100 100
                     <form class="form-horizontal form" role="form" >
101 101
                         <div class="form-group">
102 102
                             <label for="lastname" class="col-sm-2 control-label">AppName<font color="red">*</font></label>
103
-                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="请输入“AppName”" maxlength="64" ></div>
103
+                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="${I18n.system_please_input}AppName" maxlength="64" ></div>
104 104
                         </div>
105 105
                         <div class="form-group">
106
-                            <label for="lastname" class="col-sm-2 control-label">名称<font color="red">*</font></label>
107
-                            <div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="请输入“名称”" maxlength="12" ></div>
106
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font color="red">*</font></label>
107
+                            <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>
108 108
                         </div>
109 109
                         <div class="form-group">
110
-                            <label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label>
111
-                            <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div>
110
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_order}<font color="red">*</font></label>
111
+                            <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>
112 112
                         </div>
113 113
                         <div class="form-group">
114
-                            <label for="lastname" class="col-sm-2 control-label">注册方式<font color="red">*</font></label>
114
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_addressType}<font color="red">*</font></label>
115 115
                             <div class="col-sm-10">
116
-                                <input type="radio" name="addressType" value="0" checked />自动注册
116
+                                <input type="radio" name="addressType" value="0" checked />${I18n.jobgroup_field_addressType_0}
117 117
                                 &nbsp;&nbsp;&nbsp;&nbsp;
118
-                                <input type="radio" name="addressType" value="1" />手动录入
118
+                                <input type="radio" name="addressType" value="1" />${I18n.jobgroup_field_addressType_1}
119 119
                             </div>
120 120
                         </div>
121 121
                         <div class="form-group">
122
-                            <label for="lastname" class="col-sm-2 control-label">机器地址<font color="red">*</font></label>
122
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_registryList}<font color="red">*</font></label>
123 123
                             <div class="col-sm-10">
124
-                                <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>
124
+                                <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>
125 125
                             </div>
126 126
                         </div>
127 127
                         <hr>
128 128
                         <div class="form-group">
129 129
                             <div class="col-sm-offset-3 col-sm-6">
130
-                                <button type="submit" class="btn btn-primary"  >保存</button>
131
-                                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
130
+                                <button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
131
+                                <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
132 132
                             </div>
133 133
                         </div>
134 134
                     </form>
@@ -142,41 +142,41 @@
142 142
         <div class="modal-dialog ">
143 143
             <div class="modal-content">
144 144
                 <div class="modal-header">
145
-                    <h4 class="modal-title" >编辑执行器</h4>
145
+                    <h4 class="modal-title" >${I18n.jobgroup_edit}</h4>
146 146
                 </div>
147 147
                 <div class="modal-body">
148 148
                     <form class="form-horizontal form" role="form" >
149 149
                         <div class="form-group">
150 150
                             <label for="lastname" class="col-sm-2 control-label">AppName<font color="red">*</font></label>
151
-                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="请输入“AppName”" maxlength="64" ></div>
151
+                            <div class="col-sm-10"><input type="text" class="form-control" name="appName" placeholder="${I18n.system_please_input}AppName" maxlength="64" ></div>
152 152
                         </div>
153 153
                         <div class="form-group">
154
-                            <label for="lastname" class="col-sm-2 control-label">名称<font color="red">*</font></label>
155
-                            <div class="col-sm-10"><input type="text" class="form-control" name="title" placeholder="请输入“名称”" maxlength="12" ></div>
154
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font color="red">*</font></label>
155
+                            <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>
156 156
                         </div>
157 157
                         <div class="form-group">
158
-                            <label for="lastname" class="col-sm-2 control-label">排序<font color="red">*</font></label>
159
-                            <div class="col-sm-10"><input type="text" class="form-control" name="order" placeholder="请输入“排序”" maxlength="50" ></div>
158
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_order}<font color="red">*</font></label>
159
+                            <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>
160 160
                         </div>
161 161
                         <div class="form-group">
162
-                            <label for="lastname" class="col-sm-2 control-label">注册方式<font color="red">*</font></label>
162
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_addressType}<font color="red">*</font></label>
163 163
                             <div class="col-sm-10">
164
-                                <input type="radio" name="addressType" value="0" />自动注册
164
+                                <input type="radio" name="addressType" value="0" />${I18n.jobgroup_field_addressType_0}
165 165
                                 &nbsp;&nbsp;&nbsp;&nbsp;
166
-                                <input type="radio" name="addressType" value="1" />手动录入
166
+                                <input type="radio" name="addressType" value="1" />${I18n.jobgroup_field_addressType_1}
167 167
                             </div>
168 168
                         </div>
169 169
                         <div class="form-group">
170
-                            <label for="lastname" class="col-sm-2 control-label">机器地址<font color="red">*</font></label>
170
+                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_registryList}<font color="red">*</font></label>
171 171
                             <div class="col-sm-10">
172
-                                <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>
172
+                                <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>
173 173
                             </div>
174 174
                         </div>
175 175
                         <hr>
176 176
                         <div class="form-group">
177 177
                             <div class="col-sm-offset-3 col-sm-6">
178
-                                <button type="submit" class="btn btn-primary"  >保存</button>
179
-                                <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
178
+                                <button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
179
+                                <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
180 180
                                 <input type="hidden" name="id" >
181 181
                             </div>
182 182
                         </div>

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

@@ -1,12 +1,11 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-  	<title>任务调度中心</title>
5 4
   	<#import "/common/common.macro.ftl" as netCommon>
6 5
 	<@netCommon.commonStyle />
7 6
 	<!-- DataTables -->
8 7
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
9
-
8
+    <title>${I18n.admin_name}</title>
10 9
 </head>
11 10
 <body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if>">
12 11
 <div class="wrapper">
@@ -19,22 +18,16 @@
19 18
 	<div class="content-wrapper">
20 19
 		<!-- Content Header (Page header) -->
21 20
 		<section class="content-header">
22
-			<h1>任务管理<small>任务调度中心</small></h1>
23
-			<!--
24
-			<ol class="breadcrumb">
25
-				<li><a><i class="fa fa-dashboard"></i>调度管理</a></li>
26
-				<li class="active">调度中心</li>
27
-			</ol>
28
-			-->
21
+			<h1>${I18n.jobinfo_name}</h1>
29 22
 		</section>
30 23
 		
31 24
 		<!-- Main content -->
32 25
 	    <section class="content">
33 26
 	    
34 27
 	    	<div class="row">
35
-	    		<div class="col-xs-4">
28
+	    		<div class="col-xs-3">
36 29
 	              	<div class="input-group">
37
-	                	<span class="input-group-addon">执行器</span>
30
+	                	<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
38 31
                 		<select class="form-control" id="jobGroup" >
39 32
                 			<#list JobGroupList as group>
40 33
                 				<option value="${group.id}" <#if jobGroup==group.id>selected</#if> >${group.title}</option>
@@ -42,43 +35,48 @@
42 35
 	                  	</select>
43 36
 	              	</div>
44 37
 	            </div>
45
-                <div class="col-xs-4">
38
+                <div class="col-xs-3">
39
+                    <div class="input-group">
40
+                        <span class="input-group-addon">${I18n.jobinfo_field_jobdesc}</span>
41
+                        <input type="text" class="form-control" id="jobDesc" autocomplete="on" >
42
+                    </div>
43
+                </div>
44
+                <div class="col-xs-3">
46 45
                     <div class="input-group">
47 46
                         <span class="input-group-addon">JobHandler</span>
48 47
                         <input type="text" class="form-control" id="executorHandler" autocomplete="on" >
49 48
                     </div>
50 49
                 </div>
51
-	            <div class="col-xs-2">
52
-	            	<button class="btn btn-block btn-info" id="searchBtn">搜索</button>
50
+	            <div class="col-xs-1">
51
+	            	<button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
53 52
 	            </div>
54 53
 	            <div class="col-xs-2">
55
-	            	<button class="btn btn-block btn-success add" type="button">+新增任务</button>
54
+	            	<button class="btn btn-block btn-success add" type="button">${I18n.jobinfo_field_add}</button>
56 55
 	            </div>
57 56
           	</div>
58 57
 	    	
59 58
 			<div class="row">
60 59
 				<div class="col-xs-12">
61 60
 					<div class="box">
62
-			            <div class="box-header hide">
61
+			            <#--<div class="box-header hide">
63 62
 			            	<h3 class="box-title">调度列表</h3>
64
-			            </div>
63
+			            </div>-->
65 64
 			            <div class="box-body" >
66 65
 			              	<table id="job_list" class="table table-bordered table-striped" width="100%" >
67 66
 				                <thead>
68 67
 					            	<tr>
69
-					            		<th name="id" >任务ID</th>
70
-					                	<th name="jobGroup" >jobGroup</th>
71
-					                  	<th name="jobDesc" >描述</th>
72
-                                        <th name="glueType" >运行模式</th>
73
-					                  	<th name="executorParam" >任务参数</th>
68
+					            		<th name="id" >${I18n.jobinfo_field_id}</th>
69
+					                	<th name="jobGroup" >${I18n.jobinfo_field_jobgroup}</th>
70
+					                  	<th name="jobDesc" >${I18n.jobinfo_field_jobdesc}</th>
71
+                                        <th name="glueType" >${I18n.jobinfo_field_gluetype}</th>
72
+					                  	<th name="executorParam" >${I18n.jobinfo_field_executorparam}</th>
74 73
                                         <th name="jobCron" >Cron</th>
75
-					                  	<th name="addTime" >新增时间</th>
76
-					                  	<th name="updateTime" >更新时间</th>
77
-					                  	<th name="author" >负责人</th>
78
-					                  	<th name="alarmEmail" >报警邮件</th>
79
-					                  	<th name="glueType" >运行模式</th>
80
-					                  	<th name="jobStatus" >状态</th>
81
-					                  	<th>操作</th>
74
+					                  	<th name="addTime" >addTime</th>
75
+					                  	<th name="updateTime" >updateTime</th>
76
+					                  	<th name="author" >${I18n.jobinfo_field_author}</th>
77
+					                  	<th name="alarmEmail" >${I18n.jobinfo_field_alarmemail}</th>
78
+					                  	<th name="jobStatus" >${I18n.system_status}</th>
79
+					                  	<th>${I18n.system_opt}</th>
82 80
 					                </tr>
83 81
 				                </thead>
84 82
 				                <tbody></tbody>
@@ -100,12 +98,12 @@
100 98
 	<div class="modal-dialog modal-lg">
101 99
 		<div class="modal-content">
102 100
 			<div class="modal-header">
103
-            	<h4 class="modal-title" >新增任务</h4>
101
+            	<h4 class="modal-title" >${I18n.jobinfo_field_add}</h4>
104 102
          	</div>
105 103
          	<div class="modal-body">
106 104
 				<form class="form-horizontal form" role="form" >
107 105
 					<div class="form-group">
108
-						<label for="firstname" class="col-sm-2 control-label">执行器<font color="red">*</font></label>
106
+						<label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
109 107
 						<div class="col-sm-4">
110 108
 							<select class="form-control" name="jobGroup" >
111 109
 		            			<#list JobGroupList as group>
@@ -113,11 +111,11 @@
113 111
 		            			</#list>
114 112
 		                  	</select>
115 113
 						</div>
116
-                        <label for="lastname" class="col-sm-2 control-label">任务描述<font color="red">*</font></label>
117
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="请输入“描述”" maxlength="50" ></div>
114
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
115
+                        <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>
118 116
 					</div>
119 117
                     <div class="form-group">
120
-                        <label for="firstname" class="col-sm-2 control-label">路由策略<font color="red">*</font></label>
118
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
121 119
                         <div class="col-sm-4">
122 120
                             <select class="form-control" name="executorRouteStrategy" >
123 121
 							<#list ExecutorRouteStrategyEnum as item>
@@ -126,10 +124,10 @@
126 124
                             </select>
127 125
                         </div>
128 126
                         <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
129
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="请输入“Cron”" maxlength="128" ></div>
127
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
130 128
                     </div>
131 129
                     <div class="form-group">
132
-                        <label for="firstname" class="col-sm-2 control-label">运行模式<font color="red">*</font></label>
130
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
133 131
                         <div class="col-sm-4">
134 132
                             <select class="form-control glueType" name="glueType" >
135 133
 								<#list GlueTypeEnum as item>
@@ -138,16 +136,16 @@
138 136
                             </select>
139 137
                         </div>
140 138
                         <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
141
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="请输入“JobHandler”" maxlength="100" ></div>
139
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
142 140
                     </div>
143 141
                     <div class="form-group">
144
-                        <label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
145
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入“执行参数”" maxlength="512" ></div>
146
-                        <label for="lastname" class="col-sm-2 control-label">子任务ID<font color="black">*</font></label>
147
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="请输入子任务的任务ID,如存在多个逗号分隔" maxlength="100" ></div>
142
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
143
+                        <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>
144
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
145
+                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
148 146
                     </div>
149 147
                     <div class="form-group">
150
-                        <label for="firstname" class="col-sm-2 control-label">阻塞处理策略<font color="red">*</font></label>
148
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
151 149
                         <div class="col-sm-4">
152 150
                             <select class="form-control" name="executorBlockStrategy" >
153 151
 								<#list ExecutorBlockStrategyEnum as item>
@@ -155,7 +153,7 @@
155 153
 								</#list>
156 154
                             </select>
157 155
 						</div>
158
-                        <label for="lastname" class="col-sm-2 control-label">失败处理策略<font color="red">*</font></label>
156
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailStrategy}<font color="red">*</font></label>
159 157
                         <div class="col-sm-4">
160 158
                             <select class="form-control" name="executorFailStrategy" >
161 159
 								<#list ExecutorFailStrategyEnum as item>
@@ -165,17 +163,17 @@
165 163
 						</div>
166 164
                     </div>
167 165
 					<div class="form-group">
168
-                        <label for="lastname" class="col-sm-2 control-label">负责人<font color="red">*</font></label>
169
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="50" ></div>
170
-						<label for="lastname" class="col-sm-2 control-label">报警邮件<font color="black">*</font></label>
171
-						<div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="100" ></div>
166
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
167
+                        <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>
168
+						<label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
169
+						<div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></div>
172 170
 					</div>
173 171
 
174 172
                     <hr>
175 173
 					<div class="form-group">
176 174
 						<div class="col-sm-offset-3 col-sm-6">
177
-							<button type="submit" class="btn btn-primary"  >保存</button>
178
-							<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
175
+							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
176
+							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
179 177
 						</div>
180 178
 					</div>
181 179
 
@@ -202,10 +200,10 @@ public class DemoGlueJobHandler extends IJobHandler {
202 200
 #!/bin/bash
203 201
 echo "xxl-job: hello shell"
204 202
 
205
-echo "脚本位置:$0"
206
-echo "任务参数:$1"
207
-echo "分片序号 = $2"
208
-echo "分片总数 = $3"
203
+echo "${I18n.jobinfo_script_location}:$0"
204
+echo "${I18n.jobinfo_field_executorparam}:$1"
205
+echo "${I18n.jobinfo_shard_index} = $2"
206
+echo "${I18n.jobinfo_shard_total} = $3"
209 207
 <#--echo "参数数量:$#"
210 208
 for param in $*
211 209
 do
@@ -224,10 +222,10 @@ import sys
224 222
 
225 223
 print "xxl-job: hello python"
226 224
 
227
-print "脚本文件:", sys.argv[0]
228
-print "任务参数:", sys.argv[1]
229
-print "分片序号:", sys.argv[2]
230
-print "分片总数:", sys.argv[3]
225
+print "${I18n.jobinfo_script_location}:", sys.argv[0]
226
+print "${I18n.jobinfo_field_executorparam}:", sys.argv[1]
227
+print "${I18n.jobinfo_shard_index}:", sys.argv[2]
228
+print "${I18n.jobinfo_shard_total}:", sys.argv[3]
231 229
 <#--for i in range(1, len(sys.argv)):
232 230
 	time.sleep(1)
233 231
 	print "参数", i, sys.argv[i]-->
@@ -246,10 +244,10 @@ console.log("xxl-job: hello nodejs")
246 244
 
247 245
 var arguments = process.argv
248 246
 
249
-console.log("脚本文件: " + arguments[1])
250
-console.log("任务参数: " + arguments[2])
251
-console.log("分片序号: " + arguments[3])
252
-console.log("分片总数: " + arguments[4])
247
+console.log("${I18n.jobinfo_script_location}: " + arguments[1])
248
+console.log("${I18n.jobinfo_field_executorparam}: " + arguments[2])
249
+console.log("${I18n.jobinfo_shard_index}: " + arguments[3])
250
+console.log("${I18n.jobinfo_shard_total}: " + arguments[4])
253 251
 <#--for (var i = 2; i < arguments.length; i++){
254 252
 	console.log("参数 %s = %s", (i-1), arguments[i]);
255 253
 }-->
@@ -268,12 +266,12 @@ process.exit(0)
268 266
 	<div class="modal-dialog modal-lg">
269 267
 		<div class="modal-content">
270 268
 			<div class="modal-header">
271
-            	<h4 class="modal-title" >更新任务</h4>
269
+            	<h4 class="modal-title" >${I18n.jobinfo_field_update}</h4>
272 270
          	</div>
273 271
          	<div class="modal-body">
274 272
 				<form class="form-horizontal form" role="form" >
275
-                    <div class="form-group">
276
-                        <label for="firstname" class="col-sm-2 control-label">执行器<font color="red">*</font></label>
273
+					<div class="form-group">
274
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font color="red">*</font></label>
277 275
                         <div class="col-sm-4">
278 276
                             <select class="form-control" name="jobGroup" disabled >
279 277
 							<#list JobGroupList as group>
@@ -281,11 +279,11 @@ process.exit(0)
281 279
 							</#list>
282 280
                             </select>
283 281
                         </div>
284
-                        <label for="lastname" class="col-sm-2 control-label">任务描述<font color="red">*</font></label>
285
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc" placeholder="请输入“描述”" maxlength="50" ></div>
282
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font color="red">*</font></label>
283
+                        <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>
286 284
                     </div>
287 285
                     <div class="form-group">
288
-                        <label for="firstname" class="col-sm-2 control-label">路由策略<font color="red">*</font></label>
286
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font color="red">*</font></label>
289 287
                         <div class="col-sm-4">
290 288
                             <select class="form-control" name="executorRouteStrategy" >
291 289
 							<#list ExecutorRouteStrategyEnum as item>
@@ -294,10 +292,10 @@ process.exit(0)
294 292
                             </select>
295 293
                         </div>
296 294
                         <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
297
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="请输入“Cron”" maxlength="128" ></div>
295
+                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron" placeholder="${I18n.system_please_input}Cron" maxlength="128" ></div>
298 296
                     </div>
299 297
                     <div class="form-group">
300
-                        <label for="firstname" class="col-sm-2 control-label">运行模式<font color="red">*</font></label>
298
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font color="red">*</font></label>
301 299
                         <div class="col-sm-4">
302 300
                             <select class="form-control glueType" name="glueType" disabled >
303 301
 							<#list GlueTypeEnum as item>
@@ -306,16 +304,16 @@ process.exit(0)
306 304
                             </select>
307 305
                         </div>
308 306
                         <label for="firstname" class="col-sm-2 control-label">JobHandler<font color="black">*</font></label>
309
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="请输入“JobHandler”" maxlength="100" ></div>
307
+                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler" placeholder="${I18n.system_please_input}JobHandler" maxlength="100" ></div>
310 308
                     </div>
311 309
                     <div class="form-group">
312
-                        <label for="firstname" class="col-sm-2 control-label">执行参数<font color="black">*</font></label>
313
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorParam" placeholder="请输入“执行参数”" maxlength="512" ></div>
314
-                        <label for="lastname" class="col-sm-2 control-label">子任务ID<font color="black">*</font></label>
315
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="请输入子任务的任务ID,如存在多个逗号分隔" maxlength="100" ></div>
310
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font color="black">*</font></label>
311
+                        <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>
312
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font color="black">*</font></label>
313
+                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId" placeholder="${I18n.jobinfo_field_childJobId_placeholder}" maxlength="100" ></div>
316 314
                     </div>
317 315
                     <div class="form-group">
318
-                        <label for="firstname" class="col-sm-2 control-label">阻塞处理策略<font color="red">*</font></label>
316
+                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font color="red">*</font></label>
319 317
                         <div class="col-sm-4">
320 318
                             <select class="form-control" name="executorBlockStrategy" >
321 319
 							<#list ExecutorBlockStrategyEnum as item>
@@ -323,7 +321,7 @@ process.exit(0)
323 321
 							</#list>
324 322
                             </select>
325 323
                         </div>
326
-                        <label for="lastname" class="col-sm-2 control-label">失败处理策略<font color="red">*</font></label>
324
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailStrategy}<font color="red">*</font></label>
327 325
                         <div class="col-sm-4">
328 326
                             <select class="form-control" name="executorFailStrategy" >
329 327
 							<#list ExecutorFailStrategyEnum as item>
@@ -333,20 +331,21 @@ process.exit(0)
333 331
                         </div>
334 332
                     </div>
335 333
                     <div class="form-group">
336
-                        <label for="lastname" class="col-sm-2 control-label">负责人<font color="red">*</font></label>
337
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author" placeholder="请输入“负责人”" maxlength="50" ></div>
338
-                        <label for="lastname" class="col-sm-2 control-label">报警邮件<font color="black">*</font></label>
339
-                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="请输入“报警邮件”,多个邮件地址逗号分隔" maxlength="100" ></div>
334
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font color="red">*</font></label>
335
+                        <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>
336
+                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font color="black">*</font></label>
337
+                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail" placeholder="${I18n.jobinfo_field_alarmemail_placeholder}" maxlength="100" ></div>
340 338
                     </div>
341 339
 
342 340
 					<hr>
343 341
 					<div class="form-group">
344 342
                         <div class="col-sm-offset-3 col-sm-6">
345
-							<button type="submit" class="btn btn-primary"  >保存</button>
346
-							<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
343
+							<button type="submit" class="btn btn-primary"  >${I18n.system_save}</button>
344
+							<button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
347 345
                             <input type="hidden" name="id" >
348 346
 						</div>
349 347
 					</div>
348
+
350 349
 				</form>
351 350
          	</div>
352 351
 		</div>

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

@@ -1,9 +1,9 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-    <title>任务调度中心</title>
5
-<#import "/common/common.macro.ftl" as netCommon>
6
-<@netCommon.commonStyle />
4
+    <#import "/common/common.macro.ftl" as netCommon>
5
+    <@netCommon.commonStyle />
6
+    <title>${I18n.admin_name}</title>
7 7
 </head>
8 8
 <body class="hold-transition skin-blue layout-top-nav">
9 9
 
@@ -12,9 +12,9 @@
12 12
     <header class="main-header">
13 13
         <nav class="navbar navbar-static-top">
14 14
             <div class="container">
15
-            <#-- icon -->
15
+                <#-- icon -->
16 16
                 <div class="navbar-header">
17
-                    <a class="navbar-brand"><b>执行日志</b>Console</a>
17
+                    <a class="navbar-brand"><b>${I18n.joblog_rolling_log}</b> Console</a>
18 18
                     <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
19 19
                         <i class="fa fa-bars"></i>
20 20
                     </button>
@@ -33,7 +33,7 @@
33 33
                         <li>
34 34
                             <a href="javascript:window.location.reload();" >
35 35
                                 <i class="fa fa-fw fa-refresh" ></i>
36
-                                刷新
36
+                                ${I18n.joblog_rolling_log_refresh}
37 37
                             </a>
38 38
                         </li>
39 39
                     </ul>

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

@@ -1,13 +1,13 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-  	<title>任务调度中心</title>
5 4
   	<#import "/common/common.macro.ftl" as netCommon>
6 5
 	<@netCommon.commonStyle />
7 6
 	<!-- DataTables -->
8 7
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/datatables/dataTables.bootstrap.css">
9 8
   	<!-- daterangepicker -->
10 9
   	<link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/daterangepicker/daterangepicker.css">
10
+    <title>${I18n.admin_name}</title>
11 11
 </head>
12 12
 <body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
13 13
 <div class="wrapper">
@@ -20,13 +20,7 @@
20 20
 	<div class="content-wrapper">
21 21
 		<!-- Content Header (Page header) -->
22 22
 		<section class="content-header">
23
-			<h1>调度日志<small>任务调度中心</small></h1>
24
-			<!--
25
-			<ol class="breadcrumb">
26
-				<li><a><i class="fa fa-dashboard"></i>调度日志</a></li>
27
-				<li class="active">调度管理</li>
28
-			</ol>
29
-			-->
23
+			<h1>${I18n.joblog_name}</h1>
30 24
 		</section>
31 25
 		
32 26
 		<!-- Main content -->
@@ -34,9 +28,9 @@
34 28
 	    	<div class="row">
35 29
 	    		<div class="col-xs-2">
36 30
  					<div class="input-group">
37
-	                	<span class="input-group-addon">执行器</span>
31
+	                	<span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
38 32
                 		<select class="form-control" id="jobGroup"  paramVal="<#if jobInfo?exists>${jobInfo.jobGroup}</#if>" >
39
-                            <option value="0" >全部</option>
33
+                            <option value="0" >${I18n.system_all}</option>
40 34
                 			<#list JobGroupList as group>
41 35
                 				<option value="${group.id}" >${group.title}</option>
42 36
                 			</#list>
@@ -45,21 +39,21 @@
45 39
 	            </div>
46 40
 	            <div class="col-xs-2">
47 41
 	              	<div class="input-group">
48
-	                	<span class="input-group-addon">任务</span>
42
+	                	<span class="input-group-addon">${I18n.jobinfo_job}</span>
49 43
                         <select class="form-control" id="jobId" paramVal="<#if jobInfo?exists>${jobInfo.id}</#if>" >
50
-                            <option value="0" >全部</option>
44
+                            <option value="0" >${I18n.system_all}</option>
51 45
 						</select>
52 46
 	              	</div>
53 47
 	            </div>
54 48
 
55 49
                 <div class="col-xs-2">
56 50
                     <div class="input-group">
57
-                        <span class="input-group-addon">状态</span>
51
+                        <span class="input-group-addon">${I18n.joblog_status}</span>
58 52
                         <select class="form-control" id="logStatus" >
59
-                            <option value="-1" >全部</option>
60
-                            <option value="1" >成功</option>
61
-                            <option value="2" >失败</option>
62
-                            <option value="3" >进行中</option>
53
+                            <option value="-1" >${I18n.joblog_status_all}</option>
54
+                            <option value="1" >${I18n.joblog_status_suc}</option>
55
+                            <option value="2" >${I18n.joblog_status_fail}</option>
56
+                            <option value="3" >${I18n.joblog_status_running}</option>
63 57
                         </select>
64 58
                     </div>
65 59
                 </div>
@@ -67,41 +61,41 @@
67 61
 	            <div class="col-xs-4">
68 62
               		<div class="input-group">
69 63
                 		<span class="input-group-addon">
70
-	                  		调度时间
64
+	                  		${I18n.joblog_field_triggerTime}
71 65
 	                	</span>
72 66
 	                	<input type="text" class="form-control" id="filterTime" readonly >
73 67
 	              	</div>
74 68
 	            </div>
75 69
 
76 70
                 <div class="col-xs-1">
77
-                    <button class="btn btn-block btn-info" id="searchBtn">搜索</button>
71
+                    <button class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
78 72
                 </div>
79 73
 
80 74
 	            <div class="col-xs-1">
81
-                    <button class="btn btn-block btn-nomal" id="clearLog">清理</button>
75
+                    <button class="btn btn-block btn-nomal" id="clearLog">${I18n.joblog_clean}</button>
82 76
 	            </div>
83 77
           	</div>
84 78
 			
85 79
 			<div class="row">
86 80
 				<div class="col-xs-12">
87 81
 					<div class="box">
88
-			            <div class="box-header hide"><h3 class="box-title">调度日志</h3></div>
82
+			            <#--<div class="box-header hide"><h3 class="box-title">调度日志</h3></div>-->
89 83
 			            <div class="box-body">
90 84
 			              	<table id="joblog_list" class="table table-bordered table-striped display" width="100%" >
91 85
 				                <thead>
92 86
 					            	<tr>
93
-                                        <th name="jobId" >任务ID</th>
94
-                                        <th name="jobGroup" >执行器ID</th>
87
+                                        <th name="jobId" >${I18n.jobinfo_field_id}</th>
88
+                                        <th name="jobGroup" >jobGroup</th>
95 89
 										<#--<th name="executorAddress" >执行器地址</th>
96 90
 										<th name="glueType" >运行模式</th>
97 91
                                       	<th name="executorParam" >任务参数</th>-->
98
-                                        <th name="triggerTime" >调度时间</th>
99
-                                        <th name="triggerCode" >调度结果</th>
100
-                                        <th name="triggerMsg" >调度备注</th>
101
-					                  	<th name="handleTime" >执行时间</th>
102
-					                  	<th name="handleCode" >执行结果</th>
103
-					                  	<th name="handleMsg" >执行备注</th>
104
-					                  	<th name="handleMsg" >操作</th>
92
+                                        <th name="triggerTime" >${I18n.joblog_field_triggerTime}</th>
93
+                                        <th name="triggerCode" >${I18n.joblog_field_triggerCode}</th>
94
+                                        <th name="triggerMsg" >${I18n.joblog_field_triggerMsg}</th>
95
+					                  	<th name="handleTime" >${I18n.joblog_field_handleTime}</th>
96
+					                  	<th name="handleCode" >${I18n.joblog_field_handleCode}</th>
97
+					                  	<th name="handleMsg" >${I18n.joblog_field_handleMsg}</th>
98
+					                  	<th name="handleMsg" >${I18n.system_opt}</th>
105 99
 					                </tr>
106 100
 				                </thead>
107 101
 				                <tbody></tbody>
@@ -122,12 +116,12 @@
122 116
     <div class="modal-dialog">
123 117
         <div class="modal-content">
124 118
             <div class="modal-header">
125
-                <h4 class="modal-title" >日志清理</h4>
119
+                <h4 class="modal-title" >${I18n.joblog_clean_log}</h4>
126 120
             </div>
127 121
             <div class="modal-body">
128 122
                 <form class="form-horizontal form" role="form" >
129 123
                     <div class="form-group">
130
-                        <label class="col-sm-3 control-label"">执行器:</label>
124
+                        <label class="col-sm-3 control-label"">${I18n.jobinfo_field_jobgroup}:</label>
131 125
                         <div class="col-sm-9">
132 126
                             <input type="text" class="form-control jobGroupText" readonly >
133 127
 							<input type="hidden" name="jobGroup" >
@@ -135,7 +129,7 @@
135 129
                     </div>
136 130
 
137 131
                     <div class="form-group">
138
-                        <label class="col-sm-3 control-label"">任务:</label>
132
+                        <label class="col-sm-3 control-label"">${I18n.jobinfo_job}:</label>
139 133
                         <div class="col-sm-9">
140 134
                             <input type="text" class="form-control jobIdText" readonly >
141 135
                             <input type="hidden" name="jobId" >
@@ -143,18 +137,18 @@
143 137
                     </div>
144 138
 
145 139
                     <div class="form-group">
146
-                        <label class="col-sm-3 control-label"">清理类型:</label>
140
+                        <label class="col-sm-3 control-label"">${I18n.joblog_clean_type}:</label>
147 141
                         <div class="col-sm-9">
148 142
                             <select class="form-control" name="type" >
149
-                                <option value="1" >清理一个月之前日志数据</option>
150
-                                <option value="2" >清理三个月之前日志数据</option>
151
-                                <option value="3" >清理六个月之前日志数据</option>
152
-                                <option value="4" >清理一年之前日志数据</option>
153
-                                <option value="5" >清理一千条以前日志数据</option>
154
-                                <option value="6" >清理一万条以前日志数据</option>
155
-                                <option value="7" >清理三万条以前日志数据</option>
156
-                                <option value="8" >清理十万条以前日志数据</option>
157
-                                <option value="9" >清理所有日志数据</option>
143
+                                <option value="1" >${I18n.joblog_clean_type_1}</option>
144
+                                <option value="2" >${I18n.joblog_clean_type_2}</option>
145
+                                <option value="3" >${I18n.joblog_clean_type_3}</option>
146
+                                <option value="4" >${I18n.joblog_clean_type_4}</option>
147
+                                <option value="5" >${I18n.joblog_clean_type_5}</option>
148
+                                <option value="6" >${I18n.joblog_clean_type_6}</option>
149
+                                <option value="7" >${I18n.joblog_clean_type_7}</option>
150
+                                <option value="8" >${I18n.joblog_clean_type_8}</option>
151
+                                <option value="9" >${I18n.joblog_clean_type_9}</option>
158 152
                             </select>
159 153
                         </div>
160 154
                     </div>
@@ -162,8 +156,8 @@
162 156
                     <hr>
163 157
                     <div class="form-group">
164 158
                         <div class="col-sm-offset-3 col-sm-6">
165
-                            <button type="button" class="btn btn-primary ok" >确定</button>
166
-                            <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
159
+                            <button type="button" class="btn btn-primary ok" >${I18n.system_ok}</button>
160
+                            <button type="button" class="btn btn-default" data-dismiss="modal">${I18n.system_cancel}</button>
167 161
                         </div>
168 162
                     </div>
169 163
                 </form>
@@ -173,6 +167,12 @@
173 167
 </div>
174 168
 
175 169
 <@netCommon.commonScript />
170
+<script>
171
+    var GlueTypeEnum = {};
172
+    <#list GlueTypeEnum as item>
173
+    GlueTypeEnum['${item}'] = '${item.desc}';
174
+    </#list>
175
+</script>
176 176
 <!-- DataTables -->
177 177
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
178 178
 <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 Visa fil

@@ -1,10 +1,10 @@
1 1
 <!DOCTYPE html>
2 2
 <html>
3 3
 <head>
4
-  	<title>调度中心</title>
5 4
   	<#import "/common/common.macro.ftl" as netCommon>
6 5
 	<@netCommon.commonStyle />
7 6
     <link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/iCheck/square/blue.css">
7
+	<title>${I18n.admin_name}</title>
8 8
 </head>
9 9
 <body class="hold-transition login-page">
10 10
 	<div class="login-box">
@@ -13,25 +13,25 @@
13 13
 		</div>
14 14
 		<form id="loginForm" method="post" >
15 15
 			<div class="login-box-body">
16
-				<p class="login-box-msg">任务调度中心</p>
16
+				<p class="login-box-msg">${I18n.admin_name}</p>
17 17
 				<div class="form-group has-feedback">
18
-	            	<input type="text" name="userName" class="form-control" placeholder="请输入登录账号" value="admin" >
18
+	            	<input type="text" name="userName" class="form-control" placeholder="${I18n.login_username_placeholder}" value="admin" maxlength="18" >
19 19
 	            	<span class="glyphicon glyphicon-envelope form-control-feedback"></span>
20 20
 				</div>
21 21
 	          	<div class="form-group has-feedback">
22
-	            	<input type="password" name="password" class="form-control" placeholder="请输入登录密码" value="123456" >
22
+	            	<input type="password" name="password" class="form-control" placeholder="${I18n.login_password_placeholder}" value="123456" maxlength="18" >
23 23
 	            	<span class="glyphicon glyphicon-lock form-control-feedback"></span>
24 24
 	          	</div>
25 25
 				<div class="row">
26 26
 					<div class="col-xs-8">
27 27
 		              	<div class="checkbox icheck">
28 28
 		                	<label>
29
-		                  		<input type="checkbox" name="ifRemember" > Remember Me
29
+		                  		<input type="checkbox" name="ifRemember" >${I18n.login_remember_me}
30 30
 		                	</label>
31 31
 						</div>
32 32
 		            </div><!-- /.col -->
33 33
 		            <div class="col-xs-4">
34
-						<button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>
34
+						<button type="submit" class="btn btn-primary btn-block btn-flat">${I18n.login_btn}</button>
35 35
 					</div>
36 36
 				</div>
37 37
 			</div>

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

@@ -2,27 +2,24 @@ $(function(){
2 2
 
3 3
 	// logout
4 4
 	$("#logoutBtn").click(function(){
5
-		layer.confirm('确认注销登录?', {icon: 3, title:'系统提示'}, function(index){
5
+		layer.confirm( I18n.logout_confirm , {
6
+			icon: 3,
7
+			title: I18n.system_tips ,
8
+            btn: [ I18n.system_ok, I18n.system_cancel ]
9
+		}, function(index){
6 10
 			layer.close(index);
7 11
 
8 12
 			$.post(base_url + "/logout", function(data, status) {
9 13
 				if (data.code == "200") {
10
-                    layer.msg('注销成功');
14
+                    layer.msg( I18n.logout_success );
11 15
                     setTimeout(function(){
12 16
                         window.location.href = base_url + "/";
13 17
                     }, 500);
14
-					/*layer.open({
15
-						title: '系统提示',
16
-						content: '注销成功',
17
-						icon: '1',
18
-						end: function(layero, index){
19
-							window.location.href = base_url + "/";
20
-						}
21
-					});*/
22 18
 				} else {
23 19
 					layer.open({
24
-						title: '系统提示',
25
-						content: (data.msg || "操作失败"),
20
+						title: I18n.system_tips ,
21
+                        btn: [ I18n.system_ok ],
22
+						content: (data.msg || I18n.logout_fail),
26 23
 						icon: '2'
27 24
 					});
28 25
 				}
@@ -68,14 +65,14 @@ $(function(){
68 65
 		}
69 66
 	});
70 67
 	$(slideToTop).click(function () {
71
-		$("body").animate({
68
+		$("html,body").animate({		// firefox ie not support body, chrome support body. but found that new version chrome not support body too.
72 69
 			scrollTop: 0
73 70
 		}, 100);
74 71
 	});
75 72
 
76
-	// 左侧菜单状态,js + 后端 + cookie方式(新)
73
+	// left menu status v: js + server + cookie
77 74
 	$('.sidebar-toggle').click(function(){
78
-		var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings');	// 左侧菜单展开状态[xxljob_adminlte_settings]:on=展开,off=折叠
75
+		var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings');	// on=open,off=close
79 76
 		if ('off' == xxljob_adminlte_settings) {
80 77
             xxljob_adminlte_settings = 'on';
81 78
 		} else {
@@ -83,11 +80,12 @@ $(function(){
83 80
 		}
84 81
 		$.cookie('xxljob_adminlte_settings', xxljob_adminlte_settings, { expires: 7 });	//$.cookie('the_cookie', '', { expires: -1 });
85 82
 	});
86
-	// 左侧菜单状态,js + cookie方式(遗弃)
83
+
84
+	// left menu status v1: js + cookie
87 85
 	/*
88 86
 	 var xxljob_adminlte_settings = $.cookie('xxljob_adminlte_settings');
89 87
 	 if (xxljob_adminlte_settings == 'off') {
90
-	 $('body').addClass('sidebar-collapse');
88
+	 	$('body').addClass('sidebar-collapse');
91 89
 	 }
92 90
 	 */
93 91
 	

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

@@ -1,13 +1,17 @@
1 1
 /**
2 2
  * Created by xuxueli on 17/4/24.
3 3
  */
4
-
5
-
6 4
 $(function () {
7 5
 
8
-    // 过滤时间
9
-    var _startDate = moment().subtract(1, 'months');    // 默认,最近一月
10
-    var _endDate = moment();
6
+    // filter Time
7
+    var rangesConf = {};
8
+    rangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')];
9
+    rangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')];
10
+    rangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')];
11
+    rangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')];
12
+    rangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')];
13
+    rangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')];
14
+
11 15
     $('#filterTime').daterangepicker({
12 16
         autoApply:false,
13 17
         singleDatePicker:false,
@@ -16,36 +20,28 @@ $(function () {
16 20
         timePickerIncrement: 10, 	// 时间的增量,单位为分钟
17 21
         timePicker24Hour : true,
18 22
         opens : 'left', //日期选择框的弹出位置
19
-        ranges: {
20
-            //'最近1小时': [moment().subtract(1, 'hours'), moment()],
21
-            '今日': [moment().startOf('day'), moment().endOf('day')],
22
-            '昨日': [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')],
23
-            '本月': [moment().startOf('month'), moment().endOf('month')],
24
-            '上个月': [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')],
25
-            '最近1周': [moment().subtract(1, 'weeks'), moment()],
26
-            '最近1月': [_startDate, _endDate]
27
-        },
23
+        ranges: rangesConf,
28 24
         locale : {
29 25
             format: 'YYYY-MM-DD HH:mm:ss',
30 26
             separator : ' - ',
31
-            customRangeLabel : '自定义',
32
-            applyLabel : '确定',
33
-            cancelLabel : '取消',
34
-            fromLabel : '起始时间',
35
-            toLabel : '结束时间',
36
-            daysOfWeek : [ '日', '一', '二', '三', '四', '五', '六' ],
37
-            monthNames : [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ],
27
+            customRangeLabel : I18n.daterangepicker_custom_name ,
28
+            applyLabel : I18n.system_ok ,
29
+            cancelLabel : I18n.system_cancel ,
30
+            fromLabel : I18n.daterangepicker_custom_starttime ,
31
+            toLabel : I18n.daterangepicker_custom_endtime ,
32
+            daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') ,        // '日', '一', '二', '三', '四', '五', '六'
33
+            monthNames : I18n.daterangepicker_custom_monthnames.split(',') ,        // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'
38 34
             firstDay : 1
39 35
         },
40
-        startDate:_startDate,
41
-        endDate: _endDate
36
+        startDate: rangesConf[I18n.daterangepicker_ranges_recent_month][0] ,
37
+        endDate: rangesConf[I18n.daterangepicker_ranges_recent_month][1]
42 38
     }, function (start, end, label) {
43 39
         freshChartDate(start, end);
44 40
     });
45
-    freshChartDate(_startDate, _endDate);
41
+    freshChartDate(rangesConf[I18n.daterangepicker_ranges_recent_month][0], rangesConf[I18n.daterangepicker_ranges_recent_month][1]);
46 42
 
47 43
     /**
48
-     * 刷新报表
44
+     * fresh Chart Date
49 45
      *
50 46
      * @param startDate
51 47
      * @param endDate
@@ -53,7 +49,7 @@ $(function () {
53 49
     function freshChartDate(startDate, endDate) {
54 50
         $.ajax({
55 51
             type : 'POST',
56
-            url : base_url + '/triggerChartDate',
52
+            url : base_url + '/chartInfo',
57 53
             data : {
58 54
                 'startDate':startDate.format('YYYY-MM-DD HH:mm:ss'),
59 55
                 'endDate':endDate.format('YYYY-MM-DD HH:mm:ss')
@@ -65,8 +61,9 @@ $(function () {
65 61
                     pieChartInit(data);
66 62
                 } else {
67 63
                     layer.open({
68
-                        title: '系统提示',
69
-                        content: (data.msg || '调度报表数据加载异常'),
64
+                        title: I18n.system_tips ,
65
+                        btn: [ I18n.system_ok ],
66
+                        content: (data.msg || I18n.job_dashboard_report_loaddata_fail ),
70 67
                         icon: '2'
71 68
                     });
72 69
                 }
@@ -75,12 +72,12 @@ $(function () {
75 72
     }
76 73
 
77 74
     /**
78
-     * 折线图
75
+     * line Chart Init
79 76
      */
80 77
     function lineChartInit(data) {
81 78
         var option = {
82 79
                title: {
83
-                   text: '日期分布图'
80
+                   text: I18n.job_dashboard_date_report
84 81
                },
85 82
                tooltip : {
86 83
                    trigger: 'axis',
@@ -92,7 +89,7 @@ $(function () {
92 89
                    }
93 90
                },
94 91
                legend: {
95
-                   data:['成功调度次数','失败调度次数']
92
+                   data:[I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running]
96 93
                },
97 94
                toolbox: {
98 95
                    feature: {
@@ -119,16 +116,16 @@ $(function () {
119 116
                ],
120 117
                series : [
121 118
                    {
122
-                       name:'成功调度次数',
119
+                       name:I18n.joblog_status_suc,
123 120
                        type:'line',
124
-                       stack: '总量',
121
+                       stack: 'Total',
125 122
                        areaStyle: {normal: {}},
126 123
                        data: data.content.triggerDayCountSucList
127 124
                    },
128 125
                    {
129
-                       name:'失败调度次数',
126
+                       name:I18n.joblog_status_fail,
130 127
                        type:'line',
131
-                       stack: '总量',
128
+                       stack: 'Total',
132 129
                        label: {
133 130
                            normal: {
134 131
                                show: true,
@@ -137,9 +134,16 @@ $(function () {
137 134
                        },
138 135
                        areaStyle: {normal: {}},
139 136
                        data: data.content.triggerDayCountFailList
137
+                   },
138
+                   {
139
+                       name:I18n.joblog_status_running,
140
+                       type:'line',
141
+                       stack: 'Total',
142
+                       areaStyle: {normal: {}},
143
+                       data: data.content.triggerDayCountRunningList
140 144
                    }
141 145
                ],
142
-                color:['#00A65A', '#F39C12']
146
+                color:['#00A65A', '#c23632', '#F39C12']
143 147
         };
144 148
 
145 149
         var lineChart = echarts.init(document.getElementById('lineChart'));
@@ -147,38 +151,42 @@ $(function () {
147 151
     }
148 152
 
149 153
     /**
150
-     * 饼图
154
+     * pie Chart Init
151 155
      */
152 156
     function pieChartInit(data) {
153 157
         var option = {
154 158
             title : {
155
-                text: '成功比例图',
159
+                text: I18n.job_dashboard_rate_report ,
156 160
                 /*subtext: 'subtext',*/
157 161
                 x:'center'
158 162
             },
159 163
             tooltip : {
160 164
                 trigger: 'item',
161
-                formatter: "{a} <br/>{b} : {c} ({d}%)"
165
+                formatter: "{b} : {c} ({d}%)"
162 166
             },
163 167
             legend: {
164 168
                 orient: 'vertical',
165 169
                 left: 'left',
166
-                data: ['成功调度次数','失败调度次数']
170
+                data: [I18n.joblog_status_suc, I18n.joblog_status_fail, I18n.joblog_status_running ]
167 171
             },
168 172
             series : [
169 173
                 {
170
-                    name: '分布比例',
174
+                    //name: '分布比例',
171 175
                     type: 'pie',
172 176
                     radius : '55%',
173 177
                     center: ['50%', '60%'],
174 178
                     data:[
175 179
                         {
176
-                            value:data.content.triggerCountSucTotal,
177
-                            name:'成功调度次数'
180
+                            name:I18n.joblog_status_suc,
181
+                            value:data.content.triggerCountSucTotal
182
+                        },
183
+                        {
184
+                            name:I18n.joblog_status_fail,
185
+                            value:data.content.triggerCountFailTotal
178 186
                         },
179 187
                         {
180
-                            value:data.content.triggerCountFailTotal,
181
-                            name:'失败调度次数'
188
+                            name:I18n.joblog_status_running,
189
+                            value:data.content.triggerCountRunningTotal
182 190
                         }
183 191
                     ],
184 192
                     itemStyle: {
@@ -190,7 +198,7 @@ $(function () {
190 198
                     }
191 199
                 }
192 200
             ],
193
-            color:['#00A65A', '#F39C12']
201
+            color:['#00A65A', '#c23632', '#F39C12']
194 202
         };
195 203
         var pieChart = echarts.init(document.getElementById('pieChart'));
196 204
         pieChart.setOption(option);

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

@@ -1,12 +1,6 @@
1 1
 $(function() {
2 2
 
3 3
 	// init code editor
4
-	/*var codeEditor = CodeMirror.fromTextArea(document.getElementById("glueSource"), {
5
-		mode : "text/x-java",
6
-		lineNumbers : true,
7
-		matchBrackets : true
8
-	});*/
9
-
10 4
 	var codeEditor;
11 5
 	function initIde(glueSource) {
12 6
 		if (codeEditor == null) {
@@ -44,16 +38,18 @@ $(function() {
44 38
 		
45 39
 		if (!glueRemark) {
46 40
 			layer.open({
47
-				title: '系统提示',
48
-				content: '请输入备注',
41
+				title: I18n.system_tips,
42
+                btn: [ I18n.system_ok],
43
+				content: I18n.system_please_input + I18n.jobinfo_glue_remark ,
49 44
 				icon: '2'
50 45
 			});
51 46
 			return;
52 47
 		}
53 48
 		if (glueRemark.length <4 || glueRemark.length > 100) {
54 49
 			layer.open({
55
-				title: '系统提示',
56
-				content: '备注长度应该在4至100之间',
50
+				title: I18n.system_tips ,
51
+                btn: [ I18n.system_ok ],
52
+				content: I18n.jobinfo_glue_remark_limit ,
57 53
 				icon: '2'
58 54
 			});
59 55
 			return;
@@ -71,8 +67,9 @@ $(function() {
71 67
 			success : function(data){
72 68
 				if (data.code == 200) {
73 69
 					layer.open({
74
-						title: '系统提示',
75
-						content: '保存成功',
70
+						title: I18n.system_tips,
71
+                        btn: [ I18n.system_ok ],
72
+						content: (I18n.system_save + I18n.system_success) ,
76 73
 						icon: '1',
77 74
 						end: function(layero, index){
78 75
 							//$(window).unbind('beforeunload');
@@ -81,8 +78,9 @@ $(function() {
81 78
 					});
82 79
 				} else {
83 80
 					layer.open({
84
-						title: '系统提示',
85
-						content: (data.msg || "保存失败"),
81
+						title: I18n.system_tips,
82
+                        btn: [ I18n.system_ok ],
83
+						content: (data.msg || (I18n.system_save + I18n.system_fail) ),
86 84
 						icon: '2'
87 85
 					});
88 86
 				}

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

@@ -4,7 +4,11 @@ $(function() {
4 4
 	$('.remove').on('click', function(){
5 5
 		var id = $(this).attr('id');
6 6
 
7
-		layer.confirm('确认删除分组?', {icon: 3, title:'系统提示'}, function(index){
7
+		layer.confirm( (I18n.system_ok + I18n.jobgroup_del + '?') , {
8
+			icon: 3,
9
+			title: I18n.system_tips ,
10
+            btn: [ I18n.system_ok, I18n.system_cancel ]
11
+		}, function(index){
8 12
 			layer.close(index);
9 13
 
10 14
 			$.ajax({
@@ -15,8 +19,9 @@ $(function() {
15 19
 				success : function(data){
16 20
 					if (data.code == 200) {
17 21
 						layer.open({
18
-							title: '系统提示',
19
-							content: '删除成功',
22
+							title: I18n.system_tips ,
23
+                            btn: [ I18n.system_ok ],
24
+							content: (I18n.jobgroup_del + I18n.system_success),
20 25
 							icon: '1',
21 26
 							end: function(layero, index){
22 27
 								window.location.reload();
@@ -24,8 +29,9 @@ $(function() {
24 29
 						});
25 30
 					} else {
26 31
 						layer.open({
27
-							title: '系统提示',
28
-							content: (data.msg || "删除失败"),
32
+							title: I18n.system_tips,
33
+                            btn: [ I18n.system_ok ],
34
+							content: (data.msg || (I18n.jobgroup_del + I18n.system_fail)),
29 35
 							icon: '2'
30 36
 						});
31 37
 					}
@@ -35,12 +41,12 @@ $(function() {
35 41
 
36 42
 	});
37 43
 
38
-	// jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线
44
+	// jquery.validate “low letters start, limit contants、 letters、numbers and line-through.
39 45
 	jQuery.validator.addMethod("myValid01", function(value, element) {
40 46
 		var length = value.length;
41 47
 		var valid = /^[a-z][a-zA-Z0-9-]*$/;
42 48
 		return this.optional(element) || valid.test(value);
43
-	}, "限制以小写字母开头,由小写字母、数字和下划线组成");
49
+	}, I18n.jobgroup_field_appName_limit );
44 50
 
45 51
 	$('.add').on('click', function(){
46 52
 		$('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
@@ -67,18 +73,18 @@ $(function() {
67 73
 		},
68 74
 		messages : {
69 75
 			appName : {
70
-				required :"请输入“AppName",
71
-				rangelength:"AppName长度限制为4~64",
72
-				myValid01: "限制以小写字母开头,由小写字母、数字和中划线组成"
76
+				required : I18n.system_please_input+"AppName",
77
+				rangelength: I18n.jobgroup_field_appName_length ,
78
+				myValid01: I18n.jobgroup_field_appName_limit
73 79
 			},
74 80
 			title : {
75
-				required :"请输入“执行器名称”",
76
-				rangelength:"长度限制为4~12"
81
+				required : I18n.system_please_input + I18n.jobgroup_field_title ,
82
+				rangelength: I18n.jobgroup_field_title_length
77 83
 			},
78 84
 			order : {
79
-				required :"请输入“排序”",
80
-				digits: "请输入整数",
81
-				range: "取值范围为1~1000"
85
+				required : I18n.system_please_input + I18n.jobgroup_field_order ,
86
+				digits: I18n.jobgroup_field_order_digits ,
87
+				range: I18n.jobgroup_field_orderrange
82 88
 			}
83 89
 		},
84 90
 		highlight : function(element) {
@@ -96,8 +102,9 @@ $(function() {
96 102
 				if (data.code == "200") {
97 103
 					$('#addModal').modal('hide');
98 104
 					layer.open({
99
-						title: '系统提示',
100
-						content: '新增成功',
105
+						title: I18n.system_tips ,
106
+                        btn: [ I18n.system_ok ],
107
+						content: I18n.system_add_suc ,
101 108
 						icon: '1',
102 109
 						end: function(layero, index){
103 110
 							window.location.reload();
@@ -105,8 +112,9 @@ $(function() {
105 112
 					});
106 113
 				} else {
107 114
 					layer.open({
108
-						title: '系统提示',
109
-						content: (data.msg || "新增失败"),
115
+						title: I18n.system_tips,
116
+                        btn: [ I18n.system_ok ],
117
+						content: (data.msg || I18n.system_add_fail  ),
110 118
 						icon: '2'
111 119
 					});
112 120
 				}
@@ -119,7 +127,7 @@ $(function() {
119 127
 		$("#addModal .form .form-group").removeClass("has-error");
120 128
 	});
121 129
 
122
-	// 注册方式,切换
130
+	// addressType change
123 131
 	$("#addModal input[name=addressType], #updateModal input[name=addressType]").click(function(){
124 132
 		var addressType = $(this).val();
125 133
 		var $addressList = $(this).parents("form").find("textarea[name=addressList]");
@@ -171,20 +179,20 @@ $(function() {
171 179
 			}
172 180
 		},
173 181
 		messages : {
174
-			appName : {
175
-				required :"请输入“AppName”",
176
-				rangelength:"AppName长度限制为4~64",
177
-				myValid01: "限制以小写字母开头,由小写字母、数字和中划线组成"
178
-			},
179
-			title : {
180
-				required :"请输入“执行器名称”",
181
-				rangelength:"长度限制为4~12"
182
-			},
183
-			order : {
184
-				required :"请输入“排序”",
185
-				digits: "请输入整数",
186
-				range: "取值范围为1~1000"
187
-			}
182
+            appName : {
183
+                required : I18n.system_please_input+"AppName",
184
+                rangelength: I18n.jobgroup_field_appName_length ,
185
+                myValid01: I18n.jobgroup_field_appName_limit
186
+            },
187
+            title : {
188
+                required : I18n.system_please_input + I18n.jobgroup_field_title ,
189
+                rangelength: I18n.jobgroup_field_title_length
190
+            },
191
+            order : {
192
+                required : I18n.system_please_input + I18n.jobgroup_field_order ,
193
+                digits: I18n.jobgroup_field_order_digits ,
194
+                range: I18n.jobgroup_field_orderrange
195
+            }
188 196
 		},
189 197
 		highlight : function(element) {
190 198
 			$(element).closest('.form-group').addClass('has-error');
@@ -202,8 +210,9 @@ $(function() {
202 210
 					$('#addModal').modal('hide');
203 211
 
204 212
 					layer.open({
205
-						title: '系统提示',
206
-						content: '更新成功',
213
+						title: I18n.system_tips ,
214
+                        btn: [ I18n.system_ok ],
215
+						content: I18n.system_update_suc ,
207 216
 						icon: '1',
208 217
 						end: function(layero, index){
209 218
 							window.location.reload();
@@ -211,8 +220,9 @@ $(function() {
211 220
 					});
212 221
 				} else {
213 222
 					layer.open({
214
-						title: '系统提示',
215
-						content: (data.msg || "更新失败"),
223
+						title: I18n.system_tips,
224
+                        btn: [ I18n.system_ok ],
225
+						content: (data.msg || I18n.system_update_fail  ),
216 226
 						icon: '2'
217 227
 					});
218 228
 				}

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

@@ -1,4 +1,5 @@
1 1
 $(function() {
2
+
2 3
 	// init date tables
3 4
 	var jobTable = $("#job_list").dataTable({
4 5
 		"deferRender": true,
@@ -10,6 +11,7 @@ $(function() {
10 11
 	        data : function ( d ) {
11 12
 	        	var obj = {};
12 13
 	        	obj.jobGroup = $('#jobGroup').val();
14
+                obj.jobDesc = $('#jobDesc').val();
13 15
 	        	obj.executorHandler = $('#executorHandler').val();
14 16
 	        	obj.start = d.start;
15 17
 	        	obj.length = d.length;
@@ -18,12 +20,18 @@ $(function() {
18 20
 	    },
19 21
 	    "searching": false,
20 22
 	    "ordering": false,
21
-	    //"scrollX": true,	// X轴滚动条,取消自适应
23
+	    //"scrollX": true,	// scroll x,close self-adaption
22 24
 	    "columns": [
23
-	                { "data": 'id', "bSortable": false, "visible" : true},
25
+	                {
26
+	                	"data": 'id',
27
+						"bSortable": false,
28
+						"visible" : true,
29
+						"width":'10%'
30
+					},
24 31
 	                { 
25 32
 	                	"data": 'jobGroup', 
26 33
 	                	"visible" : false,
34
+						"width":'20%',
27 35
 	                	"render": function ( data, type, row ) {
28 36
 	            			var groupMenu = $("#jobGroup").find("option");
29 37
 	            			for ( var index in $("#jobGroup").find("option")) {
@@ -34,28 +42,30 @@ $(function() {
34 42
 	            			return data;
35 43
 	            		}
36 44
             		},
37
-	                { "data": 'jobDesc', "visible" : true,"width":'20%'},
45
+	                {
46
+	                	"data": 'jobDesc',
47
+						"visible" : true,
48
+						"width":'20%'
49
+					},
38 50
 					{
39 51
 						"data": 'glueType',
40 52
 						"width":'20%',
41 53
 						"visible" : true,
42 54
 						"render": function ( data, type, row ) {
43
-							if ('GLUE_GROOVY'==row.glueType) {
44
-								return "GLUE模式(Java)";
45
-							} else if ('GLUE_SHELL'==row.glueType) {
46
-								return "GLUE模式(Shell)";
47
-							} else if ('GLUE_PYTHON'==row.glueType) {
48
-								return "GLUE模式(Python)";
49
-							}else if  ('GLUE_NODEJS'==row.glueType){
50
-								return "GLUE模式(Nodejs)";
51
-							} else if ('BEAN'==row.glueType) {
52
-								return "BEAN模式:" + row.executorHandler;
53
-							}
54
-							return row.executorHandler;
55
+							var glueTypeTitle = findGlueTypeTitle(row.glueType);
56
+                            if (row.executorHandler) {
57
+                                return glueTypeTitle +":" + row.executorHandler;
58
+                            } else {
59
+                                return glueTypeTitle;
60
+                            }
55 61
 						}
56 62
 					},
57 63
 	                { "data": 'executorParam', "visible" : false},
58
-					{ "data": 'jobCron', "visible" : true,"width":'10%'},
64
+					{
65
+						"data": 'jobCron',
66
+						"visible" : true,
67
+						"width":'10%'
68
+					},
59 69
 	                { 
60 70
 	                	"data": 'addTime', 
61 71
 	                	"visible" : false, 
@@ -72,7 +82,6 @@ $(function() {
72 82
 	                },
73 83
 	                { "data": 'author', "visible" : true, "width":'10%'},
74 84
 	                { "data": 'alarmEmail', "visible" : false},
75
-	                { "data": 'glueType', "visible" : false},
76 85
 	                { 
77 86
 	                	"data": 'jobStatus',
78 87
 						"width":'10%',
@@ -81,24 +90,24 @@ $(function() {
81 90
 	                		if ('NORMAL' == data) {
82 91
 	                			return '<small class="label label-success" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
83 92
 							} else if ('PAUSED' == data){
84
-								return '<small class="label label-default" title="暂停" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
93
+								return '<small class="label label-default" ><i class="fa fa-clock-o"></i>'+ data +'</small>';
85 94
 							} else if ('BLOCKED' == data){
86
-								return '<small class="label label-default" title="阻塞[串行]" ><i class="fa fa-clock-o"></i>'+ data +'</small>'; 
95
+								return '<small class="label label-default" ><i class="fa fa-clock-o"></i>'+ data +'</small>';
87 96
 							}
88 97
 	                		return data;
89 98
 	                	}
90 99
 	                },
91 100
 	                {
92
-						"data": '操作' ,
101
+						"data": I18n.system_opt ,
93 102
 						"width":'15%',
94 103
 	                	"render": function ( data, type, row ) {
95 104
 	                		return function(){
96 105
 	                			// status
97 106
 	                			var pause_resume = "";
98 107
 	                			if ('NORMAL' == row.jobStatus) {
99
-	                				pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_pause" type="button">暂停</button>  ';
108
+	                				pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_pause" type="button">'+ I18n.jobinfo_opt_pause +'</button>  ';
100 109
 								} else if ('PAUSED' == row.jobStatus){
101
-									pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_resume" type="button">恢复</button>  ';
110
+									pause_resume = '<button class="btn btn-primary btn-xs job_operate" _type="job_resume" type="button">'+ I18n.jobinfo_opt_resume +'</button>  ';
102 111
 								}
103 112
 	                			// log url
104 113
 	                			var logUrl = base_url +'/joblog?jobId='+ row.id;
@@ -113,12 +122,12 @@ $(function() {
113 122
 								// html
114 123
                                 tableData['key'+row.id] = row;
115 124
 								var html = '<p id="'+ row.id +'" >'+
116
-									'<button class="btn btn-primary btn-xs job_operate" _type="job_trigger" type="button">执行</button>  '+
125
+									'<button class="btn btn-primary btn-xs job_operate" _type="job_trigger" type="button">'+ I18n.jobinfo_opt_run +'</button>  '+
117 126
 									pause_resume +
118
-									'<button class="btn btn-primary btn-xs" type="job_del" type="button" onclick="javascript:window.open(\'' + logUrl + '\')" >日志</button><br>  '+
119
-									'<button class="btn btn-warning btn-xs update" type="button">编辑</button>  '+
127
+									'<button class="btn btn-primary btn-xs" type="job_del" type="button" onclick="javascript:window.open(\'' + logUrl + '\')" >'+ I18n.jobinfo_opt_log +'</button><br>  '+
128
+									'<button class="btn btn-warning btn-xs update" type="button">'+ I18n.system_opt_edit +'</button>  '+
120 129
 									codeBtn +
121
-									'<button class="btn btn-danger btn-xs job_operate" _type="job_del" type="button">删除</button>  '+
130
+									'<button class="btn btn-danger btn-xs job_operate" _type="job_del" type="button">'+ I18n.system_opt_del +'</button>  '+
122 131
 									'</p>';
123 132
 
124 133
 	                			return html;
@@ -127,27 +136,27 @@ $(function() {
127 136
 	                }
128 137
 	            ],
129 138
 		"language" : {
130
-			"sProcessing" : "处理中...",
131
-			"sLengthMenu" : "每页 _MENU_ 条记录",
132
-			"sZeroRecords" : "没有匹配结果",
133
-			"sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 )",
134
-			"sInfoEmpty" : "无记录",
135
-			"sInfoFiltered" : "(由 _MAX_ 项结果过滤)",
139
+			"sProcessing" : I18n.dataTable_sProcessing ,
140
+			"sLengthMenu" : I18n.dataTable_sLengthMenu ,
141
+			"sZeroRecords" : I18n.dataTable_sZeroRecords ,
142
+			"sInfo" : I18n.dataTable_sInfo ,
143
+			"sInfoEmpty" : I18n.dataTable_sInfoEmpty ,
144
+			"sInfoFiltered" : I18n.dataTable_sInfoFiltered ,
136 145
 			"sInfoPostFix" : "",
137
-			"sSearch" : "搜索:",
146
+			"sSearch" : I18n.dataTable_sSearch ,
138 147
 			"sUrl" : "",
139
-			"sEmptyTable" : "表中数据为空",
140
-			"sLoadingRecords" : "载入中...",
148
+			"sEmptyTable" : I18n.dataTable_sEmptyTable ,
149
+			"sLoadingRecords" : I18n.dataTable_sLoadingRecords ,
141 150
 			"sInfoThousands" : ",",
142 151
 			"oPaginate" : {
143
-				"sFirst" : "首页",
144
-				"sPrevious" : "上页",
145
-				"sNext" : "下页",
146
-				"sLast" : "末页"
152
+				"sFirst" : I18n.dataTable_sFirst ,
153
+				"sPrevious" : I18n.dataTable_sPrevious ,
154
+				"sNext" : I18n.dataTable_sNext ,
155
+				"sLast" : I18n.dataTable_sLast
147 156
 			},
148 157
 			"oAria" : {
149
-				"sSortAscending" : ": 以升序排列此列",
150
-				"sSortDescending" : ": 以降序排列此列"
158
+				"sSortAscending" : I18n.dataTable_sSortAscending ,
159
+				"sSortDescending" : I18n.dataTable_sSortDescending
151 160
 			}
152 161
 		}
153 162
 	});
@@ -155,7 +164,7 @@ $(function() {
155 164
     // table data
156 165
     var tableData = {};
157 166
 
158
-	// 搜索按钮
167
+	// search btn
159 168
 	$('#searchBtn').on('click', function(){
160 169
 		jobTable.fnDraw();
161 170
 	});
@@ -175,19 +184,19 @@ $(function() {
175 184
 
176 185
 		var type = $(this).attr("_type");
177 186
 		if ("job_pause" == type) {
178
-			typeName = "暂停";
187
+			typeName = I18n.jobinfo_opt_pause ;
179 188
 			url = base_url + "/jobinfo/pause";
180 189
 			needFresh = true;
181 190
 		} else if ("job_resume" == type) {
182
-			typeName = "恢复";
191
+			typeName = I18n.jobinfo_opt_resume ;
183 192
 			url = base_url + "/jobinfo/resume";
184 193
 			needFresh = true;
185 194
 		} else if ("job_del" == type) {
186
-			typeName = "删除";
195
+			typeName = I18n.system_opt_del ;
187 196
 			url = base_url + "/jobinfo/remove";
188 197
 			needFresh = true;
189 198
 		} else if ("job_trigger" == type) {
190
-			typeName = "执行";
199
+			typeName = I18n.jobinfo_opt_run ;
191 200
 			url = base_url + "/jobinfo/trigger";
192 201
 		} else {
193 202
 			return;
@@ -195,7 +204,11 @@ $(function() {
195 204
 		
196 205
 		var id = $(this).parent('p').attr("id");
197 206
 
198
-		layer.confirm('确认' + typeName + '?', {icon: 3, title:'系统提示'}, function(index){
207
+		layer.confirm( I18n.system_ok + typeName + '?', {
208
+			icon: 3,
209
+			title: I18n.system_tips ,
210
+            btn: [ I18n.system_ok, I18n.system_cancel ]
211
+		}, function(index){
199 212
 			layer.close(index);
200 213
 
201 214
 			$.ajax({
@@ -209,8 +222,9 @@ $(function() {
209 222
 					if (data.code == 200) {
210 223
 
211 224
 						layer.open({
212
-							title: '系统提示',
213
-							content: typeName + "成功",
225
+							title: I18n.system_tips,
226
+                            btn: [ I18n.system_ok ],
227
+							content: typeName + I18n.system_success ,
214 228
 							icon: '1',
215 229
 							end: function(layero, index){
216 230
 								if (needFresh) {
@@ -221,8 +235,9 @@ $(function() {
221 235
 						});
222 236
 					} else {
223 237
 						layer.open({
224
-							title: '系统提示',
225
-							content: (data.msg || typeName + "失败"),
238
+							title: I18n.system_tips,
239
+                            btn: [ I18n.system_ok ],
240
+							content: (data.msg || typeName + I18n.system_fail ),
226 241
 							icon: '2'
227 242
 						});
228 243
 					}
@@ -230,15 +245,8 @@ $(function() {
230 245
 			});
231 246
 		});
232 247
 	});
233
-	
234
-	// jquery.validate 自定义校验 “英文字母开头,只含有英文字母、数字和下划线”
235
-	jQuery.validator.addMethod("myValid01", function(value, element) {
236
-		var length = value.length;
237
-		var valid = /^[a-zA-Z][a-zA-Z0-9_]*$/;
238
-		return this.optional(element) || valid.test(value);
239
-	}, "只支持英文字母开头,只含有英文字母、数字和下划线");
240
-	
241
-	// 新增
248
+
249
+	// add
242 250
 	$(".add").click(function(){
243 251
 		$('#addModal').modal({backdrop: false, keyboard: false}).modal('show');
244 252
 	});
@@ -260,13 +268,13 @@ $(function() {
260 268
         }, 
261 269
         messages : {  
262 270
             jobDesc : {
263
-            	required :"请输入“描述”."
271
+            	required : I18n.system_please_input + I18n.jobinfo_field_jobdesc
264 272
             },
265 273
             jobCron : {
266
-            	required :"请输入“Cron”."
274
+            	required : I18n.system_please_input + "Cron"
267 275
             },
268 276
             author : {
269
-            	required : "请输入“负责人”."
277
+            	required : I18n.system_please_input + I18n.jobinfo_field_author
270 278
             }
271 279
         },
272 280
 		highlight : function(element) {  
@@ -284,8 +292,9 @@ $(function() {
284 292
     			if (data.code == "200") {
285 293
 					$('#addModal').modal('hide');
286 294
 					layer.open({
287
-						title: '系统提示',
288
-						content: '新增任务成功',
295
+						title: I18n.system_tips ,
296
+                        btn: [ I18n.system_ok ],
297
+						content: I18n.system_add_suc ,
289 298
 						icon: '1',
290 299
 						end: function(layero, index){
291 300
 							jobTable.fnDraw();
@@ -294,8 +303,9 @@ $(function() {
294 303
 					});
295 304
     			} else {
296 305
 					layer.open({
297
-						title: '系统提示',
298
-						content: (data.msg || "新增失败"),
306
+						title: I18n.system_tips ,
307
+                        btn: [ I18n.system_ok ],
308
+						content: (data.msg || I18n.system_add_fail),
299 309
 						icon: '2'
300 310
 					});
301 311
     			}
@@ -312,7 +322,7 @@ $(function() {
312 322
 	});
313 323
 
314 324
 
315
-    // 运行模式
325
+    // glueType change
316 326
     $(".glueType").change(function(){
317 327
 		// executorHandler
318 328
         var $executorHandler = $(this).parents("form").find("input[name='executorHandler']");
@@ -339,19 +349,11 @@ $(function() {
339 349
 		}
340 350
 	});
341 351
 
342
-	// 更新
352
+	// update
343 353
 	$("#job_list").on('click', '.update',function() {
344 354
 
345 355
         var id = $(this).parent('p').attr("id");
346 356
         var row = tableData['key'+id];
347
-        if (!row) {
348
-            layer.open({
349
-                title: '系统提示',
350
-                content: ("任务信息加载失败,请刷新页面"),
351
-                icon: '2'
352
-            });
353
-            return;
354
-        }
355 357
 
356 358
 		// base data
357 359
 		$("#updateModal .form input[name='id']").val( row.id );
@@ -392,13 +394,13 @@ $(function() {
392 394
 		},
393 395
 		messages : {
394 396
 			jobDesc : {
395
-				required :"请输入“描述”."
397
+                required : I18n.system_please_input + I18n.jobinfo_field_jobdesc
396 398
 			},
397 399
 			jobCron : {
398
-				required :"请输入“Cron”."
400
+				required : I18n.system_please_input + "Cron"
399 401
 			},
400 402
 			author : {
401
-				required : "请输入“负责人”."
403
+				required : I18n.system_please_input + I18n.jobinfo_field_author
402 404
 			}
403 405
 		},
404 406
 		highlight : function(element) {
@@ -413,12 +415,13 @@ $(function() {
413 415
         },
414 416
         submitHandler : function(form) {
415 417
 			// post
416
-    		$.post(base_url + "/jobinfo/reschedule", $("#updateModal .form").serialize(), function(data, status) {
418
+    		$.post(base_url + "/jobinfo/update", $("#updateModal .form").serialize(), function(data, status) {
417 419
     			if (data.code == "200") {
418 420
 					$('#updateModal').modal('hide');
419 421
 					layer.open({
420
-						title: '系统提示',
421
-						content: '更新成功',
422
+						title: I18n.system_tips ,
423
+                        btn: [ I18n.system_ok ],
424
+						content: I18n.system_update_suc ,
422 425
 						icon: '1',
423 426
 						end: function(layero, index){
424 427
 							//window.location.reload();
@@ -427,8 +430,9 @@ $(function() {
427 430
 					});
428 431
     			} else {
429 432
 					layer.open({
430
-						title: '系统提示',
431
-						content: (data.msg || "更新失败"),
433
+						title: I18n.system_tips ,
434
+                        btn: [ I18n.system_ok ],
435
+						content: (data.msg || I18n.system_update_fail ),
432 436
 						icon: '2'
433 437
 					});
434 438
     			}
@@ -439,4 +443,20 @@ $(function() {
439 443
 		$("#updateModal .form")[0].reset()
440 444
 	});
441 445
 
446
+    /**
447
+	 * find title by name, GlueType
448
+     */
449
+	function findGlueTypeTitle(glueType) {
450
+		var glueTypeTitle;
451
+        $("#addModal .form select[name=glueType] option").each(function () {
452
+            var name = $(this).val();
453
+            var title = $(this).text();
454
+            if (glueType == name) {
455
+                glueTypeTitle = title;
456
+                return false
457
+            }
458
+        });
459
+        return glueTypeTitle;
460
+    }
461
+
442 462
 });

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

@@ -3,7 +3,7 @@ $(function() {
3 3
     // trigger fail, end
4 4
     if (triggerCode != 200) {
5 5
         $('#logConsoleRunning').hide();
6
-        $('#logConsole').append('<span style="color: red;">任务发起调度失败,无法查看执行日志</span>');
6
+        $('#logConsole').append('<span style="color: red;">'+ I18n.joblog_rolling_log_triggerfail +'</span>');
7 7
         return;
8 8
     }
9 9
 
@@ -13,7 +13,7 @@ $(function() {
13 13
     function pullLog() {
14 14
         // pullFailCount, max=20
15 15
         if (pullFailCount++ > 20) {
16
-            logRunStop('<span style="color: red;">终止请求Rolling日志,请求失败次数超上限,可刷新页面重新加载日志</span>');
16
+            logRunStop('<span style="color: red;">'+ I18n.joblog_rolling_log_failoften +'</span>');
17 17
             return;
18 18
         }
19 19
 

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

@@ -1,6 +1,6 @@
1 1
 $(function() {
2 2
 
3
-	// 任务组列表选中, 任务列表初始化和选中
3
+	// jobGroup change, job list init and select
4 4
 	$("#jobGroup").on("change", function () {
5 5
 		var jobGroup = $(this).children('option:selected').val();
6 6
 		$.ajax({
@@ -11,7 +11,7 @@ $(function() {
11 11
 			dataType : "json",
12 12
 			success : function(data){
13 13
 				if (data.code == 200) {
14
-					$("#jobId").html('<option value="0" >全部</option>');
14
+					$("#jobId").html( '<option value="0" >'+ I18n.system_all +'</option>' );
15 15
 					$.each(data.content, function (n, value) {
16 16
                         $("#jobId").append('<option value="' + value.id + '" >' + value.jobDesc + '</option>');
17 17
                     });
@@ -20,8 +20,9 @@ $(function() {
20 20
                     }
21 21
 				} else {
22 22
 					layer.open({
23
-						title: '系统提示',
24
-						content: (data.msg || "接口异常"),
23
+						title: I18n.system_tips ,
24
+                        btn: [ I18n.system_ok ],
25
+						content: (data.msg || I18n.system_api_error ),
25 26
 						icon: '2'
26 27
 					});
27 28
 				}
@@ -33,7 +34,16 @@ $(function() {
33 34
         $("#jobGroup").change();
34 35
 	}
35 36
 
36
-	// 过滤时间
37
+	// filter Time
38
+    var rangesConf = {};
39
+    rangesConf[I18n.daterangepicker_ranges_recent_hour] = [moment().subtract(1, 'hours'), moment()];
40
+    rangesConf[I18n.daterangepicker_ranges_today] = [moment().startOf('day'), moment().endOf('day')];
41
+    rangesConf[I18n.daterangepicker_ranges_yesterday] = [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')];
42
+    rangesConf[I18n.daterangepicker_ranges_this_month] = [moment().startOf('month'), moment().endOf('month')];
43
+    rangesConf[I18n.daterangepicker_ranges_last_month] = [moment().subtract(1, 'months').startOf('month'), moment().subtract(1, 'months').endOf('month')];
44
+    rangesConf[I18n.daterangepicker_ranges_recent_week] = [moment().subtract(1, 'weeks').startOf('day'), moment().endOf('day')];
45
+    rangesConf[I18n.daterangepicker_ranges_recent_month] = [moment().subtract(1, 'months').startOf('day'), moment().endOf('day')];
46
+
37 47
 	$('#filterTime').daterangepicker({
38 48
         autoApply:false,
39 49
         singleDatePicker:false,
@@ -42,29 +52,21 @@ $(function() {
42 52
 		timePickerIncrement: 10, 	// 时间的增量,单位为分钟
43 53
         timePicker24Hour : true,
44 54
         opens : 'left', //日期选择框的弹出位置
45
-		ranges: {
46
-			'最近1小时': [moment().subtract(1, 'hours'), moment()],
47
-			'今日': [moment().startOf('day'), moment().endOf('day')],
48
-			'昨日': [moment().subtract(1, 'days').startOf('day'), moment().subtract(1, 'days').endOf('day')],
49
-			'最近7日': [moment().subtract(6, 'days'), moment()],
50
-			'最近30日': [moment().subtract(29, 'days'), moment()],
51
-			'本月': [moment().startOf('month'), moment().endOf('month')],
52
-			'上个月': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
53
-		},
55
+		ranges: rangesConf,
54 56
         locale : {
55 57
             format: 'YYYY-MM-DD HH:mm:ss',
56 58
             separator : ' - ',
57
-        	customRangeLabel : '自定义',
58
-            applyLabel : '确定',
59
-            cancelLabel : '取消',
60
-            fromLabel : '起始时间',
61
-            toLabel : '结束时间',
62
-            daysOfWeek : [ '日', '一', '二', '三', '四', '五', '六' ],
63
-            monthNames : [ '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月' ],
64
-            firstDay : 1,
65
-            startDate: moment().startOf('day'),
66
-            endDate: moment().endOf('day')
67
-        }
59
+            customRangeLabel : I18n.daterangepicker_custom_name ,
60
+            applyLabel : I18n.system_ok ,
61
+            cancelLabel : I18n.system_cancel ,
62
+            fromLabel : I18n.daterangepicker_custom_starttime ,
63
+            toLabel : I18n.daterangepicker_custom_endtime ,
64
+            daysOfWeek : I18n.daterangepicker_custom_daysofweek.split(',') ,        // '日', '一', '二', '三', '四', '五', '六'
65
+            monthNames : I18n.daterangepicker_custom_monthnames.split(',') ,        // '一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'
66
+            firstDay : 1
67
+        },
68
+        startDate: rangesConf[I18n.daterangepicker_ranges_today][0],
69
+        endDate: rangesConf[I18n.daterangepicker_ranges_today][1]
68 70
 	});
69 71
 
70 72
 	// init date tables
@@ -74,6 +76,7 @@ $(function() {
74 76
 	    "serverSide": true,
75 77
 		"ajax": {
76 78
 	        url: base_url + "/joblog/pageList" ,
79
+            type:"post",
77 80
 	        data : function ( d ) {
78 81
 	        	var obj = {};
79 82
 	        	obj.jobGroup = $('#jobGroup').val();
@@ -92,24 +95,18 @@ $(function() {
92 95
 					{
93 96
 						"data": 'jobId',
94 97
 						"visible" : true,
98
+                        "width":'10%',
95 99
 						"render": function ( data, type, row ) {
96
-							var glueTypeTitle = row.glueType;
97
-							if ('GLUE_GROOVY'==row.glueType) {
98
-								glueTypeTitle = "GLUE模式(Java)";
99
-							} else if ('GLUE_SHELL'==row.glueType) {
100
-								glueTypeTitle = "GLUE模式(Shell)";
101
-							} else if ('GLUE_PYTHON'==row.glueType) {
102
-								glueTypeTitle = "GLUE模式(Python)";
103
-							}else if ('GLUE_NODEJS'==row.glueType) {
104
-								glueTypeTitle = "GLUE模式(Nodejs)";
105
-							} else if ('BEAN'==row.glueType) {
106
-								glueTypeTitle = "BEAN模式:" + row.executorHandler;
107
-							}
100
+
101
+                            var glueTypeTitle = GlueTypeEnum[row.glueType];
102
+                            if (row.executorHandler) {
103
+                                glueTypeTitle = glueTypeTitle +":" + row.executorHandler;
104
+                            }
108 105
 
109 106
 							var temp = '';
110
-							temp += '执行器地址:' + (row.executorAddress?row.executorAddress:'');
111
-							temp += '<br>运行模式:' + glueTypeTitle;
112
-							temp += '<br>任务参数:' + row.executorParam;
107
+							temp += I18n.joblog_field_executorAddress + ':' + (row.executorAddress?row.executorAddress:'');
108
+							temp += '<br>'+ I18n.jobinfo_field_gluetype +':' + glueTypeTitle;
109
+							temp += '<br>'+ I18n.jobinfo_field_executorparam +':' + row.executorParam;
113 110
 
114 111
 							return '<a class="logTips" href="javascript:;" >'+ row.jobId +'<span style="display:none;">'+ temp +'</span></a>';
115 112
 						}
@@ -117,18 +114,20 @@ $(function() {
117 114
 					{ "data": 'jobGroup', "visible" : false},
118 115
 					{
119 116
 						"data": 'triggerTime',
117
+                        "width":'16%',
120 118
 						"render": function ( data, type, row ) {
121 119
 							return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
122 120
 						}
123 121
 					},
124 122
 					{
125 123
 						"data": 'triggerCode',
124
+                        "width":'12%',
126 125
 						"render": function ( data, type, row ) {
127 126
 							var html = data;
128 127
 							if (data == 200) {
129
-								html = '<span style="color: green">成功</span>';
128
+								html = '<span style="color: green">'+ I18n.system_success +'</span>';
130 129
 							} else if (data == 500) {
131
-								html = '<span style="color: red">失败</span>';
130
+								html = '<span style="color: red">'+ I18n.system_fail +'</span>';
132 131
 							} else if (data == 0) {
133 132
                                 html = '';
134 133
 							}
@@ -137,26 +136,29 @@ $(function() {
137 136
 					},
138 137
 					{
139 138
 						"data": 'triggerMsg',
139
+                        "width":'12%',
140 140
 						"render": function ( data, type, row ) {
141
-							return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
141
+							return data?'<a class="logTips" href="javascript:;" >'+ I18n.system_show +'<span style="display:none;">'+ data +'</span></a>':I18n.system_empty;
142 142
 						}
143 143
 					},
144 144
 	                { 
145 145
 	                	"data": 'handleTime',
146
+                        "width":'16%',
146 147
 	                	"render": function ( data, type, row ) {
147 148
 	                		return data?moment(new Date(data)).format("YYYY-MM-DD HH:mm:ss"):"";
148 149
 	                	}
149 150
 	                },
150 151
 	                {
151 152
 						"data": 'handleCode',
153
+                        "width":'12%',
152 154
 						"render": function ( data, type, row ) {
153 155
                             var html = data;
154 156
                             if (data == 200) {
155
-                                html = '<span style="color: green">成功</span>';
157
+                                html = '<span style="color: green">'+ I18n.joblog_handleCode_200 +'</span>';
156 158
                             } else if (data == 500) {
157
-                                html = '<span style="color: red">失败</span>';
159
+                                html = '<span style="color: red">'+ I18n.joblog_handleCode_500 +'</span>';
158 160
                             } else if (data == 501) {
159
-                                html = '<span style="color: red">失败重试</span>';
161
+                                html = '<span style="color: red">'+ I18n.joblog_handleCode_501 +'</span>';
160 162
                             } else if (data == 0) {
161 163
                                 html = '';
162 164
                             }
@@ -165,21 +167,22 @@ $(function() {
165 167
 	                },
166 168
 	                { 
167 169
 	                	"data": 'handleMsg',
170
+                        "width":'12%',
168 171
 	                	"render": function ( data, type, row ) {
169
-	                		return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
172
+	                		return data?'<a class="logTips" href="javascript:;" >'+ I18n.system_show +'<span style="display:none;">'+ data +'</span></a>':I18n.system_empty;
170 173
 	                	}
171 174
 	                },
172 175
 	                {
173 176
 						"data": 'handleMsg' ,
174 177
 						"bSortable": false,
175
-						"width": "8%" ,
178
+                        "width":'10%',
176 179
 	                	"render": function ( data, type, row ) {
177 180
 	                		// better support expression or string, not function
178 181
 	                		return function () {
179 182
 		                		if (row.triggerCode == 200){
180
-		                			var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">执行日志</a>';
183
+		                			var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">'+ I18n.joblog_rolling_log +'</a>';
181 184
 		                			if(row.handleCode == 0){
182
-		                				temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'" style="color: red;" >终止任务</a>';
185
+		                				temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'" style="color: red;" >'+ I18n.joblog_kill_log +'</a>';
183 186
 		                			}
184 187
 		                			return temp;
185 188
 		                		}
@@ -188,44 +191,44 @@ $(function() {
188 191
 	                	}
189 192
 	                }
190 193
 	            ],
191
-		"language" : {
192
-			"sProcessing" : "处理中...",
193
-			"sLengthMenu" : "每页 _MENU_ 条记录",
194
-			"sZeroRecords" : "没有匹配结果",
195
-			"sInfo" : "第 _PAGE_ 页 ( 总共 _PAGES_ 页,_TOTAL_ 条记录 )",
196
-			"sInfoEmpty" : "无记录",
197
-			"sInfoFiltered" : "(由 _MAX_ 项结果过滤)",
198
-			"sInfoPostFix" : "",
199
-			"sSearch" : "搜索:",
200
-			"sUrl" : "",
201
-			"sEmptyTable" : "表中数据为空",
202
-			"sLoadingRecords" : "载入中...",
203
-			"sInfoThousands" : ",",
204
-			"oPaginate" : {
205
-				"sFirst" : "首页",
206
-				"sPrevious" : "上页",
207
-				"sNext" : "下页",
208
-				"sLast" : "末页"
209
-			},
210
-			"oAria" : {
211
-				"sSortAscending" : ": 以升序排列此列",
212
-				"sSortDescending" : ": 以降序排列此列"
213
-			}
214
-		}
194
+        "language" : {
195
+            "sProcessing" : I18n.dataTable_sProcessing ,
196
+            "sLengthMenu" : I18n.dataTable_sLengthMenu ,
197
+            "sZeroRecords" : I18n.dataTable_sZeroRecords ,
198
+            "sInfo" : I18n.dataTable_sInfo ,
199
+            "sInfoEmpty" : I18n.dataTable_sInfoEmpty ,
200
+            "sInfoFiltered" : I18n.dataTable_sInfoFiltered ,
201
+            "sInfoPostFix" : "",
202
+            "sSearch" : I18n.dataTable_sSearch ,
203
+            "sUrl" : "",
204
+            "sEmptyTable" : I18n.dataTable_sEmptyTable ,
205
+            "sLoadingRecords" : I18n.dataTable_sLoadingRecords ,
206
+            "sInfoThousands" : ",",
207
+            "oPaginate" : {
208
+                "sFirst" : I18n.dataTable_sFirst ,
209
+                "sPrevious" : I18n.dataTable_sPrevious ,
210
+                "sNext" : I18n.dataTable_sNext ,
211
+                "sLast" : I18n.dataTable_sLast
212
+            },
213
+            "oAria" : {
214
+                "sSortAscending" : I18n.dataTable_sSortAscending ,
215
+                "sSortDescending" : I18n.dataTable_sSortDescending
216
+            }
217
+        }
215 218
 	});
216 219
 	
217
-	// 日志弹框提示
220
+	// logTips alert
218 221
 	$('#joblog_list').on('click', '.logTips', function(){
219 222
 		var msg = $(this).find('span').html();
220 223
 		ComAlertTec.show(msg);
221 224
 	});
222 225
 	
223
-	// 搜索按钮
226
+	// search Btn
224 227
 	$('#searchBtn').on('click', function(){
225 228
 		logTable.fnDraw();
226 229
 	});
227 230
 	
228
-	// 查看执行器详细执行日志
231
+	// logDetail look
229 232
 	$('#joblog_list').on('click', '.logDetail', function(){
230 233
 		var _id = $(this).attr('_id');
231 234
 		
@@ -234,12 +237,16 @@ $(function() {
234 237
 	});
235 238
 
236 239
 	/**
237
-	 * 终止任务
240
+	 * log Kill
238 241
 	 */
239 242
 	$('#joblog_list').on('click', '.logKill', function(){
240 243
 		var _id = $(this).attr('_id');
241 244
 
242
-        layer.confirm('确认主动终止任务?', {icon: 3, title:'系统提示'}, function(index){
245
+        layer.confirm( (I18n.system_ok + I18n.joblog_kill_log + '?'), {
246
+        	icon: 3,
247
+			title: I18n.system_tips ,
248
+            btn: [ I18n.system_ok, I18n.system_cancel ]
249
+		}, function(index){
243 250
             layer.close(index);
244 251
 
245 252
             $.ajax({
@@ -250,8 +257,9 @@ $(function() {
250 257
                 success : function(data){
251 258
                     if (data.code == 200) {
252 259
                         layer.open({
253
-                            title: '系统提示',
254
-                            content: '操作成功',
260
+                            title: I18n.system_tips,
261
+                            btn: [ I18n.system_ok ],
262
+                            content: I18n.system_opt_suc ,
255 263
                             icon: '1',
256 264
                             end: function(layero, index){
257 265
                                 logTable.fnDraw();
@@ -259,8 +267,9 @@ $(function() {
259 267
                         });
260 268
                     } else {
261 269
                         layer.open({
262
-                            title: '系统提示',
263
-                            content: (data.msg || "操作失败"),
270
+                            title: I18n.system_tips,
271
+                            btn: [ I18n.system_ok ],
272
+                            content: (data.msg || I18n.system_opt_fail ),
264 273
                             icon: '2'
265 274
                         });
266 275
                     }
@@ -271,7 +280,7 @@ $(function() {
271 280
 	});
272 281
 
273 282
 	/**
274
-	 * 清理任务Log
283
+	 * clear Log
275 284
 	 */
276 285
 	$('#clearLog').on('click', function(){
277 286
 
@@ -295,8 +304,9 @@ $(function() {
295 304
 			if (data.code == "200") {
296 305
 				$('#clearLogModal').modal('hide');
297 306
 				layer.open({
298
-					title: '系统提示',
299
-					content: '日志清理成功',
307
+					title: I18n.system_tips ,
308
+                    btn: [ I18n.system_ok ],
309
+					content: (I18n.joblog_clean_log + I18n.system_success) ,
300 310
 					icon: '1',
301 311
 					end: function(layero, index){
302 312
 						logTable.fnDraw();
@@ -304,8 +314,9 @@ $(function() {
304 314
 				});
305 315
 			} else {
306 316
 				layer.open({
307
-					title: '系统提示',
308
-					content: (data.msg || "日志清理失败"),
317
+					title: I18n.system_tips ,
318
+                    btn: [ I18n.system_ok ],
319
+					content: (data.msg || (I18n.joblog_clean_log + I18n.system_fail) ),
309 320
 					icon: '2'
310 321
 				});
311 322
 			}
@@ -318,7 +329,7 @@ $(function() {
318 329
 });
319 330
 
320 331
 
321
-// 提示-科技主题
332
+// Com Alert by Tec theme
322 333
 var ComAlertTec = {
323 334
 	html:function(){
324 335
 		var html =
@@ -328,7 +339,7 @@ var ComAlertTec = {
328 339
 			'<div class="modal-body"><div class="alert" style="color:#fff;"></div></div>' +
329 340
 			'<div class="modal-footer">' +
330 341
 			'<div class="text-center" >' +
331
-			'<button type="button" class="btn btn-info ok" data-dismiss="modal" >确认</button>' +
342
+			'<button type="button" class="btn btn-info ok" data-dismiss="modal" >'+ I18n.system_ok +'</button>' +
332 343
 			'</div>' +
333 344
 			'</div>' +
334 345
 			'</div>' +
@@ -342,7 +353,7 @@ var ComAlertTec = {
342 353
 			$('body').append(ComAlertTec.html());
343 354
 		}
344 355
 
345
-		// 弹框初始
356
+		// init com alert
346 357
 		$('#ComAlertTec .alert').html(msg);
347 358
 		$('#ComAlertTec').modal('show');
348 359
 

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

@@ -1,12 +1,13 @@
1 1
 $(function(){
2
-	// 复选框
2
+
3
+	// input iCheck
3 4
     $('input').iCheck({
4 5
       checkboxClass: 'icheckbox_square-blue',
5 6
       radioClass: 'iradio_square-blue',
6 7
       increaseArea: '20%' // optional
7 8
     });
8 9
     
9
-	// 登录.规则校验
10
+	// login Form Valid
10 11
 	var loginFormValid = $("#loginForm").validate({
11 12
 		errorElement : 'span',  
12 13
         errorClass : 'help-block',
@@ -25,14 +26,13 @@ $(function(){
25 26
         }, 
26 27
         messages : {  
27 28
         	userName : {  
28
-                required :"请输入登录账号."  ,
29
-                minlength:"登录账号不应低于5位",
30
-                maxlength:"登录账号不应超过18位"
31
-            },  
29
+                required  : I18n.login_username_empty,
30
+                minlength : I18n.login_username_lt_5
31
+            },
32 32
             password : {
33
-            	required :"请输入登录密码."  ,
34
-                minlength:"登录密码不应低于5位",
35
-                maxlength:"登录密码不应超过18位"
33
+            	required  : I18n.login_password_empty  ,
34
+                minlength : I18n.login_password_lt_5
35
+                /*,maxlength:"登录密码不应超过18位"*/
36 36
             }
37 37
         }, 
38 38
 		highlight : function(element) {  
@@ -48,22 +48,15 @@ $(function(){
48 48
         submitHandler : function(form) {
49 49
 			$.post(base_url + "/login", $("#loginForm").serialize(), function(data, status) {
50 50
 				if (data.code == "200") {
51
-                    layer.msg('登录成功');
51
+                    layer.msg( I18n.login_success );
52 52
                     setTimeout(function(){
53 53
                         window.location.href = base_url;
54 54
                     }, 500);
55
-                    /*layer.open({
56
-                        title: '系统提示',
57
-                        content: '登录成功',
58
-                        icon: '1',
59
-                        end: function(layero, index){
60
-                            window.location.href = base_url;
61
-                        }
62
-                    });*/
63 55
 				} else {
64 56
                     layer.open({
65
-                        title: '系统提示',
66
-                        content: (data.msg || "登录失败"),
57
+                        title: I18n.system_tips,
58
+                        btn: [ I18n.system_ok ],
59
+                        content: (data.msg || I18n.login_fail ),
67 60
                         icon: '2'
68 61
                     });
69 62
 				}

+ 0 - 2
xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/layer.js Visa fil

@@ -1,2 +0,0 @@
1
-/*! layer mobile-v2.0.0 Web弹层组件 MIT License  http://layer.layui.com/mobile  By 贤心 */
2
- ;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'<h3 style="'+(e?n.title[1]:"")+'">'+(e?n.title[0]:n.title)+"</h3>":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type="1">'+n.btn[0]+"</span>",2===t&&(e='<span no type="0">'+n.btn[1]+"</span>"+e),'<div class="layui-m-layerbtn">'+e+"</div>"):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='<i></i><i class="layui-m-layerload"></i><i></i><p>'+(n.content||"")+"</p>"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"<div "+("string"==typeof n.shade?'style="'+n.shade+'"':"")+' class="layui-m-layershade"></div>':"")+'<div class="layui-m-layermain" '+(n.fixed?"":'style="position:static;"')+'><div class="layui-m-layersection"><div class="layui-m-layerchild '+(n.skin?"layui-m-layer-"+n.skin+" ":"")+(n.className?n.className:"")+" "+(n.anim?"layui-m-anim-"+n.anim:"")+'" '+(n.style?'style="'+n.style+'"':"")+">"+l+'<div class="layui-m-layercont">'+n.content+"</div>"+c+"</div></div></div>",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i]("layui-m-layershade")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:"2.0",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a("#"+o[0]+e)[0];n&&(n.innerHTML="",t.body.removeChild(n),clearTimeout(l.timer[e]),delete l.timer[e],"function"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute("index"))}},"function"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf("/")+1);n.getAttribute("merge")||document.head.appendChild(function(){var e=t.createElement("link");return e.href=a+"need/layer.css?2.0",e.type="text/css",e.rel="styleSheet",e.id="layermcss",e}())}()}(window);

Filskillnaden har hållits tillbaka eftersom den är för stor
+ 0 - 1
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 Visa fil

@@ -1,7 +1,7 @@
1 1
 package com.xxl.job.admin.controller;
2 2
 
3 3
 import com.xxl.job.admin.controller.interceptor.PermissionInterceptor;
4
-import com.xxl.job.admin.core.util.PropertiesUtil;
4
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
5 5
 import org.junit.Before;
6 6
 import org.junit.Test;
7 7
 import org.springframework.http.MediaType;
@@ -22,8 +22,8 @@ public class JobInfoControllerTest extends AbstractSpringMvcTest {
22 22
     MvcResult ret = mockMvc.perform(
23 23
         post("/login")
24 24
             .contentType(MediaType.APPLICATION_FORM_URLENCODED)
25
-            .param("userName", PropertiesUtil.getString("xxl.job.login.username"))
26
-            .param("password", PropertiesUtil.getString("xxl.job.login.password"))
25
+            .param("userName", XxlJobAdminConfig.getAdminConfig().getLoginUsername())
26
+            .param("password", XxlJobAdminConfig.getAdminConfig().getLoginPassword())
27 27
     ).andReturn();
28 28
     cookie = ret.getResponse().getCookie(PermissionInterceptor.LOGIN_IDENTITY_KEY);
29 29
   }

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

@@ -20,8 +20,8 @@ public class XxlJobInfoDaoTest {
20 20
 	
21 21
 	@Test
22 22
 	public void pageList(){
23
-		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, 0, null);
24
-		int list_count = xxlJobInfoDao.pageListCount(0, 20, 0, null);
23
+		List<XxlJobInfo> list = xxlJobInfoDao.pageList(0, 20, 0, null, null);
24
+		int list_count = xxlJobInfoDao.pageListCount(0, 20, 0, null, null);
25 25
 		
26 26
 		System.out.println(list);
27 27
 		System.out.println(list_count);

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

@@ -50,7 +50,7 @@ public class XxlJobLogDaoTest {
50 50
         dto = xxlJobLogDao.load(log.getId());
51 51
 
52 52
 
53
-        List<Map<String, Object>> list2 = xxlJobLogDao.triggerCountByDay(DateUtils.addDays(new Date(), 30), new Date(), 200);
53
+        List<Map<String, Object>> list2 = xxlJobLogDao.triggerCountByDay(DateUtils.addDays(new Date(), 30), new Date());
54 54
 
55 55
         int ret4 = xxlJobLogDao.clearLog(1, 1, new Date(), 100);
56 56
 

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

@@ -0,0 +1,25 @@
1
+package com.xxl.job.admin.util;
2
+
3
+import com.xxl.job.admin.core.util.I18nUtil;
4
+import org.junit.Test;
5
+import org.junit.runner.RunWith;
6
+import org.springframework.test.context.ContextConfiguration;
7
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
8
+
9
+/**
10
+ * email util test
11
+ *
12
+ * @author xuxueli 2017-12-22 17:16:23
13
+ */
14
+@RunWith(SpringJUnit4ClassRunner.class)
15
+@ContextConfiguration(locations = "classpath*:spring/applicationcontext-*.xml")
16
+public class I18nUtilTest {
17
+
18
+    @Test
19
+    public void test(){
20
+        System.out.println(I18nUtil.getString("admin_name"));
21
+        System.out.println(I18nUtil.getMultString("admin_name", "admin_name_full"));
22
+        System.out.println(I18nUtil.getMultString());
23
+    }
24
+
25
+}

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

@@ -2,6 +2,9 @@ package com.xxl.job.admin.util;
2 2
 
3 3
 import com.xxl.job.admin.core.util.MailUtil;
4 4
 import org.junit.Test;
5
+import org.junit.runner.RunWith;
6
+import org.springframework.test.context.ContextConfiguration;
7
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
5 8
 
6 9
 import java.text.MessageFormat;
7 10
 
@@ -10,6 +13,8 @@ import java.text.MessageFormat;
10 13
  *
11 14
  * @author xuxueli 2017-12-22 17:16:23
12 15
  */
16
+@RunWith(SpringJUnit4ClassRunner.class)
17
+@ContextConfiguration(locations = "classpath*:spring/applicationcontext-*.xml")
13 18
 public class MailUtilTest {
14 19
 
15 20
     @Test

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

@@ -1,18 +0,0 @@
1
-package com.xxl.job.admin.util;
2
-
3
-import com.xxl.job.admin.core.util.PropertiesUtil;
4
-import org.junit.Test;
5
-
6
-/**
7
- * prop util test
8
- *
9
- * @author xuxueli 2017-12-25 15:17:36
10
- */
11
-public class PropertiesUtilTest {
12
-
13
-    @Test
14
-    public void registryTest() throws Exception {
15
-        System.out.println(PropertiesUtil.getString("xxl.job.login.username"));
16
-    }
17
-
18
-}

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

@@ -4,7 +4,7 @@
4 4
 	<parent>
5 5
 		<groupId>com.xuxueli</groupId>
6 6
 		<artifactId>xxl-job</artifactId>
7
-		<version>1.9.0-SNAPSHOT</version>
7
+		<version>1.9.2-SNAPSHOT</version>
8 8
 	</parent>
9 9
 	<artifactId>xxl-job-core</artifactId>
10 10
 	<packaging>jar</packaging>

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

@@ -8,6 +8,7 @@ import com.xxl.job.core.handler.annotation.JobHandler;
8 8
 import com.xxl.job.core.log.XxlJobFileAppender;
9 9
 import com.xxl.job.core.rpc.netcom.NetComClientProxy;
10 10
 import com.xxl.job.core.rpc.netcom.NetComServerFactory;
11
+import com.xxl.job.core.thread.JobLogFileCleanThread;
11 12
 import com.xxl.job.core.thread.JobThread;
12 13
 import com.xxl.job.core.util.NetUtil;
13 14
 import org.slf4j.Logger;
@@ -28,32 +29,35 @@ public class XxlJobExecutor implements ApplicationContextAware {
28 29
     private static final Logger logger = LoggerFactory.getLogger(XxlJobExecutor.class);
29 30
 
30 31
     // ---------------------- param ----------------------
32
+    private String adminAddresses;
33
+    private String appName;
31 34
     private String ip;
32 35
     private int port;
33
-    private String appName;
34
-    private String adminAddresses;
35 36
     private String accessToken;
36 37
     private String logPath;
38
+    private int logRetentionDays;
37 39
 
40
+    public void setAdminAddresses(String adminAddresses) {
41
+        this.adminAddresses = adminAddresses;
42
+    }
43
+    public void setAppName(String appName) {
44
+        this.appName = appName;
45
+    }
38 46
     public void setIp(String ip) {
39 47
         this.ip = ip;
40 48
     }
41 49
     public void setPort(int port) {
42 50
         this.port = port;
43 51
     }
44
-    public void setAppName(String appName) {
45
-        this.appName = appName;
46
-    }
47
-    public void setAdminAddresses(String adminAddresses) {
48
-        this.adminAddresses = adminAddresses;
49
-    }
50 52
     public void setAccessToken(String accessToken) {
51 53
         this.accessToken = accessToken;
52 54
     }
53 55
     public void setLogPath(String logPath) {
54 56
         this.logPath = logPath;
55 57
     }
56
-
58
+    public void setLogRetentionDays(int logRetentionDays) {
59
+        this.logRetentionDays = logRetentionDays;
60
+    }
57 61
 
58 62
     // ---------------------- applicationContext ----------------------
59 63
     private static ApplicationContext applicationContext;
@@ -79,6 +83,9 @@ public class XxlJobExecutor implements ApplicationContextAware {
79 83
 
80 84
         // init executor-server
81 85
         initExecutorServer(port, ip, appName, accessToken);
86
+
87
+        // init JobLogFileCleanThread
88
+        JobLogFileCleanThread.getInstance().start(logRetentionDays);
82 89
     }
83 90
     public void destroy(){
84 91
         // destory JobThreadRepository
@@ -91,6 +98,9 @@ public class XxlJobExecutor implements ApplicationContextAware {
91 98
 
92 99
         // destory executor-server
93 100
         stopExecutorServer();
101
+
102
+        // destory JobLogFileCleanThread
103
+        JobLogFileCleanThread.getInstance().toStop();
94 104
     }
95 105
 
96 106
 

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

@@ -40,8 +40,8 @@ public class ScriptJobHandler extends IJobHandler {
40 40
         String cmd = glueType.getCmd();
41 41
 
42 42
         // make script file
43
-        String scriptFileName = XxlJobFileAppender.getLogPath()
44
-                .concat("/gluesource/")
43
+        String scriptFileName = XxlJobFileAppender.getGlueSrcPath()
44
+                .concat("/")
45 45
                 .concat(String.valueOf(jobId))
46 46
                 .concat("_")
47 47
                 .concat(String.valueOf(glueUpdatetime))

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

@@ -20,8 +20,21 @@ public class XxlJobFileAppender {
20 20
 	public static final InheritableThreadLocal<String> contextHolder = new InheritableThreadLocal<String>();
21 21
 
22 22
 
23
-	// log base path
23
+	/**
24
+	 * log base path
25
+	 *
26
+	 * strut like:
27
+	 * 	---/
28
+	 * 	---/gluesource/
29
+	 * 	---/gluesource/10_1514171108000.js
30
+	 * 	---/gluesource/10_1514171108000.js
31
+	 * 	---/2017-12-25/
32
+	 * 	---/2017-12-25/639.log
33
+	 * 	---/2017-12-25/821.log
34
+	 *
35
+	 */
24 36
 	private static String logBasePath = "/data/applogs/xxl-job/jobhandler";
37
+	private static String glueSrcPath = logBasePath.concat("/gluesource");
25 38
 	public static void initLogPath(String logPath){
26 39
 		// init
27 40
 		if (logPath!=null && logPath.trim().length()>0) {
@@ -39,11 +52,14 @@ public class XxlJobFileAppender {
39 52
 		if (!glueBaseDir.exists()) {
40 53
 			glueBaseDir.mkdirs();
41 54
 		}
55
+		glueSrcPath = glueBaseDir.getPath();
42 56
 	}
43 57
 	public static String getLogPath() {
44 58
 		return logBasePath;
45 59
 	}
46
-
60
+	public static String getGlueSrcPath() {
61
+		return glueSrcPath;
62
+	}
47 63
 
48 64
 	/**
49 65
 	 * log filename, like "logPath/yyyy-MM-dd/9999.log"

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

@@ -0,0 +1,118 @@
1
+package com.xxl.job.core.thread;
2
+
3
+import com.xxl.job.core.log.XxlJobFileAppender;
4
+import com.xxl.job.core.util.FileUtil;
5
+import org.slf4j.Logger;
6
+import org.slf4j.LoggerFactory;
7
+
8
+import java.io.File;
9
+import java.text.ParseException;
10
+import java.text.SimpleDateFormat;
11
+import java.util.Calendar;
12
+import java.util.Date;
13
+import java.util.concurrent.TimeUnit;
14
+
15
+/**
16
+ * job file clean thread
17
+ *
18
+ * @author xuxueli 2017-12-29 16:23:43
19
+ */
20
+public class JobLogFileCleanThread extends Thread {
21
+    private static Logger logger = LoggerFactory.getLogger(JobLogFileCleanThread.class);
22
+
23
+    private static JobLogFileCleanThread instance = new JobLogFileCleanThread();
24
+    public static JobLogFileCleanThread getInstance(){
25
+        return instance;
26
+    }
27
+
28
+    private Thread localThread;
29
+    private volatile boolean toStop = false;
30
+    public void start(final long logRetentionDays){
31
+
32
+        // limit min value
33
+        if (logRetentionDays < 3 ) {
34
+            return;
35
+        }
36
+
37
+        localThread = new Thread(new Runnable() {
38
+            @Override
39
+            public void run() {
40
+                while (!toStop) {
41
+                    try {
42
+                        // clean log dir, over logRetentionDays
43
+                        File[] childDirs = new File(XxlJobFileAppender.getLogPath()).listFiles();
44
+                        if (childDirs!=null && childDirs.length>0) {
45
+
46
+                            // today
47
+                            Calendar todayCal = Calendar.getInstance();
48
+                            todayCal.set(Calendar.HOUR_OF_DAY,0);
49
+                            todayCal.set(Calendar.MINUTE,0);
50
+                            todayCal.set(Calendar.SECOND,0);
51
+                            todayCal.set(Calendar.MILLISECOND,0);
52
+
53
+                            Date todayDate = todayCal.getTime();
54
+
55
+                            for (File childFile: childDirs) {
56
+
57
+                                // valid
58
+                                if (!childFile.isDirectory()) {
59
+                                    continue;
60
+                                }
61
+                                if (childFile.getName().indexOf("-") == -1) {
62
+                                    continue;
63
+                                }
64
+
65
+                                // file create date
66
+                                Date logFileCreateDate = null;
67
+                                try {
68
+                                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
69
+                                    logFileCreateDate = simpleDateFormat.parse(childFile.getName());
70
+                                } catch (ParseException e) {
71
+                                    logger.error(e.getMessage(), e);
72
+                                }
73
+                                if (logFileCreateDate == null) {
74
+                                    continue;
75
+                                }
76
+
77
+                                if ((todayDate.getTime()-logFileCreateDate.getTime()) >= logRetentionDays * (24 * 60 * 60 * 1000) ) {
78
+                                    FileUtil.deleteRecursively(childFile);
79
+                                }
80
+
81
+                            }
82
+                        }
83
+
84
+                    } catch (Exception e) {
85
+                        logger.error(e.getMessage(), e);
86
+                    }
87
+
88
+                    try {
89
+                        TimeUnit.DAYS.sleep(1);
90
+                    } catch (InterruptedException e) {
91
+                        logger.error(e.getMessage(), e);
92
+                    }
93
+                }
94
+                logger.info(">>>>>>>>>>> xxl-job, executor JobLogFileCleanThread thread destory.");
95
+
96
+            }
97
+        });
98
+        localThread.setDaemon(true);
99
+        localThread.start();
100
+    }
101
+
102
+    public void toStop() {
103
+        toStop = true;
104
+
105
+        if (localThread == null) {
106
+            return;
107
+        }
108
+
109
+        // interrupt and wait
110
+        localThread.interrupt();
111
+        try {
112
+            localThread.join();
113
+        } catch (InterruptedException e) {
114
+            logger.error(e.getMessage(), e);
115
+        }
116
+    }
117
+
118
+}

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

@@ -0,0 +1,27 @@
1
+package com.xxl.job.core.util;
2
+
3
+import java.io.File;
4
+
5
+/**
6
+ * file tool
7
+ *
8
+ * @author xuxueli 2017-12-29 17:56:48
9
+ */
10
+public class FileUtil {
11
+
12
+    public static boolean deleteRecursively(File root) {
13
+        if (root != null && root.exists()) {
14
+            if (root.isDirectory()) {
15
+                File[] children = root.listFiles();
16
+                if (children != null) {
17
+                    for (File child : children) {
18
+                        deleteRecursively(child);
19
+                    }
20
+                }
21
+            }
22
+            return root.delete();
23
+        }
24
+        return false;
25
+    }
26
+
27
+}

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

@@ -59,22 +59,23 @@ public class ScriptUtil {
59 59
         // 标准输出:print (null if watchdog timeout)
60 60
         // 错误输出:logging + 异常 (still exists if watchdog timeout)
61 61
         // 标准输入
62
-        FileOutputStream fileOutputStream = new FileOutputStream(logFile, true);
63
-        PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
62
+        try (FileOutputStream fileOutputStream = new FileOutputStream(logFile, true)) {
63
+            PumpStreamHandler streamHandler = new PumpStreamHandler(fileOutputStream, fileOutputStream, null);
64 64
 
65
-        // command
66
-        CommandLine commandline = new CommandLine(command);
67
-        commandline.addArgument(scriptFile);
68
-        if (params!=null && params.length>0) {
69
-            commandline.addArguments(params);
70
-        }
65
+            // command
66
+            CommandLine commandline = new CommandLine(command);
67
+            commandline.addArgument(scriptFile);
68
+            if (params!=null && params.length>0) {
69
+                commandline.addArguments(params);
70
+            }
71 71
 
72
-        // exec
73
-        DefaultExecutor exec = new DefaultExecutor();
74
-        exec.setExitValues(null);
75
-        exec.setStreamHandler(streamHandler);
76
-        int exitValue = exec.execute(commandline);  // exit code: 0=success, 1=error
77
-        return exitValue;
72
+            // exec
73
+            DefaultExecutor exec = new DefaultExecutor();
74
+            exec.setExitValues(null);
75
+            exec.setStreamHandler(streamHandler);
76
+            int exitValue = exec.execute(commandline);  // exit code: 0=success, 1=error
77
+            return exitValue;
78
+        }
78 79
     }
79 80
 
80 81
 }

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

@@ -5,7 +5,7 @@
5 5
     <parent>
6 6
         <groupId>com.xuxueli</groupId>
7 7
         <artifactId>xxl-job</artifactId>
8
-        <version>1.9.0-SNAPSHOT</version>
8
+        <version>1.9.2-SNAPSHOT</version>
9 9
     </parent>
10 10
     <artifactId>xxl-job-executor-samples</artifactId>
11 11
     <packaging>pom</packaging>

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

@@ -5,7 +5,7 @@
5 5
     <parent>
6 6
         <artifactId>xxl-job-executor-samples</artifactId>
7 7
         <groupId>com.xuxueli</groupId>
8
-        <version>1.9.0-SNAPSHOT</version>
8
+        <version>1.9.2-SNAPSHOT</version>
9 9
     </parent>
10 10
     <modelVersion>4.0.0</modelVersion>
11 11
     <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 Visa fil

@@ -29,12 +29,13 @@ public class JFinalCoreConfig extends JFinalConfig {
29 29
 
30 30
 		// init executor
31 31
 		xxlJobExecutor = new XxlJobExecutor();
32
+		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
33
+		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
32 34
 		xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip"));
33 35
 		xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port"));
34
-		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
35
-		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
36
-		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
37 36
 		xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken"));
37
+		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
38
+		xxlJobExecutor.setLogRetentionDays(xxlJobProp.getInt("xxl.job.executor.logretentiondays"));
38 39
 
39 40
 		// start executor
40 41
 		try {

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

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

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

@@ -5,7 +5,7 @@
5 5
     <parent>
6 6
         <groupId>com.xuxueli</groupId>
7 7
         <artifactId>xxl-job-executor-samples</artifactId>
8
-        <version>1.9.0-SNAPSHOT</version>
8
+        <version>1.9.2-SNAPSHOT</version>
9 9
     </parent>
10 10
     <modelVersion>4.0.0</modelVersion>
11 11
     <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 Visa fil

@@ -39,12 +39,13 @@ public class NutzSetup implements Setup {
39 39
 
40 40
 		// init executor
41 41
 		xxlJobExecutor = new XxlJobExecutor();
42
+		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
43
+		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
42 44
 		xxlJobExecutor.setIp(xxlJobProp.get("xxl.job.executor.ip"));
43 45
 		xxlJobExecutor.setPort(xxlJobProp.getInt("xxl.job.executor.port"));
44
-		xxlJobExecutor.setAppName(xxlJobProp.get("xxl.job.executor.appname"));
45
-		xxlJobExecutor.setAdminAddresses(xxlJobProp.get("xxl.job.admin.addresses"));
46
-		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
47 46
 		xxlJobExecutor.setAccessToken(xxlJobProp.get("xxl.job.accessToken"));
47
+		xxlJobExecutor.setLogPath(xxlJobProp.get("xxl.job.executor.logpath"));
48
+		xxlJobExecutor.setLogRetentionDays(xxlJobProp.getInt("xxl.job.executor.logretentiondays"));
48 49
 
49 50
 		// start executor
50 51
 		try {

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

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

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

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

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

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

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

@@ -4,10 +4,12 @@ xxl.job.admin.addresses=http://127.0.0.1:18080/xxl-job-admin
4 4
 ### xxl-job executor address
5 5
 xxl.job.executor.appname=xxl-job-executor-sample
6 6
 xxl.job.executor.ip=
7
-xxl.job.executor.port=9999
7
+xxl.job.executor.port=9998
8
+
9
+### xxl-job, access token
10
+xxl.job.accessToken=
8 11
 
9 12
 ### xxl-job log path
10 13
 xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
11
-
12
-### xxl-job, access token
13
-xxl.job.accessToken=
14
+### xxl-job log retention days
15
+xxl.job.executor.logretentiondays=-1

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

@@ -6,7 +6,7 @@
6 6
     <parent>
7 7
         <groupId>com.xuxueli</groupId>
8 8
         <artifactId>xxl-job-executor-samples</artifactId>
9
-        <version>1.9.0-SNAPSHOT</version>
9
+        <version>1.9.2-SNAPSHOT</version>
10 10
     </parent>
11 11
     <artifactId>xxl-job-executor-sample-springboot</artifactId>
12 12
     <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 Visa fil

@@ -18,12 +18,11 @@ import org.springframework.context.annotation.Configuration;
18 18
 public class XxlJobConfig {
19 19
     private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
20 20
 
21
-
22 21
     @Value("${xxl.job.admin.addresses}")
23
-    private String addresses;
22
+    private String adminAddresses;
24 23
 
25 24
     @Value("${xxl.job.executor.appname}")
26
-    private String appname;
25
+    private String appName;
27 26
 
28 27
     @Value("${xxl.job.executor.ip}")
29 28
     private String ip;
@@ -31,22 +30,28 @@ public class XxlJobConfig {
31 30
     @Value("${xxl.job.executor.port}")
32 31
     private int port;
33 32
 
34
-    @Value("${xxl.job.executor.logpath}")
35
-    private String logpath;
36
-
37 33
     @Value("${xxl.job.accessToken}")
38 34
     private String accessToken;
39 35
 
36
+    @Value("${xxl.job.executor.logpath}")
37
+    private String logPath;
38
+
39
+    @Value("${xxl.job.executor.logretentiondays}")
40
+    private int logRetentionDays;
41
+
42
+
40 43
     @Bean(initMethod = "start", destroyMethod = "destroy")
41 44
     public XxlJobExecutor xxlJobExecutor() {
42 45
         logger.info(">>>>>>>>>>> xxl-job config init.");
43 46
         XxlJobExecutor xxlJobExecutor = new XxlJobExecutor();
47
+        xxlJobExecutor.setAdminAddresses(adminAddresses);
48
+        xxlJobExecutor.setAppName(appName);
44 49
         xxlJobExecutor.setIp(ip);
45 50
         xxlJobExecutor.setPort(port);
46
-        xxlJobExecutor.setAppName(appname);
47
-        xxlJobExecutor.setAdminAddresses(addresses);
48
-        xxlJobExecutor.setLogPath(logpath);
49 51
         xxlJobExecutor.setAccessToken(accessToken);
52
+        xxlJobExecutor.setLogPath(logPath);
53
+        xxlJobExecutor.setLogRetentionDays(logRetentionDays);
54
+
50 55
         return xxlJobExecutor;
51 56
     }
52 57
 

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

@@ -4,17 +4,19 @@ server.port=8081
4 4
 # log config
5 5
 logging.config=classpath:logback.xml
6 6
 
7
-# xxl-job
7
+
8 8
 ### xxl-job admin address list, such as "http://address" or "http://address01,http://address02"
9 9
 xxl.job.admin.addresses=http://127.0.0.1:8080/xxl-job-admin
10 10
 
11 11
 ### xxl-job executor address
12 12
 xxl.job.executor.appname=xxl-job-executor-sample
13 13
 xxl.job.executor.ip=
14
-xxl.job.executor.port=9998
15
-
16
-### xxl-job log path
17
-xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
14
+xxl.job.executor.port=9999
18 15
 
19 16
 ### xxl-job, access token
20 17
 xxl.job.accessToken=
18
+
19
+### xxl-job log path
20
+xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler
21
+### xxl-job log retention days
22
+xxl.job.executor.logretentiondays=-1