4 Комити cd9741ec7d ... c9a8dda1be

Аутор SHA1 Порука Датум
  gtj c9a8dda1be init 20220812 пре 2 година
  lifuquan cd9741ec7d 20220811 整理了部署文档和需求文档 пре 2 година
  lifuquan eaabc4c7f8 init-从谷铜锏的移植而来 пре 2 година
  lifuquan 11c6c7f64f init 20220811 пре 2 година
100 измењених фајлова са 3293 додато и 3039 уклоњено
  1. 4 33
      .gitignore
  2. 674 0
      LICENSE
  3. 32 0
      NOTICE
  4. 589 7
      README.md
  5. 73 0
      docker-compose/docker-compose.yml
  6. 9 0
      docker-compose/postgres/init.d/init-xxl-job-db.sh
  7. 445 0
      docker-compose/postgres/sql/xxl_job_postgres.sql
  8. 143 72
      pom.xml
  9. 0 96
      xxl-job-admin-pg/pom.xml
  10. 0 47
      xxl-job-admin-pg/src/main/java/org/poem/config/JacksonMapper.java
  11. 0 60
      xxl-job-admin-pg/src/main/java/org/poem/config/jackson/BeanSerializerModifier.java
  12. 0 24
      xxl-job-admin-pg/src/main/java/org/poem/config/jackson/NullArrayJsonSerializer.java
  13. 0 22
      xxl-job-admin-pg/src/main/java/org/poem/config/jackson/NullJsonSerializer.java
  14. 0 69
      xxl-job-admin-pg/src/main/java/org/poem/controller/interceptor/WebMvcConfig.java
  15. 0 95
      xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobLosedMonitorHelper.java
  16. 0 112
      xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobRegistryMonitorHelper.java
  17. 0 176
      xxl-job-admin-pg/src/main/java/org/poem/service/impl/AdminBizImpl.java
  18. 0 4
      xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css
  19. 0 0
      xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css.map
  20. 0 5
      xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/bootstrap/js/bootstrap.min.js
  21. 0 1
      xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/jquery/jquery.min.js
  22. 0 0
      xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/moment/moment.min.js
  23. 0 6
      xxl-job-admin-pg/src/main/resources/static/adminlte/dist/css/AdminLTE.min.css
  24. 0 0
      xxl-job-admin-pg/src/main/resources/static/adminlte/dist/css/skins/_all-skins.min.css
  25. 0 13
      xxl-job-admin-pg/src/main/resources/static/adminlte/dist/js/adminlte.min.js
  26. 0 42
      xxl-job-admin-pg/src/main/resources/templates/common/common.exception.ftl
  27. 0 251
      xxl-job-admin-pg/src/main/resources/templates/common/common.macro.ftl
  28. 0 49
      xxl-job-admin-pg/src/main/resources/templates/help.ftl
  29. 0 175
      xxl-job-admin-pg/src/main/resources/templates/jobcode/jobcode.index.ftl
  30. 0 200
      xxl-job-admin-pg/src/main/resources/templates/jobgroup/jobgroup.index.ftl
  31. 0 521
      xxl-job-admin-pg/src/main/resources/templates/jobinfo/jobinfo.index.ftl
  32. 0 184
      xxl-job-admin-pg/src/main/resources/templates/joblog/joblog.index.ftl
  33. 0 47
      xxl-job-admin-pg/src/main/resources/templates/login.ftl
  34. 0 205
      xxl-job-admin-pg/src/main/resources/templates/user/user.index.ftl
  35. 1 0
      xxl-job-admin/.gitignore
  36. 11 0
      xxl-job-admin/Dockerfile
  37. 116 0
      xxl-job-admin/pom.xml
  38. 3 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java
  39. 8 8
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java
  40. 20 23
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java
  41. 10 12
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java
  42. 37 24
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java
  43. 47 30
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java
  44. 30 29
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java
  45. 34 29
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java
  46. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java
  47. 4 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java
  48. 5 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java
  49. 28 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java
  50. 5 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java
  51. 3 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java
  52. 3 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java
  53. 10 10
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java
  54. 99 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java
  55. 4 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java
  56. 78 69
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java
  57. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java
  58. 14 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java
  59. 33 18
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java
  60. 6 6
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java
  61. 6 7
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java
  62. 4 7
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java
  63. 4 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java
  64. 5 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java
  65. 3 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java
  66. 12 12
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java
  67. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java
  68. 3 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java
  69. 3 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java
  70. 9 9
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java
  71. 5 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java
  72. 8 8
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java
  73. 4 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java
  74. 6 6
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java
  75. 6 6
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java
  76. 4 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java
  77. 4 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java
  78. 6 6
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java
  79. 39 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java
  80. 46 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java
  81. 20 20
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java
  82. 184 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java
  83. 8 8
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java
  84. 3 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java
  85. 204 0
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java
  86. 55 38
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java
  87. 7 7
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java
  88. 4 3
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java
  89. 18 21
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java
  90. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java
  91. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java
  92. 2 2
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java
  93. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java
  94. 1 1
      xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java
  95. 4 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java
  96. 6 6
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java
  97. 6 6
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java
  98. 5 5
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java
  99. 2 2
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java
  100. 3 4
      xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java

+ 4 - 33
.gitignore

@@ -1,36 +1,7 @@
-HELP.md
-target/
-.mvn/wrapper/maven-wrapper.jar
-**/src/main/**/target/
-**/src/test/**/target/
-
-### STS ###
-.apt_generated
+.idea
 .classpath
-.factorypath
 .project
-.settings
-.springBeans
-.sts4-cache
-
-### IntelliJ IDEA ###
-.idea
-.mvn
-*.iws
 *.iml
-*.ipr
-
-### NetBeans ###
-/nbproject/private/
-/nbbuild/
-/dist/
-/nbdist/
-/.nb-gradle/
-build/
-!**/src/main/**/build/
-!**/src/test/**/build/
-
-### VS Code ###
-.vscode/
-/.mvn/
-/.idea/
+target/
+.DS_Store
+.gitattributes

+ 674 - 0
LICENSE

@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    {one line to give the program's name and a brief idea of what it does.}
+    Copyright (C) {year}  {name of author}
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    {project}  Copyright (C) {year}  {fullname}
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.

+ 32 - 0
NOTICE

@@ -0,0 +1,32 @@
+Copyright (c) 2015-present, xuxueli.
+
+Dependencies:
+================================================================
+
+Spring:
+
+  * LICENSE:
+    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)
+  * HOMEPAGE:
+    * http://www.springsource.org
+
+Netty:
+
+  * LICENSE:
+    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)
+  * HOMEPAGE:
+    * https://github.com/netty/netty
+
+Hessian:
+
+  * LICENSE:
+    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)
+  * HOMEPAGE:
+    * http://hessian.caucho.com
+
+SLF4J:
+
+  * LICENSE:
+    * http://www.apache.org/licenses/LICENSE-2.0 (Apache License 2.0)
+  * HOMEPAGE:
+    * http://www.slf4j.org

+ 589 - 7
README.md

@@ -1,14 +1,596 @@
 <p align="center" >
     <img src="https://www.xuxueli.com/doc/static/xxl-job/images/xxl-logo.jpg" width="150">
+    <h3 align="center">XXL-JOB</h3>
+    <p align="center">
+        XXL-JOB, a distributed task scheduling framework.
+        <br>
+        <a href="https://www.xuxueli.com/xxl-job/"><strong>-- Home Page --</strong></a>
+        <br>
+        <br>
+        <a href="https://github.com/xuxueli/xxl-job/actions">
+            <img src="https://github.com/xuxueli/xxl-job/workflows/Java%20CI/badge.svg" >
+        </a>
+        <a href="https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/">
+            <img src="https://maven-badges.herokuapp.com/maven-central/com.xuxueli/xxl-job/badge.svg" >
+        </a>
+        <a href="https://github.com/xuxueli/xxl-job/releases">
+         <img src="https://img.shields.io/github/release/xuxueli/xxl-job.svg" >
+        </a>
+        <a href="https://github.com/xuxueli/xxl-job/">
+            <img src="https://img.shields.io/github/stars/xuxueli/xxl-job" >
+        </a>
+        <a href="https://hub.docker.com/r/xuxueli/xxl-job-admin/">
+            <img src="https://img.shields.io/docker/pulls/xuxueli/xxl-job-admin" >
+        </a>
+        <a href="http://www.gnu.org/licenses/gpl-3.0.html">
+         <img src="https://img.shields.io/badge/license-GPLv3-blue.svg" >
+        </a>
+        <a href="https://www.xuxueli.com/page/donate.html">
+           <img src="https://img.shields.io/badge/%24-donate-ff69b4.svg?style=flat" >
+        </a>
+    </p>
 </p>
 
 
-## 原来项目地址
-在https://github.com/xuxueli/xxl-job 基础上做的修改
+## Introduction
+XXL-JOB is a distributed task scheduling framework. 
+It's core design goal is to develop quickly and learn simple, lightweight, and easy to expand. 
+Now, it's already open source, and many companies use it in production environments, real "out-of-the-box".
 
+XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
 
-## 修改点
-1. 数据库转化为postgres
-1. 修改主键id为long,采用雪花算法生成id
-1. 界面所有微调,button按钮增加圆角
-1. 界面table增加margin-top样式
+
+## Documentation
+- [中文文档](https://www.xuxueli.com/xxl-job/)
+- [English Documentation](https://www.xuxueli.com/xxl-job/en/)
+
+
+## Communication    
+- [社区交流](https://www.xuxueli.com/page/community.html)
+
+
+## Features
+- 1、简单:支持通过Web页面对任务进行CRUD操作,操作简单,一分钟上手;
+- 2、动态:支持动态修改任务状态、启动/停止任务,以及终止运行中任务,即时生效;
+- 3、调度中心HA(中心式):调度采用中心式设计,“调度中心”自研调度组件并支持集群部署,可保证调度中心HA;
+- 4、执行器HA(分布式):任务分布式执行,任务"执行器"支持集群部署,可保证任务执行HA;
+- 5、注册中心: 执行器会周期性自动注册任务, 调度中心将会自动发现注册的任务并触发执行。同时,也支持手动录入执行器地址;
+- 6、弹性扩容缩容:一旦有新执行器机器上线或者下线,下次调度时将会重新分配任务;
+- 7、触发策略:提供丰富的任务触发策略,包括:Cron触发、固定间隔触发、固定延时触发、API(事件)触发、人工触发、父子任务触发;
+- 8、调度过期策略:调度中心错过调度时间的补偿处理策略,包括:忽略、立即补偿触发一次等;
+- 9、阻塞处理策略:调度过于密集执行器来不及处理时的处理策略,策略包括:单机串行(默认)、丢弃后续调度、覆盖之前调度;
+- 10、任务超时控制:支持自定义任务超时时间,任务运行超时将会主动中断任务;
+- 11、任务失败重试:支持自定义任务失败重试次数,当任务失败时将会按照预设的失败重试次数主动进行重试;其中分片任务支持分片粒度的失败重试;
+- 12、任务失败告警;默认提供邮件方式失败告警,同时预留扩展接口,可方便的扩展短信、钉钉等告警方式;
+- 13、路由策略:执行器集群部署时提供丰富的路由策略,包括:第一个、最后一个、轮询、随机、一致性HASH、最不经常使用、最近最久未使用、故障转移、忙碌转移等;
+- 14、分片广播任务:执行器集群部署时,任务路由策略选择"分片广播"情况下,一次任务调度将会广播触发集群中所有执行器执行一次任务,可根据分片参数开发分片任务;
+- 15、动态分片:分片广播任务以执行器为维度进行分片,支持动态扩容执行器集群从而动态增加分片数量,协同进行业务处理;在进行大数据量业务操作时可显著提升任务处理能力和速度。
+- 16、故障转移:任务路由策略选择"故障转移"情况下,如果执行器集群中某一台机器故障,将会自动Failover切换到一台正常的执行器发送调度请求。
+- 17、任务进度监控:支持实时监控任务进度;
+- 18、Rolling实时日志:支持在线查看调度结果,并且支持以Rolling方式实时查看执行器输出的完整的执行日志;
+- 19、GLUE:提供Web IDE,支持在线开发任务逻辑代码,动态发布,实时编译生效,省略部署上线的过程。支持30个版本的历史版本回溯。
+- 20、脚本任务:支持以GLUE模式开发和运行脚本任务,包括Shell、Python、NodeJS、PHP、PowerShell等类型脚本;
+- 21、命令行任务:原生提供通用命令行任务Handler(Bean任务,"CommandJobHandler");业务方只需要提供命令行即可;
+- 22、任务依赖:支持配置子任务依赖,当父任务执行结束且执行成功后将会主动触发一次子任务的执行, 多个子任务用逗号分隔;
+- 23、一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;
+- 24、自定义任务参数:支持在线配置调度任务入参,即时生效;
+- 25、调度线程池:调度系统多线程触发调度运行,确保调度精确执行,不被堵塞;
+- 26、数据加密:调度中心和执行器之间的通讯进行数据加密,提升调度信息安全性;
+- 27、邮件报警:任务失败时支持邮件报警,支持配置多邮件地址群发报警邮件;
+- 28、推送maven中央仓库: 将会把最新稳定版推送到maven中央仓库, 方便用户接入和使用;
+- 29、运行报表:支持实时查看运行数据,如任务数量、调度次数、执行器数量等;以及调度报表,如调度日期分布图,调度成功分布图等;
+- 30、全异步:任务调度流程全异步化设计实现,如异步调度、异步运行、异步回调等,有效对密集调度进行流量削峰,理论上支持任意时长任务的运行;
+- 31、跨语言:调度中心与执行器提供语言无关的 RESTful API 服务,第三方任意语言可据此对接调度中心或者实现执行器。除此之外,还提供了 “多任务模式”和“httpJobHandler”等其他跨语言方案;
+- 32、国际化:调度中心支持国际化设置,提供中文、英文两种可选语言,默认为中文;
+- 33、容器化:提供官方docker镜像,并实时更新推送dockerhub,进一步实现产品开箱即用;
+- 34、线程池隔离:调度线程池进行隔离拆分,慢任务自动降级进入"Slow"线程池,避免耗尽调度线程,提高系统稳定性;
+- 35、用户管理:支持在线管理系统用户,存在管理员、普通用户两种角色;
+- 36、权限控制:执行器维度进行权限控制,管理员拥有全量权限,普通用户需要分配执行器权限后才允许相关操作;
+
+
+## Development
+于2015年中,我在github上创建XXL-JOB项目仓库并提交第一个commit,随之进行系统结构设计,UI选型,交互设计……
+
+于2015-11月,XXL-JOB终于RELEASE了第一个大版本V1.0, 随后我将之发布到OSCHINA,XXL-JOB在OSCHINA上获得了@红薯的热门推荐,同期分别达到了OSCHINA的“热门动弹”排行第一和git.oschina的开源软件月热度排行第一,在此特别感谢红薯,感谢大家的关注和支持。
+
+于2015-12月,我将XXL-JOB发表到我司内部知识库,并且得到内部同事认可。
+
+于2016-01月,我司展开XXL-JOB的内部接入和定制工作,在此感谢袁某和尹某两位同事的贡献,同时也感谢内部其他给与关注与支持的同事。
+
+于2017-05-13,在上海举办的 "[第62期开源中国源创会](https://www.oschina.net/event/2236961)" 的 "放码过来" 环节,我登台对XXL-JOB做了演讲,台下五百位在场观众反响热烈([图文回顾](https://www.oschina.net/question/2686220_2242120) )。
+
+于2017-10-22,又拍云 Open Talk 联合 Spring Cloud 中国社区举办的 "[进击的微服务实战派上海站](https://opentalk.upyun.com/303.html)",我登台对XXL-JOB做了演讲,现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流。
+
+于2017-12-11,XXL-JOB有幸参会《[InfoQ ArchSummit全球架构师峰会](http://bj2017.archsummit.com/)》,并被拍拍贷架构总监"杨波老师"在专题 "[微服务原理、基础架构和开源实践](http://bj2017.archsummit.com/training/2)" 中现场介绍。
+
+于2017-12-18,XXL-JOB参与"[2017年度最受欢迎中国开源软件](http://www.oschina.net/project/top_cn_2017?sort=1)"评比,在当时已录入的约九千个国产开源项目中角逐,最终进入了前30强。
+
+于2018-01-15,XXL-JOB参与"[2017码云最火开源项目](https://www.oschina.net/news/92438/2017-mayun-top-50)"评比,在当时已录入的约六千五百个码云项目中角逐,最终进去了前20强。
+
+于2018-04-14,iTechPlus在上海举办的 "[2018互联网开发者大会](http://www.itdks.com/eventlist/detail/2065)",我登台对XXL-JOB做了演讲,现场观众反响热烈并在会后与XXL-JOB用户热烈讨论交流。
+
+于2018-05-27,在上海举办的 "[第75期开源中国源创会](https://www.oschina.net/event/2278742)" 的 "架构" 主题专场,我登台进行“基础架构与中间件图谱”主题演讲,台下上千位在场观众反响热烈([图文回顾](https://www.oschina.net/question/3802184_2280606) )。
+
+于2018-12-05,XXL-JOB参与"[2018年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2018?sort=1)"评比,在当时已录入的一万多个开源项目中角逐,最终排名第19名。
+
+于2019-12-10,XXL-JOB参与"[2019年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2019)"评比,在当时已录入的一万多个开源项目中角逐,最终排名"开发框架和基础组件类"第9名。
+
+于2020-11-16,XXL-JOB参与"[2020年度最受欢迎中国开源软件](https://www.oschina.net/project/top_cn_2020)"评比,在当时已录入的一万多个开源项目中角逐,最终排名"开发框架和基础组件类"第8名。
+
+> 我司大众点评目前已接入XXL-JOB,内部别名《Ferrari》(Ferrari基于XXL-JOB的V1.1版本定制而成,新接入应用推荐升级最新版本)。
+据最新统计, 自2016-01-21接入至2017-12-01期间,该系统已调度约100万次,表现优异。新接入应用推荐使用最新版本,因为经过数十个版本的更新,系统的任务模型、UI交互模型以及底层调度通讯模型都有了较大的优化和提升,核心功能更加稳定高效。
+
+至今,XXL-JOB已接入多家公司的线上产品线,接入场景如电商业务,O2O业务和大数据作业等,截止最新统计时间为止,XXL-JOB已接入的公司包括不限于:
+    
+	- 1、大众点评【美团点评】
+	- 2、山东学而网络科技有限公司;
+	- 3、安徽慧通互联科技有限公司;
+	- 4、人人聚财金服;
+	- 5、上海棠棣信息科技股份有限公司
+	- 6、运满满【运满满】
+	- 7、米其林 (中国区)【米其林】
+	- 8、妈妈联盟
+	- 9、九樱天下(北京)信息技术有限公司
+	- 10、万普拉斯科技有限公司【一加手机】
+	- 11、上海亿保健康管理有限公司
+	- 12、海尔馨厨【海尔】
+	- 13、河南大红包电子商务有限公司
+	- 14、成都顺点科技有限公司
+	- 15、深圳市怡亚通
+	- 16、深圳麦亚信科技股份有限公司
+	- 17、上海博莹科技信息技术有限公司
+	- 18、中国平安科技有限公司【中国平安】
+	- 19、杭州知时信息科技有限公司
+	- 20、博莹科技(上海)有限公司
+	- 21、成都依能股份有限责任公司
+	- 22、湖南高阳通联信息技术有限公司
+	- 23、深圳市邦德文化发展有限公司
+	- 24、福建阿思可网络教育有限公司
+	- 25、优信二手车【优信】
+	- 26、上海悠游堂投资发展股份有限公司【悠游堂】
+	- 27、北京粉笔蓝天科技有限公司
+	- 28、中秀科技(无锡)有限公司
+	- 29、武汉空心科技有限公司
+	- 30、北京蚂蚁风暴科技有限公司
+	- 31、四川互宜达科技有限公司
+	- 32、钱包行云(北京)科技有限公司
+	- 33、重庆欣才集团
+    - 34、咪咕互动娱乐有限公司【中国移动】
+    - 35、北京诺亦腾科技有限公司
+    - 36、增长引擎(北京)信息技术有限公司
+    - 37、北京英贝思科技有限公司
+    - 38、刚泰集团
+    - 39、深圳泰久信息系统股份有限公司
+    - 40、随行付支付有限公司
+    - 41、广州瀚农网络科技有限公司
+    - 42、享点科技有限公司
+    - 43、杭州比智科技有限公司
+    - 44、圳临界线网络科技有限公司
+    - 45、广州知识圈网络科技有限公司
+    - 46、国誉商业上海有限公司
+    - 47、海尔消费金融有限公司,嗨付、够花【海尔】
+    - 48、广州巴图鲁信息科技有限公司
+    - 49、深圳市鹏海运电子数据交换有限公司
+    - 50、深圳市亚飞电子商务有限公司
+    - 51、上海趣医网络有限公司
+    - 52、聚金资本
+    - 53、北京父母邦网络科技有限公司
+    - 54、中山元赫软件科技有限公司
+    - 55、中商惠民(北京)电子商务有限公司
+    - 56、凯京集团
+    - 57、华夏票联(北京)科技有限公司
+    - 58、拍拍贷【拍拍贷】
+    - 59、北京尚德机构在线教育有限公司
+    - 60、任子行股份有限公司
+    - 61、北京时态电子商务有限公司
+    - 62、深圳卷皮网络科技有限公司
+    - 63、北京安博通科技股份有限公司
+    - 64、未来无线网
+    - 65、厦门瓷禧网络有限公司
+    - 66、北京递蓝科软件股份有限公司
+    - 67、郑州创海软件科技公司
+    - 68、北京国槐信息科技有限公司
+    - 69、浪潮软件集团
+    - 70、多立恒(北京)信息技术有限公司
+    - 71、广州极迅客信息科技有限公司
+    - 72、赫基(中国)集团股份有限公司
+    - 73、海投汇
+    - 74、上海润益创业孵化器管理股份有限公司
+    - 75、汉纳森(厦门)数据股份有限公司
+    - 76、安信信托
+    - 77、岚儒财富
+    - 78、捷道软件
+    - 79、湖北享七网络科技有限公司
+    - 80、湖南创发科技责任有限公司
+    - 81、深圳小安时代互联网金融服务有限公司
+    - 82、湖北享七网络科技有限公司
+    - 83、钱包行云(北京)科技有限公司
+    - 84、360金融【360】
+    - 85、易企秀
+    - 86、摩贝(上海)生物科技有限公司
+    - 87、广东芯智慧科技有限公司
+    - 88、联想集团【联想】
+    - 89、怪兽充电
+    - 90、行圆汽车
+    - 91、深圳店店通科技邮箱公司
+    - 92、京东【京东】
+    - 93、米庄理财
+    - 94、咖啡易融
+    - 95、梧桐诚选
+    - 96、恒大地产【恒大】
+    - 97、昆明龙慧
+    - 98、上海涩瑶软件
+    - 99、易信【网易】
+    - 100、铜板街
+    - 101、杭州云若网络科技有限公司
+    - 102、特百惠(中国)有限公司
+    - 103、常山众卡运力供应链管理有限公司
+    - 104、深圳立创电子商务有限公司
+    - 105、杭州智诺科技股份有限公司
+    - 106、北京云漾信息科技有限公司
+    - 107、深圳市多银科技有限公司
+    - 108、亲宝宝
+    - 109、上海博卡软件科技有限公司
+    - 110、智慧树在线教育平台
+    - 111、米族金融
+    - 112、北京辰森世纪
+    - 113、云南滇医通
+    - 114、广州市分领网络科技有限责任公司
+    - 115、浙江微能科技有限公司
+    - 116、上海馨飞电子商务有限公司
+    - 117、上海宝尊电子商务有限公司
+    - 118、直客通科技技术有限公司
+    - 119、科度科技有限公司
+    - 120、上海数慧系统技术有限公司
+    - 121、我的医药网
+    - 122、多粉平台
+    - 123、铁甲二手机
+    - 124、上海海新得数据技术有限公司
+    - 125、深圳市珍爱网信息技术有限公司【珍爱网】
+    - 126、小蜜蜂
+    - 127、吉荣数科技
+    - 128、上海恺域信息科技有限公司
+    - 129、广州荔支网络有限公司【荔枝FM】
+    - 130、杭州闪宝科技有限公司
+    - 131、北京互联新网科技发展有限公司
+    - 132、誉道科技
+    - 133、山西兆盛房地产开发有限公司
+    - 134、北京蓝睿通达科技有限公司
+    - 135、月亮小屋(中国)有限公司【蓝月亮】
+    - 136、青岛国瑞信息技术有限公司
+    - 137、博雅云计算(北京)有限公司
+    - 138、华泰证券香港子公司
+    - 139、杭州东方通信软件技术有限公司
+    - 140、武汉博晟安全技术股份有限公司
+    - 141、深圳市六度人和科技有限公司
+    - 142、杭州趣维科技有限公司(小影)
+    - 143、宁波单车侠之家科技有限公司【单车侠】
+    - 144、丁丁云康信息科技(北京)有限公司
+    - 145、云钱袋
+    - 146、南京中兴力维
+    - 147、上海矽昌通信技术有限公司
+    - 148、深圳萨科科技
+    - 149、中通服创立科技有限责任公司
+    - 150、深圳市对庄科技有限公司
+    - 151、上证所信息网络有限公司
+    - 152、杭州火烧云科技有限公司【婚礼纪】
+    - 153、天津青芒果科技有限公司【芒果头条】
+    - 154、长飞光纤光缆股份有限公司
+    - 155、世纪凯歌(北京)医疗科技有限公司
+    - 156、浙江霖梓控股有限公司
+    - 157、江西腾飞网络技术有限公司
+    - 158、安迅物流有限公司
+    - 159、肉联网
+    - 160、北京北广梯影广告传媒有限公司
+    - 161、上海数慧系统技术有限公司
+    - 162、大志天成
+    - 163、上海云鹊医
+    - 164、上海云鹊医
+    - 165、墨迹天气【墨迹天气】
+    - 166、上海逸橙信息科技有限公司
+    - 167、沅朋物联
+    - 168、杭州恒生云融网络科技有限公司
+    - 169、绿米联创
+    - 170、重庆易宠科技有限公司
+    - 171、安徽引航科技有限公司(乐职网)
+    - 172、上海数联医信企业发展有限公司
+    - 173、良彬建材
+    - 174、杭州求是同创网络科技有限公司
+    - 175、荷马国际
+    - 176、点雇网
+    - 177、深圳市华星光电技术有限公司
+    - 178、厦门神州鹰软件科技有限公司
+    - 179、深圳市招商信诺人寿保险有限公司
+    - 180、上海好屋网信息技术有限公司
+    - 181、海信集团【海信】
+    - 182、信凌可信息科技(上海)有限公司
+    - 183、长春天成科技发展有限公司
+    - 184、用友金融信息技术股份有限公司【用友】
+    - 185、北京咖啡易融有限公司
+    - 186、国投瑞银基金管理有限公司
+    - 187、晋松(上海)网络信息技术有限公司
+    - 188、深圳市随手科技有限公司【随手记】
+    - 189、深圳水务科技有限公司
+    - 190、易企秀【易企秀】
+    - 191、北京磁云科技
+    - 192、南京蜂泰互联网科技有限公司
+    - 193、章鱼直播
+    - 194、奖多多科技
+    - 195、天津市神州商龙科技股份有限公司
+    - 196、岩心科技
+    - 197、车码科技(北京)有限公司
+    - 198、贵阳市投资控股集团
+    - 199、康旗股份
+    - 200、龙腾出行
+    - 201、杭州华量软件
+    - 202、合肥顶岭医疗科技有限公司
+    - 203、重庆表达式科技有限公司
+    - 204、上海米道信息科技有限公司
+    - 205、北京益友会科技有限公司
+    - 206、北京融贯电子商务有限公司
+    - 207、中国外汇交易中心
+    - 208、中国外运股份有限公司
+    - 209、中国上海晓圈教育科技有限公司
+    - 210、普联软件股份有限公司
+    - 211、北京科蓝软件股份有限公司
+    - 212、江苏斯诺物联科技有限公司
+    - 213、北京搜狐-狐友【搜狐】
+    - 214、新大陆网商金融
+    - 215、山东神码中税信息科技有限公司
+    - 216、河南汇顺网络科技有限公司
+    - 217、北京华夏思源科技发展有限公司
+    - 218、上海东普信息科技有限公司
+    - 219、上海鸣勃网络科技有限公司
+    - 220、广东学苑教育发展有限公司
+    - 221、深圳强时科技有限公司
+    - 222、上海云砺信息科技有限公司
+    - 223、重庆愉客行网络有限公司
+    - 224、数云
+    - 225、国家电网运检部
+    - 226、杭州找趣
+    - 227、浩鲸云计算科技股份有限公司
+    - 228、科大讯飞【科大讯飞】
+    - 229、杭州行装网络科技有限公司
+    - 230、即有分期金融
+    - 231、深圳法司德信息科技有限公司
+    - 232、上海博复信息科技有限公司
+    - 233、杭州云嘉云计算有限公司
+    - 234、有家民宿(有家美宿)
+    - 235、北京赢销通软件技术有限公司
+    - 236、浙江聚有财金融服务外包有限公司
+    - 237、易族智汇(北京)科技有限公司
+    - 238、合肥顶岭医疗科技开发有限公司
+    - 239、车船宝(深圳)旭珩科技有限公司)
+    - 240、广州富力地产有限公司
+    - 241、氢课(上海)教育科技有限公司
+    - 242、武汉氪细胞网络技术有限公司
+    - 243、杭州有云科技有限公司
+    - 244、上海仙豆智能机器人有限公司
+    - 245、拉卡拉支付股份有限公司【拉卡拉】
+    - 246、虎彩印艺股份有限公司
+    - 247、北京数微科技有限公司
+    - 248、广东智瑞科技有限公司
+    - 249、找钢网
+    - 250、九机网
+    - 251、杭州跑跑网络科技有限公司
+    - 252、深圳未来云集
+    - 253、杭州每日给力科技有限公司
+    - 254、上海齐犇信息科技有限公司
+    - 255、滴滴出行【滴滴】
+    - 256、合肥云诊信息科技有限公司
+    - 257、云知声智能科技股份有限公司
+    - 258、南京坦道科技有限公司
+    - 259、爱乐优(二手平台)
+    - 260、猫眼电影(私有化部署)【猫眼电影】
+    - 261、美团大象(私有化部署)【美团大象】
+    - 262、作业帮教育科技(北京)有限公司【作业帮】
+    - 263、北京小年糕互联网技术有限公司
+    - 264、山东矩阵软件工程股份有限公司
+    - 265、陕西国驿软件科技有限公司
+    - 266、君开信息科技
+    - 267、村鸟网络科技有限责任公司
+    - 268、云南国际信托有限公司
+    - 269、金智教育
+    - 270、珠海市筑巢科技有限公司
+    - 271、上海百胜软件股份有限公司
+    - 272、深圳市科盾科技有限公司
+    - 273、哈啰出行【哈啰】
+    - 274、途虎养车【途虎】
+    - 275、卡思优派人力资源集团
+    - 276、南京观为智慧软件科技有限公司
+    - 277、杭州城市大脑科技有限公司
+    - 278、猿辅导【猿辅导】
+    - 279、洛阳健创网络科技有限公司
+    - 280、魔力耳朵
+    - 281、亿阳信通
+    - 282、上海招鲤科技有限公司
+    - 283、四川商旅无忧科技服务有限公司
+    - 284、UU跑腿
+    - 285、北京老虎证券【老虎证券】
+    - 286、悠活省吧(北京)网络科技有限公司
+    - 287、F5未来商店
+    - 288、深圳环阳通信息技术有限公司
+    - 289、遠傳電信
+    - 290、作业帮(北京)教育科技有限公司【作业帮】
+    - 291、成都科鸿智信科技有限公司
+    - 292、北京木屋时代科技有限公司
+    - 293、大学通(哈尔滨)科技有限责任公司
+    - 294、浙江华坤道威数据科技有限公司
+    - 295、吉祥航空【吉祥航空】
+    - 296、南京圆周网络科技有限公司
+    - 297、广州市洋葱omall电子商务
+    - 298、天津联物科技有限公司
+    - 299、跑哪儿科技(北京)有限公司
+    - 300、深圳市美西西餐饮有限公司(喜茶)
+    - 301、平安不动产有限公司【平安】
+    - 302、江苏中海昇物联科技有限公司
+    - 303、湖南牙医帮科技有限公司
+    - 304、重庆民航凯亚信息技术有限公司(易通航)
+    - 305、递易(上海)智能科技有限公司
+    - 306、亚朵
+    - 307、浙江新课堂教育股份有限公司
+    - 308、北京蜂创科技有限公司
+    - 309、德一智慧城市信息系统有限公司
+    - 310、北京翼点科技有限公司
+    - 311、湖南智数新维度信息科技有限公司
+    - 312、北京玖扬博文文化发展有限公司
+    - 313、上海宇珩信息科技有限公司
+    - 314、全景智联(武汉)科技有限公司
+    - 315、天津易客满国际物流有限公司
+    - 316、南京爱福路汽车科技有限公司
+    - 317、我房旅居集团
+    - 318、湛江亲邻科技有限公司
+    - 319、深圳市姜科网络有限公司
+    - 320、青岛日日顺物流有限公司
+    - 321、南京太川信息技术有限公司
+    - 322、美图之家科技优先公司【美图】
+    - 323、南京太川信息技术有限公司
+    - 324、众薪科技(北京)有限公司
+    - 325、武汉安安物联科技有限公司
+    - 326、北京智客朗道网络科技有限公司
+    - 327、深圳市超级猩猩健身管理管理有限公司
+    - 328、重庆达志科技有限公司
+    - 329、上海享评信息科技有限公司
+    - 330、薪得付信息科技
+    - 331、跟谁学
+    - 332、中道(苏州)旅游网络科技有限公司
+    - 333、广州小卫科技有限公司
+    - 334、上海非码网络科技有限公司
+    - 335、途家网网络技术(北京)有限公司【途家】
+    - 336、广州辉凡信息科技有限公司
+    - 337、天维尔信息科技股份有限公司
+    - 338、上海极豆科技有限公司
+    - 339、苏州触达信息技术有限公司
+    - 340、北京热云科技有限公司
+    - 341、中智企服(北京)科技有限公司
+    - 342、易联云计算(杭州)有限责任公司
+    - 343、青岛航空股份有限公司【青岛航空】
+    - 344、山西博睿通科技有限公司
+    - 345、网易杭州网络有限公司【网易】
+    - 346、北京果果乐学科技有限公司
+    - 347、百望股份有限公司
+    - 348、中保金服(深圳)科技有限公司
+    - 349、天津运友物流科技股份有限公司
+    - 350、广东创能科技股份有限公司
+    - 351、上海倚博信息科技有限公司
+    - 352、深圳百果园实业(集团)股份有限公司
+    - 353、广州细刻网络科技有限公司
+    - 354、武汉鸿业众创科技有限公司
+    - 355、金锡科技(广州)有限公司
+    - 356、易瑞国际电子商务有限公司
+    - 357、奇点云
+    - 358、中视信息科技有限公司
+    - 359、开源项目:datax-web
+    - 360、云知声智能科技股份有限公司
+    - 361、开源项目:bboss
+    - 362、成都深驾科技有限公司
+    - 363、FunPlus【趣加】
+    - 364、杭州创匠信科技有限公司
+    - 365、龙匠(北京)科技发展有限公司
+    - 366、广州一链通互联网科技有限公司
+    - 367、上海星艾网络科技有限公司
+    - 368、虎博网络技术(上海)有限公司
+    - 369、青岛优米信息技术有限公司
+    - 370、八维通科技有限公司
+    - 371、烟台合享智星数据科技有限公司
+    - 372、东吴证券股份有限公司
+    - 373、中通云仓股份有限公司【中通】
+    - 374、北京加菲猫科技有限公司
+    - 375、北京匠心演绎科技有限公司
+    - 376、宝贝走天下
+    - 377、厦门众库科技有限公司
+    - 378、海通证券数据中心
+    - 389、湖南快乐通宝小额贷款有限公司
+    - 380、浙江大华技术股份有限公司
+    - 381、杭州魔筷科技有限公司
+    - 382、青岛掌讯通区块链科技有限公司
+    - 383、新大陆金融科技
+    - 384、常州玺拓软件科技有限公司
+    - 385、北京正保网格教育科技有限公司
+    - 386、统一企业(中国)投资有限公司【统一】
+    - 387、微革网络科技有限公司
+    - 388、杭州融易算科技有限公司
+    - 399、青岛上啥班网络科技有限公司
+    - 390、京东酒世界
+    - 391、杭州爱博仕科技有限公司
+    - 392、五星金服控股有限公司
+    - 393、福建乐摩物联科技有限公司
+    - 394、百炼智能科技有限公司
+    - 395、山东能源数智云科技有限公司
+    - 396、招商局能源运输股份有限公司
+    - 397、三一集团【三一】
+    - 398、东巴文(深圳)健康管理有限公司
+    - 399、索易软件
+    - 400、深圳市宁远科技有限公司
+    - 401、熙牛医疗
+    - 402、南京智鹤电子科技有限公司
+    - 403、嘀嗒出行【嘀嗒出行】
+    - 404、广州虎牙信息科技有限公司【虎牙】
+    - 405、广州欧莱雅百库网络科技有限公司【欧莱雅】
+    - 406、微微科技有限公司
+    - 407、我爱我家房地产经纪有限公司【我爱我家】
+    - 408、九号发现
+    - 409、薪人薪事
+    - 410、武汉氪细胞网络技术有限公司
+    - 411、广州市斯凯奇商业有限公司
+    - 412、微淼商学院
+    - 413、杭州车盛科技有限公司
+    - 414、深兰科技(上海)有限公司
+    - 415、安徽中科美络信息技术有限公司
+    - 416、比亚迪汽车工业有限公司【比亚迪】
+    - 417、湖南小桔信息技术有限公司
+    - 418、安徽科大国创软件科技有限公司
+    - 419、克而瑞
+    - 420、陕西云基华海信息技术有限公司
+    - 421、安徽深宁科技有限公司
+    - 422、广东康爱多数字健康有限公司
+    - 423、嘉里电子商务
+    - 424、上海时代光华教育发展有限公司
+    - 425、CityDo
+    - 426、上海禹知信息科技有限公司
+    - 427、广东智瑞科技有限公司
+    - 428、西安爱铭网络科技有限公司
+    - 429、心医国际数字医疗系统(大连)有限公司
+    - 430、乐其电商
+    - 431、锐达科技
+    - 432、天津长城滨银汽车金融有限公司
+    - 433、代码网
+    - 434、东莞市东城乔伦软件开发工作室
+    - 435、浙江百应科技有限公司
+    - 436、上海力爱帝信息技术有限公司(Red E)
+    - 437、云徙科技有限公司
+    - 438、北京康智乐思网络科技有限公司【大姨吗APP】
+    - 439、安徽开元瞬视科技有限公司
+    - 440、立方
+    - 441、厦门纵行科技
+    - 442、乐山-菲尼克斯半导体有限公司
+    - 443、武汉光谷联合集团有限公司
+    - 444、上海金仕达软件科技有限公司
+    - 445、深圳易世通达科技有限公司
+    - 446、爱动超越人工智能科技(北京)有限责任公司
+    - ……
+
+> 更多接入的公司,欢迎在 [登记地址](https://github.com/xuxueli/xxl-job/issues/1 ) 登记,登记仅仅为了产品推广。
+
+欢迎大家的关注和使用,XXL-JOB也将拥抱变化,持续发展。
+
+
+## Contributing
+Contributions are welcome! Open a pull request to fix a bug, or open an [Issue](https://github.com/xuxueli/xxl-job/issues/) to discuss a new feature or change.
+
+欢迎参与项目贡献!比如提交PR修复一个bug,或者新建 [Issue](https://github.com/xuxueli/xxl-job/issues/) 讨论新特性或者变更。
+
+
+## Copyright and License
+This product is open source and free, and will continue to provide free community technical support. Individual or enterprise users are free to access and use.
+
+- Licensed under the GNU General Public License (GPL) v3.
+- Copyright (c) 2015-present, xuxueli.
+
+产品开源免费,并且将持续提供免费的社区技术支持。个人或企业内部可自由的接入和使用。
+
+
+## Donate
+No matter how much the donation amount is enough to express your thought, thank you very much :)     [To donate](https://www.xuxueli.com/page/donate.html )
+
+无论捐赠金额多少都足够表达您这份心意,非常感谢 :)      [前往捐赠](https://www.xuxueli.com/page/donate.html )

+ 73 - 0
docker-compose/docker-compose.yml

@@ -0,0 +1,73 @@
+version: '2.4'
+
+services:
+  postgres: # 数据库连接:jdbc:postgresql://{ip}:5432/{dbname} 用户名:postgres 密码:heliang
+    image: postgres:12.10
+    restart: always
+    environment:
+      POSTGRES_USER: postgres
+      POSTGRES_PASSWORD: heliang
+      POSTGRES_DB: postgres
+      PGDATA: /var/lib/postgresql/data/pgdata
+      LANG: C.UTF-8
+      TZ: Asia/Shanghai
+    volumes:
+      - ./postgres/data/:/var/lib/postgresql/data/pgdata/:rw
+      - ./postgres/init.d/:/docker-entrypoint-initdb.d/:rw
+      - ./postgres/sql/:/sql/:rw
+      - ./postgres/upgrade/:/upgrade/:rw
+    networks:
+      - mobe-network
+    privileged: true
+  xxl-job: #分布式任务调度 http://{ip}:8866/xxl-job-admin 后台登录用户名:admin 密码:123456
+    image: heliang230/xxl-job-admin:2.3.0
+    restart: always
+    environment:
+      APPLICATION_PORT: 8866 #调度中心web界面访问端口
+      SERVER_SERVLET_CONTEXTPATH: /xxl-job-admin #web上下文
+      POSTGRES_SERVICE_HOST: postgres #数据库
+      POSTGRES_SERVICE_PORT: 5432 #数据库端口
+      POSTGRES_SERVICE_DB_NAME: xxl_job #数据库名称
+      POSTGRES_SERVICE_USER: postgres #数据库用户名
+      POSTGRES_SERVICE_PASSWORD: heliang #数据库密码
+      SERVICE_ACCESSTOKEN: d1bacd94024ed228 #调度中心与执行器服务认证凭证
+      JAVA_OPTS: -Xmx512m
+    volumes:
+      - ./xxl-job/data/:/data/:rw
+    ports:
+      - 8866:8866
+    networks:
+      - mobe-network
+    privileged: true
+    depends_on:
+      - postgres
+  xxl-job-executor: #执行器
+    image: heliang230/xxl-job-executor:2.3.2
+    restart: always
+    environment:
+      SERVER_PORT: 8080 #执行器API端口
+      SPRING_MAIN_WEB_ENVIRONMENT: "true" #是否开启web模式
+      XXL_JOB_ADMIN_ADDRESSES: http://xxl-job:8866/xxl-job-admin #调度中心地址
+      XXL_JOB_ACCESSTOKEN: d1bacd94024ed228 #执行器与调度中心token凭证
+      XXL_JOB_EXECUTOR_APPNAME: xxl-job-executor #执行器应用名称
+      XXL_JOB_EXECUTOR_ADDRESS: http://xxl-job-executor:9999/ #注册到调度中心的执行器地址信息
+      XXL_JOB_EXECUTOR_IP: xxl-job-executor #执行器ip地址
+      XXL_JOB_EXECUTOR_PORT: 9999 #执行器端口
+      XXL_JOB_EXECUTOR_LOGPATH: /data/applogs/xxl-job/jobhandler #日志存储路径
+      XXL_JOB_EXECUTOR_LOGRETENTIONDAYS: 30 #存储日志时间
+      JAVA_OPTS: -Xmx512m
+      SLEEP: 5 #启动容器后,休眠5秒中,为了防止报错
+    volumes:
+      - ./xxl-job-executor/data/:/data/:rw
+    ports:
+      - 8080:8080
+    networks:
+      - mobe-network
+    privileged: true
+    depends_on:
+      - postgres
+      - xxl-job
+networks:
+  mobe-network:
+
+

+ 9 - 0
docker-compose/postgres/init.d/init-xxl-job-db.sh

@@ -0,0 +1,9 @@
+#!/bin/bash
+
+
+
+psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER"  <<-EOSQL
+	CREATE DATABASE xxl_job;
+	\c xxl_job;
+	\i /sql/xxl_job_postgres.sql;
+EOSQL

+ 445 - 0
docker-compose/postgres/sql/xxl_job_postgres.sql

@@ -0,0 +1,445 @@
+CREATE SEQUENCE "xxl_job_group_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 2147483647
+START 1
+CACHE 1;
+
+
+SELECT setval('"xxl_job_group_id_seq"', 2, true);
+
+CREATE SEQUENCE "xxl_job_info_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 2147483647
+START 1
+CACHE 1;
+
+
+SELECT setval('"xxl_job_info_id_seq"', 8, true);
+
+
+CREATE SEQUENCE "xxl_job_log_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 2147483647
+START 1
+CACHE 1;
+
+
+
+
+CREATE SEQUENCE "xxl_job_logglue_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 2147483647
+START 1
+CACHE 1;
+
+
+
+
+CREATE SEQUENCE "xxl_job_log_report_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 2147483647
+START 1
+CACHE 1;
+
+
+
+
+CREATE SEQUENCE "xxl_job_registry_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 2147483647
+START 1
+CACHE 1;
+
+
+
+
+CREATE SEQUENCE "xxl_job_user_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 2147483647
+START 1
+CACHE 1;
+
+SELECT setval('"xxl_job_user_id_seq"', 2, true);
+
+CREATE TABLE "xxl_job_group" (
+  "id" int4 NOT NULL DEFAULT nextval('xxl_job_group_id_seq'::regclass),
+  "app_name" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
+  "title" varchar(12) COLLATE "pg_catalog"."default" NOT NULL,
+  "address_type" int2 NOT NULL,
+  "address_list" text COLLATE "pg_catalog"."default",
+  "update_time" timestamp(6)
+)
+;
+COMMENT ON COLUMN "xxl_job_group"."app_name" IS '执行器AppName';
+COMMENT ON COLUMN "xxl_job_group"."title" IS '执行器名称';
+COMMENT ON COLUMN "xxl_job_group"."address_type" IS '执行器地址类型:0=自动注册、1=手动录入';
+COMMENT ON COLUMN "xxl_job_group"."address_list" IS '执行器地址列表,多地址逗号分隔';
+
+
+CREATE TABLE "xxl_job_info" (
+  "id" int4 NOT NULL DEFAULT nextval('xxl_job_info_id_seq'::regclass),
+  "job_group" int4 NOT NULL,
+  "job_desc" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
+  "add_time" timestamp(6),
+  "update_time" timestamp(6),
+  "author" varchar(64) COLLATE "pg_catalog"."default",
+  "alarm_email" varchar(255) COLLATE "pg_catalog"."default",
+  "schedule_type" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
+  "schedule_conf" varchar(128) COLLATE "pg_catalog"."default",
+  "misfire_strategy" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
+  "executor_route_strategy" varchar(50) COLLATE "pg_catalog"."default",
+  "executor_handler" varchar(255) COLLATE "pg_catalog"."default",
+  "executor_param" varchar(512) COLLATE "pg_catalog"."default",
+  "executor_block_strategy" varchar(50) COLLATE "pg_catalog"."default",
+  "executor_timeout" int4 NOT NULL,
+  "executor_fail_retry_count" int4 NOT NULL,
+  "glue_type" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
+  "glue_source" text COLLATE "pg_catalog"."default",
+  "glue_remark" varchar(128) COLLATE "pg_catalog"."default",
+  "glue_updatetime" timestamp(6),
+  "child_jobid" varchar(255) COLLATE "pg_catalog"."default",
+  "trigger_status" int2 NOT NULL,
+  "trigger_last_time" int8 NOT NULL,
+  "trigger_next_time" int8 NOT NULL
+)
+;
+COMMENT ON COLUMN "xxl_job_info"."job_group" IS '执行器主键ID';
+COMMENT ON COLUMN "xxl_job_info"."author" IS '作者';
+COMMENT ON COLUMN "xxl_job_info"."alarm_email" IS '报警邮件';
+COMMENT ON COLUMN "xxl_job_info"."schedule_type" IS '调度类型';
+COMMENT ON COLUMN "xxl_job_info"."schedule_conf" IS '调度配置,值含义取决于调度类型';
+COMMENT ON COLUMN "xxl_job_info"."misfire_strategy" IS '调度过期策略';
+COMMENT ON COLUMN "xxl_job_info"."executor_route_strategy" IS '执行器路由策略';
+COMMENT ON COLUMN "xxl_job_info"."executor_handler" IS '执行器任务handler';
+COMMENT ON COLUMN "xxl_job_info"."executor_param" IS '执行器任务参数';
+COMMENT ON COLUMN "xxl_job_info"."executor_block_strategy" IS '阻塞处理策略';
+COMMENT ON COLUMN "xxl_job_info"."executor_timeout" IS '任务执行超时时间,单位秒';
+COMMENT ON COLUMN "xxl_job_info"."executor_fail_retry_count" IS '失败重试次数';
+COMMENT ON COLUMN "xxl_job_info"."glue_type" IS 'GLUE类型';
+COMMENT ON COLUMN "xxl_job_info"."glue_source" IS 'GLUE源代码';
+COMMENT ON COLUMN "xxl_job_info"."glue_remark" IS 'GLUE备注';
+COMMENT ON COLUMN "xxl_job_info"."glue_updatetime" IS 'GLUE更新时间';
+COMMENT ON COLUMN "xxl_job_info"."child_jobid" IS '子任务ID,多个逗号分隔';
+COMMENT ON COLUMN "xxl_job_info"."trigger_status" IS '调度状态:0-停止,1-运行';
+COMMENT ON COLUMN "xxl_job_info"."trigger_last_time" IS '上次调度时间';
+COMMENT ON COLUMN "xxl_job_info"."trigger_next_time" IS '下次调度时间';
+
+
+CREATE TABLE "xxl_job_lock" (
+  "lock_name" varchar(50) COLLATE "pg_catalog"."default" NOT NULL
+)
+;
+COMMENT ON COLUMN "xxl_job_lock"."lock_name" IS '锁名称';
+
+
+CREATE TABLE "xxl_job_log" (
+  "id" int4 NOT NULL DEFAULT nextval('xxl_job_log_id_seq'::regclass),
+  "job_group" int4 NOT NULL,
+  "job_id" int4 NOT NULL,
+  "executor_address" varchar(255) COLLATE "pg_catalog"."default",
+  "executor_handler" varchar(255) COLLATE "pg_catalog"."default",
+  "executor_param" varchar(512) COLLATE "pg_catalog"."default",
+  "executor_sharding_param" varchar(20) COLLATE "pg_catalog"."default",
+  "executor_fail_retry_count" int4 NOT NULL DEFAULT 0,
+  "trigger_time" timestamp(6),
+  "trigger_code" int4 NOT NULL,
+  "trigger_msg" text COLLATE "pg_catalog"."default",
+  "handle_time" timestamp(6),
+  "handle_code" int4 NOT NULL,
+  "handle_msg" text COLLATE "pg_catalog"."default",
+  "alarm_status" int2 NOT NULL DEFAULT 0
+)
+;
+COMMENT ON COLUMN "xxl_job_log"."job_group" IS '执行器主键ID';
+COMMENT ON COLUMN "xxl_job_log"."job_id" IS '任务,主键ID';
+COMMENT ON COLUMN "xxl_job_log"."executor_address" IS '执行器地址,本次执行的地址';
+COMMENT ON COLUMN "xxl_job_log"."executor_handler" IS '执行器任务handler';
+COMMENT ON COLUMN "xxl_job_log"."executor_param" IS '执行器任务参数';
+COMMENT ON COLUMN "xxl_job_log"."executor_sharding_param" IS '执行器任务分片参数,格式如 1/2';
+COMMENT ON COLUMN "xxl_job_log"."executor_fail_retry_count" IS '失败重试次数';
+COMMENT ON COLUMN "xxl_job_log"."trigger_time" IS '调度-时间';
+COMMENT ON COLUMN "xxl_job_log"."trigger_code" IS '调度-结果';
+COMMENT ON COLUMN "xxl_job_log"."trigger_msg" IS '调度-日志';
+COMMENT ON COLUMN "xxl_job_log"."handle_time" IS '执行-时间';
+COMMENT ON COLUMN "xxl_job_log"."handle_code" IS '执行-状态';
+COMMENT ON COLUMN "xxl_job_log"."handle_msg" IS '执行-日志';
+COMMENT ON COLUMN "xxl_job_log"."alarm_status" IS '告警状态:0-默认、1-无需告警、2-告警成功、3-告警失败';
+
+
+CREATE TABLE "xxl_job_log_report" (
+  "id" int4 NOT NULL DEFAULT nextval('xxl_job_log_report_id_seq'::regclass),
+  "trigger_day" timestamp(6),
+  "running_count" int4 NOT NULL,
+  "suc_count" int4 NOT NULL,
+  "fail_count" int4 NOT NULL,
+  "update_time" timestamp(6)
+)
+;
+COMMENT ON COLUMN "xxl_job_log_report"."trigger_day" IS '调度-时间';
+COMMENT ON COLUMN "xxl_job_log_report"."running_count" IS '运行中-日志数量';
+COMMENT ON COLUMN "xxl_job_log_report"."suc_count" IS '执行成功-日志数量';
+COMMENT ON COLUMN "xxl_job_log_report"."fail_count" IS '执行失败-日志数量';
+
+
+CREATE TABLE "xxl_job_logglue" (
+  "id" int4 NOT NULL DEFAULT nextval('xxl_job_logglue_id_seq'::regclass),
+  "job_id" int4 NOT NULL,
+  "glue_type" varchar(50) COLLATE "pg_catalog"."default",
+  "glue_source" text COLLATE "pg_catalog"."default",
+  "glue_remark" varchar(128) COLLATE "pg_catalog"."default" NOT NULL,
+  "add_time" timestamp(6),
+  "update_time" timestamp(6)
+)
+;
+COMMENT ON COLUMN "xxl_job_logglue"."job_id" IS '任务,主键ID';
+COMMENT ON COLUMN "xxl_job_logglue"."glue_type" IS 'GLUE类型';
+COMMENT ON COLUMN "xxl_job_logglue"."glue_source" IS 'GLUE源代码';
+COMMENT ON COLUMN "xxl_job_logglue"."glue_remark" IS 'GLUE备注';
+
+
+CREATE TABLE "xxl_job_registry" (
+  "id" int4 NOT NULL DEFAULT nextval('xxl_job_registry_id_seq'::regclass),
+  "registry_group" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
+  "registry_key" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
+  "registry_value" varchar(255) COLLATE "pg_catalog"."default" NOT NULL,
+  "update_time" timestamp(6)
+)
+;
+
+
+CREATE TABLE "xxl_job_user" (
+  "id" int4 NOT NULL DEFAULT nextval('xxl_job_user_id_seq'::regclass),
+  "username" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
+  "password" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
+  "role" int2 NOT NULL,
+  "permission" varchar(255) COLLATE "pg_catalog"."default"
+)
+;
+COMMENT ON COLUMN "xxl_job_user"."username" IS '账号';
+COMMENT ON COLUMN "xxl_job_user"."password" IS '密码';
+COMMENT ON COLUMN "xxl_job_user"."role" IS '角色:0-普通用户、1-管理员';
+COMMENT ON COLUMN "xxl_job_user"."permission" IS '权限:执行器ID列表,多个逗号分割';
+
+
+ALTER TABLE "xxl_job_group" ADD CONSTRAINT "xxl_job_group_pkey" PRIMARY KEY ("id");
+
+
+ALTER TABLE "xxl_job_info" ADD CONSTRAINT "xxl_job_info_pkey" PRIMARY KEY ("id");
+
+
+ALTER TABLE "xxl_job_lock" ADD CONSTRAINT "xxl_job_lock_pkey" PRIMARY KEY ("lock_name");
+
+
+CREATE INDEX "I_handle_code" ON "xxl_job_log" USING btree (
+  "handle_code" "pg_catalog"."int4_ops" ASC NULLS LAST
+);
+CREATE INDEX "I_trigger_time" ON "xxl_job_log" USING btree (
+  "trigger_time" "pg_catalog"."timestamp_ops" ASC NULLS LAST
+);
+
+
+ALTER TABLE "xxl_job_log" ADD CONSTRAINT "xxl_job_log_pkey" PRIMARY KEY ("id");
+
+
+CREATE INDEX "i_trigger_day" ON "xxl_job_log_report" USING btree (
+  "trigger_day" "pg_catalog"."timestamp_ops" ASC NULLS LAST
+);
+
+
+ALTER TABLE "xxl_job_log_report" ADD CONSTRAINT "xxl_job_log_report_pkey" PRIMARY KEY ("id");
+
+
+ALTER TABLE "xxl_job_logglue" ADD CONSTRAINT "xxl_job_logglue_pkey" PRIMARY KEY ("id");
+
+
+CREATE INDEX "i_g_k_v" ON "xxl_job_registry" USING btree (
+  "registry_group" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "registry_key" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "registry_value" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+
+
+ALTER TABLE "xxl_job_registry" ADD CONSTRAINT "xxl_job_registry_pkey" PRIMARY KEY ("id");
+
+
+CREATE INDEX "i_username" ON "xxl_job_user" USING btree (
+  "username" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+
+ALTER TABLE "xxl_job_user" ADD CONSTRAINT "xxl_job_user_pkey" PRIMARY KEY ("id");
+
+
+
+
+INSERT INTO "xxl_job_user" ("id", "username", "password", "role", "permission") VALUES (1, 'admin', 'e10adc3949ba59abbe56e057f20f883e', 1, NULL);
+INSERT INTO "xxl_job_group" ("id", "app_name", "title", "address_type", "address_list", "update_time") VALUES (1, 'xxl-job-executor', '执行器-测试组', 0, NULL, '2022-06-05 22:21:31');
+
+INSERT INTO "xxl_job_info" ("id", "job_group", "job_desc", "add_time", "update_time", "author", "alarm_email", "schedule_type", "schedule_conf", "misfire_strategy", "executor_route_strategy", "executor_handler", "executor_param", "executor_block_strategy", "executor_timeout", "executor_fail_retry_count", "glue_type", "glue_source", "glue_remark", "glue_updatetime", "child_jobid", "trigger_status", "trigger_last_time", "trigger_next_time") VALUES (1, 1, 'java_script', '2022-06-07 01:48:38.21', '2022-06-07 01:57:43.739', 'zhangsan', '', 'CRON', '0/5 * * * * ?', 'DO_NOTHING', 'FIRST', '', 'https://api.vvhan.com/api/zhihu?username=uxiaohan', 'SERIAL_EXECUTION', 0, 0, 'GLUE_GROOVY', 'package com.xxl.job.service.handler;
+
+import com.xxl.job.core.context.XxlJobHelper;
+import com.xxl.job.core.handler.IJobHandler;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+
+public class HttpJobHandler extends IJobHandler {
+
+    public static String sendGet(String url, String param) throws Exception{
+        String result = "";
+        String urlNameString = url + "?" + param;
+        URL realUrl = new URL(urlNameString);
+        // 打开和URL之间的连接
+        URLConnection connection = realUrl.openConnection();
+        // 设置通用的请求属性
+        connection.setRequestProperty("accept", "*/*");
+        connection.setRequestProperty("connection", "Keep-Alive");
+        connection.setRequestProperty("user-agent",
+                                      "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+        // 建立实际的连接
+        connection.setRequestProperty("Accept-Charset", "utf-8");
+        connection.setRequestProperty("contentType", "utf-8");
+        connection.connect();
+        BufferedReader inbf = new BufferedReader(new InputStreamReader(
+          connection.getInputStream(),"utf-8"));
+        String line;
+        while ((line = inbf.readLine()) != null) {
+          result += line;
+        }
+
+        inbf.close();
+        return result;
+    }
+
+	@Override
+	public void execute() throws Exception {
+		XxlJobHelper.log("开始执行模拟请求!");
+        XxlJobHelper.log("接收到的参数:{}", XxlJobHelper.getJobParam());
+        // 分片参数
+        int shardIndex = XxlJobHelper.getShardIndex();
+        int shardTotal = XxlJobHelper.getShardTotal();
+
+        XxlJobHelper.log("分片参数:当前分片序号 = {}, 总分片数 = {}", shardIndex, shardTotal);
+       //获取调度器传递参数
+       String url = XxlJobHelper.getJobParam();
+ 	   XxlJobHelper.log(sendGet(url,""));
+       XxlJobHelper.log("模拟请求执行完成");
+	}
+
+}', 'java_script', '2022-06-07 01:57:43.739', '', 0, 0, 0);
+
+
+INSERT INTO "xxl_job_info" ("id", "job_group", "job_desc", "add_time", "update_time", "author", "alarm_email", "schedule_type", "schedule_conf", "misfire_strategy", "executor_route_strategy", "executor_handler", "executor_param", "executor_block_strategy", "executor_timeout", "executor_fail_retry_count", "glue_type", "glue_source", "glue_remark", "glue_updatetime", "child_jobid", "trigger_status", "trigger_last_time", "trigger_next_time") VALUES (2, 1, 'php_script', '2022-06-07 01:49:08.833', '2022-06-07 02:02:08.743', 'zhangsan', '', 'CRON', '0/5 * * * * ?', 'DO_NOTHING', 'FIRST', '', 'https://api.vvhan.com/api/zhihu?username=uxiaohan', 'SERIAL_EXECUTION', 0, 0, 'GLUE_PHP', '<?php
+
+    echo "xxl-job: hello php  \n";
+
+    echo "脚本位置:$argv[0]  \n";
+    echo "任务参数:$argv[1]  \n";
+    echo "分片序号 = $argv[2]  \n";
+    echo "分片总数 = $argv[3]  \n";
+  /**
+     * 传入json数据进行HTTP Get请求
+     *
+     * @param string $url $data_string
+     * @return string
+     */
+    function http_get($url)
+    {
+          $curl = curl_init(); // 启动一个CURL会话
+            curl_setopt($curl, CURLOPT_URL, $url);
+            curl_setopt($curl, CURLOPT_HEADER, 0);
+            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+            curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
+            curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);  // 从证书中检查SSL加密算法是否存在
+            $tmpInfo = curl_exec($curl);     //返回api的json对象
+            //关闭URL请求
+            curl_close($curl);
+            return $tmpInfo;    //返回json对象
+
+    }
+	$url=$argv[1];
+    $result=http_get($url);
+	echo $result;
+    echo "Good bye!  \n";
+    exit(0);
+
+?>
+', 'php_script', '2022-06-07 02:02:08.743', '', 0, 0, 0);
+
+INSERT INTO "xxl_job_info" ("id", "job_group", "job_desc", "add_time", "update_time", "author", "alarm_email", "schedule_type", "schedule_conf", "misfire_strategy", "executor_route_strategy", "executor_handler", "executor_param", "executor_block_strategy", "executor_timeout", "executor_fail_retry_count", "glue_type", "glue_source", "glue_remark", "glue_updatetime", "child_jobid", "trigger_status", "trigger_last_time", "trigger_next_time") VALUES (3, 1, 'python_script', '2022-06-07 01:49:40.531', '2022-06-07 02:04:03.534', 'zhangsan', '', 'CRON', '0/5 * * * * ?', 'DO_NOTHING', 'FIRST', '', 'https://api.vvhan.com/api/zhihu?username=uxiaohan', 'SERIAL_EXECUTION', 0, 0, 'GLUE_PYTHON', '#!/usr/bin/python
+# -*- coding: UTF-8 -*-
+import time
+import urllib.request
+import urllib.parse
+import sys
+import codecs
+sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())
+
+print("xxl-job: hello python")
+
+print("脚本位置:", sys.argv[0])
+print("任务参数:", sys.argv[1])
+print("分片序号:", sys.argv[2])
+print("分片总数:", sys.argv[3])
+def gethttp(http_url):
+    print(http_url)
+    response = urllib.request.urlopen(http_url)
+    result=response.read()
+    print(result)
+    pass
+
+
+gethttp(sys.argv[1])
+
+print ("Good bye!")
+exit(0)
+', 'python_script', '2022-06-07 02:04:03.534', '', 0, 0, 0);
+
+INSERT INTO "xxl_job_info" ("id", "job_group", "job_desc", "add_time", "update_time", "author", "alarm_email", "schedule_type", "schedule_conf", "misfire_strategy", "executor_route_strategy", "executor_handler", "executor_param", "executor_block_strategy", "executor_timeout", "executor_fail_retry_count", "glue_type", "glue_source", "glue_remark", "glue_updatetime", "child_jobid", "trigger_status", "trigger_last_time", "trigger_next_time") VALUES (5, 1, 'spring_bean_simple', '2022-06-07 01:53:28.497', '2022-06-07 01:53:28.497', 'zhangsan', '', 'CRON', '0/5 * * * * ?', 'DO_NOTHING', 'FIRST', 'demoJobHandler', 'test', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-06-07 01:53:28.497', '', 0, 0, 0);
+
+INSERT INTO "xxl_job_info" ("id", "job_group", "job_desc", "add_time", "update_time", "author", "alarm_email", "schedule_type", "schedule_conf", "misfire_strategy", "executor_route_strategy", "executor_handler", "executor_param", "executor_block_strategy", "executor_timeout", "executor_fail_retry_count", "glue_type", "glue_source", "glue_remark", "glue_updatetime", "child_jobid", "trigger_status", "trigger_last_time", "trigger_next_time") VALUES (6, 1, 'spring_bean_broadcast', '2022-06-07 01:54:45.836', '2022-06-07 01:54:59.474', 'zhangsan', '', 'FIX_RATE', '5', 'DO_NOTHING', 'SHARDING_BROADCAST', 'shardingJobHandler', '2022-06-01', 'SERIAL_EXECUTION', 0, 0, 'BEAN', '', 'GLUE代码初始化', '2022-06-07 01:54:45.836', '', 0, 0, 0);
+
+INSERT INTO "xxl_job_info" ("id", "job_group", "job_desc", "add_time", "update_time", "author", "alarm_email", "schedule_type", "schedule_conf", "misfire_strategy", "executor_route_strategy", "executor_handler", "executor_param", "executor_block_strategy", "executor_timeout", "executor_fail_retry_count", "glue_type", "glue_source", "glue_remark", "glue_updatetime", "child_jobid", "trigger_status", "trigger_last_time", "trigger_next_time") VALUES (7, 1, 'shell_script', '2022-06-07 01:50:13.086', '2022-06-07 02:05:11.828', 'zhangsan', '', 'CRON', '0/5 * * * * ?', 'DO_NOTHING', 'FIRST', '', 'https://api.vvhan.com/api/zhihu?username=uxiaohan', 'SERIAL_EXECUTION', 0, 0, 'GLUE_SHELL', '#!/bin/bash
+echo "xxl-job: hello shell"
+echo "脚本位置:$0"
+echo "任务参数:$1"
+echo "分片序号 = $2"
+echo "分片总数 = $3"
+echo "开始HTTP模拟请求"
+url=$1
+result=$(curl ${url} -s)
+echo $result
+echo "Good bye!"
+exit 0
+', 'shell_script', '2022-06-07 02:05:11.828', '', 0, 0, 0);
+
+INSERT INTO "xxl_job_info" ("id", "job_group", "job_desc", "add_time", "update_time", "author", "alarm_email", "schedule_type", "schedule_conf", "misfire_strategy", "executor_route_strategy", "executor_handler", "executor_param", "executor_block_strategy", "executor_timeout", "executor_fail_retry_count", "glue_type", "glue_source", "glue_remark", "glue_updatetime", "child_jobid", "trigger_status", "trigger_last_time", "trigger_next_time") VALUES (8, 1, 'node_script', '2022-06-07 01:51:43.617', '2022-06-07 02:06:47.131', 'zhangsan', '', 'CRON', '0/5 * * * * ?', 'DO_NOTHING', 'FIRST', '', 'https://api.vvhan.com/api/zhihu?username=uxiaohan', 'SERIAL_EXECUTION', 0, 0, 'GLUE_NODEJS', '#!/usr/bin/env node
+console.log("xxl-job: hello nodejs")
+
+var arguments = process.argv
+
+console.log("脚本位置: " + arguments[1])
+console.log("任务参数: " + arguments[2])
+console.log("分片序号: " + arguments[3])
+console.log("分片总数: " + arguments[4])
+let name="张三";
+console.log(`我是${name}`);
+console.log("Good bye!")
+process.exit(0)
+', 'node_script', '2022-06-07 02:06:34.115', '', 0, 0, 0);
+
+
+INSERT INTO "xxl_job_lock" ("lock_name") VALUES ('schedule_lock');

+ 143 - 72
pom.xml

@@ -1,74 +1,145 @@
-<?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <modelVersion>4.0.0</modelVersion>
-    <packaging>pom</packaging>
-    <modules>
-        <module>xxl-job-core-pg</module>
-        <module>xxl-job-admin-pg</module>
-        <module>xxl-job-springboot-example</module>
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>com.xuxueli</groupId>
+	<artifactId>xxl-job</artifactId>
+	<version>2.3.0</version>
+	<packaging>pom</packaging>
+
+	<name>${project.artifactId}</name>
+	<description>A distributed task scheduling framework.</description>
+	<url>https://www.xuxueli.com/</url>
+
+	<modules>
+		<module>xxl-job-core</module>
+		<module>xxl-job-admin</module>
+		<module>xxl-job-executor-samples</module>
     </modules>
-    <parent>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-starter-parent</artifactId>
-        <version>2.3.4.RELEASE</version>
-        <relativePath/> <!-- lookup parent from repository -->
-    </parent>
-
-    <groupId>org.poem</groupId>
-    <artifactId>xxl-job-pg</artifactId>
-    <version>2.2.0</version>
-    <name>xxl-job-pg</name>
-    <description>Demo project for Spring Boot</description>
-
-    <properties>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-
-        <java.version>1.8</java.version>
-        <maven.compiler.source>1.8</maven.compiler.source>
-        <maven.compiler.target>1.8</maven.compiler.target>
-        <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
-        <maven.test.skip>true</maven.test.skip>
-
-
-        <netty-all.version>4.1.50.Final</netty-all.version>
-        <gson.version>2.8.6</gson.version>
-
-        <spring.version>5.2.7.RELEASE</spring.version>
-        <spring-boot.version>2.3.4.RELEASE</spring-boot.version>
-
-        <mybatis-spring-boot-starter.version>2.1.3</mybatis-spring-boot-starter.version>
-        <postgresql.version>42.2.5</postgresql.version>
-
-        <slf4j-api.version>1.7.30</slf4j-api.version>
-        <junit.version>4.13</junit.version>
-        <javax.annotation-api.version>1.3.2</javax.annotation-api.version>
-
-        <groovy.version>3.0.4</groovy.version>
-
-        <maven-source-plugin.version>3.1.1</maven-source-plugin.version>
-        <maven-javadoc-plugin.version>3.1.0</maven-javadoc-plugin.version>
-        <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
-        <maven-war-plugin.version>3.3.0</maven-war-plugin.version>
-
-        <commons-lang3.version>3.8.1</commons-lang3.version>
-        <commons-pool.version>1.6</commons-pool.version>
-        <commons-pool2.version>2.6.1</commons-pool2.version>
-    </properties>
-
-    <dependencies>
-
-        <dependency>
-            <groupId>org.postgresql</groupId>
-            <artifactId>postgresql</artifactId>
-            <scope>runtime</scope>
-        </dependency>
-        <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-        </dependency>
-    </dependencies>
-
-
-</project>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+		<maven.compiler.encoding>UTF-8</maven.compiler.encoding>
+		<maven.compiler.source>1.8</maven.compiler.source>
+		<maven.compiler.target>1.8</maven.compiler.target>
+		<maven.test.skip>true</maven.test.skip>
+
+		<netty-all.version>4.1.63.Final</netty-all.version>
+		<gson.version>2.9.0</gson.version>
+
+		<spring.version>5.3.20</spring.version>
+		<spring-boot.version>2.6.7</spring-boot.version>
+
+		<mybatis-spring-boot-starter.version>2.2.2</mybatis-spring-boot-starter.version>
+		<mysql-connector-java.version>8.0.29</mysql-connector-java.version>
+
+		<slf4j-api.version>1.7.36</slf4j-api.version>
+		<junit.version>5.8.2</junit.version>
+		<javax.annotation-api.version>1.3.2</javax.annotation-api.version>
+
+		<groovy.version>3.0.10</groovy.version>
+
+		<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
+		<maven-javadoc-plugin.version>3.2.0</maven-javadoc-plugin.version>
+		<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
+		<maven-war-plugin.version>3.3.1</maven-war-plugin.version>
+	</properties>
+
+	<build>
+		<plugins>
+		</plugins>
+	</build>
+
+
+	<licenses>
+		<license>
+			<name>GNU General Public License version 3</name>
+			<url>https://opensource.org/licenses/GPL-3.0</url>
+		</license>
+	</licenses>
+
+	<scm>
+		<tag>master</tag>
+		<url>https://github.com/xuxueli/xxl-job.git</url>
+		<connection>scm:git:https://github.com/xuxueli/xxl-job.git</connection>
+		<developerConnection>scm:git:git@github.com:xuxueli/xxl-job.git</developerConnection>
+	</scm>
+	<developers>
+		<developer>
+			<id>XXL</id>
+			<name>xuxueli</name>
+			<email>931591021@qq.com</email>
+			<url>https://github.com/xuxueli</url>
+		</developer>
+	</developers>
+
+	<profiles>
+
+		<profile>
+			<id>release</id>
+			<build>
+				<plugins>
+					<!-- Source -->
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-source-plugin</artifactId>
+						<version>${maven-source-plugin.version}</version>
+						<executions>
+							<execution>
+								<phase>package</phase>
+								<goals>
+									<goal>jar-no-fork</goal>
+								</goals>
+							</execution>
+						</executions>
+					</plugin>
+					<!-- Javadoc -->
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-javadoc-plugin</artifactId>
+						<version>${maven-javadoc-plugin.version}</version>
+						<executions>
+							<execution>
+								<phase>package</phase>
+								<goals>
+									<goal>jar</goal>
+								</goals>
+								<configuration>
+									<doclint>none</doclint>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+					<!-- GPG -->
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-gpg-plugin</artifactId>
+                        <version>${maven-gpg-plugin.version}</version>
+						<configuration>
+							<useAgent>false</useAgent>
+						</configuration>
+                        <executions>
+                            <execution>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>sign</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+				</plugins>
+			</build>
+			<distributionManagement>
+				<snapshotRepository>
+					<id>oss</id>
+					<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+				</snapshotRepository>
+				<repository>
+					<id>oss</id>
+					<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+				</repository>
+			</distributionManagement>
+		</profile>
+	</profiles>
+
+</project>

+ 0 - 96
xxl-job-admin-pg/pom.xml

@@ -1,96 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>xxl-job-pg</artifactId>
-        <groupId>org.poem</groupId>
-        <version>2.2.0</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>xxl-job-admin-pg</artifactId>
-
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-dependencies</artifactId>
-                <version>${spring-boot.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.postgresql</groupId>
-                <artifactId>postgresql</artifactId>
-                <version>42.2.5</version>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
-
-
-
-    <dependencies>
-
-        <!-- starter-web:spring-webmvc + autoconfigure + logback + yaml + tomcat -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
-        <!-- starter-test:junit + spring-test + mockito -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-test</artifactId>
-            <scope>test</scope>
-        </dependency>
-
-        <!-- freemarker-starter -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-freemarker</artifactId>
-        </dependency>
-
-        <!-- mail-starter -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-mail</artifactId>
-        </dependency>
-
-        <!-- starter-actuator -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-actuator</artifactId>
-        </dependency>
-
-        <!-- mybatis-starter:mybatis + mybatis-spring + hikari(default) -->
-        <dependency>
-            <groupId>org.mybatis.spring.boot</groupId>
-            <artifactId>mybatis-spring-boot-starter</artifactId>
-            <version>${mybatis-spring-boot-starter.version}</version>
-        </dependency>
-        <!-- postgresql -->
-        <dependency>
-            <groupId>org.postgresql</groupId>
-            <artifactId>postgresql</artifactId>
-        </dependency>
-
-        <!-- xxl-job-core -->
-        <dependency>
-            <groupId>org.poem</groupId>
-            <artifactId>xxl-job-core-pg</artifactId>
-            <version>2.2.0</version>
-            <scope>compile</scope>
-        </dependency>
-
-
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-            </plugin>
-        </plugins>
-    </build>
-</project>

+ 0 - 47
xxl-job-admin-pg/src/main/java/org/poem/config/JacksonMapper.java

@@ -1,47 +0,0 @@
-package org.poem.config;
-
-/**
- * @author Administrator
- */
-
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
-import org.poem.config.jackson.BeanSerializerModifier;
-
-import java.time.LocalDateTime;
-import java.util.TimeZone;
-
-/**
- * 返回Long转换为String
- *
- * @author sangfor
- */
-public class JacksonMapper extends ObjectMapper {
-
-    public JacksonMapper() {
-        super();
-        this.configure(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN, true);
-        this.configure(JsonGenerator.Feature.IGNORE_UNKNOWN, true);
-        this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
-        this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
-        this.setTimeZone(TimeZone.getTimeZone("GMT+8"));
-        SimpleModule simpleModule = new SimpleModule();
-        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
-        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
-        simpleModule.addSerializer(long.class, ToStringSerializer.instance);
-        //添加LocalDateTime序列化及反序列化,返回前端以及接收前端时间字符串时不必手动转化
-        simpleModule.addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE);
-        simpleModule.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);
-        // 为mapper注册一个带有SerializerModifier的Factory,此modifier主要做的事情为:当序列化类型为array,list、set时,当值为空时,序列化成[]
-        simpleModule.setSerializerModifier(new BeanSerializerModifier());
-
-        registerModule(simpleModule);
-
-    }
-}

+ 0 - 60
xxl-job-admin-pg/src/main/java/org/poem/config/jackson/BeanSerializerModifier.java

@@ -1,60 +0,0 @@
-package org.poem.config.jackson;
-
-
-import com.fasterxml.jackson.databind.BeanDescription;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializationConfig;
-import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * @author Administrator
- */
-public class BeanSerializerModifier extends com.fasterxml.jackson.databind.ser.BeanSerializerModifier {
-
-    /**
-     * 数组类型
-     */
-    private JsonSerializer _nullArrayJsonSerializer = new NullArrayJsonSerializer();
-    /**
-     * 字符串等类型
-     */
-    private JsonSerializer _nullJsonSerializer = new NullJsonSerializer();
-
-    /**
-     * @param config
-     * @param beanDesc
-     * @param beanProperties
-     * @return
-     */
-    @Override
-    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
-                                                     List<BeanPropertyWriter> beanProperties) {
-        //循环所有的beanPropertyWriter
-        for (int i = 0; i < beanProperties.size(); i++) {
-            BeanPropertyWriter writer = (BeanPropertyWriter) beanProperties.get(i);
-            //判断字段的类型,如果是array,list,set则注册nullSerializer
-            if (isArrayType(writer)) {
-                //给writer注册一个自己的nullSerializer
-                writer.assignNullSerializer(this._nullArrayJsonSerializer);
-            } else {
-                writer.assignNullSerializer(this._nullJsonSerializer);
-            }
-        }
-        return beanProperties;
-    }
-
-    /**
-     * 判断是什么类型
-     *
-     * @param writer
-     * @return
-     */
-    protected boolean isArrayType(BeanPropertyWriter writer) {
-        Class clazz = writer.getPropertyType();
-        return clazz.isArray() || clazz.equals(List.class) || clazz.equals(Set.class);
-    }
-
-}

+ 0 - 24
xxl-job-admin-pg/src/main/java/org/poem/config/jackson/NullArrayJsonSerializer.java

@@ -1,24 +0,0 @@
-package org.poem.config.jackson;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import java.io.IOException;
-
-/**
- * 处理数组类型的null值
- *
- * @author Administrator
- */
-public class NullArrayJsonSerializer extends JsonSerializer {
-
-    @Override
-    public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
-        if (value == null) {
-            jgen.writeStartArray();
-            jgen.writeEndArray();
-        }
-    }
-}

+ 0 - 22
xxl-job-admin-pg/src/main/java/org/poem/config/jackson/NullJsonSerializer.java

@@ -1,22 +0,0 @@
-package org.poem.config.jackson;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-
-import java.io.IOException;
-
-/**
- * 处理字符串等类型的null值
- *
- * @author Administrator
- */
-public class NullJsonSerializer extends JsonSerializer {
-
-    @Override
-    public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
-            throws IOException, JsonProcessingException {
-       jsonGenerator.writeNull();;
-    }
-}

+ 0 - 69
xxl-job-admin-pg/src/main/java/org/poem/controller/interceptor/WebMvcConfig.java

@@ -1,69 +0,0 @@
-package org.poem.controller.interceptor;
-
-import org.poem.config.JacksonMapper;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.converter.HttpMessageConverter;
-import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-import javax.annotation.Resource;
-import java.util.List;
-
-/**
- * web mvc config
- *
- * @author xuxueli 2018-04-02 20:48:20
- */
-@Configuration
-public class WebMvcConfig implements WebMvcConfigurer {
-
-    @Resource
-    private PermissionInterceptor permissionInterceptor;
-    @Resource
-    private CookieInterceptor cookieInterceptor;
-    @Autowired
-    private HttpMessageConverters httpMessageConverters;
-
-    @Override
-    public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
-        registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
-    }
-
-
-    /**
-     * 跨域支持
-     *
-     * @param registry
-     */
-    @Override
-    public void addCorsMappings(CorsRegistry registry) {
-        registry.addMapping("/**")
-                .allowedOrigins("*")
-                .allowCredentials(true)
-                .maxAge(180)
-                .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS");
-    }
-
-    /**
-     * MappingJackson2HttpMessageConverter 实现了HttpMessageConverter 接口,
-     * httpMessageConverters.getConverters() 返回的对象里包含了MappingJackson2HttpMessageConverter
-     *
-     * @return
-     */
-    @Bean
-    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {
-        return new MappingJackson2HttpMessageConverter(new JacksonMapper());
-    }
-
-
-    @Override
-    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
-        converters.addAll(httpMessageConverters.getConverters());
-    }
-}

+ 0 - 95
xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobLosedMonitorHelper.java

@@ -1,95 +0,0 @@
-package org.poem.core.thread;
-
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.model.XxlJobLog;
-import org.poem.core.util.I18nUtil;
-import org.poem.biz.model.ReturnT;
-import org.poem.util.DateUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Date;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * job lose-monitor instance
- *
- * @author xuxueli 2015-9-1 18:05:56
- */
-public class JobLosedMonitorHelper {
-	private static Logger logger = LoggerFactory.getLogger(JobLosedMonitorHelper.class);
-	
-	private static JobLosedMonitorHelper instance = new JobLosedMonitorHelper();
-	public static JobLosedMonitorHelper getInstance(){
-		return instance;
-	}
-
-	// ---------------------- monitor ----------------------
-
-	private Thread monitorThread;
-	private volatile boolean toStop = false;
-	public void start(){
-		monitorThread = new Thread(new Runnable() {
-
-			@Override
-			public void run() {
-
-				// monitor
-				while (!toStop) {
-					try {
-						// 任务结果丢失处理:调度记录停留在 "运行中" 状态超过10min,且对应执行器心跳注册失败不在线,则将本地调度主动标记失败;
-						Date losedTime = DateUtil.addMinutes(new Date(), -10);
-						List<Long> losedJobIds  = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findLostJobIds(losedTime);
-
-						if (losedJobIds!=null && losedJobIds.size()>0) {
-							for (Long logId: losedJobIds) {
-
-								XxlJobLog jobLog = new XxlJobLog();
-								jobLog.setId(Math.toIntExact(logId));
-
-								jobLog.setHandleTime(new Date());
-								jobLog.setHandleCode(ReturnT.FAIL_CODE);
-								jobLog.setHandleMsg( I18nUtil.getString("joblog_lost_fail") );
-
-								XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateHandleInfo(jobLog);
-							}
-
-						}
-					} catch (Exception e) {
-						if (!toStop) {
-							logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);
-						}
-					}
-
-                    try {
-                        TimeUnit.SECONDS.sleep(60);
-                    } catch (Exception e) {
-                        if (!toStop) {
-                            logger.error(e.getMessage(), e);
-                        }
-                    }
-
-                }
-
-				logger.info(">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop");
-
-			}
-		});
-		monitorThread.setDaemon(true);
-		monitorThread.setName("xxl-job, admin JobLosedMonitorHelper");
-		monitorThread.start();
-	}
-
-	public void toStop(){
-		toStop = true;
-		// interrupt and wait
-		monitorThread.interrupt();
-		try {
-			monitorThread.join();
-		} catch (InterruptedException e) {
-			logger.error(e.getMessage(), e);
-		}
-	}
-
-}

+ 0 - 112
xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobRegistryMonitorHelper.java

@@ -1,112 +0,0 @@
-package org.poem.core.thread;
-
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.model.XxlJobGroup;
-import org.poem.core.model.XxlJobRegistry;
-import org.poem.enums.RegistryConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-
-/**
- * job registry instance
- * @author xuxueli 2016-10-02 19:10:24
- */
-public class JobRegistryMonitorHelper {
-	private static Logger logger = LoggerFactory.getLogger(JobRegistryMonitorHelper.class);
-
-	private static JobRegistryMonitorHelper instance = new JobRegistryMonitorHelper();
-	public static JobRegistryMonitorHelper getInstance(){
-		return instance;
-	}
-
-	private Thread registryThread;
-	private volatile boolean toStop = false;
-	public void start(){
-		registryThread = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				while (!toStop) {
-					try {
-						// auto registry group
-						List<XxlJobGroup> groupList = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0);
-						if (groupList!=null && !groupList.isEmpty()) {
-
-							// remove dead address (admin/executor)
-							List<Integer> ids = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findDead(RegistryConfig.DEAD_TIMEOUT, new Date());
-							if (ids!=null && ids.size()>0) {
-								XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(ids);
-							}
-
-							// fresh online address (admin/executor)
-							HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
-							List<XxlJobRegistry> list = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
-							if (list != null) {
-								for (XxlJobRegistry item: list) {
-									if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
-										String appname = item.getRegistryKey();
-										List<String> registryList = appAddressMap.get(appname);
-										if (registryList == null) {
-											registryList = new ArrayList<String>();
-										}
-
-										if (!registryList.contains(item.getRegistryValue())) {
-											registryList.add(item.getRegistryValue());
-										}
-										appAddressMap.put(appname, registryList);
-									}
-								}
-							}
-
-							// fresh group address
-							for (XxlJobGroup group: groupList) {
-								List<String> registryList = appAddressMap.get(group.getAppname());
-								String addressListStr = null;
-								if (registryList!=null && !registryList.isEmpty()) {
-									Collections.sort(registryList);
-									StringBuilder addressListSB = new StringBuilder();
-									for (String item:registryList) {
-										addressListSB.append(item).append(",");
-									}
-									addressListStr = addressListSB.toString();
-									addressListStr = addressListStr.substring(0, addressListStr.length()-1);
-								}
-								group.setAddressList(addressListStr);
-								XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().update(group);
-							}
-						}
-					} catch (Exception e) {
-						if (!toStop) {
-							logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
-						}
-					}
-					try {
-						TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
-					} catch (InterruptedException e) {
-						if (!toStop) {
-							logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
-						}
-					}
-				}
-				logger.info(">>>>>>>>>>> xxl-job, job registry monitor thread stop");
-			}
-		});
-		registryThread.setDaemon(true);
-		registryThread.setName("xxl-job, admin JobRegistryMonitorHelper");
-		registryThread.start();
-	}
-
-	public void toStop(){
-		toStop = true;
-		// interrupt and wait
-		registryThread.interrupt();
-		try {
-			registryThread.join();
-		} catch (InterruptedException e) {
-			logger.error(e.getMessage(), e);
-		}
-	}
-
-}

+ 0 - 176
xxl-job-admin-pg/src/main/java/org/poem/service/impl/AdminBizImpl.java

@@ -1,176 +0,0 @@
-package org.poem.service.impl;
-
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLog;
-import org.poem.core.thread.JobTriggerPoolHelper;
-import org.poem.core.trigger.TriggerTypeEnum;
-import org.poem.core.util.I18nUtil;
-import org.poem.dao.XxlJobGroupDao;
-import org.poem.dao.XxlJobInfoDao;
-import org.poem.dao.XxlJobLogDao;
-import org.poem.dao.XxlJobRegistryDao;
-import org.poem.biz.AdminBiz;
-import org.poem.biz.model.HandleCallbackParam;
-import org.poem.biz.model.RegistryParam;
-import org.poem.biz.model.ReturnT;
-import org.poem.handler.IJobHandler;
-import org.poem.util.SnowFlake;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
-
-import javax.annotation.Resource;
-import java.text.MessageFormat;
-import java.util.Date;
-import java.util.List;
-
-/**
- * @author xuxueli 2017-07-27 21:54:20
- */
-@Service
-public class AdminBizImpl implements AdminBiz {
-    private static Logger logger = LoggerFactory.getLogger(AdminBizImpl.class);
-
-    @Resource
-    public XxlJobLogDao xxlJobLogDao;
-    @Resource
-    private XxlJobInfoDao xxlJobInfoDao;
-    @Resource
-    private XxlJobRegistryDao xxlJobRegistryDao;
-    @Resource
-    private XxlJobGroupDao xxlJobGroupDao;
-
-
-    @Override
-    public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {
-        for (HandleCallbackParam handleCallbackParam: callbackParamList) {
-            ReturnT<String> callbackResult = callback(handleCallbackParam);
-            logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
-                    (callbackResult.getCode()==IJobHandler.SUCCESS.getCode()?"success":"fail"), handleCallbackParam, callbackResult);
-        }
-
-        return ReturnT.SUCCESS;
-    }
-
-    private ReturnT<String> callback(HandleCallbackParam handleCallbackParam) {
-        // valid log item
-        XxlJobLog log = xxlJobLogDao.load(handleCallbackParam.getLogId());
-        if (log == null) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found.");
-        }
-        if (log.getHandleCode() > 0) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, "log repeate callback.");     // avoid repeat callback, trigger child job etc
-        }
-
-        // trigger success, to trigger child job
-        String callbackMsg = null;
-        if (IJobHandler.SUCCESS.getCode() == handleCallbackParam.getExecuteResult().getCode()) {
-            XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(log.getJobId());
-            if (xxlJobInfo!=null && xxlJobInfo.getChildJobId()!=null && xxlJobInfo.getChildJobId().trim().length()>0) {
-                callbackMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";
-
-                String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
-                for (int i = 0; i < childJobIds.length; i++) {
-                    Long childJobId = (childJobIds[i]!=null && childJobIds[i].trim().length()>0 && isNumeric(childJobIds[i]))?Long.parseLong(childJobIds[i]):-1;
-                    if (childJobId > 0) {
-
-                        JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null);
-                        ReturnT<String> triggerChildResult = ReturnT.SUCCESS;
-
-                        // add msg
-                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
-                                (i+1),
-                                childJobIds.length,
-                                childJobIds[i],
-                                (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")),
-                                triggerChildResult.getMsg());
-                    } else {
-                        callbackMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
-                                (i+1),
-                                childJobIds.length,
-                                childJobIds[i]);
-                    }
-                }
-
-            }
-        }
-
-        // handle msg
-        StringBuffer handleMsg = new StringBuffer();
-        if (log.getHandleMsg()!=null) {
-            handleMsg.append(log.getHandleMsg()).append("<br>");
-        }
-        if (handleCallbackParam.getExecuteResult().getMsg() != null) {
-            handleMsg.append(handleCallbackParam.getExecuteResult().getMsg());
-        }
-        if (callbackMsg != null) {
-            handleMsg.append(callbackMsg);
-        }
-
-        if (handleMsg.length() > 15000) {
-            handleMsg = new StringBuffer(handleMsg.substring(0, 15000));  // text最大64kb 避免长度过长
-        }
-
-        // success, save log
-        log.setHandleTime(new Date());
-        log.setHandleCode(handleCallbackParam.getExecuteResult().getCode());
-        log.setHandleMsg(handleMsg.toString());
-        xxlJobLogDao.updateHandleInfo(log);
-
-        return ReturnT.SUCCESS;
-    }
-
-    private boolean isNumeric(String str){
-        try {
-            int result = Integer.valueOf(str);
-            return true;
-        } catch (NumberFormatException e) {
-            return false;
-        }
-    }
-
-    @Override
-    public ReturnT<String> registry(RegistryParam registryParam) {
-
-        // valid
-        if (!StringUtils.hasText(registryParam.getRegistryGroup())
-                || !StringUtils.hasText(registryParam.getRegistryKey())
-                || !StringUtils.hasText(registryParam.getRegistryValue())) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
-        }
-
-        int ret = xxlJobRegistryDao.registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
-        if (ret < 1) {
-            xxlJobRegistryDao.registrySave((int) SnowFlake.genLongId(), registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
-
-            // fresh
-            freshGroupRegistryInfo(registryParam);
-        }
-        return ReturnT.SUCCESS;
-    }
-
-    @Override
-    public ReturnT<String> registryRemove(RegistryParam registryParam) {
-
-        // valid
-        if (!StringUtils.hasText(registryParam.getRegistryGroup())
-                || !StringUtils.hasText(registryParam.getRegistryKey())
-                || !StringUtils.hasText(registryParam.getRegistryValue())) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
-        }
-
-        int ret = xxlJobRegistryDao.registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
-        if (ret > 0) {
-
-            // fresh
-            freshGroupRegistryInfo(registryParam);
-        }
-        return ReturnT.SUCCESS;
-    }
-
-    private void freshGroupRegistryInfo(RegistryParam registryParam){
-        // Under consideration, prevent affecting core tables
-    }
-
-}

Разлика између датотеке није приказан због своје велике величине
+ 0 - 4
xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css.map


Разлика између датотеке није приказан због своје велике величине
+ 0 - 5
xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/bootstrap/js/bootstrap.min.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 1
xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/jquery/jquery.min.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
xxl-job-admin-pg/src/main/resources/static/adminlte/bower_components/moment/moment.min.js


Разлика између датотеке није приказан због своје велике величине
+ 0 - 6
xxl-job-admin-pg/src/main/resources/static/adminlte/dist/css/AdminLTE.min.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 0
xxl-job-admin-pg/src/main/resources/static/adminlte/dist/css/skins/_all-skins.min.css


Разлика између датотеке није приказан због своје велике величине
+ 0 - 13
xxl-job-admin-pg/src/main/resources/static/adminlte/dist/js/adminlte.min.js


+ 0 - 42
xxl-job-admin-pg/src/main/resources/templates/common/common.exception.ftl

@@ -1,42 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <meta charset="UTF-8">
-    <title>Error</title>
-    <style type="text/css">
-        body {
-            background-color: #fff;
-            color: #666;
-            text-align: center;
-            font-family: arial, sans-serif;
-        }
-
-        div.dialog {
-            width: 80%;
-            padding: 1em 4em;
-            margin: 4em auto 0 auto;
-            border: 1px solid #ccc;
-            border-right-color: #999;
-            border-bottom-color: #999;
-        }
-
-        h1 {
-            font-size: 100%;
-            color: #f00;
-            line-height: 1.5em;
-        }
-    </style>
-
-</head>
-</head>
-<body>
-
-<div class="dialog">
-    <h1>System Error</h1>
-    <p>${exceptionMsg}</p>
-    <a href="javascript:window.location.href='${request.contextPath}/'">Back</a>
-    </p>
-</div>
-
-</body>
-</html>

+ 0 - 251
xxl-job-admin-pg/src/main/resources/templates/common/common.macro.ftl

@@ -1,251 +0,0 @@
-<#macro commonStyle>
-
-<#-- favicon -->
-    <link rel="icon" href="${request.contextPath}/static/favicon.ico"/>
-
-    <meta charset="utf-8">
-    <meta http-equiv="X-UA-Compatible" content="IE=edge">
-    <!-- Tell the browser to be responsive to screen width -->
-    <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
-    <!-- Bootstrap -->
-    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/bower_components/bootstrap/css/bootstrap.min.css">
-    <!-- Font Awesome -->
-    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/bower_components/font-awesome/css/font-awesome.min.css">
-    <!-- Ionicons -->
-    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/bower_components/Ionicons/css/ionicons.min.css">
-    <!-- Theme style -->
-    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/AdminLTE.min.css">
-    <!-- AdminLTE Skins. Choose a skin from the css/skins folder instead of downloading all of them to reduce the load. -->
-    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/dist/css/skins/_all-skins.min.css">
-
-    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
-    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
-    <!--[if lt IE 9]>
-    <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
-    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
-    <![endif]-->
-
-    <!-- pace -->
-    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/bower_components/PACE/themes/blue/pace-theme-flash.css">
-
-<#-- i18n -->
-    <#global I18n = I18nUtil.getMultString()?eval />
-
-</#macro>
-
-<#macro commonScript>
-    <!-- jQuery 2.1.4 -->
-    <script src="${request.contextPath}/static/adminlte/bower_components/jquery/jquery.min.js"></script>
-    <!-- Bootstrap 3.3.5 -->
-    <script src="${request.contextPath}/static/adminlte/bower_components/bootstrap/js/bootstrap.min.js"></script>
-    <!-- FastClick -->
-    <script src="${request.contextPath}/static/adminlte/bower_components/fastclick/fastclick.js"></script>
-    <!-- AdminLTE App -->
-    <script src="${request.contextPath}/static/adminlte/dist/js/adminlte.min.js"></script>
-    <!-- jquery.slimscroll -->
-    <script src="${request.contextPath}/static/adminlte/bower_components/jquery-slimscroll/jquery.slimscroll.min.js"></script>
-
-    <!-- pace -->
-    <script src="${request.contextPath}/static/adminlte/bower_components/PACE/pace.min.js"></script>
-<#-- jquery cookie -->
-    <script src="${request.contextPath}/static/plugins/jquery/jquery.cookie.js"></script>
-<#-- jquery.validate -->
-    <script src="${request.contextPath}/static/plugins/jquery/jquery.validate.min.js"></script>
-
-<#-- layer -->
-    <script src="${request.contextPath}/static/plugins/layer/layer.js"></script>
-
-<#-- common -->
-    <script src="${request.contextPath}/static/js/common.1.js"></script>
-    <script>
-        var base_url = '${request.contextPath}';
-        var I18n = ${I18nUtil.getMultString()};
-    </script>
-
-</#macro>
-
-<#macro commonHeader>
-    <header class="main-header">
-        <a href="${request.contextPath}/" class="logo">
-            <span class="logo-mini"><b>XXL</b></span>
-            <span class="logo-lg"><b>${I18n.admin_name}</b></span>
-        </a>
-        <nav class="navbar navbar-static-top" role="navigation">
-
-            <a href="#" class="sidebar-toggle" data-toggle="push-menu" role="button">
-                <span class="sr-only">Toggle navigation</span>
-                <span class="icon-bar"></span>
-                <span class="icon-bar"></span>
-                <span class="icon-bar"></span>
-            </a>
-
-            <div class="navbar-custom-menu">
-                <ul class="nav navbar-nav">
-                    <#-- login user -->
-                    <li class="dropdown">
-                        <a href="javascript:" class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
-                            ${I18n.system_welcome} ${Request["XXL_JOB_LOGIN_IDENTITY"].username}
-                            <span class="caret"></span>
-                        </a>
-                        <ul class="dropdown-menu" role="menu">
-                            <li id="updatePwd"><a href="javascript:">${I18n.change_pwd}</a></li>
-                            <li id="logoutBtn"><a href="javascript:">${I18n.logout_btn}</a></li>
-                        </ul>
-                    </li>
-                </ul>
-            </div>
-
-        </nav>
-    </header>
-
-    <!-- 修改密码.模态框 -->
-    <div class="modal fade" id="updatePwdModal" tabindex="-1" role="dialog" aria-hidden="true">
-        <div class="modal-dialog ">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h4 class="modal-title">${I18n.change_pwd}</h4>
-                </div>
-                <div class="modal-body">
-                    <form class="form-horizontal form" role="form">
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">${I18n.change_pwd_field_newpwd}<font
-                                        color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="password"
-                                                          placeholder="${I18n.system_please_input} ${I18n.change_pwd_field_newpwd}"
-                                                          maxlength="18"></div>
-                        </div>
-                        <hr>
-                        <div class="form-group">
-                            <div class="col-sm-offset-3 col-sm-6">
-                                <button type="submit" style="border-radius:10px" class="btn btn-primary">${I18n.system_save}</button>
-                                <button type="button" style="border-radius:10px" class="btn btn-default"
-                                        data-dismiss="modal">${I18n.system_cancel}</button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-
-</#macro>
-
-<#macro commonLeft pageName >
-    <!-- Left side column. contains the logo and sidebar -->
-    <aside class="main-sidebar">
-        <!-- sidebar: style can be found in sidebar.less -->
-        <section class="sidebar">
-            <!-- sidebar menu: : style can be found in sidebar.less -->
-            <ul class="sidebar-menu">
-                <li class="header">${I18n.system_nav}</li>
-                <li class="nav-click <#if pageName == "index">active</#if>"><a href="${request.contextPath}/"><i
-                                class="fa fa-circle-o text-aqua"></i><span>${I18n.job_dashboard_name}</span></a></li>
-                <li class="nav-click <#if pageName == "jobinfo">active</#if>"><a
-                            href="${request.contextPath}/jobinfo"><i
-                                class="fa fa-circle-o text-yellow"></i><span>${I18n.jobinfo_name}</span></a></li>
-                <li class="nav-click <#if pageName == "joblog">active</#if>"><a href="${request.contextPath}/joblog"><i
-                                class="fa fa-circle-o text-green"></i><span>${I18n.joblog_name}</span></a></li>
-                <#if Request["XXL_JOB_LOGIN_IDENTITY"].role == 1>
-                    <li class="nav-click <#if pageName == "jobgroup">active</#if>"><a
-                                href="${request.contextPath}/jobgroup"><i
-                                    class="fa fa-circle-o text-red"></i><span>${I18n.jobgroup_name}</span></a></li>
-                    <li class="nav-click <#if pageName == "user">active</#if>"><a href="${request.contextPath}/user"><i
-                                    class="fa fa-circle-o text-purple"></i><span>${I18n.user_manage}</span></a></li>
-                </#if>
-                <li class="nav-click <#if pageName == "help">active</#if>"><a href="${request.contextPath}/help"><i
-                                class="fa fa-circle-o text-gray"></i><span>${I18n.job_help}</span></a></li>
-            </ul>
-        </section>
-        <!-- /.sidebar -->
-    </aside>
-</#macro>
-
-<#macro commonControl >
-    <!-- Control Sidebar -->
-    <aside class="control-sidebar control-sidebar-dark">
-        <!-- Create the tabs -->
-        <ul class="nav nav-tabs nav-justified control-sidebar-tabs">
-            <li class="active"><a href="#control-sidebar-home-tab" data-toggle="tab"><i class="fa fa-home"></i></a></li>
-            <li><a href="#control-sidebar-settings-tab" data-toggle="tab"><i class="fa fa-gears"></i></a></li>
-        </ul>
-        <!-- Tab panes -->
-        <div class="tab-content">
-            <!-- Home tab content -->
-            <div class="tab-pane active" id="control-sidebar-home-tab">
-                <h3 class="control-sidebar-heading">近期活动</h3>
-                <ul class="control-sidebar-menu">
-                    <li>
-                        <a href="javascript::;">
-                            <i class="menu-icon fa fa-birthday-cake bg-red"></i>
-                            <div class="menu-info">
-                                <h4 class="control-sidebar-subheading">张三今天过生日</h4>
-                                <p>2015-09-10</p>
-                            </div>
-                        </a>
-                    </li>
-                    <li>
-                        <a href="javascript::;">
-                            <i class="menu-icon fa fa-user bg-yellow"></i>
-                            <div class="menu-info">
-                                <h4 class="control-sidebar-subheading">Frodo 更新了资料</h4>
-                                <p>更新手机号码 +1(800)555-1234</p>
-                            </div>
-                        </a>
-                    </li>
-                    <li>
-                        <a href="javascript::;">
-                            <i class="menu-icon fa fa-envelope-o bg-light-blue"></i>
-                            <div class="menu-info">
-                                <h4 class="control-sidebar-subheading">Nora 加入邮件列表</h4>
-                                <p>nora@example.com</p>
-                            </div>
-                        </a>
-                    </li>
-                    <li>
-                        <a href="javascript::;">
-                            <i class="menu-icon fa fa-file-code-o bg-green"></i>
-                            <div class="menu-info">
-                                <h4 class="control-sidebar-subheading">001号定时作业调度</h4>
-                                <p>5秒前执行</p>
-                            </div>
-                        </a>
-                    </li>
-                </ul>
-                <!-- /.control-sidebar-menu -->
-            </div>
-            <!-- /.tab-pane -->
-
-            <!-- Settings tab content -->
-            <div class="tab-pane" id="control-sidebar-settings-tab">
-                <form method="post">
-                    <h3 class="control-sidebar-heading">个人设置</h3>
-                    <div class="form-group">
-                        <label class="control-sidebar-subheading"> 左侧菜单自适应
-                            <input type="checkbox" class="pull-right" checked>
-                        </label>
-                        <p>左侧菜单栏样式自适应</p>
-                    </div>
-                    <!-- /.form-group -->
-
-                </form>
-            </div>
-            <!-- /.tab-pane -->
-        </div>
-    </aside>
-    <!-- /.control-sidebar -->
-    <!-- Add the sidebar's background. This div must be placed immediately after the control sidebar -->
-    <div class="control-sidebar-bg"></div>
-</#macro>
-
-<#macro commonFooter >
-    <footer class="main-footer">
-        Powered by <b>XXL-JOB</b> ${I18n.admin_version}
-        <div class="pull-right hidden-xs">
-            <strong>Copyright &copy; 2015-${.now?string('yyyy')} &nbsp;
-                <a href="https://www.xuxueli.com/" target="_blank">xuxueli</a>
-                &nbsp;
-                <a href="https://github.com/xuxueli/xxl-job" target="_blank">github</a>
-            </strong><!-- All rights reserved. -->
-        </div>
-    </footer>
-</#macro>

+ 0 - 49
xxl-job-admin-pg/src/main/resources/templates/help.ftl

@@ -1,49 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <#import "./common/common.macro.ftl" as netCommon>
-    <@netCommon.commonStyle />
-    <title>${I18n.admin_name}</title>
-</head>
-<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && cookieMap["xxljob_adminlte_settings"]?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
-<div class="wrapper">
-    <!-- header -->
-    <@netCommon.commonHeader />
-    <!-- left -->
-    <@netCommon.commonLeft "help" />
-
-    <!-- Content Wrapper. Contains page content -->
-    <div class="content-wrapper">
-        <!-- Content Header (Page header) -->
-        <section class="content-header">
-            <h1>${I18n.job_help}</h1>
-        </section>
-
-        <!-- Main content -->
-        <section class="content">
-            <div class="callout callout-info">
-                <h4>${I18n.admin_name_full}</h4>
-                <br>
-                <p>
-                    <a target="_blank" href="https://github.com/xuxueli/xxl-job">Github</a>&nbsp;&nbsp;&nbsp;&nbsp;
-                    <iframe src="https://ghbtns.com/github-btn.html?user=xuxueli&repo=xxl-job&type=star&count=true"
-                            frameborder="0" scrolling="0" width="170px" height="20px"
-                            style="margin-bottom:-5px;"></iframe>
-                    <br><br>
-                    <a target="_blank" href="https://www.xuxueli.com/xxl-job/">${I18n.job_help_document}</a>
-                    <br><br>
-
-                </p>
-                <p></p>
-            </div>
-        </section>
-        <!-- /.content -->
-    </div>
-    <!-- /.content-wrapper -->
-
-    <!-- footer -->
-    <@netCommon.commonFooter />
-</div>
-<@netCommon.commonScript />
-</body>
-</html>

+ 0 - 175
xxl-job-admin-pg/src/main/resources/templates/jobcode/jobcode.index.ftl

@@ -1,175 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <#import "../common/common.macro.ftl" as netCommon>
-    <@netCommon.commonStyle />
-    <link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/lib/codemirror.css">
-    <link rel="stylesheet" href="${request.contextPath}/static/plugins/codemirror/addon/hint/show-hint.css">
-    <title>${I18n.admin_name}</title>
-    <style type="text/css">
-        .CodeMirror {
-            font-size: 16px;
-            width: 100%;
-            height: 100%;
-            /*bottom: 0;
-            top: 0px;*/
-            position: absolute;
-        }
-    </style>
-</head>
-<body class="skin-blue fixed layout-top-nav">
-
-<div class="wrapper">
-
-    <header class="main-header">
-        <nav class="navbar navbar-static-top">
-            <div class="container">
-                <#-- icon -->
-                <div class="navbar-header">
-                    <a class="navbar-brand"><b>Web</b>IDE</a>
-                    <button type="button" style="border-radius:10px" class="navbar-toggle collapsed" data-toggle="collapse"
-                            data-target="#navbar-collapse">
-                        <i class="fa fa-bars"></i>
-                    </button>
-                </div>
-
-                <#-- left nav -->
-                <div class="collapse navbar-collapse pull-left" id="navbar-collapse">
-                    <ul class="nav navbar-nav">
-                        <li class="active"><a href="javascript:;">
-                                <span class="sr-only">(current)</span>
-                                【<#list GlueTypeEnum as item><#if item == jobInfo.glueType>${item.desc}</#if></#list>】
-                                ${jobInfo.jobDesc}
-                            </a></li>
-                    </ul>
-                </div>
-
-                <#-- right nav -->
-                <div class="navbar-custom-menu">
-                    <ul class="nav navbar-nav">
-                        <li class="dropdown">
-                            <a href="#" class="dropdown-toggle" data-toggle="dropdown"
-                               aria-expanded="false">${I18n.jobinfo_glue_rollback} <span class="caret"></span></a>
-                            <ul class="dropdown-menu" role="menu">
-                                <li <#if jobLogGlues?exists && jobLogGlues?size gt 0 >style="display: none;"</#if> >
-                                    <a href="javascript:;" class="source_version" version="version_now"
-                                       glueType="${jobInfo.glueType}">
-                                        <#list GlueTypeEnum as item><#if item == jobInfo.glueType>${item.desc}</#if></#list>
-                                        : ${jobInfo.glueRemark}
-                                    </a>
-                                </li>
-                                <textarea id="version_now" style="display:none;">${jobInfo.glueSource}</textarea>
-                                <#if jobLogGlues?exists && jobLogGlues?size gt 0 >
-                                    <#list jobLogGlues as glue>
-                                        <li>
-                                            <a href="javascript:;" class="source_version" version="version_${glue.id}"
-                                               glueType="${glue.glueType}">
-                                                <#list GlueTypeEnum as item><#if item == glue.glueType>${item.desc}</#if></#list>
-                                                : ${glue.glueRemark}
-                                            </a>
-                                        </li>
-                                        <textarea id="version_${glue.id}"
-                                                  style="display:none;">${glue.glueSource}</textarea>
-                                    </#list>
-                                </#if>
-                            </ul>
-                        </li>
-                        <li id="save">
-                            <a href="javascript:;">
-                                <i class="fa fa-fw fa-save"></i>
-                                ${I18n.system_save}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="javascript:window.close();">
-                                <i class="fa fa-fw fa-close"></i>
-                                ${I18n.system_close}
-                            </a>
-                        </li>
-                    </ul>
-                </div>
-
-            </div>
-        </nav>
-    </header>
-
-    <div class="content-wrapper" id="ideWindow"></div>
-
-    <!-- footer -->
-    <#--<@netCommon.commonFooter />-->
-</div>
-
-<!-- 保存.模态框 -->
-<div class="modal fade" id="saveModal" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog ">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title"><i class="fa fa-fw fa-save"></i>${I18n.system_save}</h4>
-            </div>
-            <div class="modal-body">
-                <div class="form-horizontal form" role="form">
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_glue_remark}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-10"><input type="text" class="form-control" id="glueRemark"
-                                                      placeholder="${I18n.system_please_input}${I18n.jobinfo_glue_remark}"
-                                                      maxlength="64"></div>
-                    </div>
-                    <hr>
-                    <div class="form-group">
-                        <div class="col-sm-offset-3 col-sm-6">
-                            <button type="button" style="border-radius:10px" class="btn btn-primary ok">${I18n.system_save}</button>
-                            <button type="button" style="border-radius:10px" class="btn btn-default"
-                                    data-dismiss="modal">${I18n.system_cancel}</button>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-</div>
-
-<@netCommon.commonScript />
-
-
-<#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/clike/clike.js" />
-<#assign glueTypeIdeMode = "text/x-java" />
-
-<#if jobInfo.glueType == "GLUE_GROOVY" >
-    <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/clike/clike.js" />
-    <#assign glueTypeIdeMode = "text/x-java" />
-<#elseif jobInfo.glueType == "GLUE_SHELL" >
-    <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/shell/shell.js" />
-    <#assign glueTypeIdeMode = "text/x-sh" />
-<#elseif jobInfo.glueType == "GLUE_PYTHON" >
-    <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/python/python.js" />
-    <#assign glueTypeIdeMode = "text/x-python" />
-<#elseif jobInfo.glueType == "GLUE_PHP" >
-    <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/php/php.js" />
-    <#assign glueTypeIdeMode = "text/x-php" />
-    <#assign glueTypeModeSrc02 = "${request.contextPath}/static/plugins/codemirror/mode/clike/clike.js" />
-<#elseif jobInfo.glueType == "GLUE_NODEJS" >
-    <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/javascript/javascript.js" />
-    <#assign glueTypeIdeMode = "text/javascript" />
-<#elseif jobInfo.glueType == "GLUE_POWERSHELL" >
-    <#assign glueTypeModeSrc = "${request.contextPath}/static/plugins/codemirror/mode/powershell/powershell.js" />
-    <#assign glueTypeIdeMode = "powershell" />
-</#if>
-
-
-<script src="${request.contextPath}/static/plugins/codemirror/lib/codemirror.js"></script>
-<script src="${glueTypeModeSrc}"></script>
-<#if glueTypeModeSrc02?exists>
-    <script src="${glueTypeModeSrc02}"></script>
-</#if>
-<script src="${request.contextPath}/static/plugins/codemirror/addon/hint/show-hint.js"></script>
-<script src="${request.contextPath}/static/plugins/codemirror/addon/hint/anyword-hint.js"></script>
-
-<script>
-    var id = '${jobInfo.id}';
-    var ideMode = '${glueTypeIdeMode}';
-</script>
-<script src="${request.contextPath}/static/js/jobcode.index.1.js"></script>
-
-</body>
-</html>

+ 0 - 200
xxl-job-admin-pg/src/main/resources/templates/jobgroup/jobgroup.index.ftl

@@ -1,200 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <#import "../common/common.macro.ftl" as netCommon>
-    <@netCommon.commonStyle />
-    <!-- DataTables -->
-    <link rel="stylesheet"
-          href="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
-    <title>${I18n.admin_name}</title>
-</head>
-<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && cookieMap["xxljob_adminlte_settings"]?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
-<div class="wrapper">
-    <!-- header -->
-    <@netCommon.commonHeader />
-    <!-- left -->
-    <@netCommon.commonLeft "jobgroup" />
-
-    <!-- Content Wrapper. Contains page content -->
-    <div class="content-wrapper">
-        <!-- Content Header (Page header) -->
-        <section class="content-header">
-            <h1>${I18n.jobgroup_name}</h1>
-        </section>
-
-        <!-- Main content -->
-        <section class="content">
-
-            <div class="row">
-                <div class="col-xs-3">
-                    <div class="input-group">
-                        <span class="input-group-addon">AppName</span>
-                        <input type="text" class="form-control" id="appname" autocomplete="on"
-                               placeholder="${I18n.system_please_input}AppName">
-                    </div>
-                </div>
-                <div class="col-xs-3">
-                    <div class="input-group">
-                        <span class="input-group-addon">${I18n.jobgroup_field_title}</span>
-                        <input type="text" class="form-control" id="title" autocomplete="on"
-                               placeholder="${I18n.jobgroup_field_title}">
-                    </div>
-                </div>
-                <div class="col-xs-2">
-                    <button class="btn btn-block btn-info" style="border-radius:10px" id="searchBtn">${I18n.system_search}</button>
-                </div>
-                <div class="col-xs-2">
-                    <button class="btn btn-block btn-success add" style="border-radius:10px" type="button">${I18n.jobinfo_field_add}</button>
-                </div>
-            </div>
-
-            <div class="row">
-                <div class="col-xs-12"  style="margin-top: 20px">
-                    <div class="box">
-                        <div class="box-body">
-                            <table id="jobgroup_list" class="table table-bordered table-striped display" width="100%">
-                                <thead>
-                                <tr>
-                                    <th name="id">ID</th>
-                                    <th name="appname">AppName</th>
-                                    <th name="title">${I18n.jobgroup_field_title}</th>
-                                    <th name="addressType">${I18n.jobgroup_field_addressType}</th>
-                                    <th name="registryList">OnLine ${I18n.jobgroup_field_registryList}</th>
-                                    <th>${I18n.system_opt}</th>
-                                </tr>
-                                </thead>
-                                <tbody>
-                                </tbody>
-                            </table>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </section>
-    </div>
-
-    <!-- 新增.模态框 -->
-    <div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-hidden="true">
-        <div class="modal-dialog ">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h4 class="modal-title">${I18n.jobgroup_add}</h4>
-                </div>
-                <div class="modal-body">
-                    <form class="form-horizontal form" role="form">
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">AppName<font
-                                        color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="appname"
-                                                          placeholder="${I18n.system_please_input}AppName"
-                                                          maxlength="64"></div>
-                        </div>
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font
-                                        color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="title"
-                                                          placeholder="${I18n.system_please_input}${I18n.jobgroup_field_title}"
-                                                          maxlength="12"></div>
-                        </div>
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_addressType}<font
-                                        color="red">*</font></label>
-                            <div class="col-sm-10">
-                                <input type="radio" name="addressType" value="0"
-                                       checked/>${I18n.jobgroup_field_addressType_0}
-                                &nbsp;&nbsp;&nbsp;&nbsp;
-                                <input type="radio" name="addressType" value="1"/>${I18n.jobgroup_field_addressType_1}
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_registryList}
-                                <font color="red">*</font></label>
-                            <div class="col-sm-10">
-                                <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: 15px; border: 1px solid #dddddd; padding: 5px;"></textarea>
-                            </div>
-                        </div>
-                        <hr>
-                        <div class="form-group">
-                            <div class="col-sm-offset-3 col-sm-6">
-                                <button type="submit" class="btn btn-primary" style="border-radius:10px" >${I18n.system_save}</button>
-                                <button type="button" class="btn btn-default" style="border-radius:10px"
-                                        data-dismiss="modal">${I18n.system_cancel}</button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-
-    <!-- 更新.模态框 -->
-    <div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-hidden="true">
-        <div class="modal-dialog ">
-            <div class="modal-content">
-                <div class="modal-header">
-                    <h4 class="modal-title">${I18n.jobgroup_edit}</h4>
-                </div>
-                <div class="modal-body">
-                    <form class="form-horizontal form" role="form">
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">AppName<font
-                                        color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="appname"
-                                                          placeholder="${I18n.system_please_input}AppName"
-                                                          maxlength="64"></div>
-                        </div>
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_title}<font
-                                        color="red">*</font></label>
-                            <div class="col-sm-10"><input type="text" class="form-control" name="title"
-                                                          placeholder="${I18n.system_please_input}${I18n.jobgroup_field_title}"
-                                                          maxlength="12"></div>
-                        </div>
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_addressType}<font
-                                        color="red">*</font></label>
-                            <div class="col-sm-10">
-                                <input type="radio" name="addressType" value="0"/>${I18n.jobgroup_field_addressType_0}
-                                &nbsp;&nbsp;&nbsp;&nbsp;
-                                <input type="radio" name="addressType" value="1"/>${I18n.jobgroup_field_addressType_1}
-                            </div>
-                        </div>
-                        <div class="form-group">
-                            <label for="lastname" class="col-sm-2 control-label">${I18n.jobgroup_field_registryList}
-                                <font color="red">*</font></label>
-                            <div class="col-sm-10">
-                                <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: 15px; border: 1px solid #dddddd; padding: 5px;"></textarea>
-                            </div>
-                        </div>
-                        <hr>
-                        <div class="form-group">
-                            <div class="col-sm-offset-3 col-sm-6">
-                                <button style="border-radius:10px" style="border-radius:10px" type="submit" class="btn btn-primary">${I18n.system_save}</button>
-                                <button type="button" class="btn btn-default"
-                                        data-dismiss="modal">${I18n.system_cancel}</button>
-                                <input type="hidden" name="id">
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
-
-    <!-- footer -->
-    <@netCommon.commonFooter />
-</div>
-
-<@netCommon.commonScript />
-<!-- DataTables -->
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
-<script src="${request.contextPath}/static/js/jobgroup.index.1.js"></script>
-</body>
-</html>

+ 0 - 521
xxl-job-admin-pg/src/main/resources/templates/jobinfo/jobinfo.index.ftl

@@ -1,521 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <#import "../common/common.macro.ftl" as netCommon>
-    <@netCommon.commonStyle />
-    <!-- DataTables -->
-    <link rel="stylesheet"
-          href="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
-    <title>${I18n.admin_name}</title>
-</head>
-<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && cookieMap["xxljob_adminlte_settings"]?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if>">
-<div class="wrapper">
-    <!-- header -->
-    <@netCommon.commonHeader />
-    <!-- left -->
-    <@netCommon.commonLeft "jobinfo" />
-
-    <!-- Content Wrapper. Contains page content -->
-    <div class="content-wrapper">
-        <!-- Content Header (Page header) -->
-        <section class="content-header">
-            <h1>${I18n.jobinfo_name}</h1>
-        </section>
-
-        <!-- Main content -->
-        <section class="content">
-
-            <div class="row">
-                <div class="col-xs-3">
-                    <div class="input-group">
-                        <span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
-                        <select class="form-control" id="jobGroup">
-                            <#list JobGroupList as group>
-                                <option value="${group.id}"
-                                        <#if jobGroup==group.id>selected</#if> >${group.title}</option>
-                            </#list>
-                        </select>
-                    </div>
-                </div>
-                <div class="col-xs-1">
-                    <div class="input-group">
-                        <select class="form-control" id="triggerStatus">
-                            <option value="-1">${I18n.system_all}</option>
-                            <option value="0">${I18n.jobinfo_opt_stop}</option>
-                            <option value="1">${I18n.jobinfo_opt_start}</option>
-                        </select>
-                    </div>
-                </div>
-                <div class="col-xs-2">
-                    <div class="input-group">
-                        <input type="text" class="form-control" id="jobDesc" autocomplete="on"
-                               placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}">
-                    </div>
-                </div>
-                <div class="col-xs-2">
-                    <div class="input-group">
-                        <input type="text" class="form-control" id="executorHandler" autocomplete="on"
-                               placeholder="${I18n.system_please_input}JobHandler">
-                    </div>
-                </div>
-                <div class="col-xs-2">
-                    <div class="input-group">
-                        <input type="text" class="form-control" id="author" autocomplete="on"
-                               placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}">
-                    </div>
-                </div>
-                <div class="col-xs-1">
-                    <button class="btn btn-block btn-info" style="border-radius:10px" id="searchBtn">${I18n.system_search}</button>
-                </div>
-                <div class="col-xs-1">
-                    <button class="btn btn-block btn-success add" type="button" style="border-radius:10px" >${I18n.jobinfo_field_add}</button>
-                </div>
-            </div>
-
-            <div class="row">
-                <div class="col-xs-12" style="margin-top: 20px">
-                    <div class="box">
-                        <#--<div class="box-header hide">
-                            <h3 class="box-title">调度列表</h3>
-                        </div>-->
-                        <div class="box-body">
-                            <table id="job_list" class="table table-bordered table-striped" width="100%">
-                                <thead>
-                                <tr>
-                                    <th name="id">${I18n.jobinfo_field_id}</th>
-                                    <th name="jobGroup">${I18n.jobinfo_field_jobgroup}</th>
-                                    <th name="jobDesc">${I18n.jobinfo_field_jobdesc}</th>
-                                    <th name="glueType">${I18n.jobinfo_field_gluetype}</th>
-                                    <th name="executorParam">${I18n.jobinfo_field_executorparam}</th>
-                                    <th name="jobCron">Cron</th>
-                                    <th name="addTime">addTime</th>
-                                    <th name="updateTime">updateTime</th>
-                                    <th name="author">${I18n.jobinfo_field_author}</th>
-                                    <th name="alarmEmail">${I18n.jobinfo_field_alarmemail}</th>
-                                    <th name="triggerStatus">${I18n.system_status}</th>
-                                    <th>${I18n.system_opt}</th>
-                                </tr>
-                                </thead>
-                                <tbody></tbody>
-                                <tfoot></tfoot>
-                            </table>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </section>
-    </div>
-
-    <!-- footer -->
-    <@netCommon.commonFooter />
-</div>
-
-<!-- job新增.模态框 -->
-<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog modal-lg">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">${I18n.jobinfo_field_add}</h4>
-            </div>
-            <div class="modal-body">
-                <form class="form-horizontal form" role="form">
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control" name="jobGroup">
-                                <#list JobGroupList as group>
-                                    <option value="${group.id}"
-                                            <#if jobGroup==group.id>selected</#if> >${group.title}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc"
-                                                     placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}"
-                                                     maxlength="50"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname"
-                               class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control" name="executorRouteStrategy">
-                                <#list ExecutorRouteStrategyEnum as item>
-                                    <option value="${item}">${item.title}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron"
-                                                     placeholder="${I18n.system_please_input}Cron" maxlength="128">
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control glueType" name="glueType">
-                                <#list GlueTypeEnum as item>
-                                    <option value="${item}">${item.desc}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="firstname" class="col-sm-2 control-label">JobHandler<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler"
-                                                     placeholder="${I18n.system_please_input}JobHandler"
-                                                     maxlength="100"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname"
-                               class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control" name="executorBlockStrategy">
-                                <#list ExecutorBlockStrategyEnum as item>
-                                    <option value="${item}">${item.title}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId"
-                                                     placeholder="${I18n.jobinfo_field_childJobId_placeholder}"
-                                                     maxlength="100"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout"
-                                                     placeholder="${I18n.jobinfo_field_executorTimeout_placeholder}"
-                                                     maxlength="6"></div>
-                        <label for="lastname"
-                               class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailRetryCount}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorFailRetryCount"
-                                                     placeholder="${I18n.jobinfo_field_executorFailRetryCount_placeholder}"
-                                                     maxlength="4"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author"
-                                                     placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}"
-                                                     maxlength="50"></div>
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail"
-                                                     placeholder="${I18n.jobinfo_field_alarmemail_placeholder}"
-                                                     maxlength="100"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-10">
-                            <textarea class="textarea form-control" name="executorParam"
-                                      placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}"
-                                      maxlength="512" style="height: 63px; line-height: 1.2;"></textarea>
-                        </div>
-                    </div>
-
-                    <hr>
-                    <div class="form-group">
-                        <div class="col-sm-offset-3 col-sm-6">
-                            <button type="submit" style="border-radius:10px" class="btn btn-primary">${I18n.system_save}</button>
-                            <button type="button" style="border-radius:10px" class="btn btn-default"
-                                    data-dismiss="modal">${I18n.system_cancel}</button>
-                        </div>
-                    </div>
-
-                    <input type="hidden" name="glueRemark" value="GLUE代码初始化">
-                    <textarea name="glueSource" style="display:none;"></textarea>
-                    <textarea class="glueSource_java" style="display:none;">
-package com.xxl.job.service.handler;
-
-import com.xxl.job.core.log.XxlJobLogger;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.handler.IJobHandler;
-
-public class DemoGlueJobHandler extends IJobHandler {
-
-	@Override
-	public ReturnT<String> execute(String param) throws Exception {
-		XxlJobLogger.log("XXL-JOB, Hello World.");
-		return ReturnT.SUCCESS;
-	}
-
-}
-</textarea>
-                    <textarea class="glueSource_shell" style="display:none;">
-#!/bin/bash
-echo "xxl-job: hello shell"
-
-echo "${I18n.jobinfo_script_location}:$0"
-echo "${I18n.jobinfo_field_executorparam}:$1"
-echo "${I18n.jobinfo_shard_index} = $2"
-echo "${I18n.jobinfo_shard_total} = $3"
-<#--echo "参数数量:$#"
-for param in $*
-do
-    echo "参数 : $param"
-    sleep 1s
-done-->
-
-echo "Good bye!"
-exit 0
-</textarea>
-                    <textarea class="glueSource_python" style="display:none;">
-#!/usr/bin/python
-# -*- coding: UTF-8 -*-
-import time
-import sys
-
-print "xxl-job: hello python"
-
-print "${I18n.jobinfo_script_location}:", sys.argv[0]
-print "${I18n.jobinfo_field_executorparam}:", sys.argv[1]
-print "${I18n.jobinfo_shard_index}:", sys.argv[2]
-print "${I18n.jobinfo_shard_total}:", sys.argv[3]
-<#--for i in range(1, len(sys.argv)):
-	time.sleep(1)
-	print "参数", i, sys.argv[i]-->
-
-print "Good bye!"
-exit(0)
-<#--
-import logging
-logging.basicConfig(level=logging.DEBUG)
-logging.info("脚本文件:" + sys.argv[0])
--->
-</textarea>
-                    <#--这里有问题,新建一个运行模式为 php 的任务后,GLUE 中没有下边的 php 代码-->
-                    <textarea class="glueSource_php" style="display:none;">
-<?php
-
-    echo "xxl-job: hello php  \n";
-
-    echo "${I18n.jobinfo_script_location}:$argv[0]  \n";
-    echo "${I18n.jobinfo_field_executorparam}:$argv[1]  \n";
-    echo "${I18n.jobinfo_shard_index} = $argv[2]  \n";
-    echo "${I18n.jobinfo_shard_total} = $argv[3]  \n";
-
-    echo "Good bye!  \n";
-    exit(0);
-
-?>
-</textarea>
-                    <textarea class="glueSource_nodejs" style="display:none;">
-#!/usr/bin/env node
-console.log("xxl-job: hello nodejs")
-
-var arguments = process.argv
-
-console.log("${I18n.jobinfo_script_location}: " + arguments[1])
-console.log("${I18n.jobinfo_field_executorparam}: " + arguments[2])
-console.log("${I18n.jobinfo_shard_index}: " + arguments[3])
-console.log("${I18n.jobinfo_shard_total}: " + arguments[4])
-<#--for (var i = 2; i < arguments.length; i++){
-	console.log("参数 %s = %s", (i-1), arguments[i]);
-}-->
-
-console.log("Good bye!")
-process.exit(0)
-</textarea>
-                    <textarea class="glueSource_powershell" style="display:none;">
-Write-Host "xxl-job: hello powershell"
-
-Write-Host "${I18n.jobinfo_script_location}: " $MyInvocation.MyCommand.Definition
-Write-Host "${I18n.jobinfo_field_executorparam}: "
-	if ($args.Count -gt 2) { $args[0..($args.Count-3)] }
-Write-Host "${I18n.jobinfo_shard_index}: " $args[$args.Count-2]
-Write-Host "${I18n.jobinfo_shard_total}: " $args[$args.Count-1]
-
-Write-Host "Good bye!"
-exit 0
-</textarea>
-                </form>
-            </div>
-        </div>
-    </div>
-</div>
-
-<!-- 更新.模态框 -->
-<div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog modal-lg">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">${I18n.jobinfo_field_update}</h4>
-            </div>
-            <div class="modal-body">
-                <form class="form-horizontal form" role="form">
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobgroup}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control" name="jobGroup">
-                                <#list JobGroupList as group>
-                                    <option value="${group.id}">${group.title}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_jobdesc}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobDesc"
-                                                     placeholder="${I18n.system_please_input}${I18n.jobinfo_field_jobdesc}"
-                                                     maxlength="50"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname"
-                               class="col-sm-2 control-label">${I18n.jobinfo_field_executorRouteStrategy}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control" name="executorRouteStrategy">
-                                <#list ExecutorRouteStrategyEnum as item>
-                                    <option value="${item}">${item.title}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="lastname" class="col-sm-2 control-label">Cron<font color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="jobCron"
-                                                     placeholder="${I18n.system_please_input}Cron" maxlength="128">
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_gluetype}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control glueType" name="glueType" disabled>
-                                <#list GlueTypeEnum as item>
-                                    <option value="${item}">${item.desc}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="firstname" class="col-sm-2 control-label">JobHandler<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorHandler"
-                                                     placeholder="${I18n.system_please_input}JobHandler"
-                                                     maxlength="100"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname"
-                               class="col-sm-2 control-label">${I18n.jobinfo_field_executorBlockStrategy}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4">
-                            <select class="form-control" name="executorBlockStrategy">
-                                <#list ExecutorBlockStrategyEnum as item>
-                                    <option value="${item}">${item.title}</option>
-                                </#list>
-                            </select>
-                        </div>
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_childJobId}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="childJobId"
-                                                     placeholder="${I18n.jobinfo_field_childJobId_placeholder}"
-                                                     maxlength="100"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_timeout}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorTimeout"
-                                                     placeholder="${I18n.jobinfo_field_executorTimeout_placeholder}"
-                                                     maxlength="6"></div>
-                        <label for="lastname"
-                               class="col-sm-2 control-label">${I18n.jobinfo_field_executorFailRetryCount}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="executorFailRetryCount"
-                                                     placeholder="${I18n.jobinfo_field_executorFailRetryCount_placeholder}"
-                                                     maxlength="4"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_author}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="author"
-                                                     placeholder="${I18n.system_please_input}${I18n.jobinfo_field_author}"
-                                                     maxlength="50"></div>
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.jobinfo_field_alarmemail}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-4"><input type="text" class="form-control" name="alarmEmail"
-                                                     placeholder="${I18n.jobinfo_field_alarmemail_placeholder}"
-                                                     maxlength="100"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-10">
-                            <textarea class="textarea form-control" name="executorParam"
-                                      placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}"
-                                      maxlength="512" style="height: 63px; line-height: 1.2;"></textarea>
-                        </div>
-                    </div>
-
-                    <hr>
-                    <div class="form-group">
-                        <div class="col-sm-offset-3 col-sm-6">
-                            <button type="submit"style="border-radius:10px"  class="btn btn-primary">${I18n.system_save}</button>
-                            <button type="button" style="border-radius:10px" class="btn btn-default"
-                                    data-dismiss="modal">${I18n.system_cancel}</button>
-                            <input type="hidden" name="id">
-                        </div>
-                    </div>
-
-                </form>
-            </div>
-        </div>
-    </div>
-</div>
-
-<#-- trigger -->
-<div class="modal fade" id="jobTriggerModal" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog ">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">${I18n.jobinfo_opt_run}</h4>
-            </div>
-            <div class="modal-body">
-                <form class="form-horizontal form" role="form">
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobinfo_field_executorparam}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-10">
-                            <textarea class="textarea form-control" name="executorParam"
-                                      placeholder="${I18n.system_please_input}${I18n.jobinfo_field_executorparam}"
-                                      maxlength="512" style="height: 63px; line-height: 1.2;"></textarea>
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <label for="firstname" class="col-sm-2 control-label">${I18n.jobgroup_field_registryList}<font
-                                    color="black">*</font></label>
-                        <div class="col-sm-10">
-                            <textarea class="textarea form-control" name="addressList"
-                                      placeholder="${I18n.jobinfo_opt_run_tips}" maxlength="512"
-                                      style="height: 63px; line-height: 1.2;"></textarea>
-                        </div>
-                    </div>
-                    <hr>
-                    <div class="form-group">
-                        <div class="col-sm-offset-3 col-sm-6">
-                            <button type="button" style="border-radius:10px" class="btn btn-primary ok">${I18n.system_save}</button>
-                            <button type="button" style="border-radius:10px" class="btn btn-default"
-                                    data-dismiss="modal">${I18n.system_cancel}</button>
-                            <input type="hidden" name="id">
-                        </div>
-                    </div>
-                </form>
-            </div>
-        </div>
-    </div>
-</div>
-
-<@netCommon.commonScript />
-<!-- DataTables -->
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
-<!-- moment -->
-<script src="${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js"></script>
-<#-- cronGen -->
-<script src="${request.contextPath}/static/plugins/cronGen/cronGen<#if I18n.admin_i18n?default('')?length gt 0 >_${I18n.admin_i18n}</#if>.js"></script>
-<script src="${request.contextPath}/static/js/jobinfo.index.1.js"></script>
-</body>
-</html>

+ 0 - 184
xxl-job-admin-pg/src/main/resources/templates/joblog/joblog.index.ftl

@@ -1,184 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <#import "../common/common.macro.ftl" as netCommon>
-    <@netCommon.commonStyle />
-    <!-- DataTables -->
-    <link rel="stylesheet"
-          href="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
-    <!-- daterangepicker -->
-    <link rel="stylesheet"
-          href="${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.css">
-    <title>${I18n.admin_name}</title>
-</head>
-<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && cookieMap["xxljob_adminlte_settings"]?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if> ">
-<div class="wrapper">
-    <!-- header -->
-    <@netCommon.commonHeader />
-    <!-- left -->
-    <@netCommon.commonLeft "joblog" />
-
-    <!-- Content Wrapper. Contains page content -->
-    <div class="content-wrapper">
-        <!-- Content Header (Page header) -->
-        <section class="content-header">
-            <h1>${I18n.joblog_name}</h1>
-        </section>
-
-        <!-- Main content -->
-        <section class="content">
-            <div class="row">
-                <div class="col-xs-2">
-                    <div class="input-group">
-                        <span class="input-group-addon">${I18n.jobinfo_field_jobgroup}</span>
-                        <select class="form-control" id="jobGroup"
-                                paramVal="<#if jobInfo?exists>${jobInfo.jobGroup}</#if>">
-                            <#if Request["XXL_JOB_LOGIN_IDENTITY"].role == 1>
-                                <option value="0">${I18n.system_all}</option>  <#-- 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup -->
-                            </#if>
-                            <#list JobGroupList as group>
-                                <option value="${group.id}">${group.title}</option>
-                            </#list>
-                        </select>
-                    </div>
-                </div>
-                <div class="col-xs-2">
-                    <div class="input-group">
-                        <span class="input-group-addon">${I18n.jobinfo_job}</span>
-                        <select class="form-control" id="jobId" paramVal="<#if jobInfo?exists>${jobInfo.id}</#if>">
-                            <option value="0">${I18n.system_all}</option>
-                        </select>
-                    </div>
-                </div>
-
-                <div class="col-xs-2">
-                    <div class="input-group">
-                        <span class="input-group-addon">${I18n.joblog_status}</span>
-                        <select class="form-control" id="logStatus">
-                            <option value="-1">${I18n.joblog_status_all}</option>
-                            <option value="1">${I18n.joblog_status_suc}</option>
-                            <option value="2">${I18n.joblog_status_fail}</option>
-                            <option value="3">${I18n.joblog_status_running}</option>
-                        </select>
-                    </div>
-                </div>
-
-                <div class="col-xs-4">
-                    <div class="input-group">
-                		<span class="input-group-addon">
-	                  		${I18n.joblog_field_triggerTime}
-	                	</span>
-                        <input type="text" class="form-control" id="filterTime" readonly>
-                    </div>
-                </div>
-
-                <div class="col-xs-1">
-                    <button style="border-radius:10px" class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
-                </div>
-
-                <div class="col-xs-1">
-                    <button style="border-radius:10px" class="btn btn-block btn-nomal" id="clearLog">${I18n.joblog_clean}</button>
-                </div>
-            </div>
-
-            <div class="row">
-                <div class="col-xs-12"  style="margin-top: 20px">
-                    <div class="box">
-                        <#--<div class="box-header hide"><h3 class="box-title">调度日志</h3></div>-->
-                        <div class="box-body">
-                            <table id="joblog_list" class="table table-bordered table-striped display" width="100%">
-                                <thead>
-                                <tr>
-                                    <th name="jobId">${I18n.jobinfo_field_id}</th>
-                                    <th name="jobGroup">jobGroup</th>
-                                    <#--<th name="executorAddress" >执行器地址</th>
-                                    <th name="glueType" >运行模式</th>
-                                      <th name="executorParam" >任务参数</th>-->
-                                    <th name="triggerTime">${I18n.joblog_field_triggerTime}</th>
-                                    <th name="triggerCode">${I18n.joblog_field_triggerCode}</th>
-                                    <th name="triggerMsg">${I18n.joblog_field_triggerMsg}</th>
-                                    <th name="handleTime">${I18n.joblog_field_handleTime}</th>
-                                    <th name="handleCode">${I18n.joblog_field_handleCode}</th>
-                                    <th name="handleMsg">${I18n.joblog_field_handleMsg}</th>
-                                    <th name="handleMsg">${I18n.system_opt}</th>
-                                </tr>
-                                </thead>
-                                <tbody></tbody>
-                            </table>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </section>
-    </div>
-
-    <!-- footer -->
-    <@netCommon.commonFooter />
-</div>
-
-<!-- 日志清理.模态框 -->
-<div class="modal fade" id="clearLogModal" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">${I18n.joblog_clean_log}</h4>
-            </div>
-            <div class="modal-body">
-                <form class="form-horizontal form" role="form">
-                    <div class="form-group">
-                        <label class="col-sm-3 control-label"">${I18n.jobinfo_field_jobgroup}:</label>
-                        <div class="col-sm-9">
-                            <input type="text" class="form-control jobGroupText" readonly>
-                            <input type="hidden" name="jobGroup">
-                        </div>
-                    </div>
-
-                    <div class="form-group">
-                        <label class="col-sm-3 control-label"">${I18n.jobinfo_job}:</label>
-                        <div class="col-sm-9">
-                            <input type="text" class="form-control jobIdText" readonly>
-                            <input type="hidden" name="jobId">
-                        </div>
-                    </div>
-
-                    <div class="form-group">
-                        <label class="col-sm-3 control-label"">${I18n.joblog_clean_type}:</label>
-                        <div class="col-sm-9">
-                            <select class="form-control" name="type">
-                                <option value="1">${I18n.joblog_clean_type_1}</option>
-                                <option value="2">${I18n.joblog_clean_type_2}</option>
-                                <option value="3">${I18n.joblog_clean_type_3}</option>
-                                <option value="4">${I18n.joblog_clean_type_4}</option>
-                                <option value="5">${I18n.joblog_clean_type_5}</option>
-                                <option value="6">${I18n.joblog_clean_type_6}</option>
-                                <option value="7">${I18n.joblog_clean_type_7}</option>
-                                <option value="8">${I18n.joblog_clean_type_8}</option>
-                                <option value="9">${I18n.joblog_clean_type_9}</option>
-                            </select>
-                        </div>
-                    </div>
-
-                    <hr>
-                    <div class="form-group">
-                        <div class="col-sm-offset-3 col-sm-6">
-                            <button style="border-radius:10px" type="button" class="btn btn-primary ok">${I18n.system_ok}</button>
-                            <button style="border-radius:10px" type="button" class="btn btn-default"
-                                    data-dismiss="modal">${I18n.system_cancel}</button>
-                        </div>
-                    </div>
-                </form>
-            </div>
-        </div>
-    </div>
-</div>
-
-<@netCommon.commonScript />
-<!-- DataTables -->
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
-<!-- daterangepicker -->
-<script src="${request.contextPath}/static/adminlte/bower_components/moment/moment.min.js"></script>
-<script src="${request.contextPath}/static/adminlte/bower_components/bootstrap-daterangepicker/daterangepicker.js"></script>
-<script src="${request.contextPath}/static/js/joblog.index.1.js"></script>
-</body>
-</html>

+ 0 - 47
xxl-job-admin-pg/src/main/resources/templates/login.ftl

@@ -1,47 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <#import "./common/common.macro.ftl" as netCommon>
-    <@netCommon.commonStyle />
-    <link rel="stylesheet" href="${request.contextPath}/static/adminlte/plugins/iCheck/square/blue.css">
-    <title>${I18n.admin_name}</title>
-</head>
-<body class="hold-transition login-page">
-<div class="login-box">
-    <div class="login-logo">
-        <a><b>XXL</b>JOB</a>
-    </div>
-    <form id="loginForm" method="post">
-        <div class="login-box-body">
-            <p class="login-box-msg">${I18n.admin_name}</p>
-            <div class="form-group has-feedback">
-                <input type="text" name="userName" class="form-control" placeholder="${I18n.login_username_placeholder}"
-                       maxlength="18">
-                <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
-            </div>
-            <div class="form-group has-feedback">
-                <input type="password" name="password" class="form-control"
-                       placeholder="${I18n.login_password_placeholder}" maxlength="18">
-                <span class="glyphicon glyphicon-lock form-control-feedback"></span>
-            </div>
-            <div class="row">
-                <div class="col-xs-8">
-                    <div class="checkbox icheck">
-                        <label>
-                            <input type="checkbox" name="ifRemember"> &nbsp; ${I18n.login_remember_me}
-                        </label>
-                    </div>
-                </div><!-- /.col -->
-                <div class="col-xs-4">
-                    <button style="border-radius:10px" type="submit" class="btn btn-primary btn-block btn-flat">${I18n.login_btn}</button>
-                </div>
-            </div>
-        </div>
-    </form>
-</div>
-<@netCommon.commonScript />
-<script src="${request.contextPath}/static/adminlte/plugins/iCheck/icheck.min.js"></script>
-<script src="${request.contextPath}/static/js/login.1.js"></script>
-
-</body>
-</html>

+ 0 - 205
xxl-job-admin-pg/src/main/resources/templates/user/user.index.ftl

@@ -1,205 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <#import "../common/common.macro.ftl" as netCommon>
-    <@netCommon.commonStyle />
-    <!-- DataTables -->
-    <link rel="stylesheet"
-          href="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/css/dataTables.bootstrap.min.css">
-    <title>${I18n.admin_name}</title>
-</head>
-<body class="hold-transition skin-blue sidebar-mini <#if cookieMap?exists && cookieMap["xxljob_adminlte_settings"]?exists && "off" == cookieMap["xxljob_adminlte_settings"].value >sidebar-collapse</#if>">
-<div class="wrapper">
-    <!-- header -->
-    <@netCommon.commonHeader />
-    <!-- left -->
-    <@netCommon.commonLeft "user" />
-
-    <!-- Content Wrapper. Contains page content -->
-    <div class="content-wrapper">
-        <!-- Content Header (Page header) -->
-        <section class="content-header">
-            <h1>${I18n.user_manage}</h1>
-        </section>
-
-        <!-- Main content -->
-        <section class="content">
-
-            <div class="row">
-                <div class="col-xs-3">
-                    <div class="input-group">
-                        <span class="input-group-addon">${I18n.user_role}</span>
-                        <select class="form-control" id="role">
-                            <option value="-1">${I18n.system_all}</option>
-                            <option value="1">${I18n.user_role_admin}</option>
-                            <option value="0">${I18n.user_role_normal}</option>
-                        </select>
-                    </div>
-                </div>
-                <div class="col-xs-3">
-                    <div class="input-group">
-                        <span class="input-group-addon">${I18n.user_username}</span>
-                        <input type="text" class="form-control" id="username" autocomplete="on">
-                    </div>
-                </div>
-                <div class="col-xs-1">
-                    <button style="border-radius:10px" class="btn btn-block btn-info" id="searchBtn">${I18n.system_search}</button>
-                </div>
-                <div class="col-xs-2">
-                    <button style="border-radius:10px" class="btn btn-block btn-success add" type="button">${I18n.user_add}</button>
-                </div>
-            </div>
-
-            <div class="row">
-                <div class="col-xs-12"  style="margin-top: 20px">
-                    <div class="box">
-                        <div class="box-body">
-                            <table id="user_list" class="table table-bordered table-striped" width="100%">
-                                <thead>
-                                <tr>
-                                    <th name="id">ID</th>
-                                    <th name="username">${I18n.user_username}</th>
-                                    <th name="password">${I18n.user_password}</th>
-                                    <th name="role">${I18n.user_role}</th>
-                                    <th name="permission">${I18n.user_permission}</th>
-                                    <th>${I18n.system_opt}</th>
-                                </tr>
-                                </thead>
-                                <tbody></tbody>
-                                <tfoot></tfoot>
-                            </table>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </section>
-    </div>
-
-    <!-- footer -->
-    <@netCommon.commonFooter />
-</div>
-
-<!-- 新增.模态框 -->
-<div class="modal fade" id="addModal" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">${I18n.user_add}</h4>
-            </div>
-            <div class="modal-body">
-                <form class="form-horizontal form" role="form">
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_username}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-8"><input type="text" class="form-control" name="username"
-                                                     placeholder="${I18n.system_please_input}${I18n.user_username}"
-                                                     maxlength="20"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_password}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-8"><input type="text" class="form-control" name="password"
-                                                     placeholder="${I18n.system_please_input}${I18n.user_password}"
-                                                     maxlength="20"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_role}<font color="red">*</font></label>
-                        <div class="col-sm-10">
-                            <input type="radio" name="role" value="0" checked/>${I18n.user_role_normal}
-                            &nbsp;&nbsp;&nbsp;&nbsp;
-                            <input type="radio" name="role" value="1"/>${I18n.user_role_admin}
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_permission}<font color="black">*</font></label>
-                        <div class="col-sm-10">
-                            <#if groupList?exists && groupList?size gt 0>
-                                <#list groupList as item>
-                                    <input type="checkbox" name="permission"
-                                           value="${item.id}" />${item.title}(${item.appname})<br>
-                                </#list>
-                            </#if>
-                        </div>
-                    </div>
-
-                    <hr>
-                    <div class="form-group">
-                        <div class="col-sm-offset-3 col-sm-6">
-                            <button style="border-radius:10px" type="submit" class="btn btn-primary">${I18n.system_save}</button>
-                            <button style="border-radius:10px" type="button" class="btn btn-default"
-                                    data-dismiss="modal">${I18n.system_cancel}</button>
-                        </div>
-                    </div>
-
-                </form>
-            </div>
-        </div>
-    </div>
-</div>
-
-<!-- 更新.模态框 -->
-<div class="modal fade" id="updateModal" tabindex="-1" role="dialog" aria-hidden="true">
-    <div class="modal-dialog">
-        <div class="modal-content">
-            <div class="modal-header">
-                <h4 class="modal-title">${I18n.user_update}</h4>
-            </div>
-            <div class="modal-body">
-                <form class="form-horizontal form" role="form">
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_username}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-8"><input type="text" class="form-control" name="username"
-                                                     placeholder="${I18n.system_please_input}${I18n.user_username}"
-                                                     maxlength="20" readonly></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_password}<font
-                                    color="red">*</font></label>
-                        <div class="col-sm-8"><input type="text" class="form-control" name="password"
-                                                     placeholder="${I18n.user_password_update_placeholder}"
-                                                     maxlength="20"></div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_role}<font color="red">*</font></label>
-                        <div class="col-sm-10">
-                            <input type="radio" name="role" value="0"/>${I18n.user_role_normal}
-                            &nbsp;&nbsp;&nbsp;&nbsp;
-                            <input type="radio" name="role" value="1"/>${I18n.user_role_admin}
-                        </div>
-                    </div>
-                    <div class="form-group">
-                        <label for="lastname" class="col-sm-2 control-label">${I18n.user_permission}<font color="black">*</font></label>
-                        <div class="col-sm-10">
-                            <#if groupList?exists && groupList?size gt 0>
-                                <#list groupList as item>
-                                    <input type="checkbox" name="permission"
-                                           value="${item.id}" />${item.title}(${item.appname})<br>
-                                </#list>
-                            </#if>
-                        </div>
-                    </div>
-
-                    <hr>
-                    <div class="form-group">
-                        <div class="col-sm-offset-3 col-sm-6">
-                            <button style="border-radius:10px" type="submit" class="btn btn-primary">${I18n.system_save}</button>
-                            <button style="border-radius:10px" type="button" class="btn btn-default"
-                                    data-dismiss="modal">${I18n.system_cancel}</button>
-                            <input type="hidden" name="id">
-                        </div>
-                    </div>
-
-                </form>
-            </div>
-        </div>
-    </div>
-</div>
-
-<@netCommon.commonScript />
-<!-- DataTables -->
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net/js/jquery.dataTables.min.js"></script>
-<script src="${request.contextPath}/static/adminlte/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js"></script>
-<script src="${request.contextPath}/static/js/user.index.1.js"></script>
-</body>
-</html>

+ 1 - 0
xxl-job-admin/.gitignore

@@ -0,0 +1 @@
+target/

+ 11 - 0
xxl-job-admin/Dockerfile

@@ -0,0 +1,11 @@
+FROM heliang230/centos:7.5.1804
+MAINTAINER xuxueli
+
+ENV PARAMS=""
+
+ENV TZ=PRC
+RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
+
+ADD target/xxl-job-admin-*.jar /app.jar
+
+ENTRYPOINT ["sh","-c","java -jar $JAVA_OPTS /app.jar $PARAMS  --spring.profiles.active=pro"]

+ 116 - 0
xxl-job-admin/pom.xml

@@ -0,0 +1,116 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>com.xuxueli</groupId>
+		<artifactId>xxl-job</artifactId>
+		<version>2.3.0</version>
+	</parent>
+	<artifactId>xxl-job-admin</artifactId>
+	<packaging>jar</packaging>
+
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-starter-parent</artifactId>
+				<version>${spring-boot.version}</version>
+				<type>pom</type>
+				<scope>import</scope>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+
+	<dependencies>
+
+		<!-- starter-web:spring-webmvc + autoconfigure + logback + yaml + tomcat -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		<!-- starter-test:junit + spring-test + mockito -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+		<!-- freemarker-starter -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-freemarker</artifactId>
+		</dependency>
+
+		<!-- mail-starter -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-mail</artifactId>
+		</dependency>
+
+		<!-- starter-actuator -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-actuator</artifactId>
+		</dependency>
+
+		<!-- mybatis-starter:mybatis + mybatis-spring + hikari(default) -->
+		<dependency>
+			<groupId>org.mybatis.spring.boot</groupId>
+			<artifactId>mybatis-spring-boot-starter</artifactId>
+			<version>${mybatis-spring-boot-starter.version}</version>
+		</dependency>
+		<!-- mysql -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>${mysql-connector-java.version}</version>
+		</dependency>
+
+		<!-- xxl-job-core -->
+		<dependency>
+			<groupId>com.xuxueli</groupId>
+			<artifactId>xxl-job-core</artifactId>
+			<version>${project.parent.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.postgresql</groupId>
+			<artifactId>postgresql</artifactId>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<version>${spring-boot.version}</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>repackage</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<!-- docker -->
+			<plugin>
+				<groupId>com.spotify</groupId>
+				<artifactId>docker-maven-plugin</artifactId>
+				<version>0.4.13</version>
+				<configuration>
+					<!-- made of '[a-z0-9-_.]' -->
+					<imageName>${project.artifactId}:${project.version}</imageName>
+					<dockerDirectory>${project.basedir}</dockerDirectory>
+					<resources>
+						<resource>
+							<targetPath>/</targetPath>
+							<directory>${project.build.directory}</directory>
+							<include>${project.build.finalName}.jar</include>
+						</resource>
+					</resources>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+</project>

+ 3 - 3
xxl-job-admin-pg/src/main/java/org/poem/XxlJobAdminApplication.java → xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java

@@ -1,4 +1,4 @@
-package org.poem;
+package com.xxl.job.admin;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -9,8 +9,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
 @SpringBootApplication
 public class XxlJobAdminApplication {
 
-    public static void main(String[] args) {
+	public static void main(String[] args) {
         SpringApplication.run(XxlJobAdminApplication.class, args);
-    }
+	}
 
 }

+ 8 - 8
xxl-job-admin-pg/src/main/java/org/poem/controller/IndexController.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java

@@ -1,9 +1,9 @@
-package org.poem.controller;
+package com.xxl.job.admin.controller;
 
-import org.poem.controller.annotation.PermissionLimit;
-import org.poem.service.LoginService;
-import org.poem.service.XxlJobService;
-import org.poem.biz.model.ReturnT;
+import com.xxl.job.admin.controller.annotation.PermissionLimit;
+import com.xxl.job.admin.service.LoginService;
+import com.xxl.job.admin.service.XxlJobService;
+import com.xxl.job.core.biz.model.ReturnT;
 import org.springframework.beans.propertyeditors.CustomDateEditor;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
@@ -53,7 +53,7 @@ public class IndexController {
 	
 	@RequestMapping("/toLogin")
 	@PermissionLimit(limit=false)
-	public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {
+	public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response,ModelAndView modelAndView) {
 		if (loginService.ifLogin(request, response) != null) {
 			modelAndView.setView(new RedirectView("/",true,false));
 			return modelAndView;
@@ -61,7 +61,7 @@ public class IndexController {
 		return new ModelAndView("login");
 	}
 	
-	@RequestMapping(value="login", method= RequestMethod.POST)
+	@RequestMapping(value="login", method=RequestMethod.POST)
 	@ResponseBody
 	@PermissionLimit(limit=false)
 	public ReturnT<String> loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember){
@@ -69,7 +69,7 @@ public class IndexController {
 		return loginService.login(request, response, userName, password, ifRem);
 	}
 	
-	@RequestMapping(value="logout", method= RequestMethod.POST)
+	@RequestMapping(value="logout", method=RequestMethod.POST)
 	@ResponseBody
 	@PermissionLimit(limit=false)
 	public ReturnT<String> logout(HttpServletRequest request, HttpServletResponse response){

+ 20 - 23
xxl-job-admin-pg/src/main/java/org/poem/controller/JobApiController.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java

@@ -1,13 +1,13 @@
-package org.poem.controller;
+package com.xxl.job.admin.controller;
 
-import org.poem.controller.annotation.PermissionLimit;
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.biz.AdminBiz;
-import org.poem.biz.model.HandleCallbackParam;
-import org.poem.biz.model.RegistryParam;
-import org.poem.biz.model.ReturnT;
-import org.poem.util.GsonTool;
-import org.poem.util.XxlJobRemotingUtil;
+import com.xxl.job.admin.controller.annotation.PermissionLimit;
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.core.biz.AdminBiz;
+import com.xxl.job.core.biz.model.HandleCallbackParam;
+import com.xxl.job.core.biz.model.RegistryParam;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.util.GsonTool;
+import com.xxl.job.core.util.XxlJobRemotingUtil;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -54,20 +54,17 @@ public class JobApiController {
         }
 
         // services mapping
-        switch (uri) {
-            case "callback":
-                List<HandleCallbackParam> callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);
-                return adminBiz.callback(callbackParamList);
-            case "registry": {
-                RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
-                return adminBiz.registry(registryParam);
-            }
-            case "registryRemove": {
-                RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
-                return adminBiz.registryRemove(registryParam);
-            }
-            default:
-                return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");
+        if ("callback".equals(uri)) {
+            List<HandleCallbackParam> callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);
+            return adminBiz.callback(callbackParamList);
+        } else if ("registry".equals(uri)) {
+            RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
+            return adminBiz.registry(registryParam);
+        } else if ("registryRemove".equals(uri)) {
+            RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
+            return adminBiz.registryRemove(registryParam);
+        } else {
+            return new ReturnT<String>(ReturnT.FAIL_CODE, "invalid request, uri-mapping("+ uri +") not found.");
         }
 
     }

+ 10 - 12
xxl-job-admin-pg/src/main/java/org/poem/controller/JobCodeController.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java

@@ -1,13 +1,12 @@
-package org.poem.controller;
+package com.xxl.job.admin.controller;
 
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLogGlue;
-import org.poem.core.util.I18nUtil;
-import org.poem.dao.XxlJobInfoDao;
-import org.poem.dao.XxlJobLogGlueDao;
-import org.poem.biz.model.ReturnT;
-import org.poem.glue.GlueTypeEnum;
-import org.poem.util.SnowFlake;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLogGlue;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.admin.dao.XxlJobInfoDao;
+import com.xxl.job.admin.dao.XxlJobLogGlueDao;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.glue.GlueTypeEnum;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -56,7 +55,7 @@ public class JobCodeController {
 	
 	@RequestMapping("/save")
 	@ResponseBody
-	public ReturnT<String> save(Model model, long id, String glueSource, String glueRemark) {
+	public ReturnT<String> save(Model model, int id, String glueSource, String glueRemark) {
 		// valid
 		if (glueRemark==null) {
 			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")) );
@@ -79,14 +78,13 @@ public class JobCodeController {
 
 		// log old code
 		XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue();
-		xxlJobLogGlue.setJobId((int) exists_jobInfo.getId());
+		xxlJobLogGlue.setJobId(exists_jobInfo.getId());
 		xxlJobLogGlue.setGlueType(exists_jobInfo.getGlueType());
 		xxlJobLogGlue.setGlueSource(glueSource);
 		xxlJobLogGlue.setGlueRemark(glueRemark);
 
 		xxlJobLogGlue.setAddTime(new Date());
 		xxlJobLogGlue.setUpdateTime(new Date());
-		xxlJobLogGlue.setId(SnowFlake.genLongId());
 		xxlJobLogGlueDao.save(xxlJobLogGlue);
 
 		// remove code backup more than 30

+ 37 - 24
xxl-job-admin-pg/src/main/java/org/poem/controller/JobGroupController.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java

@@ -1,14 +1,13 @@
-package org.poem.controller;
-
-import org.poem.core.model.XxlJobGroup;
-import org.poem.core.model.XxlJobRegistry;
-import org.poem.core.util.I18nUtil;
-import org.poem.dao.XxlJobGroupDao;
-import org.poem.dao.XxlJobInfoDao;
-import org.poem.dao.XxlJobRegistryDao;
-import org.poem.biz.model.ReturnT;
-import org.poem.enums.RegistryConfig;
-import org.poem.util.SnowFlake;
+package com.xxl.job.admin.controller;
+
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobRegistry;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.admin.dao.XxlJobGroupDao;
+import com.xxl.job.admin.dao.XxlJobInfoDao;
+import com.xxl.job.admin.dao.XxlJobRegistryDao;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.enums.RegistryConfig;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -42,9 +41,9 @@ public class JobGroupController {
 	@RequestMapping("/pageList")
 	@ResponseBody
 	public Map<String, Object> pageList(HttpServletRequest request,
-                                        @RequestParam(required = false, defaultValue = "0") int start,
-                                        @RequestParam(required = false, defaultValue = "10") int length,
-                                        String appname, String title) {
+										@RequestParam(required = false, defaultValue = "0") int start,
+										@RequestParam(required = false, defaultValue = "10") int length,
+										String appname, String title) {
 
 		// page query
 		List<XxlJobGroup> list = xxlJobGroupDao.pageList(start, length, appname, title);
@@ -69,13 +68,23 @@ public class JobGroupController {
 		if (xxlJobGroup.getAppname().length()<4 || xxlJobGroup.getAppname().length()>64) {
 			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_appname_length") );
 		}
+		if (xxlJobGroup.getAppname().contains(">") || xxlJobGroup.getAppname().contains("<")) {
+			return new ReturnT<String>(500, "AppName"+I18nUtil.getString("system_unvalid") );
+		}
 		if (xxlJobGroup.getTitle()==null || xxlJobGroup.getTitle().trim().length()==0) {
 			return new ReturnT<String>(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")) );
 		}
+		if (xxlJobGroup.getTitle().contains(">") || xxlJobGroup.getTitle().contains("<")) {
+			return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_title")+I18nUtil.getString("system_unvalid") );
+		}
 		if (xxlJobGroup.getAddressType()!=0) {
 			if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
 				return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_addressType_limit") );
 			}
+			if (xxlJobGroup.getAddressList().contains(">") || xxlJobGroup.getAddressList().contains("<")) {
+				return new ReturnT<String>(500, I18nUtil.getString("jobgroup_field_registryList")+I18nUtil.getString("system_unvalid") );
+			}
+
 			String[] addresss = xxlJobGroup.getAddressList().split(",");
 			for (String item: addresss) {
 				if (item==null || item.trim().length()==0) {
@@ -83,7 +92,10 @@ public class JobGroupController {
 				}
 			}
 		}
-		xxlJobGroup.setId(SnowFlake.genLongId());
+
+		// process
+		xxlJobGroup.setUpdateTime(new Date());
+
 		int ret = xxlJobGroupDao.save(xxlJobGroup);
 		return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
 	}
@@ -104,18 +116,16 @@ public class JobGroupController {
 		if (xxlJobGroup.getAddressType() == 0) {
 			// 0=自动注册
 			List<String> registryList = findRegistryByAppName(xxlJobGroup.getAppname());
-			StringBuilder addressListStr = null;
+			String addressListStr = null;
 			if (registryList!=null && !registryList.isEmpty()) {
 				Collections.sort(registryList);
-				addressListStr = new StringBuilder();
+				addressListStr = "";
 				for (String item:registryList) {
-					addressListStr.append(item).append(",");
+					addressListStr += item + ",";
 				}
-				addressListStr = new StringBuilder(addressListStr.substring(0, addressListStr.length() - 1));
-			}
-			if (addressListStr != null) {
-				xxlJobGroup.setAddressList(addressListStr.toString());
+				addressListStr = addressListStr.substring(0, addressListStr.length()-1);
 			}
+			xxlJobGroup.setAddressList(addressListStr);
 		} else {
 			// 1=手动录入
 			if (xxlJobGroup.getAddressList()==null || xxlJobGroup.getAddressList().trim().length()==0) {
@@ -129,6 +139,9 @@ public class JobGroupController {
 			}
 		}
 
+		// process
+		xxlJobGroup.setUpdateTime(new Date());
+
 		int ret = xxlJobGroupDao.update(xxlJobGroup);
 		return (ret>0)?ReturnT.SUCCESS:ReturnT.FAIL;
 	}
@@ -157,7 +170,7 @@ public class JobGroupController {
 
 	@RequestMapping("/remove")
 	@ResponseBody
-	public ReturnT<String> remove(long id){
+	public ReturnT<String> remove(int id){
 
 		// valid
 		int count = xxlJobInfoDao.pageListCount(0, 10, id, -1,  null, null, null);
@@ -176,7 +189,7 @@ public class JobGroupController {
 
 	@RequestMapping("/loadById")
 	@ResponseBody
-	public ReturnT<XxlJobGroup> loadById(long id){
+	public ReturnT<XxlJobGroup> loadById(int id){
 		XxlJobGroup jobGroup = xxlJobGroupDao.load(id);
 		return jobGroup!=null?new ReturnT<XxlJobGroup>(jobGroup):new ReturnT<XxlJobGroup>(ReturnT.FAIL_CODE, null);
 	}

+ 47 - 30
xxl-job-admin-pg/src/main/java/org/poem/controller/JobInfoController.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java

@@ -1,21 +1,26 @@
-package org.poem.controller;
+package com.xxl.job.admin.controller;
 
-import org.poem.core.cron.CronExpression;
-import org.poem.core.exception.XxlJobException;
-import org.poem.core.model.XxlJobGroup;
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobUser;
-import org.poem.core.route.ExecutorRouteStrategyEnum;
-import org.poem.core.thread.JobTriggerPoolHelper;
-import org.poem.core.trigger.TriggerTypeEnum;
-import org.poem.core.util.I18nUtil;
-import org.poem.dao.XxlJobGroupDao;
-import org.poem.service.LoginService;
-import org.poem.service.XxlJobService;
-import org.poem.biz.model.ReturnT;
-import org.poem.enums.ExecutorBlockStrategyEnum;
-import org.poem.glue.GlueTypeEnum;
-import org.poem.util.DateUtil;
+import com.xxl.job.admin.core.cron.CronExpression;
+import com.xxl.job.admin.core.exception.XxlJobException;
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobUser;
+import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
+import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
+import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
+import com.xxl.job.admin.core.thread.JobScheduleHelper;
+import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
+import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.admin.dao.XxlJobGroupDao;
+import com.xxl.job.admin.service.LoginService;
+import com.xxl.job.admin.service.XxlJobService;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
+import com.xxl.job.core.glue.GlueTypeEnum;
+import com.xxl.job.core.util.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -34,6 +39,7 @@ import java.util.*;
 @Controller
 @RequestMapping("/jobinfo")
 public class JobInfoController {
+	private static Logger logger = LoggerFactory.getLogger(JobInfoController.class);
 
 	@Resource
 	private XxlJobGroupDao xxlJobGroupDao;
@@ -41,12 +47,14 @@ public class JobInfoController {
 	private XxlJobService xxlJobService;
 	
 	@RequestMapping
-	public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") Long jobGroup) {
+	public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
 
 		// 枚举-字典
 		model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values());	    // 路由策略-列表
 		model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());								// Glue类型-字典
 		model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values());	    // 阻塞处理策略-字典
+		model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values());	    				// 调度类型
+		model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values());	    			// 调度过期策略
 
 		// 执行器列表
 		List<XxlJobGroup> jobGroupList_all =  xxlJobGroupDao.findAll();
@@ -83,7 +91,7 @@ public class JobInfoController {
 		}
 		return jobGroupList;
 	}
-	public static void validPermission(HttpServletRequest request, long jobGroup) {
+	public static void validPermission(HttpServletRequest request, int jobGroup) {
 		XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
 		if (!loginUser.validPermission(jobGroup)) {
 			throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username="+ loginUser.getUsername() +"]");
@@ -92,9 +100,9 @@ public class JobInfoController {
 	
 	@RequestMapping("/pageList")
 	@ResponseBody
-	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,
+	public Map<String, Object> pageList(@RequestParam(required = false, defaultValue = "0") int start,  
 			@RequestParam(required = false, defaultValue = "10") int length,
-										long jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
+			int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
 		
 		return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
 	}
@@ -113,26 +121,26 @@ public class JobInfoController {
 	
 	@RequestMapping("/remove")
 	@ResponseBody
-	public ReturnT<String> remove(long id) {
+	public ReturnT<String> remove(int id) {
 		return xxlJobService.remove(id);
 	}
 	
 	@RequestMapping("/stop")
 	@ResponseBody
-	public ReturnT<String> pause(long id) {
+	public ReturnT<String> pause(int id) {
 		return xxlJobService.stop(id);
 	}
 	
 	@RequestMapping("/start")
 	@ResponseBody
-	public ReturnT<String> start(long id) {
+	public ReturnT<String> start(int id) {
 		return xxlJobService.start(id);
 	}
 	
 	@RequestMapping("/trigger")
 	@ResponseBody
 	//@PermissionLimit(limit = false)
-	public ReturnT<String> triggerJob(long id, String executorParam, String addressList) {
+	public ReturnT<String> triggerJob(int id, String executorParam, String addressList) {
 		// force cover job param
 		if (executorParam == null) {
 			executorParam = "";
@@ -144,23 +152,32 @@ public class JobInfoController {
 
 	@RequestMapping("/nextTriggerTime")
 	@ResponseBody
-	public ReturnT<List<String>> nextTriggerTime(String cron) {
+	public ReturnT<List<String>> nextTriggerTime(String scheduleType, String scheduleConf) {
+
+		if(scheduleConf==null||"".equals(scheduleConf)){
+			 	return new ReturnT<List<String>>(new ArrayList<>());
+		}
+		XxlJobInfo paramXxlJobInfo = new XxlJobInfo();
+		paramXxlJobInfo.setScheduleType(scheduleType);
+		paramXxlJobInfo.setScheduleConf(scheduleConf);
+
 		List<String> result = new ArrayList<>();
 		try {
-			CronExpression cronExpression = new CronExpression(cron);
 			Date lastTime = new Date();
 			for (int i = 0; i < 5; i++) {
-				lastTime = cronExpression.getNextValidTimeAfter(lastTime);
+				lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime);
 				if (lastTime != null) {
 					result.add(DateUtil.formatDateTime(lastTime));
 				} else {
 					break;
 				}
 			}
-		} catch (ParseException e) {
-			return new ReturnT<List<String>>(ReturnT.FAIL_CODE, I18nUtil.getString("jobinfo_field_cron_unvalid"));
+		} catch (Exception e) {
+//			logger.error(e.getMessage(), e);
+			return new ReturnT<List<String>>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) + e.getMessage());
 		}
 		return new ReturnT<List<String>>(result);
+
 	}
 	
 }

+ 30 - 29
xxl-job-admin-pg/src/main/java/org/poem/controller/JobLogController.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java

@@ -1,20 +1,21 @@
-package org.poem.controller;
-
-import org.poem.core.exception.XxlJobException;
-import org.poem.core.model.XxlJobGroup;
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLog;
-import org.poem.core.scheduler.XxlJobScheduler;
-import org.poem.core.util.I18nUtil;
-import org.poem.dao.XxlJobGroupDao;
-import org.poem.dao.XxlJobInfoDao;
-import org.poem.dao.XxlJobLogDao;
-import org.poem.biz.ExecutorBiz;
-import org.poem.biz.model.KillParam;
-import org.poem.biz.model.LogParam;
-import org.poem.biz.model.LogResult;
-import org.poem.biz.model.ReturnT;
-import org.poem.util.DateUtil;
+package com.xxl.job.admin.controller;
+
+import com.xxl.job.admin.core.exception.XxlJobException;
+import com.xxl.job.admin.core.complete.XxlJobCompleter;
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLog;
+import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.admin.dao.XxlJobGroupDao;
+import com.xxl.job.admin.dao.XxlJobInfoDao;
+import com.xxl.job.admin.dao.XxlJobLogDao;
+import com.xxl.job.core.biz.ExecutorBiz;
+import com.xxl.job.core.biz.model.KillParam;
+import com.xxl.job.core.biz.model.LogParam;
+import com.xxl.job.core.biz.model.LogResult;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.util.DateUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Controller;
@@ -47,7 +48,7 @@ public class JobLogController {
 	public XxlJobLogDao xxlJobLogDao;
 
 	@RequestMapping
-	public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "0") long jobId) {
+	public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "0") Integer jobId) {
 
 		// 执行器列表
 		List<XxlJobGroup> jobGroupList_all =  xxlJobGroupDao.findAll();
@@ -78,7 +79,7 @@ public class JobLogController {
 
 	@RequestMapping("/getJobsByGroup")
 	@ResponseBody
-	public ReturnT<List<XxlJobInfo>> getJobsByGroup(long jobGroup){
+	public ReturnT<List<XxlJobInfo>> getJobsByGroup(int jobGroup){
 		List<XxlJobInfo> list = xxlJobInfoDao.getJobsByGroup(jobGroup);
 		return new ReturnT<List<XxlJobInfo>>(list);
 	}
@@ -86,9 +87,9 @@ public class JobLogController {
 	@RequestMapping("/pageList")
 	@ResponseBody
 	public Map<String, Object> pageList(HttpServletRequest request,
-                                        @RequestParam(required = false, defaultValue = "0") int start,
-                                        @RequestParam(required = false, defaultValue = "10") int length,
-										long jobGroup, long jobId, int logStatus, String filterTime) {
+										@RequestParam(required = false, defaultValue = "0") int start,
+										@RequestParam(required = false, defaultValue = "10") int length,
+										int jobGroup, int jobId, int logStatus, String filterTime) {
 
 		// valid permission
 		JobInfoController.validPermission(request, jobGroup);	// 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
@@ -105,8 +106,8 @@ public class JobLogController {
 		}
 		
 		// page query
-		List<XxlJobLog> list = xxlJobLogDao.pageList(start, length, jobGroup, (int) jobId, triggerTimeStart, triggerTimeEnd, logStatus);
-		int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, (int) jobId, triggerTimeStart, triggerTimeEnd, logStatus);
+		List<XxlJobLog> list = xxlJobLogDao.pageList(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
+		int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
 		
 		// package result
 		Map<String, Object> maps = new HashMap<String, Object>();
@@ -117,7 +118,7 @@ public class JobLogController {
 	}
 
 	@RequestMapping("/logDetailPage")
-	public String logDetailPage(long id, Model model){
+	public String logDetailPage(int id, Model model){
 
 		// base check
 		ReturnT<String> logStatue = ReturnT.SUCCESS;
@@ -158,7 +159,7 @@ public class JobLogController {
 
 	@RequestMapping("/logKill")
 	@ResponseBody
-	public ReturnT<String> logKill(long id){
+	public ReturnT<String> logKill(int id){
 		// base check
 		XxlJobLog log = xxlJobLogDao.load(id);
 		XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
@@ -183,7 +184,7 @@ public class JobLogController {
 			log.setHandleCode(ReturnT.FAIL_CODE);
 			log.setHandleMsg( I18nUtil.getString("joblog_kill_log_byman")+":" + (runResult.getMsg()!=null?runResult.getMsg():""));
 			log.setHandleTime(new Date());
-			xxlJobLogDao.updateHandleInfo(log);
+			XxlJobCompleter.updateHandleInfoAndFinish(log);
 			return new ReturnT<String>(runResult.getMsg());
 		} else {
 			return new ReturnT<String>(500, runResult.getMsg());
@@ -192,7 +193,7 @@ public class JobLogController {
 
 	@RequestMapping("/clearLog")
 	@ResponseBody
-	public ReturnT<String> clearLog(long jobGroup, long jobId, int type){
+	public ReturnT<String> clearLog(int jobGroup, int jobId, int type){
 
 		Date clearBeforeTime = null;
 		int clearBeforeNum = 0;
@@ -220,7 +221,7 @@ public class JobLogController {
 
 		List<Long> logIds = null;
 		do {
-			logIds = xxlJobLogDao.findClearLogIds(jobGroup, (int) jobId, clearBeforeTime, clearBeforeNum, 1000);
+			logIds = xxlJobLogDao.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);
 			if (logIds!=null && logIds.size()>0) {
 				xxlJobLogDao.clearLog(logIds);
 			}

+ 34 - 29
xxl-job-admin-pg/src/main/java/org/poem/controller/UserController.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java

@@ -1,14 +1,13 @@
-package org.poem.controller;
-
-import org.poem.controller.annotation.PermissionLimit;
-import org.poem.core.model.XxlJobGroup;
-import org.poem.core.model.XxlJobUser;
-import org.poem.core.util.I18nUtil;
-import org.poem.dao.XxlJobGroupDao;
-import org.poem.dao.XxlJobUserDao;
-import org.poem.service.LoginService;
-import org.poem.biz.model.ReturnT;
-import org.poem.util.SnowFlake;
+package com.xxl.job.admin.controller;
+
+import com.xxl.job.admin.controller.annotation.PermissionLimit;
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobUser;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.admin.dao.XxlJobGroupDao;
+import com.xxl.job.admin.dao.XxlJobUserDao;
+import com.xxl.job.admin.service.LoginService;
+import com.xxl.job.core.biz.model.ReturnT;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.util.DigestUtils;
@@ -57,11 +56,18 @@ public class UserController {
         List<XxlJobUser> list = xxlJobUserDao.pageList(start, length, username, role);
         int list_count = xxlJobUserDao.pageListCount(start, length, username, role);
 
+        // filter
+        if (list!=null && list.size()>0) {
+            for (XxlJobUser item: list) {
+                item.setPassword(null);
+            }
+        }
+
         // package result
         Map<String, Object> maps = new HashMap<String, Object>();
-        maps.put("recordsTotal", list_count);        // 总记录数
-        maps.put("recordsFiltered", list_count);    // 过滤后的总记录数
-        maps.put("data", list);                    // 分页列表
+        maps.put("recordsTotal", list_count);		// 总记录数
+        maps.put("recordsFiltered", list_count);	// 过滤后的总记录数
+        maps.put("data", list);  					// 分页列表
         return maps;
     }
 
@@ -72,19 +78,19 @@ public class UserController {
 
         // valid username
         if (!StringUtils.hasText(xxlJobUser.getUsername())) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_username"));
+            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input")+I18nUtil.getString("user_username") );
         }
         xxlJobUser.setUsername(xxlJobUser.getUsername().trim());
-        if (!(xxlJobUser.getUsername().length() >= 4 && xxlJobUser.getUsername().length() <= 20)) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
+        if (!(xxlJobUser.getUsername().length()>=4 && xxlJobUser.getUsername().length()<=20)) {
+            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
         }
         // valid password
         if (!StringUtils.hasText(xxlJobUser.getPassword())) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_password"));
+            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input")+I18nUtil.getString("user_password") );
         }
         xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
-        if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
+        if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {
+            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
         }
         // md5 password
         xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
@@ -92,11 +98,10 @@ public class UserController {
         // check repeat
         XxlJobUser existUser = xxlJobUserDao.loadByUserName(xxlJobUser.getUsername());
         if (existUser != null) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat"));
+            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat") );
         }
 
         // write
-        xxlJobUser.setId(SnowFlake.genLongId());
         xxlJobUserDao.save(xxlJobUser);
         return ReturnT.SUCCESS;
     }
@@ -115,8 +120,8 @@ public class UserController {
         // valid password
         if (StringUtils.hasText(xxlJobUser.getPassword())) {
             xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
-            if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) {
-                return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
+            if (!(xxlJobUser.getPassword().length()>=4 && xxlJobUser.getPassword().length()<=20)) {
+                return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
             }
             // md5 password
             xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
@@ -132,7 +137,7 @@ public class UserController {
     @RequestMapping("/remove")
     @ResponseBody
     @PermissionLimit(adminuser = true)
-    public ReturnT<String> remove(HttpServletRequest request, long id) {
+    public ReturnT<String> remove(HttpServletRequest request, int id) {
 
         // avoid opt login seft
         XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
@@ -146,15 +151,15 @@ public class UserController {
 
     @RequestMapping("/updatePwd")
     @ResponseBody
-    public ReturnT<String> updatePwd(HttpServletRequest request, String password) {
+    public ReturnT<String> updatePwd(HttpServletRequest request, String password){
 
         // valid password
-        if (password == null || password.trim().length() == 0) {
+        if (password==null || password.trim().length()==0){
             return new ReturnT<String>(ReturnT.FAIL.getCode(), "密码不可为空");
         }
         password = password.trim();
-        if (!(password.length() >= 4 && password.length() <= 20)) {
-            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
+        if (!(password.length()>=4 && password.length()<=20)) {
+            return new ReturnT<String>(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit")+"[4-20]" );
         }
 
         // md5 password

+ 1 - 1
xxl-job-admin-pg/src/main/java/org/poem/controller/annotation/PermissionLimit.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java

@@ -1,4 +1,4 @@
-package org.poem.controller.annotation;
+package com.xxl.job.admin.controller.annotation;
 
 
 import java.lang.annotation.ElementType;

+ 4 - 4
xxl-job-admin-pg/src/main/java/org/poem/controller/interceptor/CookieInterceptor.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java

@@ -1,7 +1,7 @@
-package org.poem.controller.interceptor;
+package com.xxl.job.admin.controller.interceptor;
 
-import org.poem.core.util.FtlUtil;
-import org.poem.core.util.I18nUtil;
+import com.xxl.job.admin.core.util.FtlUtil;
+import com.xxl.job.admin.core.util.I18nUtil;
 import org.springframework.stereotype.Component;
 import org.springframework.web.servlet.ModelAndView;
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
@@ -21,7 +21,7 @@ public class CookieInterceptor extends HandlerInterceptorAdapter {
 
 	@Override
 	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
-                           ModelAndView modelAndView) throws Exception {
+			ModelAndView modelAndView) throws Exception {
 
 		// cookie
 		if (modelAndView!=null && request.getCookies()!=null && request.getCookies().length>0) {

+ 5 - 5
xxl-job-admin-pg/src/main/java/org/poem/controller/interceptor/PermissionInterceptor.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java

@@ -1,9 +1,9 @@
-package org.poem.controller.interceptor;
+package com.xxl.job.admin.controller.interceptor;
 
-import org.poem.controller.annotation.PermissionLimit;
-import org.poem.core.model.XxlJobUser;
-import org.poem.core.util.I18nUtil;
-import org.poem.service.LoginService;
+import com.xxl.job.admin.controller.annotation.PermissionLimit;
+import com.xxl.job.admin.core.model.XxlJobUser;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.admin.service.LoginService;
 import org.springframework.stereotype.Component;
 import org.springframework.web.method.HandlerMethod;
 import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

+ 28 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java

@@ -0,0 +1,28 @@
+package com.xxl.job.admin.controller.interceptor;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import javax.annotation.Resource;
+
+/**
+ * web mvc config
+ *
+ * @author xuxueli 2018-04-02 20:48:20
+ */
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+    @Resource
+    private PermissionInterceptor permissionInterceptor;
+    @Resource
+    private CookieInterceptor cookieInterceptor;
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
+        registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
+    }
+
+}

+ 5 - 5
xxl-job-admin-pg/src/main/java/org/poem/controller/resolver/WebExceptionResolver.java → xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java

@@ -1,8 +1,8 @@
-package org.poem.controller.resolver;
+package com.xxl.job.admin.controller.resolver;
 
-import org.poem.core.exception.XxlJobException;
-import org.poem.core.util.JacksonUtil;
-import org.poem.biz.model.ReturnT;
+import com.xxl.job.admin.core.exception.XxlJobException;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.admin.core.util.JacksonUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
@@ -26,7 +26,7 @@ public class WebExceptionResolver implements HandlerExceptionResolver {
 
 	@Override
 	public ModelAndView resolveException(HttpServletRequest request,
-                                         HttpServletResponse response, Object handler, Exception ex) {
+			HttpServletResponse response, Object handler, Exception ex) {
 
 		if (!(ex instanceof XxlJobException)) {
 			logger.error("WebExceptionResolver:{}", ex);

+ 3 - 3
xxl-job-admin-pg/src/main/java/org/poem/core/alarm/JobAlarm.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java

@@ -1,7 +1,7 @@
-package org.poem.core.alarm;
+package com.xxl.job.admin.core.alarm;
 
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLog;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLog;
 
 /**
  * @author xuxueli 2020-01-19

+ 3 - 3
xxl-job-admin-pg/src/main/java/org/poem/core/alarm/JobAlarmer.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java

@@ -1,7 +1,7 @@
-package org.poem.core.alarm;
+package com.xxl.job.admin.core.alarm;
 
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLog;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeansException;

+ 10 - 10
xxl-job-admin-pg/src/main/java/org/poem/core/alarm/impl/EmailJobAlarm.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java

@@ -1,12 +1,12 @@
-package org.poem.core.alarm.impl;
-
-import org.poem.core.alarm.JobAlarm;
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.model.XxlJobGroup;
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLog;
-import org.poem.core.util.I18nUtil;
-import org.poem.biz.model.ReturnT;
+package com.xxl.job.admin.core.alarm.impl;
+
+import com.xxl.job.admin.core.alarm.JobAlarm;
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLog;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.core.biz.model.ReturnT;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.mail.javamail.MimeMessageHelper;
@@ -48,7 +48,7 @@ public class EmailJobAlarm implements JobAlarm {
             }
 
             // email info
-            XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(info.getJobGroup());
+            XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));
             String personal = I18nUtil.getString("admin_name_full");
             String title = I18nUtil.getString("jobconf_monitor");
             String content = MessageFormat.format(loadEmailJobAlarmTemplate(),

+ 99 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java

@@ -0,0 +1,99 @@
+package com.xxl.job.admin.core.complete;
+
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLog;
+import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
+import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.context.XxlJobContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.text.MessageFormat;
+
+/**
+ * @author xuxueli 2020-10-30 20:43:10
+ */
+public class XxlJobCompleter {
+    private static Logger logger = LoggerFactory.getLogger(XxlJobCompleter.class);
+
+    /**
+     * common fresh handle entrance (limit only once)
+     *
+     * @param xxlJobLog
+     * @return
+     */
+    public static int updateHandleInfoAndFinish(XxlJobLog xxlJobLog) {
+
+        // finish
+        finishJob(xxlJobLog);
+
+        // text最大64kb 避免长度过长
+        if (xxlJobLog.getHandleMsg().length() > 15000) {
+            xxlJobLog.setHandleMsg( xxlJobLog.getHandleMsg().substring(0, 15000) );
+        }
+
+        // fresh handle
+        return XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateHandleInfo(xxlJobLog);
+    }
+
+
+    /**
+     * do somethind to finish job
+     */
+    private static void finishJob(XxlJobLog xxlJobLog){
+
+        // 1、handle success, to trigger child job
+        String triggerChildMsg = null;
+        if (XxlJobContext.HANDLE_COCE_SUCCESS == xxlJobLog.getHandleCode()) {
+            XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(xxlJobLog.getJobId());
+            if (xxlJobInfo!=null && xxlJobInfo.getChildJobId()!=null && xxlJobInfo.getChildJobId().trim().length()>0) {
+                triggerChildMsg = "<br><br><span style=\"color:#00c0ef;\" > >>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_child_run") +"<<<<<<<<<<< </span><br>";
+
+                String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
+                for (int i = 0; i < childJobIds.length; i++) {
+                    int childJobId = (childJobIds[i]!=null && childJobIds[i].trim().length()>0 && isNumeric(childJobIds[i]))?Integer.valueOf(childJobIds[i]):-1;
+                    if (childJobId > 0) {
+
+                        JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null);
+                        ReturnT<String> triggerChildResult = ReturnT.SUCCESS;
+
+                        // add msg
+                        triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
+                                (i+1),
+                                childJobIds.length,
+                                childJobIds[i],
+                                (triggerChildResult.getCode()==ReturnT.SUCCESS_CODE?I18nUtil.getString("system_success"):I18nUtil.getString("system_fail")),
+                                triggerChildResult.getMsg());
+                    } else {
+                        triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
+                                (i+1),
+                                childJobIds.length,
+                                childJobIds[i]);
+                    }
+                }
+
+            }
+        }
+
+        if (triggerChildMsg != null) {
+            xxlJobLog.setHandleMsg( xxlJobLog.getHandleMsg() + triggerChildMsg );
+        }
+
+        // 2、fix_delay trigger next
+        // on the way
+
+    }
+
+    private static boolean isNumeric(String str){
+        try {
+            int result = Integer.valueOf(str);
+            return true;
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
+
+}

+ 4 - 4
xxl-job-admin-pg/src/main/java/org/poem/core/conf/XxlJobAdminConfig.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java

@@ -1,8 +1,8 @@
-package org.poem.core.conf;
+package com.xxl.job.admin.core.conf;
 
-import org.poem.core.alarm.JobAlarmer;
-import org.poem.core.scheduler.XxlJobScheduler;
-import org.poem.dao.*;
+import com.xxl.job.admin.core.alarm.JobAlarmer;
+import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
+import com.xxl.job.admin.dao.*;
 import org.springframework.beans.factory.DisposableBean;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Value;

+ 78 - 69
xxl-job-admin-pg/src/main/java/org/poem/core/cron/CronExpression.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java

@@ -15,11 +15,20 @@
  * 
  */
 
-package org.poem.core.cron;
+package com.xxl.job.admin.core.cron;
 
 import java.io.Serializable;
 import java.text.ParseException;
-import java.util.*;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
+import java.util.TreeSet;
 
 /**
  * Provides a parser and evaluator for unix-like cron expressions. Cron 
@@ -256,24 +265,24 @@ public final class CronExpression implements Serializable, Cloneable {
      * 
      * @param cronExpression String representation of the cron expression the
      *                       new object should represent
-     * @throws ParseException
-     *         if the string expression cannot be parsed into a valid
+     * @throws java.text.ParseException
+     *         if the string expression cannot be parsed into a valid 
      *         <CODE>CronExpression</CODE>
      */
     public CronExpression(String cronExpression) throws ParseException {
         if (cronExpression == null) {
             throw new IllegalArgumentException("cronExpression cannot be null");
         }
-
+        
         this.cronExpression = cronExpression.toUpperCase(Locale.US);
-
+        
         buildExpression(this.cronExpression);
     }
-
+    
     /**
      * Constructs a new {@code CronExpression} as a copy of an existing
      * instance.
-     *
+     * 
      * @param expression
      *            The existing cron expression to be copied
      */
@@ -298,7 +307,7 @@ public final class CronExpression implements Serializable, Cloneable {
      * Indicates whether the given date satisfies the cron expression. Note that
      * milliseconds are ignored, so two Dates falling on different milliseconds
      * of the same second will always have the same result here.
-     *
+     * 
      * @param date the date to evaluate
      * @return a boolean indicating whether the given date satisfies the cron
      *         expression
@@ -308,18 +317,18 @@ public final class CronExpression implements Serializable, Cloneable {
         testDateCal.setTime(date);
         testDateCal.set(Calendar.MILLISECOND, 0);
         Date originalDate = testDateCal.getTime();
-
+        
         testDateCal.add(Calendar.SECOND, -1);
-
+        
         Date timeAfter = getTimeAfter(testDateCal.getTime());
 
         return ((timeAfter != null) && (timeAfter.equals(originalDate)));
     }
-
+    
     /**
      * Returns the next date/time <I>after</I> the given date/time which
      * satisfies the cron expression.
-     *
+     * 
      * @param date the date/time at which to begin the search for the next valid
      *             date/time
      * @return the next valid date/time
@@ -327,28 +336,28 @@ public final class CronExpression implements Serializable, Cloneable {
     public Date getNextValidTimeAfter(Date date) {
         return getTimeAfter(date);
     }
-
+    
     /**
      * Returns the next date/time <I>after</I> the given date/time which does
      * <I>not</I> satisfy the expression
-     *
-     * @param date the date/time at which to begin the search for the next
+     * 
+     * @param date the date/time at which to begin the search for the next 
      *             invalid date/time
      * @return the next valid date/time
      */
     public Date getNextInvalidTimeAfter(Date date) {
         long difference = 1000;
-
+        
         //move back to the nearest second so differences will be accurate
         Calendar adjustCal = Calendar.getInstance(getTimeZone());
         adjustCal.setTime(date);
         adjustCal.set(Calendar.MILLISECOND, 0);
         Date lastDate = adjustCal.getTime();
-
+        
         Date newDate;
-
+        
         //FUTURE_TODO: (QUARTZ-481) IMPROVE THIS! The following is a BAD solution to this problem. Performance will be very bad here, depending on the cron expression. It is, however A solution.
-
+        
         //keep getting the next included time until it's farther than one second
         // apart. At that point, lastDate is the last valid fire time. We return
         // the second immediately following it.
@@ -356,19 +365,19 @@ public final class CronExpression implements Serializable, Cloneable {
             newDate = getTimeAfter(lastDate);
             if(newDate == null)
                 break;
-
+            
             difference = newDate.getTime() - lastDate.getTime();
-
+            
             if (difference == 1000) {
                 lastDate = newDate;
             }
         }
-
+        
         return new Date(lastDate.getTime() + 1000);
     }
-
+    
     /**
-     * Returns the time zone for which this <code>CronExpression</code>
+     * Returns the time zone for which this <code>CronExpression</code> 
      * will be resolved.
      */
     public TimeZone getTimeZone() {
@@ -380,16 +389,16 @@ public final class CronExpression implements Serializable, Cloneable {
     }
 
     /**
-     * Sets the time zone for which  this <code>CronExpression</code>
+     * Sets the time zone for which  this <code>CronExpression</code> 
      * will be resolved.
      */
     public void setTimeZone(TimeZone timeZone) {
         this.timeZone = timeZone;
     }
-
+    
     /**
      * Returns the string representation of the <CODE>CronExpression</CODE>
-     *
+     * 
      * @return a string representation of the <CODE>CronExpression</CODE>
      */
     @Override
@@ -398,30 +407,30 @@ public final class CronExpression implements Serializable, Cloneable {
     }
 
     /**
-     * Indicates whether the specified cron expression can be parsed into a
+     * Indicates whether the specified cron expression can be parsed into a 
      * valid cron expression
-     *
+     * 
      * @param cronExpression the expression to evaluate
      * @return a boolean indicating whether the given expression is a valid cron
      *         expression
      */
     public static boolean isValidExpression(String cronExpression) {
-
+        
         try {
             new CronExpression(cronExpression);
         } catch (ParseException pe) {
             return false;
         }
-
+        
         return true;
     }
 
     public static void validateExpression(String cronExpression) throws ParseException {
-
+        
         new CronExpression(cronExpression);
     }
-
-
+    
+    
     ////////////////////////////////////////////////////////////////////////////
     //
     // Expression Parsing Functions
@@ -474,7 +483,7 @@ public final class CronExpression implements Serializable, Cloneable {
                 if(exprOn == DAY_OF_WEEK && expr.indexOf('#') != -1 && expr.indexOf('#', expr.indexOf('#') +1) != -1) {
                     throw new ParseException("Support for specifying multiple \"nth\" days is not implemented.", -1);
                 }
-
+                
                 StringTokenizer vTok = new StringTokenizer(expr, ",");
                 while (vTok.hasMoreTokens()) {
                     String v = vTok.nextToken();
@@ -592,7 +601,7 @@ public final class CronExpression implements Serializable, Cloneable {
 
         if (c == '?') {
             i++;
-            if ((i + 1) < s.length()
+            if ((i + 1) < s.length() 
                     && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) {
                 throw new ParseException("Illegal character after '?': "
                             + s.charAt(i), i);
@@ -621,7 +630,7 @@ public final class CronExpression implements Serializable, Cloneable {
                 return i + 1;
             } else if (c == '/'
                     && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s
-                            .charAt(i + 1) == '\t')) {
+                            .charAt(i + 1) == '\t')) { 
                 throw new ParseException("'/' must be followed by an integer.", i);
             } else if (c == '*') {
                 i++;
@@ -662,7 +671,7 @@ public final class CronExpression implements Serializable, Cloneable {
                     if(lastdayOffset > 30)
                         throw new ParseException("Offset from last day must be <= 30", i+1);
                     i = vs.pos;
-                }
+                }                        
                 if(s.length() > i) {
                     c = s.charAt(i);
                     if(c == 'W') {
@@ -710,7 +719,7 @@ public final class CronExpression implements Serializable, Cloneable {
 
     protected int checkNext(int pos, String s, int val, int type)
         throws ParseException {
-
+        
         int end = -1;
         int i = pos;
 
@@ -734,7 +743,7 @@ public final class CronExpression implements Serializable, Cloneable {
             i++;
             return i;
         }
-
+        
         if (c == 'W') {
             if (type == DAY_OF_MONTH) {
                 nearestWeekday = true;
@@ -742,7 +751,7 @@ public final class CronExpression implements Serializable, Cloneable {
                 throw new ParseException("'W' option is not valid here. (pos=" + i + ")", i);
             }
             if(val > 31)
-                throw new ParseException("The 'W' option does not make sense with values larger than 31 (max number of days in a month)", i);
+                throw new ParseException("The 'W' option does not make sense with values larger than 31 (max number of days in a month)", i); 
             TreeSet<Integer> set = getSet(type);
             set.add(val);
             i++;
@@ -848,7 +857,7 @@ public final class CronExpression implements Serializable, Cloneable {
     public String getCronExpression() {
         return cronExpression;
     }
-
+    
     public String getExpressionSummary() {
         StringBuilder buf = new StringBuilder();
 
@@ -957,7 +966,7 @@ public final class CronExpression implements Serializable, Cloneable {
 
     protected void addToSet(int val, int end, int incr, int type)
         throws ParseException {
-
+        
         TreeSet<Integer> set = getSet(type);
 
         if (type == SECOND || type == MINUTE) {
@@ -972,7 +981,7 @@ public final class CronExpression implements Serializable, Cloneable {
                         "Hour values must be between 0 and 23", -1);
             }
         } else if (type == DAY_OF_MONTH) {
-            if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT)
+            if ((val < 1 || val > 31 || end > 31) && (val != ALL_SPEC_INT) 
                     && (val != NO_SPEC_INT)) {
                 throw new ParseException(
                         "Day of month values must be between 1 and 31", -1);
@@ -996,7 +1005,7 @@ public final class CronExpression implements Serializable, Cloneable {
             } else {
                 set.add(NO_SPEC);
             }
-
+            
             return;
         }
 
@@ -1052,8 +1061,8 @@ public final class CronExpression implements Serializable, Cloneable {
             }
         }
 
-        // if the end of the range is before the start, then we need to overflow into
-        // the next day, month etc. This is done by adding the maximum amount for that
+        // if the end of the range is before the start, then we need to overflow into 
+        // the next day, month etc. This is done by adding the maximum amount for that 
         // type, and using modulus max to determine the value being added.
         int max = -1;
         if (stopAt < startAt) {
@@ -1121,7 +1130,7 @@ public final class CronExpression implements Serializable, Cloneable {
             c = s.charAt(i);
         }
         ValueSet val = new ValueSet();
-
+        
         val.pos = (i < s.length()) ? i : i + 1;
         val.value = Integer.parseInt(s1.toString());
         return val;
@@ -1162,7 +1171,7 @@ public final class CronExpression implements Serializable, Cloneable {
     public Date getTimeAfter(Date afterTime) {
 
         // Computation is based on Gregorian year only.
-        Calendar cl = new java.util.GregorianCalendar(getTimeZone());
+        Calendar cl = new java.util.GregorianCalendar(getTimeZone()); 
 
         // move ahead one second, since we're computing the time *after* the
         // given time
@@ -1246,7 +1255,7 @@ public final class CronExpression implements Serializable, Cloneable {
             // 1-based
             t = -1;
             int tmon = mon;
-
+            
             // get day...................................................
             boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC);
             boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC);
@@ -1259,7 +1268,7 @@ public final class CronExpression implements Serializable, Cloneable {
                         day -= lastdayOffset;
                         if(t > day) {
                             mon++;
-                            if(mon > 12) {
+                            if(mon > 12) { 
                                 mon = 1;
                                 tmon = 3333; // ensure test of mon != tmon further below fails
                                 cl.add(Calendar.YEAR, 1);
@@ -1270,15 +1279,15 @@ public final class CronExpression implements Serializable, Cloneable {
                         t = day;
                         day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
                         day -= lastdayOffset;
-
-                        Calendar tcal = Calendar.getInstance(getTimeZone());
+                        
+                        java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone());
                         tcal.set(Calendar.SECOND, 0);
                         tcal.set(Calendar.MINUTE, 0);
                         tcal.set(Calendar.HOUR_OF_DAY, 0);
                         tcal.set(Calendar.DAY_OF_MONTH, day);
                         tcal.set(Calendar.MONTH, mon - 1);
                         tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR));
-
+                        
                         int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
                         int dow = tcal.get(Calendar.DAY_OF_WEEK);
 
@@ -1286,12 +1295,12 @@ public final class CronExpression implements Serializable, Cloneable {
                             day += 2;
                         } else if(dow == Calendar.SATURDAY) {
                             day -= 1;
-                        } else if(dow == Calendar.SUNDAY && day == ldom) {
+                        } else if(dow == Calendar.SUNDAY && day == ldom) { 
                             day -= 2;
-                        } else if(dow == Calendar.SUNDAY) {
+                        } else if(dow == Calendar.SUNDAY) { 
                             day += 1;
                         }
-
+                    
                         tcal.set(Calendar.SECOND, sec);
                         tcal.set(Calendar.MINUTE, min);
                         tcal.set(Calendar.HOUR_OF_DAY, hr);
@@ -1307,14 +1316,14 @@ public final class CronExpression implements Serializable, Cloneable {
                     t = day;
                     day = daysOfMonth.first();
 
-                    Calendar tcal = Calendar.getInstance(getTimeZone());
+                    java.util.Calendar tcal = java.util.Calendar.getInstance(getTimeZone());
                     tcal.set(Calendar.SECOND, 0);
                     tcal.set(Calendar.MINUTE, 0);
                     tcal.set(Calendar.HOUR_OF_DAY, 0);
                     tcal.set(Calendar.DAY_OF_MONTH, day);
                     tcal.set(Calendar.MONTH, mon - 1);
                     tcal.set(Calendar.YEAR, cl.get(Calendar.YEAR));
-
+                    
                     int ldom = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
                     int dow = tcal.get(Calendar.DAY_OF_WEEK);
 
@@ -1322,13 +1331,13 @@ public final class CronExpression implements Serializable, Cloneable {
                         day += 2;
                     } else if(dow == Calendar.SATURDAY) {
                         day -= 1;
-                    } else if(dow == Calendar.SUNDAY && day == ldom) {
+                    } else if(dow == Calendar.SUNDAY && day == ldom) { 
                         day -= 2;
-                    } else if(dow == Calendar.SUNDAY) {
+                    } else if(dow == Calendar.SUNDAY) { 
                         day += 1;
                     }
-
-
+                        
+                
                     tcal.set(Calendar.SECOND, sec);
                     tcal.set(Calendar.MINUTE, min);
                     tcal.set(Calendar.HOUR_OF_DAY, hr);
@@ -1352,7 +1361,7 @@ public final class CronExpression implements Serializable, Cloneable {
                     day = daysOfMonth.first();
                     mon++;
                 }
-
+                
                 if (day != t || mon != tmon) {
                     cl.set(Calendar.SECOND, 0);
                     cl.set(Calendar.MINUTE, 0);
@@ -1566,14 +1575,14 @@ public final class CronExpression implements Serializable, Cloneable {
     /**
      * Advance the calendar to the particular hour paying particular attention
      * to daylight saving problems.
-     *
+     * 
      * @param cal the calendar to operate on
      * @param hour the hour to set
      */
     protected void setCalendarHour(Calendar cal, int hour) {
-        cal.set(Calendar.HOUR_OF_DAY, hour);
-        if (cal.get(Calendar.HOUR_OF_DAY) != hour && hour != 24) {
-            cal.set(Calendar.HOUR_OF_DAY, hour + 1);
+        cal.set(java.util.Calendar.HOUR_OF_DAY, hour);
+        if (cal.get(java.util.Calendar.HOUR_OF_DAY) != hour && hour != 24) {
+            cal.set(java.util.Calendar.HOUR_OF_DAY, hour + 1);
         }
     }
 

+ 1 - 1
xxl-job-admin-pg/src/main/java/org/poem/core/exception/XxlJobException.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java

@@ -1,4 +1,4 @@
-package org.poem.core.exception;
+package com.xxl.job.admin.core.exception;
 
 /**
  * @author xuxueli 2019-05-04 23:19:29

+ 14 - 4
xxl-job-admin-pg/src/main/java/org/poem/core/model/XxlJobGroup.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java

@@ -1,7 +1,8 @@
-package org.poem.core.model;
+package com.xxl.job.admin.core.model;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -9,11 +10,12 @@ import java.util.List;
  */
 public class XxlJobGroup {
 
-    private int id;
+    private Integer id;
     private String appname;
     private String title;
     private int addressType;        // 执行器地址类型:0=自动注册、1=手动录入
     private String addressList;     // 执行器地址列表,多地址逗号分隔(手动录入)
+    private Date updateTime;
 
     // registry list
     private List<String> registryList;  // 执行器地址列表(系统注册)
@@ -24,11 +26,11 @@ public class XxlJobGroup {
         return registryList;
     }
 
-    public long getId() {
+    public Integer getId() {
         return id;
     }
 
-    public void setId(int id) {
+    public void setId(Integer id) {
         this.id = id;
     }
 
@@ -60,6 +62,14 @@ public class XxlJobGroup {
         return addressList;
     }
 
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
     public void setAddressList(String addressList) {
         this.addressList = addressList;
     }

+ 33 - 18
xxl-job-admin-pg/src/main/java/org/poem/core/model/XxlJobInfo.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java

@@ -1,4 +1,4 @@
-package org.poem.core.model;
+package com.xxl.job.admin.core.model;
 
 import java.util.Date;
 
@@ -9,17 +9,16 @@ import java.util.Date;
  */
 public class XxlJobInfo {
 	
-	private int id;				// 主键ID
-	
+	private Integer id;				// 主键ID
 	private int jobGroup;		// 执行器主键ID
-	private String jobCron;		// 任务执行CRON表达式
 	private String jobDesc;
-	
 	private Date addTime;
 	private Date updateTime;
-	
 	private String author;		// 负责人
 	private String alarmEmail;	// 报警邮件
+	private String scheduleType;			// 调度类型
+	private String scheduleConf;			// 调度配置,值含义取决于调度类型
+	private String misfireStrategy;			// 调度过期策略
 
 	private String executorRouteStrategy;	// 执行器路由策略
 	private String executorHandler;		    // 执行器,任务Handler名称
@@ -28,7 +27,7 @@ public class XxlJobInfo {
 	private int executorTimeout;     		// 任务执行超时时间,单位秒
 	private int executorFailRetryCount;		// 失败重试次数
 	
-	private String glueType;		// GLUE类型	#org.poem.glue.GlueTypeEnum
+	private String glueType;		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnum
 	private String glueSource;		// GLUE源代码
 	private String glueRemark;		// GLUE备注
 	private Date glueUpdatetime;	// GLUE更新时间
@@ -40,15 +39,15 @@ public class XxlJobInfo {
 	private long triggerNextTime;	// 下次调度时间
 
 
-	public long getId() {
+	public Integer getId() {
 		return id;
 	}
 
-	public void setId(int id) {
+	public void setId(Integer id) {
 		this.id = id;
 	}
 
-	public long getJobGroup() {
+	public int getJobGroup() {
 		return jobGroup;
 	}
 
@@ -56,14 +55,6 @@ public class XxlJobInfo {
 		this.jobGroup = jobGroup;
 	}
 
-	public String getJobCron() {
-		return jobCron;
-	}
-
-	public void setJobCron(String jobCron) {
-		this.jobCron = jobCron;
-	}
-
 	public String getJobDesc() {
 		return jobDesc;
 	}
@@ -104,6 +95,30 @@ public class XxlJobInfo {
 		this.alarmEmail = alarmEmail;
 	}
 
+	public String getScheduleType() {
+		return scheduleType;
+	}
+
+	public void setScheduleType(String scheduleType) {
+		this.scheduleType = scheduleType;
+	}
+
+	public String getScheduleConf() {
+		return scheduleConf;
+	}
+
+	public void setScheduleConf(String scheduleConf) {
+		this.scheduleConf = scheduleConf;
+	}
+
+	public String getMisfireStrategy() {
+		return misfireStrategy;
+	}
+
+	public void setMisfireStrategy(String misfireStrategy) {
+		this.misfireStrategy = misfireStrategy;
+	}
+
 	public String getExecutorRouteStrategy() {
 		return executorRouteStrategy;
 	}

+ 6 - 6
xxl-job-admin-pg/src/main/java/org/poem/core/model/XxlJobLog.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java

@@ -1,4 +1,4 @@
-package org.poem.core.model;
+package com.xxl.job.admin.core.model;
 
 import java.util.Date;
 
@@ -8,7 +8,7 @@ import java.util.Date;
  */
 public class XxlJobLog {
 	
-	private int id;
+	private Long id;
 	
 	// job info
 	private int jobGroup;
@@ -34,15 +34,15 @@ public class XxlJobLog {
 	// alarm info
 	private int alarmStatus;
 
-	public long getId() {
+	public Long getId() {
 		return id;
 	}
 
-	public void setId(int id) {
+	public void setId(Long id) {
 		this.id = id;
 	}
 
-	public long getJobGroup() {
+	public int getJobGroup() {
 		return jobGroup;
 	}
 
@@ -50,7 +50,7 @@ public class XxlJobLog {
 		this.jobGroup = jobGroup;
 	}
 
-	public long getJobId() {
+	public int getJobId() {
 		return jobId;
 	}
 

+ 6 - 7
xxl-job-admin-pg/src/main/java/org/poem/core/model/XxlJobLogGlue.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java

@@ -1,4 +1,4 @@
-package org.poem.core.model;
+package com.xxl.job.admin.core.model;
 
 import java.util.Date;
 
@@ -7,24 +7,23 @@ import java.util.Date;
  * @author xuxueli 2016-5-19 17:57:46
  */
 public class XxlJobLogGlue {
-	
-	private int id;
+	private Integer id;
 	private int jobId;				// 任务主键ID
-	private String glueType;		// GLUE类型	#org.poem.glue.GlueTypeEnum
+	private String glueType;		// GLUE类型	#com.xxl.job.core.glue.GlueTypeEnum
 	private String glueSource;
 	private String glueRemark;
 	private Date addTime;
 	private Date updateTime;
 
-	public long getId() {
+	public Integer getId() {
 		return id;
 	}
 
-	public void setId(int id) {
+	public void setId(Integer id) {
 		this.id = id;
 	}
 
-	public long getJobId() {
+	public int getJobId() {
 		return jobId;
 	}
 

+ 4 - 7
xxl-job-admin-pg/src/main/java/org/poem/core/model/XxlJobLogReport.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java

@@ -1,22 +1,19 @@
-package org.poem.core.model;
+package com.xxl.job.admin.core.model;
 
 import java.util.Date;
 
 public class XxlJobLogReport {
-
-    private int id;
-
+    private Integer id;
     private Date triggerDay;
-
     private int runningCount;
     private int sucCount;
     private int failCount;
 
-    public long getId() {
+    public Integer getId() {
         return id;
     }
 
-    public void setId(int id) {
+    public void setId(Integer id) {
         this.id = id;
     }
 

+ 4 - 4
xxl-job-admin-pg/src/main/java/org/poem/core/model/XxlJobRegistry.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java

@@ -1,4 +1,4 @@
-package org.poem.core.model;
+package com.xxl.job.admin.core.model;
 
 import java.util.Date;
 
@@ -7,17 +7,17 @@ import java.util.Date;
  */
 public class XxlJobRegistry {
 
-    private int id;
+    private Integer id;
     private String registryGroup;
     private String registryKey;
     private String registryValue;
     private Date updateTime;
 
-    public long getId() {
+    public Integer getId() {
         return id;
     }
 
-    public void setId(int id) {
+    public void setId(Integer id) {
         this.id = id;
     }
 

+ 5 - 5
xxl-job-admin-pg/src/main/java/org/poem/core/model/XxlJobUser.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java

@@ -1,4 +1,4 @@
-package org.poem.core.model;
+package com.xxl.job.admin.core.model;
 
 import org.springframework.util.StringUtils;
 
@@ -7,17 +7,17 @@ import org.springframework.util.StringUtils;
  */
 public class XxlJobUser {
 	
-	private int id;
+	private Integer id;
 	private String username;		// 账号
 	private String password;		// 密码
 	private int role;				// 角色:0-普通用户、1-管理员
 	private String permission;	// 权限:执行器ID列表,多个逗号分割
 
-	public long getId() {
+	public Integer getId() {
 		return id;
 	}
 
-	public void setId(int id) {
+	public void setId(Integer id) {
 		this.id = id;
 	}
 
@@ -54,7 +54,7 @@ public class XxlJobUser {
 	}
 
 	// plugin
-	public boolean validPermission(long jobGroup){
+	public boolean validPermission(int jobGroup){
 		if (this.role == 1) {
 			return true;
 		} else {

+ 3 - 3
xxl-job-admin-pg/src/main/java/org/poem/core/old/RemoteHttpJobBean.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java

@@ -1,7 +1,7 @@
-package org.poem.core.old;//package org.poem.core.jobbean;
+//package com.xxl.job.admin.core.jobbean;
 //
-//import org.poem.core.thread.JobTriggerPoolHelper;
-//import org.poem.core.trigger.TriggerTypeEnum;
+//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
+//import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
 //import org.quartz.JobExecutionContext;
 //import org.quartz.JobExecutionException;
 //import org.quartz.JobKey;

+ 12 - 12
xxl-job-admin-pg/src/main/java/org/poem/core/old/XxlJobDynamicScheduler.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java

@@ -1,15 +1,15 @@
-package org.poem.core.old;//package org.poem.core.schedule;
-//
-//import org.poem.core.conf.XxlJobAdminConfig;
-//import org.poem.core.jobbean.RemoteHttpJobBean;
-//import org.poem.core.model.XxlJobInfo;
-//import org.poem.core.thread.JobFailMonitorHelper;
-//import org.poem.core.thread.JobRegistryMonitorHelper;
-//import org.poem.core.thread.JobTriggerPoolHelper;
-//import org.poem.core.util.I18nUtil;
-//import org.poem.biz.AdminBiz;
-//import org.poem.biz.ExecutorBiz;
-//import org.poem.enums.ExecutorBlockStrategyEnum;
+//package com.xxl.job.admin.core.schedule;
+//
+//import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+//import com.xxl.job.admin.core.jobbean.RemoteHttpJobBean;
+//import com.xxl.job.admin.core.model.XxlJobInfo;
+//import com.xxl.job.admin.core.thread.JobFailMonitorHelper;
+//import com.xxl.job.admin.core.thread.JobRegistryMonitorHelper;
+//import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
+//import com.xxl.job.admin.core.util.I18nUtil;
+//import com.xxl.job.core.biz.AdminBiz;
+//import com.xxl.job.core.biz.ExecutorBiz;
+//import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
 //import com.xxl.rpc.remoting.invoker.XxlRpcInvokerFactory;
 //import com.xxl.rpc.remoting.invoker.call.CallType;
 //import com.xxl.rpc.remoting.invoker.reference.XxlRpcReferenceBean;

+ 1 - 1
xxl-job-admin-pg/src/main/java/org/poem/core/old/XxlJobThreadPool.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java

@@ -1,4 +1,4 @@
-package org.poem.core.old;//package org.poem.core.quartz;
+//package com.xxl.job.admin.core.quartz;
 //
 //import org.quartz.SchedulerConfigException;
 //import org.quartz.spi.ThreadPool;

+ 3 - 3
xxl-job-admin-pg/src/main/java/org/poem/core/route/ExecutorRouteStrategyEnum.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java

@@ -1,7 +1,7 @@
-package org.poem.core.route;
+package com.xxl.job.admin.core.route;
 
-import org.poem.core.route.strategy.*;
-import org.poem.core.util.I18nUtil;
+import com.xxl.job.admin.core.route.strategy.*;
+import com.xxl.job.admin.core.util.I18nUtil;
 
 /**
  * Created by xuxueli on 17/3/10.

+ 3 - 3
xxl-job-admin-pg/src/main/java/org/poem/core/route/ExecutorRouter.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java

@@ -1,7 +1,7 @@
-package org.poem.core.route;
+package com.xxl.job.admin.core.route;
 
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 

+ 9 - 9
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteBusyover.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java

@@ -1,12 +1,12 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.core.scheduler.XxlJobScheduler;
-import org.poem.core.util.I18nUtil;
-import org.poem.biz.ExecutorBiz;
-import org.poem.biz.model.IdleBeatParam;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.core.biz.ExecutorBiz;
+import com.xxl.job.core.biz.model.IdleBeatParam;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.List;
 
@@ -23,7 +23,7 @@ public class ExecutorRouteBusyover extends ExecutorRouter {
             ReturnT<String> idleBeatResult = null;
             try {
                 ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
-                idleBeatResult = executorBiz.idleBeat(new IdleBeatParam((int) triggerParam.getJobId()));
+                idleBeatResult = executorBiz.idleBeat(new IdleBeatParam(triggerParam.getJobId()));
             } catch (Exception e) {
                 logger.error(e.getMessage(), e);
                 idleBeatResult = new ReturnT<String>(ReturnT.FAIL_CODE, ""+e );

+ 5 - 5
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteConsistentHash.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java

@@ -1,8 +1,8 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
@@ -56,7 +56,7 @@ public class ExecutorRouteConsistentHash extends ExecutorRouter {
         return truncateHashCode;
     }
 
-    public String hashJob(Long jobId, List<String> addressList) {
+    public String hashJob(int jobId, List<String> addressList) {
 
         // ------A1------A2-------A3------
         // -----------J1------------------

+ 8 - 8
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteFailover.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java

@@ -1,11 +1,11 @@
-package org.poem.core.route.strategy;
-
-import org.poem.core.route.ExecutorRouter;
-import org.poem.core.scheduler.XxlJobScheduler;
-import org.poem.core.util.I18nUtil;
-import org.poem.biz.ExecutorBiz;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+package com.xxl.job.admin.core.route.strategy;
+
+import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.core.biz.ExecutorBiz;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.List;
 

+ 4 - 4
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteFirst.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java

@@ -1,8 +1,8 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.List;
 

+ 6 - 6
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteLFU.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java

@@ -1,8 +1,8 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
@@ -17,10 +17,10 @@ import java.util.concurrent.ConcurrentMap;
  */
 public class ExecutorRouteLFU extends ExecutorRouter {
 
-    private static ConcurrentMap<Long, HashMap<String, Integer>> jobLfuMap = new ConcurrentHashMap<Long, HashMap<String, Integer>>();
+    private static ConcurrentMap<Integer, HashMap<String, Integer>> jobLfuMap = new ConcurrentHashMap<Integer, HashMap<String, Integer>>();
     private static long CACHE_VALID_TIME = 0;
 
-    public String route(Long jobId, List<String> addressList) {
+    public String route(int jobId, List<String> addressList) {
 
         // cache clear
         if (System.currentTimeMillis() > CACHE_VALID_TIME) {

+ 6 - 6
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteLRU.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java

@@ -1,8 +1,8 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -19,10 +19,10 @@ import java.util.concurrent.ConcurrentMap;
  */
 public class ExecutorRouteLRU extends ExecutorRouter {
 
-    private static ConcurrentMap<Long, LinkedHashMap<String, String>> jobLRUMap = new ConcurrentHashMap<Long, LinkedHashMap<String, String>>();
+    private static ConcurrentMap<Integer, LinkedHashMap<String, String>> jobLRUMap = new ConcurrentHashMap<Integer, LinkedHashMap<String, String>>();
     private static long CACHE_VALID_TIME = 0;
 
-    public String route(Long jobId, List<String> addressList) {
+    public String route(int jobId, List<String> addressList) {
 
         // cache clear
         if (System.currentTimeMillis() > CACHE_VALID_TIME) {

+ 4 - 4
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteLast.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java

@@ -1,8 +1,8 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.List;
 

+ 4 - 4
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteRandom.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java

@@ -1,8 +1,8 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.List;
 import java.util.Random;

+ 6 - 6
xxl-job-admin-pg/src/main/java/org/poem/core/route/strategy/ExecutorRouteRound.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java

@@ -1,8 +1,8 @@
-package org.poem.core.route.strategy;
+package com.xxl.job.admin.core.route.strategy;
 
-import org.poem.core.route.ExecutorRouter;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
+import com.xxl.job.admin.core.route.ExecutorRouter;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
 
 import java.util.List;
 import java.util.Random;
@@ -15,10 +15,10 @@ import java.util.concurrent.atomic.AtomicInteger;
  */
 public class ExecutorRouteRound extends ExecutorRouter {
 
-    private static ConcurrentMap<Long, AtomicInteger> routeCountEachJob = new ConcurrentHashMap<>();
+    private static ConcurrentMap<Integer, AtomicInteger> routeCountEachJob = new ConcurrentHashMap<>();
     private static long CACHE_VALID_TIME = 0;
 
-    private static int count(long jobId) {
+    private static int count(int jobId) {
         // cache clear
         if (System.currentTimeMillis() > CACHE_VALID_TIME) {
             routeCountEachJob.clear();

+ 39 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java

@@ -0,0 +1,39 @@
+package com.xxl.job.admin.core.scheduler;
+
+import com.xxl.job.admin.core.util.I18nUtil;
+
+/**
+ * @author xuxueli 2020-10-29 21:11:23
+ */
+public enum MisfireStrategyEnum {
+
+    /**
+     * do nothing
+     */
+    DO_NOTHING(I18nUtil.getString("misfire_strategy_do_nothing")),
+
+    /**
+     * fire once now
+     */
+    FIRE_ONCE_NOW(I18nUtil.getString("misfire_strategy_fire_once_now"));
+
+    private String title;
+
+    MisfireStrategyEnum(String title) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public static MisfireStrategyEnum match(String name, MisfireStrategyEnum defaultItem){
+        for (MisfireStrategyEnum item: MisfireStrategyEnum.values()) {
+            if (item.name().equals(name)) {
+                return item;
+            }
+        }
+        return defaultItem;
+    }
+
+}

+ 46 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java

@@ -0,0 +1,46 @@
+package com.xxl.job.admin.core.scheduler;
+
+import com.xxl.job.admin.core.util.I18nUtil;
+
+/**
+ * @author xuxueli 2020-10-29 21:11:23
+ */
+public enum ScheduleTypeEnum {
+
+    NONE(I18nUtil.getString("schedule_type_none")),
+
+    /**
+     * schedule by cron
+     */
+    CRON(I18nUtil.getString("schedule_type_cron")),
+
+    /**
+     * schedule by fixed rate (in seconds)
+     */
+    FIX_RATE(I18nUtil.getString("schedule_type_fix_rate")),
+
+    /**
+     * schedule by fix delay (in seconds), after the last time
+     */
+    /*FIX_DELAY(I18nUtil.getString("schedule_type_fix_delay"))*/;
+
+    private String title;
+
+    ScheduleTypeEnum(String title) {
+        this.title = title;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public static ScheduleTypeEnum match(String name, ScheduleTypeEnum defaultItem){
+        for (ScheduleTypeEnum item: ScheduleTypeEnum.values()) {
+            if (item.name().equals(name)) {
+                return item;
+            }
+        }
+        return defaultItem;
+    }
+
+}

+ 20 - 20
xxl-job-admin-pg/src/main/java/org/poem/core/scheduler/XxlJobScheduler.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java

@@ -1,11 +1,11 @@
-package org.poem.core.scheduler;
-
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.thread.*;
-import org.poem.core.util.I18nUtil;
-import org.poem.biz.ExecutorBiz;
-import org.poem.biz.client.ExecutorBizClient;
-import org.poem.enums.ExecutorBlockStrategyEnum;
+package com.xxl.job.admin.core.scheduler;
+
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.thread.*;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.core.biz.ExecutorBiz;
+import com.xxl.job.core.biz.client.ExecutorBizClient;
+import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -24,22 +24,22 @@ public class XxlJobScheduler  {
         // init i18n
         initI18n();
 
+        // admin trigger pool start
+        JobTriggerPoolHelper.toStart();
+
         // admin registry monitor run
-        JobRegistryMonitorHelper.getInstance().start();
+        JobRegistryHelper.getInstance().start();
 
         // admin fail-monitor run
         JobFailMonitorHelper.getInstance().start();
 
-        // admin lose-monitor run
-        JobLosedMonitorHelper.getInstance().start();
-
-        // admin trigger pool start
-        JobTriggerPoolHelper.toStart();
+        // admin lose-monitor run ( depend on JobTriggerPoolHelper )
+        JobCompleteHelper.getInstance().start();
 
         // admin log report start
         JobLogReportHelper.getInstance().start();
 
-        // start-schedule
+        // start-schedule  ( depend on JobTriggerPoolHelper )
         JobScheduleHelper.getInstance().start();
 
         logger.info(">>>>>>>>> init xxl-job admin success.");
@@ -54,17 +54,17 @@ public class XxlJobScheduler  {
         // admin log report stop
         JobLogReportHelper.getInstance().toStop();
 
-        // admin trigger pool stop
-        JobTriggerPoolHelper.toStop();
-
         // admin lose-monitor stop
-        JobLosedMonitorHelper.getInstance().toStop();
+        JobCompleteHelper.getInstance().toStop();
 
         // admin fail-monitor stop
         JobFailMonitorHelper.getInstance().toStop();
 
         // admin registry stop
-        JobRegistryMonitorHelper.getInstance().toStop();
+        JobRegistryHelper.getInstance().toStop();
+
+        // admin trigger pool stop
+        JobTriggerPoolHelper.toStop();
 
     }
 

+ 184 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java

@@ -0,0 +1,184 @@
+package com.xxl.job.admin.core.thread;
+
+import com.xxl.job.admin.core.complete.XxlJobCompleter;
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobLog;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.core.biz.model.HandleCallbackParam;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.util.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.*;
+
+/**
+ * job lose-monitor instance
+ *
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobCompleteHelper {
+	private static Logger logger = LoggerFactory.getLogger(JobCompleteHelper.class);
+	
+	private static JobCompleteHelper instance = new JobCompleteHelper();
+	public static JobCompleteHelper getInstance(){
+		return instance;
+	}
+
+	// ---------------------- monitor ----------------------
+
+	private ThreadPoolExecutor callbackThreadPool = null;
+	private Thread monitorThread;
+	private volatile boolean toStop = false;
+	public void start(){
+
+		// for callback
+		callbackThreadPool = new ThreadPoolExecutor(
+				2,
+				20,
+				30L,
+				TimeUnit.SECONDS,
+				new LinkedBlockingQueue<Runnable>(3000),
+				new ThreadFactory() {
+					@Override
+					public Thread newThread(Runnable r) {
+						return new Thread(r, "xxl-job, admin JobLosedMonitorHelper-callbackThreadPool-" + r.hashCode());
+					}
+				},
+				new RejectedExecutionHandler() {
+					@Override
+					public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+						r.run();
+						logger.warn(">>>>>>>>>>> xxl-job, callback too fast, match threadpool rejected handler(run now).");
+					}
+				});
+
+
+		// for monitor
+		monitorThread = new Thread(new Runnable() {
+
+			@Override
+			public void run() {
+
+				// wait for JobTriggerPoolHelper-init
+				try {
+					TimeUnit.MILLISECONDS.sleep(50);
+				} catch (InterruptedException e) {
+					if (!toStop) {
+						logger.error(e.getMessage(), e);
+					}
+				}
+
+				// monitor
+				while (!toStop) {
+					try {
+						// 任务结果丢失处理:调度记录停留在 "运行中" 状态超过10min,且对应执行器心跳注册失败不在线,则将本地调度主动标记失败;
+						Date losedTime = DateUtil.addMinutes(new Date(), -10);
+						List<Long> losedJobIds  = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findLostJobIds(losedTime);
+
+						if (losedJobIds!=null && losedJobIds.size()>0) {
+							for (Long logId: losedJobIds) {
+
+								XxlJobLog jobLog = new XxlJobLog();
+								jobLog.setId(logId);
+
+								jobLog.setHandleTime(new Date());
+								jobLog.setHandleCode(ReturnT.FAIL_CODE);
+								jobLog.setHandleMsg( I18nUtil.getString("joblog_lost_fail") );
+
+								XxlJobCompleter.updateHandleInfoAndFinish(jobLog);
+							}
+
+						}
+					} catch (Exception e) {
+						if (!toStop) {
+							logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);
+						}
+					}
+
+                    try {
+                        TimeUnit.SECONDS.sleep(60);
+                    } catch (Exception e) {
+                        if (!toStop) {
+                            logger.error(e.getMessage(), e);
+                        }
+                    }
+
+                }
+
+				logger.info(">>>>>>>>>>> xxl-job, JobLosedMonitorHelper stop");
+
+			}
+		});
+		monitorThread.setDaemon(true);
+		monitorThread.setName("xxl-job, admin JobLosedMonitorHelper");
+		monitorThread.start();
+	}
+
+	public void toStop(){
+		toStop = true;
+
+		// stop registryOrRemoveThreadPool
+		callbackThreadPool.shutdownNow();
+
+		// stop monitorThread (interrupt and wait)
+		monitorThread.interrupt();
+		try {
+			monitorThread.join();
+		} catch (InterruptedException e) {
+			logger.error(e.getMessage(), e);
+		}
+	}
+
+
+	// ---------------------- helper ----------------------
+
+	public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {
+
+		callbackThreadPool.execute(new Runnable() {
+			@Override
+			public void run() {
+				for (HandleCallbackParam handleCallbackParam: callbackParamList) {
+					ReturnT<String> callbackResult = callback(handleCallbackParam);
+					logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
+							(callbackResult.getCode()== ReturnT.SUCCESS_CODE?"success":"fail"), handleCallbackParam, callbackResult);
+				}
+			}
+		});
+
+		return ReturnT.SUCCESS;
+	}
+
+	private ReturnT<String> callback(HandleCallbackParam handleCallbackParam) {
+		// valid log item
+		XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(handleCallbackParam.getLogId());
+		if (log == null) {
+			return new ReturnT<String>(ReturnT.FAIL_CODE, "log item not found.");
+		}
+		if (log.getHandleCode() > 0) {
+			return new ReturnT<String>(ReturnT.FAIL_CODE, "log repeate callback.");     // avoid repeat callback, trigger child job etc
+		}
+
+		// handle msg
+		StringBuffer handleMsg = new StringBuffer();
+		if (log.getHandleMsg()!=null) {
+			handleMsg.append(log.getHandleMsg()).append("<br>");
+		}
+		if (handleCallbackParam.getHandleMsg() != null) {
+			handleMsg.append(handleCallbackParam.getHandleMsg());
+		}
+
+		// success, save log
+		log.setHandleTime(new Date());
+		log.setHandleCode(handleCallbackParam.getHandleCode());
+		log.setHandleMsg(handleMsg.toString());
+		XxlJobCompleter.updateHandleInfoAndFinish(log);
+
+		return ReturnT.SUCCESS;
+	}
+
+
+
+}

+ 8 - 8
xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobFailMonitorHelper.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java

@@ -1,10 +1,10 @@
-package org.poem.core.thread;
+package com.xxl.job.admin.core.thread;
 
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLog;
-import org.poem.core.trigger.TriggerTypeEnum;
-import org.poem.core.util.I18nUtil;
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLog;
+import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
+import com.xxl.job.admin.core.util.I18nUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,7 +43,7 @@ public class JobFailMonitorHelper {
 							for (long failLogId: failLogIds) {
 
 								// lock log
-								int lockRet = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus((int) failLogId, 0, -1);
+								int lockRet = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, 0, -1);
 								if (lockRet < 1) {
 									continue;
 								}
@@ -67,7 +67,7 @@ public class JobFailMonitorHelper {
 									newAlarmStatus = 1;
 								}
 
-								XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus((int) failLogId, -1, newAlarmStatus);
+								XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, -1, newAlarmStatus);
 							}
 						}
 

+ 3 - 5
xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobLogReportHelper.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java

@@ -1,8 +1,7 @@
-package org.poem.core.thread;
+package com.xxl.job.admin.core.thread;
 
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.model.XxlJobLogReport;
-import org.poem.util.SnowFlake;
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobLogReport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -84,7 +83,6 @@ public class JobLogReportHelper {
                             // do refresh
                             int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().update(xxlJobLogReport);
                             if (ret < 1) {
-                                xxlJobLogReport.setId(SnowFlake.genLongId());
                                 XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().save(xxlJobLogReport);
                             }
                         }

+ 204 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java

@@ -0,0 +1,204 @@
+package com.xxl.job.admin.core.thread;
+
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobRegistry;
+import com.xxl.job.core.biz.model.RegistryParam;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.enums.RegistryConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * job registry instance
+ * @author xuxueli 2016-10-02 19:10:24
+ */
+public class JobRegistryHelper {
+	private static Logger logger = LoggerFactory.getLogger(JobRegistryHelper.class);
+
+	private static JobRegistryHelper instance = new JobRegistryHelper();
+	public static JobRegistryHelper getInstance(){
+		return instance;
+	}
+
+	private ThreadPoolExecutor registryOrRemoveThreadPool = null;
+	private Thread registryMonitorThread;
+	private volatile boolean toStop = false;
+
+	public void start(){
+
+		// for registry or remove
+		registryOrRemoveThreadPool = new ThreadPoolExecutor(
+				2,
+				10,
+				30L,
+				TimeUnit.SECONDS,
+				new LinkedBlockingQueue<Runnable>(2000),
+				new ThreadFactory() {
+					@Override
+					public Thread newThread(Runnable r) {
+						return new Thread(r, "xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-" + r.hashCode());
+					}
+				},
+				new RejectedExecutionHandler() {
+					@Override
+					public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
+						r.run();
+						logger.warn(">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now).");
+					}
+				});
+
+		// for monitor
+		registryMonitorThread = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				while (!toStop) {
+					try {
+						// auto registry group
+						List<XxlJobGroup> groupList = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0);
+						if (groupList!=null && !groupList.isEmpty()) {
+
+							// remove dead address (admin/executor)
+							List<Integer> ids = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findDead(RegistryConfig.DEAD_TIMEOUT, new Date());
+							if (ids!=null && ids.size()>0) {
+								XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(ids);
+							}
+
+							// fresh online address (admin/executor)
+							HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
+							List<XxlJobRegistry> list = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
+							if (list != null) {
+								for (XxlJobRegistry item: list) {
+									if (RegistryConfig.RegistType.EXECUTOR.name().equals(item.getRegistryGroup())) {
+										String appname = item.getRegistryKey();
+										List<String> registryList = appAddressMap.get(appname);
+										if (registryList == null) {
+											registryList = new ArrayList<String>();
+										}
+
+										if (!registryList.contains(item.getRegistryValue())) {
+											registryList.add(item.getRegistryValue());
+										}
+										appAddressMap.put(appname, registryList);
+									}
+								}
+							}
+
+							// fresh group address
+							for (XxlJobGroup group: groupList) {
+								List<String> registryList = appAddressMap.get(group.getAppname());
+								String addressListStr = null;
+								if (registryList!=null && !registryList.isEmpty()) {
+									Collections.sort(registryList);
+									StringBuilder addressListSB = new StringBuilder();
+									for (String item:registryList) {
+										addressListSB.append(item).append(",");
+									}
+									addressListStr = addressListSB.toString();
+									addressListStr = addressListStr.substring(0, addressListStr.length()-1);
+								}
+								group.setAddressList(addressListStr);
+								group.setUpdateTime(new Date());
+
+								XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().update(group);
+							}
+						}
+					} catch (Exception e) {
+						if (!toStop) {
+							logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
+						}
+					}
+					try {
+						TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);
+					} catch (InterruptedException e) {
+						if (!toStop) {
+							logger.error(">>>>>>>>>>> xxl-job, job registry monitor thread error:{}", e);
+						}
+					}
+				}
+				logger.info(">>>>>>>>>>> xxl-job, job registry monitor thread stop");
+			}
+		});
+		registryMonitorThread.setDaemon(true);
+		registryMonitorThread.setName("xxl-job, admin JobRegistryMonitorHelper-registryMonitorThread");
+		registryMonitorThread.start();
+	}
+
+	public void toStop(){
+		toStop = true;
+
+		// stop registryOrRemoveThreadPool
+		registryOrRemoveThreadPool.shutdownNow();
+
+		// stop monitir (interrupt and wait)
+		registryMonitorThread.interrupt();
+		try {
+			registryMonitorThread.join();
+		} catch (InterruptedException e) {
+			logger.error(e.getMessage(), e);
+		}
+	}
+
+
+	// ---------------------- helper ----------------------
+
+	public ReturnT<String> registry(RegistryParam registryParam) {
+
+		// valid
+		if (!StringUtils.hasText(registryParam.getRegistryGroup())
+				|| !StringUtils.hasText(registryParam.getRegistryKey())
+				|| !StringUtils.hasText(registryParam.getRegistryValue())) {
+			return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
+		}
+
+		// async execute
+		registryOrRemoveThreadPool.execute(new Runnable() {
+			@Override
+			public void run() {
+				int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registryUpdate(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
+				if (ret < 1) {
+					XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registrySave(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue(), new Date());
+
+					// fresh
+					freshGroupRegistryInfo(registryParam);
+				}
+			}
+		});
+
+		return ReturnT.SUCCESS;
+	}
+
+	public ReturnT<String> registryRemove(RegistryParam registryParam) {
+
+		// valid
+		if (!StringUtils.hasText(registryParam.getRegistryGroup())
+				|| !StringUtils.hasText(registryParam.getRegistryKey())
+				|| !StringUtils.hasText(registryParam.getRegistryValue())) {
+			return new ReturnT<String>(ReturnT.FAIL_CODE, "Illegal Argument.");
+		}
+
+		// async execute
+		registryOrRemoveThreadPool.execute(new Runnable() {
+			@Override
+			public void run() {
+				int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().registryDelete(registryParam.getRegistryGroup(), registryParam.getRegistryKey(), registryParam.getRegistryValue());
+				if (ret > 0) {
+					// fresh
+					freshGroupRegistryInfo(registryParam);
+				}
+			}
+		});
+
+		return ReturnT.SUCCESS;
+	}
+
+	private void freshGroupRegistryInfo(RegistryParam registryParam){
+		// Under consideration, prevent affecting core tables
+	}
+
+
+}

+ 55 - 38
xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobScheduleHelper.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java

@@ -1,20 +1,19 @@
-package org.poem.core.thread;
-
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.cron.CronExpression;
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.trigger.TriggerTypeEnum;
+package com.xxl.job.admin.core.thread;
+
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.cron.CronExpression;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
+import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
+import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.SQLException;
-import java.text.ParseException;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
-
 /**
  * @author xuxueli 2019-05-21
  */
@@ -32,7 +31,7 @@ public class JobScheduleHelper {
     private Thread ringThread;
     private volatile boolean scheduleThreadToStop = false;
     private volatile boolean ringThreadToStop = false;
-    private volatile static Map<Integer, List<Long>> ringData = new ConcurrentHashMap<>();
+    private volatile static Map<Integer, List<Integer>> ringData = new ConcurrentHashMap<>();
 
     public void start(){
 
@@ -69,7 +68,7 @@ public class JobScheduleHelper {
                         connAutoCommit = conn.getAutoCommit();
                         conn.setAutoCommit(false);
 
-                        preparedStatement = conn.prepareStatement(  "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" );
+                        preparedStatement = conn.prepareStatement(  "select * from xxl_job.xxl_job_lock where lock_name = 'schedule_lock' for update" );
                         preparedStatement.execute();
 
                         // tx start
@@ -86,7 +85,15 @@ public class JobScheduleHelper {
                                     // 2.1、trigger-expire > 5s:pass && make next-trigger-time
                                     logger.warn(">>>>>>>>>>> xxl-job, schedule misfire, jobId = " + jobInfo.getId());
 
-                                    // fresh next
+                                    // 1、misfire match
+                                    MisfireStrategyEnum misfireStrategyEnum = MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), MisfireStrategyEnum.DO_NOTHING);
+                                    if (MisfireStrategyEnum.FIRE_ONCE_NOW == misfireStrategyEnum) {
+                                        // FIRE_ONCE_NOW 》 trigger
+                                        JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.MISFIRE, -1, null, null, null);
+                                        logger.debug(">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId() );
+                                    }
+
+                                    // 2、fresh next
                                     refreshNextValidTime(jobInfo, new Date());
 
                                 } else if (nowTime > jobInfo.getTriggerNextTime()) {
@@ -213,23 +220,23 @@ public class JobScheduleHelper {
             @Override
             public void run() {
 
-                // align second
-                try {
-                    TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis()%1000 );
-                } catch (InterruptedException e) {
-                    if (!ringThreadToStop) {
-                        logger.error(e.getMessage(), e);
-                    }
-                }
-
                 while (!ringThreadToStop) {
 
+                    // align second
+                    try {
+                        TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis() % 1000);
+                    } catch (InterruptedException e) {
+                        if (!ringThreadToStop) {
+                            logger.error(e.getMessage(), e);
+                        }
+                    }
+
                     try {
                         // second data
-                        List<Long> ringItemData = new ArrayList<>();
+                        List<Integer> ringItemData = new ArrayList<>();
                         int nowSecond = Calendar.getInstance().get(Calendar.SECOND);   // 避免处理耗时太长,跨过刻度,向前校验一个刻度;
                         for (int i = 0; i < 2; i++) {
-                            List<Long> tmpData = ringData.remove( (nowSecond+60-i)%60 );
+                            List<Integer> tmpData = ringData.remove( (nowSecond+60-i)%60 );
                             if (tmpData != null) {
                                 ringItemData.addAll(tmpData);
                             }
@@ -239,7 +246,7 @@ public class JobScheduleHelper {
                         logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + Arrays.asList(ringItemData) );
                         if (ringItemData.size() > 0) {
                             // do trigger
-                            for (Long jobId: ringItemData) {
+                            for (int jobId: ringItemData) {
                                 // do trigger
                                 JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null);
                             }
@@ -251,15 +258,6 @@ public class JobScheduleHelper {
                             logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e);
                         }
                     }
-
-                    // next second, align second
-                    try {
-                        TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis()%1000);
-                    } catch (InterruptedException e) {
-                        if (!ringThreadToStop) {
-                            logger.error(e.getMessage(), e);
-                        }
-                    }
                 }
                 logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop");
             }
@@ -269,8 +267,8 @@ public class JobScheduleHelper {
         ringThread.start();
     }
 
-    private void refreshNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws ParseException {
-        Date nextValidTime = new CronExpression(jobInfo.getJobCron()).getNextValidTimeAfter(fromTime);
+    private void refreshNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws Exception {
+        Date nextValidTime = generateNextValidTime(jobInfo, fromTime);
         if (nextValidTime != null) {
             jobInfo.setTriggerLastTime(jobInfo.getTriggerNextTime());
             jobInfo.setTriggerNextTime(nextValidTime.getTime());
@@ -278,12 +276,18 @@ public class JobScheduleHelper {
             jobInfo.setTriggerStatus(0);
             jobInfo.setTriggerLastTime(0);
             jobInfo.setTriggerNextTime(0);
+            logger.warn(">>>>>>>>>>> xxl-job, refreshNextValidTime fail for job: jobId={}, scheduleType={}, scheduleConf={}",
+                    jobInfo.getId(), jobInfo.getScheduleType(), jobInfo.getScheduleConf());
         }
     }
 
-    private void pushTimeRing(int ringSecond, Long jobId){
+    private void pushTimeRing(int ringSecond, int jobId){
         // push async ring
-        List<Long> ringItemData = ringData.computeIfAbsent(ringSecond, k -> new ArrayList<Long>());
+        List<Integer> ringItemData = ringData.get(ringSecond);
+        if (ringItemData == null) {
+            ringItemData = new ArrayList<Integer>();
+            ringData.put(ringSecond, ringItemData);
+        }
         ringItemData.add(jobId);
 
         logger.debug(">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData) );
@@ -312,7 +316,7 @@ public class JobScheduleHelper {
         boolean hasRingData = false;
         if (!ringData.isEmpty()) {
             for (int second : ringData.keySet()) {
-                List<Long> tmpData = ringData.get(second);
+                List<Integer> tmpData = ringData.get(second);
                 if (tmpData!=null && tmpData.size()>0) {
                     hasRingData = true;
                     break;
@@ -347,4 +351,17 @@ public class JobScheduleHelper {
         logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper stop");
     }
 
+
+    // ---------------------- tools ----------------------
+    public static Date generateNextValidTime(XxlJobInfo jobInfo, Date fromTime) throws Exception {
+        ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
+        if (ScheduleTypeEnum.CRON == scheduleTypeEnum) {
+            Date nextValidTime = new CronExpression(jobInfo.getScheduleConf()).getNextValidTimeAfter(fromTime);
+            return nextValidTime;
+        } else if (ScheduleTypeEnum.FIX_RATE == scheduleTypeEnum /*|| ScheduleTypeEnum.FIX_DELAY == scheduleTypeEnum*/) {
+            return new Date(fromTime.getTime() + Integer.valueOf(jobInfo.getScheduleConf())*1000 );
+        }
+        return null;
+    }
+
 }

+ 7 - 7
xxl-job-admin-pg/src/main/java/org/poem/core/thread/JobTriggerPoolHelper.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java

@@ -1,8 +1,8 @@
-package org.poem.core.thread;
+package com.xxl.job.admin.core.thread;
 
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.trigger.TriggerTypeEnum;
-import org.poem.core.trigger.XxlJobTrigger;
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
+import com.xxl.job.admin.core.trigger.XxlJobTrigger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -63,13 +63,13 @@ public class JobTriggerPoolHelper {
 
     // job timeout count
     private volatile long minTim = System.currentTimeMillis()/60000;     // ms > min
-    private volatile ConcurrentMap<Long, AtomicInteger> jobTimeoutCountMap = new ConcurrentHashMap<>();
+    private volatile ConcurrentMap<Integer, AtomicInteger> jobTimeoutCountMap = new ConcurrentHashMap<>();
 
 
     /**
      * add trigger
      */
-    public void addTrigger(final long jobId,
+    public void addTrigger(final int jobId,
                            final TriggerTypeEnum triggerType,
                            final int failRetryCount,
                            final String executorShardingParam,
@@ -143,7 +143,7 @@ public class JobTriggerPoolHelper {
      *          null: use job param
      *          not null: cover job param
      */
-    public static void trigger(Long jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam, String addressList) {
+    public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam, String addressList) {
         helper.addTrigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);
     }
 

+ 4 - 3
xxl-job-admin-pg/src/main/java/org/poem/core/trigger/TriggerTypeEnum.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java

@@ -1,6 +1,6 @@
-package org.poem.core.trigger;
+package com.xxl.job.admin.core.trigger;
 
-import org.poem.core.util.I18nUtil;
+import com.xxl.job.admin.core.util.I18nUtil;
 
 /**
  * trigger type enum
@@ -13,7 +13,8 @@ public enum TriggerTypeEnum {
     CRON(I18nUtil.getString("jobconf_trigger_type_cron")),
     RETRY(I18nUtil.getString("jobconf_trigger_type_retry")),
     PARENT(I18nUtil.getString("jobconf_trigger_type_parent")),
-    API(I18nUtil.getString("jobconf_trigger_type_api"));
+    API(I18nUtil.getString("jobconf_trigger_type_api")),
+    MISFIRE(I18nUtil.getString("jobconf_trigger_type_misfire"));
 
     private TriggerTypeEnum(String title){
         this.title = title;

+ 18 - 21
xxl-job-admin-pg/src/main/java/org/poem/core/trigger/XxlJobTrigger.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java

@@ -1,19 +1,18 @@
-package org.poem.core.trigger;
-
-import org.poem.core.conf.XxlJobAdminConfig;
-import org.poem.core.model.XxlJobGroup;
-import org.poem.core.model.XxlJobInfo;
-import org.poem.core.model.XxlJobLog;
-import org.poem.core.route.ExecutorRouteStrategyEnum;
-import org.poem.core.scheduler.XxlJobScheduler;
-import org.poem.core.util.I18nUtil;
-import org.poem.biz.ExecutorBiz;
-import org.poem.biz.model.ReturnT;
-import org.poem.biz.model.TriggerParam;
-import org.poem.enums.ExecutorBlockStrategyEnum;
-import org.poem.util.IpUtil;
-import org.poem.util.SnowFlake;
-import org.poem.util.ThrowableUtil;
+package com.xxl.job.admin.core.trigger;
+
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLog;
+import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
+import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.core.biz.ExecutorBiz;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
+import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
+import com.xxl.job.core.util.IpUtil;
+import com.xxl.job.core.util.ThrowableUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,7 +41,7 @@ public class XxlJobTrigger {
      *          null: use executor addressList
      *          not null: cover
      */
-    public static void trigger(long jobId,
+    public static void trigger(int jobId,
                                TriggerTypeEnum triggerType,
                                int failRetryCount,
                                String executorShardingParam,
@@ -118,11 +117,9 @@ public class XxlJobTrigger {
 
         // 1、save log-id
         XxlJobLog jobLog = new XxlJobLog();
-        jobLog.setJobGroup((int) jobInfo.getJobGroup());
-        jobLog.setJobId((int) jobInfo.getId());
+        jobLog.setJobGroup(jobInfo.getJobGroup());
+        jobLog.setJobId(jobInfo.getId());
         jobLog.setTriggerTime(new Date());
-        jobLog.setExecutorFailRetryCount(0);
-        jobLog.setId(SnowFlake.genLongId());
         XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().save(jobLog);
         logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());
 

+ 1 - 1
xxl-job-admin-pg/src/main/java/org/poem/core/util/CookieUtil.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java

@@ -1,4 +1,4 @@
-package org.poem.core.util;
+package com.xxl.job.admin.core.util;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;

+ 1 - 1
xxl-job-admin-pg/src/main/java/org/poem/core/util/FtlUtil.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java

@@ -1,4 +1,4 @@
-package org.poem.core.util;
+package com.xxl.job.admin.core.util;
 
 import freemarker.ext.beans.BeansWrapper;
 import freemarker.ext.beans.BeansWrapperBuilder;

+ 2 - 2
xxl-job-admin-pg/src/main/java/org/poem/core/util/I18nUtil.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java

@@ -1,6 +1,6 @@
-package org.poem.core.util;
+package com.xxl.job.admin.core.util;
 
-import org.poem.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.core.io.ClassPathResource;

+ 1 - 1
xxl-job-admin-pg/src/main/java/org/poem/core/util/JacksonUtil.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java

@@ -1,4 +1,4 @@
-package org.poem.core.util;
+package com.xxl.job.admin.core.util;
 
 import com.fasterxml.jackson.core.JsonGenerationException;
 import com.fasterxml.jackson.core.JsonParseException;

+ 1 - 1
xxl-job-admin-pg/src/main/java/org/poem/core/util/LocalCacheUtil.java → xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java

@@ -1,4 +1,4 @@
-package org.poem.core.util;
+package com.xxl.job.admin.core.util;
 
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;

+ 4 - 4
xxl-job-admin-pg/src/main/java/org/poem/dao/XxlJobGroupDao.java → xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java

@@ -1,6 +1,6 @@
-package org.poem.dao;
+package com.xxl.job.admin.dao;
 
-import org.poem.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobGroup;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -20,9 +20,9 @@ public interface XxlJobGroupDao {
 
     public int update(XxlJobGroup xxlJobGroup);
 
-    public int remove(@Param("id") long id);
+    public int remove(@Param("id") int id);
 
-    public XxlJobGroup load(@Param("id") long id);
+    public XxlJobGroup load(@Param("id") int id);
 
     public List<XxlJobGroup> pageList(@Param("offset") int offset,
                                       @Param("pagesize") int pagesize,

+ 6 - 6
xxl-job-admin-pg/src/main/java/org/poem/dao/XxlJobInfoDao.java → xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java

@@ -1,6 +1,6 @@
-package org.poem.dao;
+package com.xxl.job.admin.dao;
 
-import org.poem.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobInfo;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -16,14 +16,14 @@ public interface XxlJobInfoDao {
 
 	public List<XxlJobInfo> pageList(@Param("offset") int offset,
 									 @Param("pagesize") int pagesize,
-									 @Param("jobGroup") long jobGroup,
+									 @Param("jobGroup") int jobGroup,
 									 @Param("triggerStatus") int triggerStatus,
 									 @Param("jobDesc") String jobDesc,
 									 @Param("executorHandler") String executorHandler,
 									 @Param("author") String author);
 	public int pageListCount(@Param("offset") int offset,
 							 @Param("pagesize") int pagesize,
-							 @Param("jobGroup") long jobGroup,
+							 @Param("jobGroup") int jobGroup,
 							 @Param("triggerStatus") int triggerStatus,
 							 @Param("jobDesc") String jobDesc,
 							 @Param("executorHandler") String executorHandler,
@@ -31,13 +31,13 @@ public interface XxlJobInfoDao {
 	
 	public int save(XxlJobInfo info);
 
-	public XxlJobInfo loadById(@Param("id") long id);
+	public XxlJobInfo loadById(@Param("id") int id);
 	
 	public int update(XxlJobInfo xxlJobInfo);
 	
 	public int delete(@Param("id") long id);
 
-	public List<XxlJobInfo> getJobsByGroup(@Param("jobGroup") long jobGroup);
+	public List<XxlJobInfo> getJobsByGroup(@Param("jobGroup") int jobGroup);
 
 	public int findAllCount();
 

+ 6 - 6
xxl-job-admin-pg/src/main/java/org/poem/dao/XxlJobLogDao.java → xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java

@@ -1,6 +1,6 @@
-package org.poem.dao;
+package com.xxl.job.admin.dao;
 
-import org.poem.core.model.XxlJobLog;
+import com.xxl.job.admin.core.model.XxlJobLog;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -18,14 +18,14 @@ public interface XxlJobLogDao {
 	// exist jobId not use jobGroup, not exist use jobGroup
 	public List<XxlJobLog> pageList(@Param("offset") int offset,
 									@Param("pagesize") int pagesize,
-									@Param("jobGroup") long jobGroup,
+									@Param("jobGroup") int jobGroup,
 									@Param("jobId") int jobId,
 									@Param("triggerTimeStart") Date triggerTimeStart,
 									@Param("triggerTimeEnd") Date triggerTimeEnd,
 									@Param("logStatus") int logStatus);
 	public int pageListCount(@Param("offset") int offset,
 							 @Param("pagesize") int pagesize,
-							 @Param("jobGroup") long jobGroup,
+							 @Param("jobGroup") int jobGroup,
 							 @Param("jobId") int jobId,
 							 @Param("triggerTimeStart") Date triggerTimeStart,
 							 @Param("triggerTimeEnd") Date triggerTimeEnd,
@@ -44,7 +44,7 @@ public interface XxlJobLogDao {
 	public Map<String, Object> findLogReport(@Param("from") Date from,
 											 @Param("to") Date to);
 
-	public List<Long> findClearLogIds(@Param("jobGroup") long jobGroup,
+	public List<Long> findClearLogIds(@Param("jobGroup") int jobGroup,
 									  @Param("jobId") int jobId,
 									  @Param("clearBeforeTime") Date clearBeforeTime,
 									  @Param("clearBeforeNum") int clearBeforeNum,
@@ -53,7 +53,7 @@ public interface XxlJobLogDao {
 
 	public List<Long> findFailJobLogIds(@Param("pagesize") int pagesize);
 
-	public int updateAlarmStatus(@Param("logId") int logId,
+	public int updateAlarmStatus(@Param("logId") long logId,
 								 @Param("oldAlarmStatus") int oldAlarmStatus,
 								 @Param("newAlarmStatus") int newAlarmStatus);
 

+ 5 - 5
xxl-job-admin-pg/src/main/java/org/poem/dao/XxlJobLogGlueDao.java → xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java

@@ -1,6 +1,6 @@
-package org.poem.dao;
+package com.xxl.job.admin.dao;
 
-import org.poem.core.model.XxlJobLogGlue;
+import com.xxl.job.admin.core.model.XxlJobLogGlue;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -15,10 +15,10 @@ public interface XxlJobLogGlueDao {
 	
 	public int save(XxlJobLogGlue xxlJobLogGlue);
 	
-	public List<XxlJobLogGlue> findByJobId(@Param("jobId") long jobId);
+	public List<XxlJobLogGlue> findByJobId(@Param("jobId") int jobId);
 
-	public int removeOld(@Param("jobId") long jobId, @Param("limit") int limit);
+	public int removeOld(@Param("jobId") int jobId, @Param("limit") int limit);
 
-	public int deleteByJobId(@Param("jobId") long jobId);
+	public int deleteByJobId(@Param("jobId") int jobId);
 	
 }

+ 2 - 2
xxl-job-admin-pg/src/main/java/org/poem/dao/XxlJobLogReportDao.java → xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java

@@ -1,6 +1,6 @@
-package org.poem.dao;
+package com.xxl.job.admin.dao;
 
-import org.poem.core.model.XxlJobLogReport;
+import com.xxl.job.admin.core.model.XxlJobLogReport;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 

+ 3 - 4
xxl-job-admin-pg/src/main/java/org/poem/dao/XxlJobRegistryDao.java → xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java

@@ -1,6 +1,6 @@
-package org.poem.dao;
+package com.xxl.job.admin.dao;
 
-import org.poem.core.model.XxlJobRegistry;
+import com.xxl.job.admin.core.model.XxlJobRegistry;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -26,8 +26,7 @@ public interface XxlJobRegistryDao {
                               @Param("registryValue") String registryValue,
                               @Param("updateTime") Date updateTime);
 
-    public int registrySave(@Param("id") int id,
-                            @Param("registryGroup") String registryGroup,
+    public int registrySave(@Param("registryGroup") String registryGroup,
                             @Param("registryKey") String registryKey,
                             @Param("registryValue") String registryValue,
                             @Param("updateTime") Date updateTime);

Неке датотеке нису приказане због велике количине промена