@@ -128,6 +131,13 @@
${jwt.version}
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ ${jaxb.version}
+
+
com.baomidou
@@ -158,6 +168,7 @@
${hutool.version}
+
org.springframework.cloud
spring-cloud-starter-openfeign
@@ -169,7 +180,7 @@
-
+
io.github.openfeign
feign-okhttp
@@ -204,13 +215,62 @@
lock4j-redisson-spring-boot-starter
${lock4j.version}
-
+
+
+
+ com.xuxueli
+ xxl-job-core
+ ${xxl-job.version}
+
+
+
+ com.yomahub
+ tlog-spring-boot-configuration
+ ${tlog.version}
+
+
+
+ com.yomahub
+ tlog-webroot
+ ${tlog.version}
+
+
+ javassist
+ org.javassist
+
+
+ guava
+ com.google.guava
+
+
+
+
+
+ com.yomahub
+ tlog-feign
+ ${tlog.version}
+
+
+
+ com.yomahub
+ tlog-xxl-job
+ ${tlog.version}
+
+
+
com.ruoyi
ruoyi-quartz
${ruoyi-vue-plus.version}
+
+
+ com.ruoyi
+ ruoyi-job
+ ${ruoyi-vue-plus.version}
+
+
com.ruoyi
@@ -239,7 +299,7 @@
${ruoyi-vue-plus.version}
-
+
com.ruoyi
ruoyi-oss
@@ -261,6 +321,7 @@
ruoyi-framework
ruoyi-system
ruoyi-quartz
+ ruoyi-job
ruoyi-generator
ruoyi-common
ruoyi-demo
@@ -269,16 +330,6 @@
pom
-
-
-
-
- com.sun.xml.bind
- jaxb-impl
- ${jaxb.version}
-
-
-
@@ -360,4 +411,4 @@
-
\ No newline at end of file
+
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 12327e305..9ec68cdd1 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -5,7 +5,7 @@
ruoyi-vue-plus
com.ruoyi
- 3.2.0
+ 3.3.0
4.0.0
jar
@@ -41,10 +41,15 @@
ruoyi-system
-
+
+
+
+
+
+
com.ruoyi
- ruoyi-quartz
+ ruoyi-job
@@ -115,4 +120,4 @@
-
\ No newline at end of file
+
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
index 3a1a4aef0..f389ff437 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -10,12 +10,12 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
*/
@SpringBootApplication
-public class RuoYiApplication
-{
- public static void main(String[] args)
- {
+public class RuoYiApplication {
+
+ public static void main(String[] args) {
System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(RuoYiApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ RuoYi-Vue-Plus启动成功 ლ(´ڡ`ლ)゙");
}
+
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
index 6de67dc76..dd0562684 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
@@ -5,14 +5,14 @@ import org.springframework.boot.web.servlet.support.SpringBootServletInitializer
/**
* web容器中进行部署
- *
+ *
* @author ruoyi
*/
-public class RuoYiServletInitializer extends SpringBootServletInitializer
-{
+public class RuoYiServletInitializer extends SpringBootServletInitializer {
+
@Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
- {
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(RuoYiApplication.class);
}
+
}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
index b6f8a5087..4a2bf30d7 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
@@ -13,6 +13,9 @@ import com.ruoyi.common.utils.reflect.ReflectUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.framework.config.properties.CaptchaProperties;
import com.ruoyi.system.service.ISysConfigService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -24,61 +27,61 @@ import java.util.concurrent.TimeUnit;
/**
* 验证码操作处理
*
- * @author ruoyi
+ * @author Lion Li
*/
+@Api(value = "验证码操作处理", tags = {"验证码管理"})
+@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RestController
public class CaptchaController {
- @Autowired
- private CaptchaProperties captchaProperties;
+ private final CaptchaProperties captchaProperties;
+ private final ISysConfigService configService;
- @Autowired
- private ISysConfigService configService;
+ /**
+ * 生成验证码
+ */
+ @ApiOperation("生成验证码")
+ @GetMapping("/captchaImage")
+ public AjaxResult
-
+
io.jsonwebtoken
jjwt
+
+
+ com.sun.xml.bind
+ jaxb-impl
+
+
org.springframework.boot
@@ -111,11 +117,13 @@
lombok
+
org.springframework.cloud
spring-cloud-starter-openfeign
+
io.github.openfeign
feign-okhttp
@@ -156,6 +164,21 @@
com.baomidou
lock4j-redisson-spring-boot-starter
+
+
+ com.yomahub
+ tlog-spring-boot-configuration
+
+
+
+ com.yomahub
+ tlog-webroot
+
+
+
+ com.yomahub
+ tlog-feign
+
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
index 155f7c3a7..feaa3f42c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
@@ -1,10 +1,6 @@
package com.ruoyi.common.annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
/**
* 数据权限过滤注解
@@ -14,20 +10,19 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
-public @interface DataScope
-{
+public @interface DataScope {
/**
* 部门表的别名
*/
- public String deptAlias() default "";
+ String deptAlias() default "";
/**
* 用户表的别名
*/
- public String userAlias() default "";
+ String userAlias() default "";
- /**
- * 是否过滤用户权限
- */
- public boolean isUser() default false;
+ /**
+ * 是否过滤用户权限
+ */
+ boolean isUser() default false;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
index 79cd191f8..e7d2250a6 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
@@ -1,28 +1,23 @@
package com.ruoyi.common.annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
import com.ruoyi.common.enums.DataSourceType;
+import java.lang.annotation.*;
+
/**
* 自定义多数据源切换注解
- *
+ *
* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
*
* @author ruoyi
*/
-@Target({ ElementType.METHOD, ElementType.TYPE })
+@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
-public @interface DataSource
-{
+public @interface DataSource {
/**
* 切换数据源名称
*/
- public DataSourceType value() default DataSourceType.MASTER;
+ DataSourceType value() default DataSourceType.MASTER;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java
index a51116b5c..400080ea7 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/ExcelDictFormat.java
@@ -12,19 +12,19 @@ import java.lang.annotation.*;
@Inherited
public @interface ExcelDictFormat {
- /**
- * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
- */
- String dictType() default "";
+ /**
+ * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+ */
+ String dictType() default "";
- /**
- * 读取内容转表达式 (如: 0=男,1=女,2=未知)
- */
- String readConverterExp() default "";
+ /**
+ * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+ */
+ String readConverterExp() default "";
- /**
- * 分隔符,读取字符串组内容
- */
- String separator() default ",";
+ /**
+ * 分隔符,读取字符串组内容
+ */
+ String separator() default ",";
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
index ca02c6c4a..32c39a3b0 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
@@ -1,46 +1,41 @@
package com.ruoyi.common.annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.OperatorType;
+import java.lang.annotation.*;
+
/**
* 自定义操作日志记录注解
- *
- * @author ruoyi
*
+ * @author ruoyi
*/
-@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
-public @interface Log
-{
+public @interface Log {
/**
- * 模块
+ * 模块
*/
- public String title() default "";
+ String title() default "";
/**
* 功能
*/
- public BusinessType businessType() default BusinessType.OTHER;
+ BusinessType businessType() default BusinessType.OTHER;
/**
* 操作人类别
*/
- public OperatorType operatorType() default OperatorType.MANAGE;
+ OperatorType operatorType() default OperatorType.MANAGE;
/**
* 是否保存请求的参数
*/
- public boolean isSaveRequestData() default true;
+ boolean isSaveRequestData() default true;
/**
* 是否保存响应的参数
*/
- public boolean isSaveResponseData() default true;
+ boolean isSaveResponseData() default true;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
index 564203861..90db9d776 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
@@ -1,40 +1,36 @@
package com.ruoyi.common.annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.enums.LimitType;
+import java.lang.annotation.*;
+
/**
* 限流注解
- *
- * @author ruoyi
+ *
+ * @author Lion Li
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
-public @interface RateLimiter
-{
+public @interface RateLimiter {
/**
* 限流key
*/
- public String key() default Constants.RATE_LIMIT_KEY;
+ String key() default Constants.RATE_LIMIT_KEY;
/**
* 限流时间,单位秒
*/
- public int time() default 60;
+ int time() default 60;
/**
* 限流次数
*/
- public int count() default 100;
+ int count() default 100;
/**
* 限流类型
*/
- public LimitType limitType() default LimitType.DEFAULT;
+ LimitType limitType() default LimitType.DEFAULT;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
index 512f4bf52..a87466768 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
@@ -1,11 +1,6 @@
package com.ruoyi.common.annotation;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
/**
@@ -19,16 +14,16 @@ import java.util.concurrent.TimeUnit;
@Documented
public @interface RepeatSubmit {
- /**
- * 间隔时间(ms),小于此时间视为重复提交
- */
- int interval() default 5000;
+ /**
+ * 间隔时间(ms),小于此时间视为重复提交
+ */
+ int interval() default 5000;
- TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
+ TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
/**
* 提示消息
*/
- String message() default "不允许重复提交,请稍后再试";
+ String message() default "不允许重复提交,请稍候再试";
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
index 408295a36..9343a4a08 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
@@ -2,7 +2,6 @@ package com.ruoyi.common.config;
import lombok.Data;
import lombok.Getter;
-import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@@ -10,34 +9,42 @@ import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
-@NoArgsConstructor
@Accessors(chain = true)
@Component
@ConfigurationProperties(prefix = "ruoyi")
-public class RuoYiConfig
-{
- /** 项目名称 */
+public class RuoYiConfig {
+
+ /**
+ * 项目名称
+ */
private String name;
- /** 版本 */
+ /**
+ * 版本
+ */
private String version;
- /** 版权年份 */
+ /**
+ * 版权年份
+ */
private String copyrightYear;
- /** 实例演示开关 */
+ /**
+ * 实例演示开关
+ */
private boolean demoEnabled;
- /** 获取地址开关 */
+ /**
+ * 获取地址开关
+ */
@Getter
private static boolean addressEnabled;
- public void setAddressEnabled(boolean addressEnabled)
- {
+ public void setAddressEnabled(boolean addressEnabled) {
RuoYiConfig.addressEnabled = addressEnabled;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
index c2cb29dcb..6d83fe30e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -7,8 +7,7 @@ import io.jsonwebtoken.Claims;
*
* @author ruoyi
*/
-public class Constants
-{
+public class Constants {
/**
* UTF-8 字符集
*/
@@ -134,13 +133,13 @@ public class Constants
*/
public static final String SYS_DICT_KEY = "sys_dict:";
- /**
- * RMI 远程方法调用
- */
- public static final String LOOKUP_RMI = "rmi://";
+ /**
+ * RMI 远程方法调用
+ */
+ public static final String LOOKUP_RMI = "rmi://";
- /**
- * LDAP 远程方法调用
- */
- public static final String LOOKUP_LDAP = "ldap://";
+ /**
+ * LDAP 远程方法调用
+ */
+ public static final String LOOKUP_LDAP = "ldap://";
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
index 072fb403c..4d0a4e8a7 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -2,118 +2,187 @@ package com.ruoyi.common.constant;
/**
* 代码生成通用常量
- *
+ *
* @author ruoyi
*/
-public class GenConstants
-{
- /** 单表(增删改查) */
+public class GenConstants {
+ /**
+ * 单表(增删改查)
+ */
public static final String TPL_CRUD = "crud";
- /** 树表(增删改查) */
+ /**
+ * 树表(增删改查)
+ */
public static final String TPL_TREE = "tree";
- /** 主子表(增删改查) */
+ /**
+ * 主子表(增删改查)
+ */
public static final String TPL_SUB = "sub";
- /** 树编码字段 */
+ /**
+ * 树编码字段
+ */
public static final String TREE_CODE = "treeCode";
- /** 树父编码字段 */
+ /**
+ * 树父编码字段
+ */
public static final String TREE_PARENT_CODE = "treeParentCode";
- /** 树名称字段 */
+ /**
+ * 树名称字段
+ */
public static final String TREE_NAME = "treeName";
- /** 上级菜单ID字段 */
+ /**
+ * 上级菜单ID字段
+ */
public static final String PARENT_MENU_ID = "parentMenuId";
- /** 上级菜单名称字段 */
+ /**
+ * 上级菜单名称字段
+ */
public static final String PARENT_MENU_NAME = "parentMenuName";
- /** 数据库字符串类型 */
- public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
+ /**
+ * 数据库字符串类型
+ */
+ public static final String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"};
- /** 数据库文本类型 */
- public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
+ /**
+ * 数据库文本类型
+ */
+ public static final String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"};
- /** 数据库时间类型 */
- public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
+ /**
+ * 数据库时间类型
+ */
+ public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"};
- /** 数据库数字类型 */
- public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
- "bit", "bigint", "float", "double", "decimal" };
+ /**
+ * 数据库数字类型
+ */
+ public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
+ "bit", "bigint", "float", "double", "decimal"};
- /** 页面不需要添加字段 */
- public static final String[] COLUMNNAME_NOT_ADD = { "create_by", "create_time", "del_flag", "update_by",
- "update_time", "version" };
+ /**
+ * BO对象 不需要添加字段
+ */
+ public static final String[] COLUMNNAME_NOT_ADD = {"create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version"};
- /** 页面不需要编辑字段 */
- public static final String[] COLUMNNAME_NOT_EDIT = { "create_by", "create_time", "del_flag", "update_by",
- "update_time", "version" };
+ /**
+ * BO对象 不需要编辑字段
+ */
+ public static final String[] COLUMNNAME_NOT_EDIT = {"create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version"};
- /** 页面不需要显示的列表字段 */
- public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
- "update_time", "version" };
+ /**
+ * VO对象 不需要返回字段
+ */
+ public static final String[] COLUMNNAME_NOT_LIST = {"create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version"};
- /** 页面不需要查询字段 */
- public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
- "update_time", "remark", "version" };
+ /**
+ * BO对象 不需要查询字段
+ */
+ public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "remark", "version"};
- /** Entity基类字段 */
- public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
+ /**
+ * Entity基类字段
+ */
+ public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime"};
- /** Tree基类字段 */
- public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };
+ /**
+ * Tree基类字段
+ */
+ public static final String[] TREE_ENTITY = {"parentName", "parentId", "children"};
- /** 文本框 */
+ /**
+ * 文本框
+ */
public static final String HTML_INPUT = "input";
- /** 文本域 */
+ /**
+ * 文本域
+ */
public static final String HTML_TEXTAREA = "textarea";
- /** 下拉框 */
+ /**
+ * 下拉框
+ */
public static final String HTML_SELECT = "select";
- /** 单选框 */
+ /**
+ * 单选框
+ */
public static final String HTML_RADIO = "radio";
- /** 复选框 */
+ /**
+ * 复选框
+ */
public static final String HTML_CHECKBOX = "checkbox";
- /** 日期控件 */
+ /**
+ * 日期控件
+ */
public static final String HTML_DATETIME = "datetime";
- /** 图片上传控件 */
+ /**
+ * 图片上传控件
+ */
public static final String HTML_IMAGE_UPLOAD = "imageUpload";
- /** 文件上传控件 */
+ /**
+ * 文件上传控件
+ */
public static final String HTML_FILE_UPLOAD = "fileUpload";
- /** 富文本控件 */
+ /**
+ * 富文本控件
+ */
public static final String HTML_EDITOR = "editor";
- /** 字符串类型 */
+ /**
+ * 字符串类型
+ */
public static final String TYPE_STRING = "String";
- /** 整型 */
+ /**
+ * 整型
+ */
public static final String TYPE_INTEGER = "Integer";
- /** 长整型 */
+ /**
+ * 长整型
+ */
public static final String TYPE_LONG = "Long";
- /** 浮点型 */
+ /**
+ * 浮点型
+ */
public static final String TYPE_DOUBLE = "Double";
- /** 高精度计算类型 */
+ /**
+ * 高精度计算类型
+ */
public static final String TYPE_BIGDECIMAL = "BigDecimal";
- /** 时间类型 */
+ /**
+ * 时间类型
+ */
public static final String TYPE_DATE = "Date";
- /** 模糊查询 */
+ /**
+ * 模糊查询
+ */
public static final String QUERY_LIKE = "LIKE";
- /** 需要 */
+ /**
+ * 需要
+ */
public static final String REQUIRE = "1";
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
index 8318b8f5f..ec430c26a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
@@ -2,7 +2,8 @@ package com.ruoyi.common.constant;
/**
* 任务调度通用常量
- *
+ *
+ * @deprecated 3.4.0删除 迁移至xxl-job
* @author ruoyi
*/
public class ScheduleConstants
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
index a936cd838..fa88e7c17 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -5,62 +5,96 @@ package com.ruoyi.common.constant;
*
* @author ruoyi
*/
-public class UserConstants
-{
+public class UserConstants {
+
/**
* 平台内系统用户的唯一标志
*/
public static final String SYS_USER = "SYS_USER";
- /** 正常状态 */
+ /**
+ * 正常状态
+ */
public static final String NORMAL = "0";
- /** 异常状态 */
+ /**
+ * 异常状态
+ */
public static final String EXCEPTION = "1";
- /** 用户封禁状态 */
+ /**
+ * 用户封禁状态
+ */
public static final String USER_DISABLE = "1";
- /** 角色封禁状态 */
+ /**
+ * 角色封禁状态
+ */
public static final String ROLE_DISABLE = "1";
- /** 部门正常状态 */
+ /**
+ * 部门正常状态
+ */
public static final String DEPT_NORMAL = "0";
- /** 部门停用状态 */
+ /**
+ * 部门停用状态
+ */
public static final String DEPT_DISABLE = "1";
- /** 字典正常状态 */
+ /**
+ * 字典正常状态
+ */
public static final String DICT_NORMAL = "0";
- /** 是否为系统默认(是) */
+ /**
+ * 是否为系统默认(是)
+ */
public static final String YES = "Y";
- /** 是否菜单外链(是) */
+ /**
+ * 是否菜单外链(是)
+ */
public static final String YES_FRAME = "0";
- /** 是否菜单外链(否) */
+ /**
+ * 是否菜单外链(否)
+ */
public static final String NO_FRAME = "1";
- /** 菜单类型(目录) */
+ /**
+ * 菜单类型(目录)
+ */
public static final String TYPE_DIR = "M";
- /** 菜单类型(菜单) */
+ /**
+ * 菜单类型(菜单)
+ */
public static final String TYPE_MENU = "C";
- /** 菜单类型(按钮) */
+ /**
+ * 菜单类型(按钮)
+ */
public static final String TYPE_BUTTON = "F";
- /** Layout组件标识 */
+ /**
+ * Layout组件标识
+ */
public final static String LAYOUT = "Layout";
- /** ParentView组件标识 */
+ /**
+ * ParentView组件标识
+ */
public final static String PARENT_VIEW = "ParentView";
- /** InnerLink组件标识 */
+ /**
+ * InnerLink组件标识
+ */
public final static String INNER_LINK = "InnerLink";
- /** 校验返回结果码 */
+ /**
+ * 校验返回结果码
+ */
public final static String UNIQUE = "0";
public final static String NOT_UNIQUE = "1";
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
index 04a21a7b4..bad8f77a5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
@@ -4,58 +4,49 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* web层通用数据处理
*
* @author ruoyi
*/
-public class BaseController
-{
- protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+public class BaseController {
/**
* 返回成功
*/
- public AjaxResult success()
- {
+ public AjaxResult success() {
return AjaxResult.success();
}
/**
* 返回失败消息
*/
- public AjaxResult error()
- {
+ public AjaxResult error() {
return AjaxResult.error();
}
/**
* 返回成功消息
*/
- public AjaxResult success(String message)
- {
+ public AjaxResult success(String message) {
return AjaxResult.success(message);
}
/**
* 返回失败消息
*/
- public AjaxResult error(String message)
- {
+ public AjaxResult error(String message) {
return AjaxResult.error(message);
}
/**
* 响应返回结果
- *
+ *
* @param rows 影响行数
* @return 操作结果
*/
- protected AjaxResult toAjax(int rows)
- {
+ protected AjaxResult toAjax(int rows) {
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
}
@@ -65,48 +56,42 @@ public class BaseController
* @param result 结果
* @return 操作结果
*/
- protected AjaxResult toAjax(boolean result)
- {
+ protected AjaxResult toAjax(boolean result) {
return result ? success() : error();
}
/**
* 页面跳转
*/
- public String redirect(String url)
- {
+ public String redirect(String url) {
return StringUtils.format("redirect:{}", url);
}
/**
* 获取用户缓存信息
*/
- public LoginUser getLoginUser()
- {
+ public LoginUser getLoginUser() {
return SecurityUtils.getLoginUser();
}
/**
* 获取登录用户id
*/
- public Long getUserId()
- {
+ public Long getUserId() {
return getLoginUser().getUserId();
}
/**
* 获取登录部门id
*/
- public Long getDeptId()
- {
+ public Long getDeptId() {
return getLoginUser().getDeptId();
}
/**
* 获取登录用户名
*/
- public String getUsername()
- {
+ public String getUsername() {
return getLoginUser().getUsername();
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
index a5a92f4d3..18a8d66e9 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
@@ -1,9 +1,10 @@
package com.ruoyi.common.core.domain;
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
-import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@@ -14,11 +15,10 @@ import java.util.Map;
/**
* Entity基类
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
-@NoArgsConstructor
@Accessors(chain = true)
public class BaseEntity implements Serializable {
@@ -28,43 +28,43 @@ public class BaseEntity implements Serializable {
* 搜索值
*/
@ApiModelProperty(value = "搜索值")
+ @TableField(exist = false)
private String searchValue;
/**
* 创建者
*/
@ApiModelProperty(value = "创建者")
+ @TableField(fill = FieldFill.INSERT)
private String createBy;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
+ @TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 更新者
*/
@ApiModelProperty(value = "更新者")
+ @TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/**
* 更新时间
*/
@ApiModelProperty(value = "更新时间")
+ @TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
- /**
- * 备注
- */
- @ApiModelProperty(value = "备注")
- private String remark;
-
/**
* 请求参数
*/
@JsonIgnore
@ApiModelProperty(value = "请求参数")
+ @TableField(exist = false)
private Map params = new HashMap<>();
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
index 8db10aa2b..c0e62c710 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
@@ -1,9 +1,9 @@
package com.ruoyi.common.core.domain;
+import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
-import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.ArrayList;
@@ -12,12 +12,11 @@ import java.util.List;
/**
* Tree基类
*
- * @author ruoyi
+ * @author Lion Li
*/
-@EqualsAndHashCode(callSuper = true)
@Data
-@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class TreeEntity extends BaseEntity {
@@ -26,6 +25,7 @@ public class TreeEntity extends BaseEntity {
/**
* 父菜单名称
*/
+ @TableField(exist = false)
@ApiModelProperty(value = "父菜单名称")
private String parentName;
@@ -35,21 +35,10 @@ public class TreeEntity extends BaseEntity {
@ApiModelProperty(value = "父菜单ID")
private Long parentId;
- /**
- * 显示顺序
- */
- @ApiModelProperty(value = "显示顺序")
- private Integer orderNum;
-
- /**
- * 祖级列表
- */
- @ApiModelProperty(value = "祖级列表")
- private String ancestors;
-
/**
* 子部门
*/
+ @TableField(exist = false)
@ApiModelProperty(value = "子部门")
private List> children = new ArrayList<>();
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
index 2049486fc..963ac5c4d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
@@ -3,7 +3,10 @@ package com.ruoyi.common.core.domain;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysMenu;
-import lombok.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
@@ -12,39 +15,53 @@ import java.util.stream.Collectors;
/**
* Treeselect树结构实体类
- *
- * @author ruoyi
+ *
+ * @author Lion Li
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
-public class TreeSelect implements Serializable
-{
+@ApiModel("树结构实体类")
+public class TreeSelect implements Serializable {
+
private static final long serialVersionUID = 1L;
- /** 节点ID */
+ /**
+ * 节点ID
+ */
+ @ApiModelProperty(value = "节点ID")
private Long id;
- /** 节点名称 */
+ /**
+ * 节点名称
+ */
+ @ApiModelProperty(value = "节点名称")
private String label;
- /** 子节点 */
+ /**
+ * 子节点
+ */
+ @ApiModelProperty(value = "子节点")
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private List children;
- public TreeSelect(SysDept dept)
- {
+ public TreeSelect(SysDept dept) {
this.id = dept.getDeptId();
this.label = dept.getDeptName();
- this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+ this.children = dept.getChildren()
+ .stream()
+ .map(d -> new TreeSelect((SysDept) d))
+ .collect(Collectors.toList());
}
- public TreeSelect(SysMenu menu)
- {
+ public TreeSelect(SysMenu menu) {
this.id = menu.getMenuId();
this.label = menu.getMenuName();
- this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+ this.children = menu.getChildren()
+ .stream()
+ .map(d -> new TreeSelect((SysMenu) d))
+ .collect(Collectors.toList());
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/dto/OperLogDTO.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/dto/OperLogDTO.java
index f5132efe6..773858f64 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/dto/OperLogDTO.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/dto/OperLogDTO.java
@@ -8,15 +8,16 @@ import java.io.Serializable;
import java.util.Date;
/**
- * 操作日志记录表 oper_log
+ * 通用操作日志实体
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
public class OperLogDTO implements Serializable {
+
private static final long serialVersionUID = 1L;
/**
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
index 62056e027..17ff6606e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
@@ -1,48 +1,44 @@
package com.ruoyi.common.core.domain.entity;
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.TreeEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
-import java.io.Serializable;
-import java.util.*;
/**
* 部门表 sys_dept
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
-@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_dept")
-public class SysDept implements Serializable {
+@ApiModel("部门业务对象")
+public class SysDept extends TreeEntity {
private static final long serialVersionUID = 1L;
/**
* 部门ID
*/
- @TableId(value = "dept_id", type = IdType.AUTO)
+ @ApiModelProperty(value = "部门id")
+ @TableId(value = "dept_id")
private Long deptId;
- /**
- * 父部门ID
- */
- private Long parentId;
-
- /**
- * 祖级列表
- */
- private String ancestors;
-
/**
* 部门名称
*/
+ @ApiModelProperty(value = "部门名称")
@NotBlank(message = "部门名称不能为空")
@Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
private String deptName;
@@ -50,23 +46,27 @@ public class SysDept implements Serializable {
/**
* 显示顺序
*/
+ @ApiModelProperty(value = "显示顺序")
@NotBlank(message = "显示顺序不能为空")
private String orderNum;
/**
* 负责人
*/
+ @ApiModelProperty(value = "负责人")
private String leader;
/**
* 联系电话
*/
+ @ApiModelProperty(value = "联系电话")
@Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
private String phone;
/**
* 邮箱
*/
+ @ApiModelProperty(value = "邮箱")
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
private String email;
@@ -74,54 +74,20 @@ public class SysDept implements Serializable {
/**
* 部门状态:0正常,1停用
*/
+ @ApiModelProperty(value = "部门状态:0正常,1停用")
private String status;
/**
* 删除标志(0代表存在 2代表删除)
*/
+ @ApiModelProperty(value = "删除标志(0代表存在 2代表删除)")
@TableLogic
private String delFlag;
/**
- * 父部门名称
+ * 祖级列表
*/
- @TableField(exist = false)
- private String parentName;
-
- /**
- * 创建者
- */
- @TableField(fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
-
- /**
- * 更新者
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
-
- /**
- * 子部门
- */
- @TableField(exist = false)
- private List children = new ArrayList();
-
- /**
- * 请求参数
- */
- @TableField(exist = false)
- private Map params = new HashMap<>();
+ @ApiModelProperty(value = "祖级列表")
+ private String ancestors;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
index 89ee1c1bc..3c572bd27 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
@@ -2,51 +2,54 @@ package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.convert.ExcelDictConvert;
+import com.ruoyi.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
-import java.io.Serializable;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
/**
* 字典数据表 sys_dict_data
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
-@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_dict_data")
@ExcelIgnoreUnannotated
-public class SysDictData implements Serializable {
- private static final long serialVersionUID = 1L;
+@ApiModel("字典数据业务对象")
+public class SysDictData extends BaseEntity {
/**
* 字典编码
*/
+ @ApiModelProperty(value = "字典编码")
@ExcelProperty(value = "字典编码")
- @TableId(value = "dict_code", type = IdType.AUTO)
+ @TableId(value = "dict_code")
private Long dictCode;
/**
* 字典排序
*/
+ @ApiModelProperty(value = "字典排序")
@ExcelProperty(value = "字典排序")
private Long dictSort;
/**
* 字典标签
*/
+ @ApiModelProperty(value = "字典标签")
@ExcelProperty(value = "字典标签")
@NotBlank(message = "字典标签不能为空")
@Size(min = 0, max = 100, message = "字典标签长度不能超过100个字符")
@@ -55,6 +58,7 @@ public class SysDictData implements Serializable {
/**
* 字典键值
*/
+ @ApiModelProperty(value = "字典键值")
@ExcelProperty(value = "字典键值")
@NotBlank(message = "字典键值不能为空")
@Size(min = 0, max = 100, message = "字典键值长度不能超过100个字符")
@@ -63,6 +67,7 @@ public class SysDictData implements Serializable {
/**
* 字典类型
*/
+ @ApiModelProperty(value = "字典类型")
@ExcelProperty(value = "字典类型")
@NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型长度不能超过100个字符")
@@ -71,17 +76,20 @@ public class SysDictData implements Serializable {
/**
* 样式属性(其他样式扩展)
*/
+ @ApiModelProperty(value = "样式属性(其他样式扩展)")
@Size(min = 0, max = 100, message = "样式属性长度不能超过100个字符")
private String cssClass;
/**
* 表格字典样式
*/
+ @ApiModelProperty(value = "表格字典样式")
private String listClass;
/**
* 是否默认(Y是 N否)
*/
+ @ApiModelProperty(value = "是否默认(Y是 N否)")
@ExcelProperty(value = "是否默认", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_yes_no")
private String isDefault;
@@ -89,47 +97,19 @@ public class SysDictData implements Serializable {
/**
* 状态(0正常 1停用)
*/
+ @ApiModelProperty(value = "状态(0正常 1停用)")
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private String status;
- /**
- * 创建者
- */
- @TableField(fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
-
- /**
- * 更新者
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
-
/**
* 备注
*/
+ @ApiModelProperty(value = "备注")
private String remark;
- /**
- * 请求参数
- */
- @TableField(exist = false)
- private Map params = new HashMap<>();
-
public boolean getDefault() {
- return UserConstants.YES.equals(this.isDefault) ? true : false;
+ return UserConstants.YES.equals(this.isDefault);
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
index 35d9a60fe..c6c9b1a29 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
@@ -2,44 +2,46 @@ package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
+import com.ruoyi.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
-import java.io.Serializable;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
/**
* 字典类型表 sys_dict_type
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
-@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_dict_type")
@ExcelIgnoreUnannotated
-public class SysDictType implements Serializable {
- private static final long serialVersionUID = 1L;
+@ApiModel("字典类型业务对象")
+public class SysDictType extends BaseEntity {
/**
* 字典主键
*/
+ @ApiModelProperty(value = "字典主键")
@ExcelProperty(value = "字典主键")
- @TableId(value = "dict_id", type = IdType.AUTO)
+ @TableId(value = "dict_id")
private Long dictId;
/**
* 字典名称
*/
+ @ApiModelProperty(value = "字典名称")
@ExcelProperty(value = "字典名称")
@NotBlank(message = "字典名称不能为空")
@Size(min = 0, max = 100, message = "字典类型名称长度不能超过100个字符")
@@ -48,6 +50,7 @@ public class SysDictType implements Serializable {
/**
* 字典类型
*/
+ @ApiModelProperty(value = "字典类型")
@ExcelProperty(value = "字典类型")
@NotBlank(message = "字典类型不能为空")
@Size(min = 0, max = 100, message = "字典类型类型长度不能超过100个字符")
@@ -56,43 +59,15 @@ public class SysDictType implements Serializable {
/**
* 状态(0正常 1停用)
*/
+ @ApiModelProperty(value = "状态(0正常 1停用)")
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private String status;
- /**
- * 创建者
- */
- @TableField(fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
-
- /**
- * 更新者
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
-
/**
* 备注
*/
+ @ApiModelProperty(value = "备注")
private String remark;
- /**
- * 请求参数
- */
- @TableField(exist = false)
- private Map params = new HashMap<>();
-
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
index d2c5bbf94..30d074b75 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
@@ -1,154 +1,120 @@
package com.ruoyi.common.core.domain.entity;
-import com.baomidou.mybatisplus.annotation.*;
-import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.ruoyi.common.core.domain.TreeEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
-import java.io.Serializable;
-import java.util.*;
/**
* 菜单权限表 sys_menu
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
-@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_menu")
-public class SysMenu implements Serializable {
- private static final long serialVersionUID = 1L;
+@ApiModel("菜单权限业务对象")
+public class SysMenu extends TreeEntity {
/**
* 菜单ID
*/
- @TableId(value = "menu_id", type = IdType.AUTO)
+ @ApiModelProperty(value = "菜单ID")
+ @TableId(value = "menu_id")
private Long menuId;
/**
* 菜单名称
*/
+ @ApiModelProperty(value = "菜单名称")
@NotBlank(message = "菜单名称不能为空")
@Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
private String menuName;
- /**
- * 父菜单名称
- */
- @TableField(exist = false)
- private String parentName;
-
- /**
- * 父菜单ID
- */
- private Long parentId;
-
/**
* 显示顺序
*/
+ @ApiModelProperty(value = "显示顺序")
@NotBlank(message = "显示顺序不能为空")
private String orderNum;
/**
* 路由地址
*/
+ @ApiModelProperty(value = "路由地址")
@Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
private String path;
/**
* 组件路径
*/
+ @ApiModelProperty(value = "组件路径")
@Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
private String component;
/**
* 路由参数
*/
+ @ApiModelProperty(value = "路由参数")
private String query;
/**
* 是否为外链(0是 1否)
*/
+ @ApiModelProperty(value = "是否为外链(0是 1否)")
private String isFrame;
/**
* 是否缓存(0缓存 1不缓存)
*/
+ @ApiModelProperty(value = "是否缓存(0缓存 1不缓存)")
private String isCache;
/**
* 类型(M目录 C菜单 F按钮)
*/
+ @ApiModelProperty(value = "类型(M目录 C菜单 F按钮)")
@NotBlank(message = "菜单类型不能为空")
private String menuType;
/**
* 显示状态(0显示 1隐藏)
*/
+ @ApiModelProperty(value = "显示状态(0显示 1隐藏)")
private String visible;
/**
* 菜单状态(0显示 1隐藏)
*/
+ @ApiModelProperty(value = "菜单状态(0显示 1隐藏)")
private String status;
/**
* 权限字符串
*/
+ @ApiModelProperty(value = "权限字符串")
@Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
private String perms;
/**
* 菜单图标
*/
+ @ApiModelProperty(value = "菜单图标")
private String icon;
- /**
- * 创建者
- */
- @TableField(fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(fill = FieldFill.INSERT)
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date createTime;
-
- /**
- * 更新者
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date updateTime;
-
/**
* 备注
*/
+ @ApiModelProperty(value = "备注")
private String remark;
- /**
- * 请求参数
- */
- @TableField(exist = false)
- private Map params = new HashMap<>();
-
- /**
- * 子菜单
- */
- @TableField(exist = false)
- private List children = new ArrayList();
-
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
index 516352458..1d186db52 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
@@ -2,44 +2,48 @@ package com.ruoyi.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
-import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
+import com.ruoyi.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
-import java.io.Serializable;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
/**
* 角色表 sys_role
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_role")
@ExcelIgnoreUnannotated
-public class SysRole implements Serializable {
- private static final long serialVersionUID = 1L;
+public class SysRole extends BaseEntity {
/**
* 角色ID
*/
+ @ApiModelProperty(value = "角色ID")
@ExcelProperty(value = "角色序号")
- @TableId(value = "role_id", type = IdType.AUTO)
+ @TableId(value = "role_id")
private Long roleId;
/**
* 角色名称
*/
+ @ApiModelProperty(value = "角色名称")
@ExcelProperty(value = "角色名称")
@NotBlank(message = "角色名称不能为空")
@Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
@@ -48,6 +52,7 @@ public class SysRole implements Serializable {
/**
* 角色权限
*/
+ @ApiModelProperty(value = "角色权限")
@ExcelProperty(value = "角色权限")
@NotBlank(message = "权限字符不能为空")
@Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
@@ -56,6 +61,7 @@ public class SysRole implements Serializable {
/**
* 角色排序
*/
+ @ApiModelProperty(value = "角色排序")
@ExcelProperty(value = "角色排序")
@NotBlank(message = "显示顺序不能为空")
private String roleSort;
@@ -63,6 +69,7 @@ public class SysRole implements Serializable {
/**
* 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
*/
+ @ApiModelProperty(value = "数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)")
@ExcelProperty(value = "数据范围", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
private String dataScope;
@@ -70,16 +77,19 @@ public class SysRole implements Serializable {
/**
* 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)
*/
+ @ApiModelProperty(value = "菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)")
private boolean menuCheckStrictly;
/**
* 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 )
*/
+ @ApiModelProperty(value = "部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 )")
private boolean deptCheckStrictly;
/**
* 角色状态(0正常 1停用)
*/
+ @ApiModelProperty(value = "角色状态(0正常 1停用)")
@ExcelProperty(value = "角色状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_common_status")
private String status;
@@ -87,59 +97,34 @@ public class SysRole implements Serializable {
/**
* 删除标志(0代表存在 2代表删除)
*/
+ @ApiModelProperty(value = "删除标志(0代表存在 2代表删除)")
@TableLogic
private String delFlag;
- /**
- * 创建者
- */
- @TableField(fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
-
- /**
- * 更新者
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
-
/**
* 备注
*/
+ @ApiModelProperty(value = "备注")
private String remark;
- /**
- * 请求参数
- */
- @TableField(exist = false)
- private Map params = new HashMap<>();
-
/**
* 用户是否存在此角色标识 默认不存在
*/
+ @ApiModelProperty(value = "用户是否存在此角色标识 默认不存在")
@TableField(exist = false)
private boolean flag = false;
/**
* 菜单组
*/
+ @ApiModelProperty(value = "菜单组")
@TableField(exist = false)
private Long[] menuIds;
/**
* 部门组(数据权限)
*/
+ @ApiModelProperty(value = "部门组(数据权限)")
@TableField(exist = false)
private Long[] deptIds;
@@ -147,6 +132,7 @@ public class SysRole implements Serializable {
this.roleId = roleId;
}
+ @ApiModelProperty(value = "是否管理员")
public boolean isAdmin() {
return isAdmin(this.roleId);
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
index 770998126..2fa57f5ca 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -3,46 +3,51 @@ package com.ruoyi.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ruoyi.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
+import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
-import java.io.Serializable;
import java.util.Date;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
* 用户对象 sys_user
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@TableName("sys_user")
-public class SysUser implements Serializable {
- private static final long serialVersionUID = 1L;
+@ApiModel("用户信息业务对象")
+public class SysUser extends BaseEntity {
/**
* 用户ID
*/
- @TableId(value = "user_id", type = IdType.AUTO)
+ @ApiModelProperty(value = "用户ID")
+ @TableId(value = "user_id")
private Long userId;
/**
* 部门ID
*/
+ @ApiModelProperty(value = "部门ID")
private Long deptId;
/**
* 用户账号
*/
+ @ApiModelProperty(value = "用户账号")
@NotBlank(message = "用户账号不能为空")
@Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
private String userName;
@@ -50,12 +55,14 @@ public class SysUser implements Serializable {
/**
* 用户昵称
*/
+ @ApiModelProperty(value = "用户昵称")
@Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
private String nickName;
/**
* 用户邮箱
*/
+ @ApiModelProperty(value = "用户邮箱")
@Email(message = "邮箱格式不正确")
@Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
private String email;
@@ -63,21 +70,25 @@ public class SysUser implements Serializable {
/**
* 手机号码
*/
+ @ApiModelProperty(value = "手机号码")
private String phonenumber;
/**
* 用户性别
*/
+ @ApiModelProperty(value = "用户性别")
private String sex;
/**
* 用户头像
*/
+ @ApiModelProperty(value = "用户头像")
private String avatar;
/**
* 密码
*/
+ @ApiModelProperty(value = "密码")
@TableField(
insertStrategy = FieldStrategy.NOT_EMPTY,
updateStrategy = FieldStrategy.NOT_EMPTY,
@@ -94,86 +105,66 @@ public class SysUser implements Serializable {
/**
* 帐号状态(0正常 1停用)
*/
+ @ApiModelProperty(value = "帐号状态(0正常 1停用)")
private String status;
/**
* 删除标志(0代表存在 2代表删除)
*/
+ @ApiModelProperty(value = "删除标志(0代表存在 2代表删除)")
@TableLogic
private String delFlag;
/**
* 最后登录IP
*/
+ @ApiModelProperty(value = "最后登录IP")
private String loginIp;
/**
* 最后登录时间
*/
+ @ApiModelProperty(value = "最后登录时间")
private Date loginDate;
- /**
- * 创建者
- */
- @TableField(fill = FieldFill.INSERT)
- private String createBy;
-
- /**
- * 创建时间
- */
- @TableField(fill = FieldFill.INSERT)
- private Date createTime;
-
- /**
- * 更新者
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private String updateBy;
-
- /**
- * 更新时间
- */
- @TableField(fill = FieldFill.INSERT_UPDATE)
- private Date updateTime;
-
/**
* 备注
*/
+ @ApiModelProperty(value = "备注")
private String remark;
- /**
- * 请求参数
- */
- @TableField(exist = false)
- private Map params = new HashMap<>();
-
/**
* 部门对象
*/
+ @ApiModelProperty(value = "部门对象")
@TableField(exist = false)
private SysDept dept;
/**
* 角色对象
*/
+ @ApiModelProperty(value = "角色对象")
@TableField(exist = false)
private List roles;
/**
* 角色组
*/
+ @ApiModelProperty(value = "角色组")
@TableField(exist = false)
private Long[] roleIds;
/**
* 岗位组
*/
+ @ApiModelProperty(value = "岗位组")
@TableField(exist = false)
private Long[] postIds;
/**
* 角色ID
*/
+ @ApiModelProperty(value = "角色ID")
@TableField(exist = false)
private Long roleId;
@@ -181,6 +172,7 @@ public class SysUser implements Serializable {
this.userId = userId;
}
+ @ApiModelProperty(value = "是否管理员")
public boolean isAdmin() {
return isAdmin(this.userId);
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
index ae2c9e252..d47053694 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
@@ -1,37 +1,43 @@
package com.ruoyi.common.core.domain.model;
-import lombok.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
import lombok.experimental.Accessors;
/**
* 用户登录对象
- *
- * @author ruoyi
+ *
+ * @author Lion Li
*/
@Data
-@NoArgsConstructor
@Accessors(chain = true)
-public class LoginBody
-{
+@ApiModel("用户登录对象")
+public class LoginBody {
+
/**
* 用户名
*/
+ @ApiModelProperty(value = "用户名")
private String username;
/**
* 用户密码
*/
+ @ApiModelProperty(value = "用户密码")
private String password;
/**
* 验证码
*/
+ @ApiModelProperty(value = "验证码")
private String code;
/**
* 唯一标识
*/
+ @ApiModelProperty(value = "唯一标识")
private String uuid = "";
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
index 7bc072af7..9f7727abb 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
@@ -2,7 +2,8 @@ package com.ruoyi.common.core.domain.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ruoyi.common.core.domain.entity.SysUser;
-import lombok.*;
+import lombok.Data;
+import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
@@ -13,14 +14,14 @@ import java.util.Set;
/**
* 登录用户身份权限
*
- * @author ruoyi
+ * @author Lion Li
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
-public class LoginUser implements UserDetails
-{
+public class LoginUser implements UserDetails {
+
private static final long serialVersionUID = 1L;
/**
@@ -78,14 +79,12 @@ public class LoginUser implements UserDetails
*/
private SysUser user;
- public LoginUser(SysUser user, Set permissions)
- {
+ public LoginUser(SysUser user, Set permissions) {
this.user = user;
this.permissions = permissions;
}
- public LoginUser(Long userId, Long deptId, SysUser user, Set permissions)
- {
+ public LoginUser(Long userId, Long deptId, SysUser user, Set permissions) {
this.userId = userId;
this.deptId = deptId;
this.user = user;
@@ -94,14 +93,12 @@ public class LoginUser implements UserDetails
@JsonIgnore
@Override
- public String getPassword()
- {
+ public String getPassword() {
return user.getPassword();
}
@Override
- public String getUsername()
- {
+ public String getUsername() {
return user.getUserName();
}
@@ -110,50 +107,39 @@ public class LoginUser implements UserDetails
*/
@JsonIgnore
@Override
- public boolean isAccountNonExpired()
- {
+ public boolean isAccountNonExpired() {
return true;
}
/**
* 指定用户是否解锁,锁定的用户无法进行身份验证
- *
- * @return
*/
@JsonIgnore
@Override
- public boolean isAccountNonLocked()
- {
+ public boolean isAccountNonLocked() {
return true;
}
/**
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
- *
- * @return
*/
@JsonIgnore
@Override
- public boolean isCredentialsNonExpired()
- {
+ public boolean isCredentialsNonExpired() {
return true;
}
/**
* 是否可用 ,禁用的用户不能身份验证
- *
- * @return
*/
@JsonIgnore
@Override
- public boolean isEnabled()
- {
+ public boolean isEnabled() {
return true;
}
@Override
- public Collection extends GrantedAuthority> getAuthorities()
- {
+ public Collection extends GrantedAuthority> getAuthorities() {
return null;
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
index 5baa88781..ce6c385ae 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
@@ -1,11 +1,13 @@
package com.ruoyi.common.core.domain.model;
+import io.swagger.annotations.ApiModel;
+
/**
* 用户注册对象
- *
- * @author ruoyi
+ *
+ * @author Lion Li
*/
-public class RegisterBody extends LoginBody
-{
+@ApiModel("用户注册对象")
+public class RegisterBody extends LoginBody {
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java
index 51b9ec38e..c790c663b 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/mybatisplus/cache/MybatisPlusRedisCache.java
@@ -18,6 +18,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* 使用方法 配置文件开启 mybatis-plus 二级缓存
* 在 XxxMapper.java 类上添加注解 @CacheNamespace(implementation = MybatisPlusRedisCache.class, eviction = MybatisPlusRedisCache.class)
*
+ * @deprecated 3.4.0删除 推荐使用spirng-cache
* @author Lion Li
*/
@Slf4j
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java
index 10b7306fe..ce32cb41c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java
@@ -2,12 +2,10 @@ package com.ruoyi.common.enums;
/**
* 操作状态
- *
- * @author ruoyi
*
+ * @author ruoyi
*/
-public enum BusinessStatus
-{
+public enum BusinessStatus {
/**
* 成功
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java
index 2e17c4a5d..2d2f2e463 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java
@@ -2,11 +2,10 @@ package com.ruoyi.common.enums;
/**
* 业务操作类型
- *
+ *
* @author ruoyi
*/
-public enum BusinessType
-{
+public enum BusinessType {
/**
* 其它
*/
@@ -51,7 +50,7 @@ public enum BusinessType
* 生成代码
*/
GENCODE,
-
+
/**
* 清空数据
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
index d5f546536..d6fe72864 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
@@ -10,16 +10,16 @@ import lombok.Getter;
*/
@AllArgsConstructor
public enum DataSourceType {
- /**
- * 主库
- */
- MASTER("master"),
+ /**
+ * 主库
+ */
+ MASTER("master"),
- /**
- * 从库
- */
- SLAVE("slave");
+ /**
+ * 从库
+ */
+ SLAVE("slave");
- @Getter
- private final String source;
+ @Getter
+ private final String source;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java
index be6f73929..bd1bfcc46 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java
@@ -1,36 +1,32 @@
package com.ruoyi.common.enums;
+import org.springframework.lang.Nullable;
+
import java.util.HashMap;
import java.util.Map;
-import org.springframework.lang.Nullable;
/**
* 请求方式
*
* @author ruoyi
*/
-public enum HttpMethod
-{
+public enum HttpMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
private static final Map mappings = new HashMap<>(16);
- static
- {
- for (HttpMethod httpMethod : values())
- {
+ static {
+ for (HttpMethod httpMethod : values()) {
mappings.put(httpMethod.name(), httpMethod);
}
}
@Nullable
- public static HttpMethod resolve(@Nullable String method)
- {
+ public static HttpMethod resolve(@Nullable String method) {
return (method != null ? mappings.get(method) : null);
}
- public boolean matches(String method)
- {
+ public boolean matches(String method) {
return (this == resolve(method));
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
index 02c2b3d30..897f7068f 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
@@ -6,8 +6,7 @@ package com.ruoyi.common.enums;
* @author ruoyi
*/
-public enum LimitType
-{
+public enum LimitType {
/**
* 默认策略全局限流
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java
index bdd143c1c..3c4127d98 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java
@@ -2,11 +2,10 @@ package com.ruoyi.common.enums;
/**
* 操作人类别
- *
+ *
* @author ruoyi
*/
-public enum OperatorType
-{
+public enum OperatorType {
/**
* 其它
*/
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
index d7ff44a98..673ddebd2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
@@ -2,29 +2,25 @@ package com.ruoyi.common.enums;
/**
* 用户状态
- *
+ *
* @author ruoyi
*/
-public enum UserStatus
-{
+public enum UserStatus {
OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除");
private final String code;
private final String info;
- UserStatus(String code, String info)
- {
+ UserStatus(String code, String info) {
this.code = code;
this.info = info;
}
- public String getCode()
- {
+ public String getCode() {
return code;
}
- public String getInfo()
- {
+ public String getInfo() {
return info;
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java
index f6ad2ab49..9178131d7 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java
@@ -2,14 +2,12 @@ package com.ruoyi.common.exception;
/**
* 演示模式异常
- *
+ *
* @author ruoyi
*/
-public class DemoModeException extends RuntimeException
-{
+public class DemoModeException extends RuntimeException {
private static final long serialVersionUID = 1L;
- public DemoModeException()
- {
+ public DemoModeException() {
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
index 318b9aecc..5584cbce3 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
@@ -2,11 +2,10 @@ package com.ruoyi.common.exception;
/**
* 全局异常
- *
+ *
* @author ruoyi
*/
-public class GlobalException extends RuntimeException
-{
+public class GlobalException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -17,7 +16,7 @@ public class GlobalException extends RuntimeException
/**
* 错误明细,内部调试错误
- *
+ *
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
*/
private String detailMessage;
@@ -25,33 +24,28 @@ public class GlobalException extends RuntimeException
/**
* 空构造方法,避免反序列化问题
*/
- public GlobalException()
- {
+ public GlobalException() {
}
- public GlobalException(String message)
- {
+ public GlobalException(String message) {
this.message = message;
}
- public String getDetailMessage()
- {
+ public String getDetailMessage() {
return detailMessage;
}
- public GlobalException setDetailMessage(String detailMessage)
- {
+ public GlobalException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
- public String getMessage()
- {
+ @Override
+ public String getMessage() {
return message;
}
- public GlobalException setMessage(String message)
- {
+ public GlobalException setMessage(String message) {
this.message = message;
return this;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
index 734e8fc5d..95ce6d84c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
@@ -2,11 +2,10 @@ package com.ruoyi.common.exception;
/**
* 业务异常
- *
+ *
* @author ruoyi
*/
-public final class ServiceException extends RuntimeException
-{
+public final class ServiceException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
@@ -21,7 +20,7 @@ public final class ServiceException extends RuntimeException
/**
* 错误明细,内部调试错误
- *
+ *
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
*/
private String detailMessage;
@@ -29,44 +28,37 @@ public final class ServiceException extends RuntimeException
/**
* 空构造方法,避免反序列化问题
*/
- public ServiceException()
- {
+ public ServiceException() {
}
- public ServiceException(String message)
- {
+ public ServiceException(String message) {
this.message = message;
}
- public ServiceException(String message, Integer code)
- {
+ public ServiceException(String message, Integer code) {
this.message = message;
this.code = code;
}
- public String getDetailMessage()
- {
+ public String getDetailMessage() {
return detailMessage;
}
- public String getMessage()
- {
+ @Override
+ public String getMessage() {
return message;
}
- public Integer getCode()
- {
+ public Integer getCode() {
return code;
}
- public ServiceException setMessage(String message)
- {
+ public ServiceException setMessage(String message) {
this.message = message;
return this;
}
- public ServiceException setDetailMessage(String detailMessage)
- {
+ public ServiceException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
return this;
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java
index 980fa465e..01cc8782b 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java
@@ -2,25 +2,21 @@ package com.ruoyi.common.exception;
/**
* 工具类异常
- *
+ *
* @author ruoyi
*/
-public class UtilException extends RuntimeException
-{
+public class UtilException extends RuntimeException {
private static final long serialVersionUID = 8247610319171014183L;
- public UtilException(Throwable e)
- {
+ public UtilException(Throwable e) {
super(e.getMessage(), e);
}
- public UtilException(String message)
- {
+ public UtilException(String message) {
super(message);
}
- public UtilException(String message, Throwable throwable)
- {
+ public UtilException(String message, Throwable throwable) {
super(message, throwable);
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
index 5f97a3bab..13c0d2fef 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
@@ -2,14 +2,17 @@ package com.ruoyi.common.exception.base;
import com.ruoyi.common.utils.MessageUtils;
import com.ruoyi.common.utils.StringUtils;
+import lombok.*;
/**
* 基础异常
*
* @author ruoyi
*/
-public class BaseException extends RuntimeException
-{
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+public class BaseException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
@@ -32,66 +35,39 @@ public class BaseException extends RuntimeException
*/
private String defaultMessage;
- public BaseException(String module, String code, Object[] args, String defaultMessage)
- {
+ public BaseException(String module, String code, Object[] args, String defaultMessage) {
this.module = module;
this.code = code;
this.args = args;
this.defaultMessage = defaultMessage;
}
- public BaseException(String module, String code, Object[] args)
- {
+ public BaseException(String module, String code, Object[] args) {
this(module, code, args, null);
}
- public BaseException(String module, String defaultMessage)
- {
+ public BaseException(String module, String defaultMessage) {
this(module, null, null, defaultMessage);
}
- public BaseException(String code, Object[] args)
- {
+ public BaseException(String code, Object[] args) {
this(null, code, args, null);
}
- public BaseException(String defaultMessage)
- {
+ public BaseException(String defaultMessage) {
this(null, null, null, defaultMessage);
}
@Override
- public String getMessage()
- {
+ public String getMessage() {
String message = null;
- if (!StringUtils.isEmpty(code))
- {
+ if (!StringUtils.isEmpty(code)) {
message = MessageUtils.message(code, args);
}
- if (message == null)
- {
+ if (message == null) {
message = defaultMessage;
}
return message;
}
- public String getModule()
- {
- return module;
- }
-
- public String getCode()
- {
- return code;
- }
-
- public Object[] getArgs()
- {
- return args;
- }
-
- public String getDefaultMessage()
- {
- return defaultMessage;
- }
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
index b4c57f6d3..794f4e1a7 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
@@ -7,12 +7,10 @@ import com.ruoyi.common.exception.base.BaseException;
*
* @author ruoyi
*/
-public class FileException extends BaseException
-{
+public class FileException extends BaseException {
private static final long serialVersionUID = 1L;
- public FileException(String code, Object[] args)
- {
+ public FileException(String code, Object[] args) {
super("file", code, args, null);
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
index 70e0ec9b1..64a5020d0 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
@@ -2,15 +2,13 @@ package com.ruoyi.common.exception.file;
/**
* 文件名称超长限制异常类
- *
+ *
* @author ruoyi
*/
-public class FileNameLengthLimitExceededException extends FileException
-{
+public class FileNameLengthLimitExceededException extends FileException {
private static final long serialVersionUID = 1L;
- public FileNameLengthLimitExceededException(int defaultFileNameLength)
- {
- super("upload.filename.exceed.length", new Object[] { defaultFileNameLength });
+ public FileNameLengthLimitExceededException(int defaultFileNameLength) {
+ super("upload.filename.exceed.length", new Object[]{defaultFileNameLength});
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
index ec6ab054d..93e9e1c60 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
@@ -2,15 +2,13 @@ package com.ruoyi.common.exception.file;
/**
* 文件名大小限制异常类
- *
+ *
* @author ruoyi
*/
-public class FileSizeLimitExceededException extends FileException
-{
+public class FileSizeLimitExceededException extends FileException {
private static final long serialVersionUID = 1L;
- public FileSizeLimitExceededException(long defaultMaxSize)
- {
- super("upload.exceed.maxSize", new Object[] { defaultMaxSize });
+ public FileSizeLimitExceededException(long defaultMaxSize) {
+ super("upload.exceed.maxSize", new Object[]{defaultMaxSize});
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
index f1c8e8354..7de92e24c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
@@ -1,80 +1,60 @@
package com.ruoyi.common.exception.file;
-import java.util.Arrays;
+import lombok.*;
import org.apache.commons.fileupload.FileUploadException;
+import java.util.Arrays;
+
/**
* 文件上传 误异常类
- *
+ *
* @author ruoyi
*/
-public class InvalidExtensionException extends FileUploadException
-{
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+public class InvalidExtensionException extends FileUploadException {
private static final long serialVersionUID = 1L;
private String[] allowedExtension;
private String extension;
private String filename;
- public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
- {
+ public InvalidExtensionException(String[] allowedExtension, String extension, String filename) {
super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
this.allowedExtension = allowedExtension;
this.extension = extension;
this.filename = filename;
}
- public String[] getAllowedExtension()
- {
- return allowedExtension;
- }
-
- public String getExtension()
- {
- return extension;
- }
-
- public String getFilename()
- {
- return filename;
- }
-
- public static class InvalidImageExtensionException extends InvalidExtensionException
- {
+ public static class InvalidImageExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;
- public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
- {
+ public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}
- public static class InvalidFlashExtensionException extends InvalidExtensionException
- {
+ public static class InvalidFlashExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;
- public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
- {
+ public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}
- public static class InvalidMediaExtensionException extends InvalidExtensionException
- {
+ public static class InvalidMediaExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;
- public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
- {
+ public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}
- public static class InvalidVideoExtensionException extends InvalidExtensionException
- {
+ public static class InvalidVideoExtensionException extends InvalidExtensionException {
private static final long serialVersionUID = 1L;
- public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
- {
+ public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename) {
super(allowedExtension, extension, filename);
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
index 14b2361d0..59ea3a687 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
@@ -2,7 +2,8 @@ package com.ruoyi.common.exception.job;
/**
* 计划策略异常
- *
+ *
+ * @deprecated 3.4.0删除 迁移至xxl-job
* @author ruoyi
*/
public class TaskException extends Exception
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
index 389dbc753..90404854c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
@@ -2,15 +2,13 @@ package com.ruoyi.common.exception.user;
/**
* 验证码错误异常类
- *
+ *
* @author ruoyi
*/
-public class CaptchaException extends UserException
-{
+public class CaptchaException extends UserException {
private static final long serialVersionUID = 1L;
- public CaptchaException()
- {
+ public CaptchaException() {
super("user.jcaptcha.error", null);
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
index 85f94861b..ae5f759f0 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
@@ -2,15 +2,13 @@ package com.ruoyi.common.exception.user;
/**
* 验证码失效异常类
- *
+ *
* @author ruoyi
*/
-public class CaptchaExpireException extends UserException
-{
+public class CaptchaExpireException extends UserException {
private static final long serialVersionUID = 1L;
- public CaptchaExpireException()
- {
+ public CaptchaExpireException() {
super("user.jcaptcha.expire", null);
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
index f25afc5eb..94dbcdd52 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
@@ -7,12 +7,10 @@ import com.ruoyi.common.exception.base.BaseException;
*
* @author ruoyi
*/
-public class UserException extends BaseException
-{
+public class UserException extends BaseException {
private static final long serialVersionUID = 1L;
- public UserException(String code, Object[] args)
- {
+ public UserException(String code, Object[] args) {
super("user", code, args, null);
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
index a7f3e5ffe..0fab11678 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
@@ -2,15 +2,13 @@ package com.ruoyi.common.exception.user;
/**
* 用户密码不正确或不符合规范异常类
- *
+ *
* @author ruoyi
*/
-public class UserPasswordNotMatchException extends UserException
-{
+public class UserPasswordNotMatchException extends UserException {
private static final long serialVersionUID = 1L;
- public UserPasswordNotMatchException()
- {
+ public UserPasswordNotMatchException() {
super("user.password.not.match", null);
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
index ffe614ceb..0e4b2658b 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
@@ -12,37 +12,29 @@ import java.io.IOException;
*
* @author ruoyi
*/
-public class RepeatableFilter implements Filter
-{
+public class RepeatableFilter implements Filter {
@Override
- public void init(FilterConfig filterConfig) throws ServletException
- {
+ public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException
- {
+ throws IOException, ServletException {
ServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest
- && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE))
- {
+ && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
}
- if (null == requestWrapper)
- {
+ if (null == requestWrapper) {
chain.doFilter(request, response);
- }
- else
- {
+ } else {
chain.doFilter(requestWrapper, response);
}
}
@Override
- public void destroy()
- {
+ public void destroy() {
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
index 74659bfdd..b6fd0b65a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
@@ -18,12 +18,10 @@ import java.nio.charset.StandardCharsets;
*
* @author ruoyi
*/
-public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
-{
+public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
- public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException
- {
+ public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException {
super(request);
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
@@ -32,44 +30,36 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
}
@Override
- public BufferedReader getReader() throws IOException
- {
+ public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
- public ServletInputStream getInputStream() throws IOException
- {
+ public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
- return new ServletInputStream()
- {
+ return new ServletInputStream() {
@Override
- public int read() throws IOException
- {
+ public int read() throws IOException {
return bais.read();
}
@Override
- public int available() throws IOException
- {
+ public int available() throws IOException {
return body.length;
}
@Override
- public boolean isFinished()
- {
+ public boolean isFinished() {
return false;
}
@Override
- public boolean isReady()
- {
+ public boolean isReady() {
return false;
}
@Override
- public void setReadListener(ReadListener readListener)
- {
+ public void setReadListener(ReadListener readListener) {
}
};
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
index 7c141671a..f397de1ec 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
@@ -14,22 +14,18 @@ import java.util.List;
*
* @author ruoyi
*/
-public class XssFilter implements Filter
-{
+public class XssFilter implements Filter {
/**
* 排除链接
*/
public List excludes = new ArrayList<>();
@Override
- public void init(FilterConfig filterConfig) throws ServletException
- {
+ public void init(FilterConfig filterConfig) throws ServletException {
String tempExcludes = filterConfig.getInitParameter("excludes");
- if (StringUtils.isNotEmpty(tempExcludes))
- {
+ if (StringUtils.isNotEmpty(tempExcludes)) {
String[] url = tempExcludes.split(",");
- for (int i = 0; url != null && i < url.length; i++)
- {
+ for (int i = 0; url != null && i < url.length; i++) {
excludes.add(url[i]);
}
}
@@ -37,12 +33,10 @@ public class XssFilter implements Filter
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- throws IOException, ServletException
- {
+ throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
- if (handleExcludeURL(req, resp))
- {
+ if (handleExcludeURL(req, resp)) {
chain.doFilter(request, response);
return;
}
@@ -50,21 +44,18 @@ public class XssFilter implements Filter
chain.doFilter(xssRequest, response);
}
- private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
- {
+ private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response) {
String url = request.getServletPath();
String method = request.getMethod();
// GET DELETE 不过滤
- if (method == null || method.matches("GET") || method.matches("DELETE"))
- {
+ if (method == null || method.matches("GET") || method.matches("DELETE")) {
return true;
}
return StringUtils.matches(url, excludes);
}
@Override
- public void destroy()
- {
+ public void destroy() {
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
index 8af1257df..a8ffd66cc 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
@@ -19,26 +19,21 @@ import java.nio.charset.StandardCharsets;
*
* @author ruoyi
*/
-public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
-{
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
/**
* @param request
*/
- public XssHttpServletRequestWrapper(HttpServletRequest request)
- {
+ public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
- public String[] getParameterValues(String name)
- {
+ public String[] getParameterValues(String name) {
String[] values = super.getParameterValues(name);
- if (values != null)
- {
+ if (values != null) {
int length = values.length;
String[] escapseValues = new String[length];
- for (int i = 0; i < length; i++)
- {
+ for (int i = 0; i < length; i++) {
// 防xss攻击和过滤前后空格
escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
}
@@ -48,18 +43,15 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
}
@Override
- public ServletInputStream getInputStream() throws IOException
- {
+ public ServletInputStream getInputStream() throws IOException {
// 非json类型,直接返回
- if (!isJsonRequest())
- {
+ if (!isJsonRequest()) {
return super.getInputStream();
}
// 为空,直接返回
String json = IoUtil.read(super.getInputStream(), StandardCharsets.UTF_8);
- if (StringUtils.isEmpty(json))
- {
+ if (StringUtils.isEmpty(json)) {
return super.getInputStream();
}
@@ -67,34 +59,28 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
json = HtmlUtil.cleanHtmlTag(json).trim();
byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
final ByteArrayInputStream bis = IoUtil.toStream(jsonBytes);
- return new ServletInputStream()
- {
+ return new ServletInputStream() {
@Override
- public boolean isFinished()
- {
+ public boolean isFinished() {
return true;
}
@Override
- public boolean isReady()
- {
+ public boolean isReady() {
return true;
}
@Override
- public int available() throws IOException
- {
+ public int available() throws IOException {
return jsonBytes.length;
}
@Override
- public void setReadListener(ReadListener readListener)
- {
+ public void setReadListener(ReadListener readListener) {
}
@Override
- public int read() throws IOException
- {
+ public int read() throws IOException {
return bis.read();
}
};
@@ -105,8 +91,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
*
* @param request
*/
- public boolean isJsonRequest()
- {
+ public boolean isJsonRequest() {
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/BeanCopyUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/BeanCopyUtils.java
index 16a252d0f..8bf40d16a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/BeanCopyUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/BeanCopyUtils.java
@@ -16,51 +16,51 @@ import java.util.stream.Collectors;
*/
public class BeanCopyUtils {
- /**
- * 单对象基于class创建拷贝
- *
- * @param source 数据来源实体
- * @param copyOptions copy条件
- * @param desc 描述对象 转换后的对象
- * @return desc
- */
- public static V oneCopy(T source, CopyOptions copyOptions, Class desc) {
- V v = ReflectUtil.newInstanceIfPossible(desc);
- return oneCopy(source, copyOptions, v);
- }
+ /**
+ * 单对象基于class创建拷贝
+ *
+ * @param source 数据来源实体
+ * @param copyOptions copy条件
+ * @param desc 描述对象 转换后的对象
+ * @return desc
+ */
+ public static V oneCopy(T source, CopyOptions copyOptions, Class desc) {
+ V v = ReflectUtil.newInstanceIfPossible(desc);
+ return oneCopy(source, copyOptions, v);
+ }
- /**
- * 单对象基于对象创建拷贝
- *
- * @param source 数据来源实体
- * @param copyOptions copy条件
- * @param desc 转换后的对象
- * @return desc
- */
- public static V oneCopy(T source, CopyOptions copyOptions, V desc) {
- if (ObjectUtil.isNull(source)) {
- return null;
- }
- return BeanCopier.create(source, desc, copyOptions).copy();
- }
+ /**
+ * 单对象基于对象创建拷贝
+ *
+ * @param source 数据来源实体
+ * @param copyOptions copy条件
+ * @param desc 转换后的对象
+ * @return desc
+ */
+ public static V oneCopy(T source, CopyOptions copyOptions, V desc) {
+ if (ObjectUtil.isNull(source)) {
+ return null;
+ }
+ return BeanCopier.create(source, desc, copyOptions).copy();
+ }
- /**
- * 列表对象基于class创建拷贝
- *
- * @param sourceList 数据来源实体列表
- * @param copyOptions copy条件
- * @param desc 描述对象 转换后的对象
- * @return desc
- */
- public static List listCopy(List sourceList, CopyOptions copyOptions, Class desc) {
- if (ObjectUtil.isNull(sourceList)) {
- return null;
- }
- if (CollUtil.isEmpty(sourceList)) {
- return CollUtil.newArrayList();
- }
- return sourceList.stream()
- .map(source -> oneCopy(source, copyOptions, desc))
- .collect(Collectors.toList());
- }
+ /**
+ * 列表对象基于class创建拷贝
+ *
+ * @param sourceList 数据来源实体列表
+ * @param copyOptions copy条件
+ * @param desc 描述对象 转换后的对象
+ * @return desc
+ */
+ public static List listCopy(List sourceList, CopyOptions copyOptions, Class desc) {
+ if (ObjectUtil.isNull(sourceList)) {
+ return null;
+ }
+ if (CollUtil.isEmpty(sourceList)) {
+ return CollUtil.newArrayList();
+ }
+ return sourceList.stream()
+ .map(source -> oneCopy(source, copyOptions, desc))
+ .collect(Collectors.toList());
+ }
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
index 536cb3cf0..1e27f2494 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -1,18 +1,19 @@
package com.ruoyi.common.utils;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
-import org.apache.commons.lang3.time.DateFormatUtils;
/**
* 时间工具类
- *
+ *
* @author ruoyi
*/
-public class DateUtils extends org.apache.commons.lang3.time.DateUtils
-{
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
+
public static String YYYY = "yyyy";
public static String YYYY_MM = "yyyy-MM";
@@ -22,65 +23,54 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
-
+
private static String[] parsePatterns = {
- "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
+ "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
/**
* 获取当前Date型日期
- *
+ *
* @return Date() 当前日期
*/
- public static Date getNowDate()
- {
+ public static Date getNowDate() {
return new Date();
}
/**
* 获取当前日期, 默认格式为yyyy-MM-dd
- *
+ *
* @return String
*/
- public static String getDate()
- {
+ public static String getDate() {
return dateTimeNow(YYYY_MM_DD);
}
- public static final String getTime()
- {
+ public static final String getTime() {
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
}
- public static final String dateTimeNow()
- {
+ public static final String dateTimeNow() {
return dateTimeNow(YYYYMMDDHHMMSS);
}
- public static final String dateTimeNow(final String format)
- {
+ public static final String dateTimeNow(final String format) {
return parseDateToStr(format, new Date());
}
- public static final String dateTime(final Date date)
- {
+ public static final String dateTime(final Date date) {
return parseDateToStr(YYYY_MM_DD, date);
}
- public static final String parseDateToStr(final String format, final Date date)
- {
+ public static final String parseDateToStr(final String format, final Date date) {
return new SimpleDateFormat(format).format(date);
}
- public static final Date dateTime(final String format, final String ts)
- {
- try
- {
+ public static final Date dateTime(final String format, final String ts) {
+ try {
return new SimpleDateFormat(format).parse(ts);
- }
- catch (ParseException e)
- {
+ } catch (ParseException e) {
throw new RuntimeException(e);
}
}
@@ -88,8 +78,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
/**
* 日期路径 即年/月/日 如2018/08/08
*/
- public static final String datePath()
- {
+ public static final String datePath() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyy/MM/dd");
}
@@ -97,8 +86,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
/**
* 日期路径 即年/月/日 如20180808
*/
- public static final String dateTime()
- {
+ public static final String dateTime() {
Date now = new Date();
return DateFormatUtils.format(now, "yyyyMMdd");
}
@@ -106,27 +94,21 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
/**
* 日期型字符串转化为日期 格式
*/
- public static Date parseDate(Object str)
- {
- if (str == null)
- {
+ public static Date parseDate(Object str) {
+ if (str == null) {
return null;
}
- try
- {
+ try {
return parseDate(str.toString(), parsePatterns);
- }
- catch (ParseException e)
- {
+ } catch (ParseException e) {
return null;
}
}
-
+
/**
* 获取服务器启动时间
*/
- public static Date getServerStartDate()
- {
+ public static Date getServerStartDate() {
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
return new Date(time);
}
@@ -134,8 +116,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
/**
* 计算两个时间差
*/
- public static String getDatePoor(Date endDate, Date nowDate)
- {
+ public static String getDatePoor(Date endDate, Date nowDate) {
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
index 39e71a66a..f24d0e8b4 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
@@ -12,8 +12,8 @@ import java.util.List;
*
* @author ruoyi
*/
-public class DictUtils
-{
+public class DictUtils {
+
/**
* 分隔符
*/
@@ -22,11 +22,10 @@ public class DictUtils
/**
* 设置字典缓存
*
- * @param key 参数键
+ * @param key 参数键
* @param dictDatas 字典数据列表
*/
- public static void setDictCache(String key, List dictDatas)
- {
+ public static void setDictCache(String key, List dictDatas) {
RedisUtils.setCacheObject(getCacheKey(key), dictDatas);
}
@@ -36,12 +35,10 @@ public class DictUtils
* @param key 参数键
* @return dictDatas 字典数据列表
*/
- public static List getDictCache(String key)
- {
+ public static List getDictCache(String key) {
Object cacheObj = RedisUtils.getCacheObject(getCacheKey(key));
- if (StringUtils.isNotNull(cacheObj))
- {
- List dictDatas = (List)cacheObj;
+ if (StringUtils.isNotNull(cacheObj)) {
+ List dictDatas = (List) cacheObj;
return dictDatas;
}
return null;
@@ -50,60 +47,49 @@ public class DictUtils
/**
* 根据字典类型和字典值获取字典标签
*
- * @param dictType 字典类型
+ * @param dictType 字典类型
* @param dictValue 字典值
* @return 字典标签
*/
- public static String getDictLabel(String dictType, String dictValue)
- {
+ public static String getDictLabel(String dictType, String dictValue) {
return getDictLabel(dictType, dictValue, SEPARATOR);
}
/**
* 根据字典类型和字典标签获取字典值
*
- * @param dictType 字典类型
+ * @param dictType 字典类型
* @param dictLabel 字典标签
* @return 字典值
*/
- public static String getDictValue(String dictType, String dictLabel)
- {
+ public static String getDictValue(String dictType, String dictLabel) {
return getDictValue(dictType, dictLabel, SEPARATOR);
}
/**
* 根据字典类型和字典值获取字典标签
*
- * @param dictType 字典类型
+ * @param dictType 字典类型
* @param dictValue 字典值
* @param separator 分隔符
* @return 字典标签
*/
- public static String getDictLabel(String dictType, String dictValue, String separator)
- {
+ public static String getDictLabel(String dictType, String dictValue, String separator) {
StringBuilder propertyString = new StringBuilder();
List datas = getDictCache(dictType);
- if (StringUtils.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas))
- {
- for (SysDictData dict : datas)
- {
- for (String value : dictValue.split(separator))
- {
- if (value.equals(dict.getDictValue()))
- {
+ if (StringUtils.containsAny(dictValue, separator) && CollUtil.isNotEmpty(datas)) {
+ for (SysDictData dict : datas) {
+ for (String value : dictValue.split(separator)) {
+ if (value.equals(dict.getDictValue())) {
propertyString.append(dict.getDictLabel() + separator);
break;
}
}
}
- }
- else
- {
- for (SysDictData dict : datas)
- {
- if (dictValue.equals(dict.getDictValue()))
- {
+ } else {
+ for (SysDictData dict : datas) {
+ if (dictValue.equals(dict.getDictValue())) {
return dict.getDictLabel();
}
}
@@ -114,36 +100,27 @@ public class DictUtils
/**
* 根据字典类型和字典标签获取字典值
*
- * @param dictType 字典类型
+ * @param dictType 字典类型
* @param dictLabel 字典标签
* @param separator 分隔符
* @return 字典值
*/
- public static String getDictValue(String dictType, String dictLabel, String separator)
- {
+ public static String getDictValue(String dictType, String dictLabel, String separator) {
StringBuilder propertyString = new StringBuilder();
List datas = getDictCache(dictType);
- if (StringUtils.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas))
- {
- for (SysDictData dict : datas)
- {
- for (String label : dictLabel.split(separator))
- {
- if (label.equals(dict.getDictLabel()))
- {
+ if (StringUtils.containsAny(dictLabel, separator) && CollUtil.isNotEmpty(datas)) {
+ for (SysDictData dict : datas) {
+ for (String label : dictLabel.split(separator)) {
+ if (label.equals(dict.getDictLabel())) {
propertyString.append(dict.getDictValue() + separator);
break;
}
}
}
- }
- else
- {
- for (SysDictData dict : datas)
- {
- if (dictLabel.equals(dict.getDictLabel()))
- {
+ } else {
+ for (SysDictData dict : datas) {
+ if (dictLabel.equals(dict.getDictLabel())) {
return dict.getDictValue();
}
}
@@ -156,16 +133,14 @@ public class DictUtils
*
* @param key 字典键
*/
- public static void removeDictCache(String key)
- {
+ public static void removeDictCache(String key) {
RedisUtils.deleteObject(getCacheKey(key));
}
/**
* 清空字典缓存
*/
- public static void clearDictCache()
- {
+ public static void clearDictCache() {
Collection keys = RedisUtils.keys(Constants.SYS_DICT_KEY + "*");
RedisUtils.deleteObject(keys);
}
@@ -176,8 +151,7 @@ public class DictUtils
* @param configKey 参数键
* @return 缓存键key
*/
- public static String getCacheKey(String configKey)
- {
+ public static String getCacheKey(String configKey) {
return Constants.SYS_DICT_KEY + configKey;
}
}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java
index 7246b0af6..b65c23dc8 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/JsonUtils.java
@@ -24,9 +24,9 @@ public class JsonUtils {
private static ObjectMapper objectMapper = SpringUtils.getBean(ObjectMapper.class);
public static String toJsonString(Object object) {
- if (StringUtils.isNull(object)) {
- return null;
- }
+ if (StringUtils.isNull(object)) {
+ return null;
+ }
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
@@ -57,9 +57,9 @@ public class JsonUtils {
}
public static T parseObject(String text, TypeReference typeReference) {
- if (StringUtils.isBlank(text)) {
- return null;
- }
+ if (StringUtils.isBlank(text)) {
+ return null;
+ }
try {
return objectMapper.readValue(text, typeReference);
} catch (IOException e) {
@@ -67,16 +67,17 @@ public class JsonUtils {
}
}
- public static Map parseMap(String text) {
- if (StringUtils.isBlank(text)) {
- return null;
- }
- try {
- return objectMapper.readValue(text, new TypeReference
+ *
+ *
+ * @author Sharada Jambula, James House
+ * @author Contributions from Mads Henderson
+ * @author Refactoring from CronTrigger to CronExpression by Aaron Craven
+ *
+ * Borrowed from quartz v2.3.1
+ *
+ */
+public final class CronExpression implements Serializable, Cloneable {
+
+ private static final long serialVersionUID = 12423409423L;
+
+ protected static final int SECOND = 0;
+ protected static final int MINUTE = 1;
+ protected static final int HOUR = 2;
+ protected static final int DAY_OF_MONTH = 3;
+ protected static final int MONTH = 4;
+ protected static final int DAY_OF_WEEK = 5;
+ protected static final int YEAR = 6;
+ protected static final int ALL_SPEC_INT = 99; // '*'
+ protected static final int NO_SPEC_INT = 98; // '?'
+ protected static final Integer ALL_SPEC = ALL_SPEC_INT;
+ protected static final Integer NO_SPEC = NO_SPEC_INT;
+
+ protected static final Map monthMap = new HashMap(20);
+ protected static final Map dayMap = new HashMap(60);
+ static {
+ monthMap.put("JAN", 0);
+ monthMap.put("FEB", 1);
+ monthMap.put("MAR", 2);
+ monthMap.put("APR", 3);
+ monthMap.put("MAY", 4);
+ monthMap.put("JUN", 5);
+ monthMap.put("JUL", 6);
+ monthMap.put("AUG", 7);
+ monthMap.put("SEP", 8);
+ monthMap.put("OCT", 9);
+ monthMap.put("NOV", 10);
+ monthMap.put("DEC", 11);
+
+ dayMap.put("SUN", 1);
+ dayMap.put("MON", 2);
+ dayMap.put("TUE", 3);
+ dayMap.put("WED", 4);
+ dayMap.put("THU", 5);
+ dayMap.put("FRI", 6);
+ dayMap.put("SAT", 7);
+ }
+
+ private final String cronExpression;
+ private TimeZone timeZone = null;
+ protected transient TreeSet seconds;
+ protected transient TreeSet minutes;
+ protected transient TreeSet hours;
+ protected transient TreeSet daysOfMonth;
+ protected transient TreeSet months;
+ protected transient TreeSet daysOfWeek;
+ protected transient TreeSet years;
+
+ protected transient boolean lastdayOfWeek = false;
+ protected transient int nthdayOfWeek = 0;
+ protected transient boolean lastdayOfMonth = false;
+ protected transient boolean nearestWeekday = false;
+ protected transient int lastdayOffset = 0;
+ protected transient boolean expressionParsed = false;
+
+ public static final int MAX_YEAR = Calendar.getInstance().get(Calendar.YEAR) + 100;
+
+ /**
+ * Constructs a new CronExpression
based on the specified
+ * parameter.
+ *
+ * @param cronExpression String representation of the cron expression the
+ * new object should represent
+ * @throws java.text.ParseException
+ * if the string expression cannot be parsed into a valid
+ * CronExpression
+ */
+ 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
+ */
+ public CronExpression(CronExpression expression) {
+ /*
+ * We don't call the other constructor here since we need to swallow the
+ * ParseException. We also elide some of the sanity checking as it is
+ * not logically trippable.
+ */
+ this.cronExpression = expression.getCronExpression();
+ try {
+ buildExpression(cronExpression);
+ } catch (ParseException ex) {
+ throw new AssertionError();
+ }
+ if (expression.getTimeZone() != null) {
+ setTimeZone((TimeZone) expression.getTimeZone().clone());
+ }
+ }
+
+ /**
+ * 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
+ */
+ public boolean isSatisfiedBy(Date date) {
+ Calendar testDateCal = Calendar.getInstance(getTimeZone());
+ 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 after 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
+ */
+ public Date getNextValidTimeAfter(Date date) {
+ return getTimeAfter(date);
+ }
+
+ /**
+ * Returns the next date/time after the given date/time which does
+ * not satisfy the expression
+ *
+ * @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.
+ while (difference == 1000) {
+ 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 CronExpression
+ * will be resolved.
+ */
+ public TimeZone getTimeZone() {
+ if (timeZone == null) {
+ timeZone = TimeZone.getDefault();
+ }
+
+ return timeZone;
+ }
+
+ /**
+ * Sets the time zone for which this CronExpression
+ * will be resolved.
+ */
+ public void setTimeZone(TimeZone timeZone) {
+ this.timeZone = timeZone;
+ }
+
+ /**
+ * Returns the string representation of the CronExpression
+ *
+ * @return a string representation of the CronExpression
+ */
+ @Override
+ public String toString() {
+ return cronExpression;
+ }
+
+ /**
+ * 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
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ protected void buildExpression(String expression) throws ParseException {
+ expressionParsed = true;
+
+ try {
+
+ if (seconds == null) {
+ seconds = new TreeSet();
+ }
+ if (minutes == null) {
+ minutes = new TreeSet();
+ }
+ if (hours == null) {
+ hours = new TreeSet();
+ }
+ if (daysOfMonth == null) {
+ daysOfMonth = new TreeSet();
+ }
+ if (months == null) {
+ months = new TreeSet();
+ }
+ if (daysOfWeek == null) {
+ daysOfWeek = new TreeSet();
+ }
+ if (years == null) {
+ years = new TreeSet();
+ }
+
+ int exprOn = SECOND;
+
+ StringTokenizer exprsTok = new StringTokenizer(expression, " \t",
+ false);
+
+ while (exprsTok.hasMoreTokens() && exprOn <= YEAR) {
+ String expr = exprsTok.nextToken().trim();
+
+ // throw an exception if L is used with other days of the month
+ if(exprOn == DAY_OF_MONTH && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) {
+ throw new ParseException("Support for specifying 'L' and 'LW' with other days of the month is not implemented", -1);
+ }
+ // throw an exception if L is used with other days of the week
+ if(exprOn == DAY_OF_WEEK && expr.indexOf('L') != -1 && expr.length() > 1 && expr.contains(",")) {
+ throw new ParseException("Support for specifying 'L' with other days of the week is not implemented", -1);
+ }
+ 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();
+ storeExpressionVals(0, v, exprOn);
+ }
+
+ exprOn++;
+ }
+
+ if (exprOn <= DAY_OF_WEEK) {
+ throw new ParseException("Unexpected end of expression.",
+ expression.length());
+ }
+
+ if (exprOn <= YEAR) {
+ storeExpressionVals(0, "*", YEAR);
+ }
+
+ TreeSet dow = getSet(DAY_OF_WEEK);
+ TreeSet dom = getSet(DAY_OF_MONTH);
+
+ // Copying the logic from the UnsupportedOperationException below
+ boolean dayOfMSpec = !dom.contains(NO_SPEC);
+ boolean dayOfWSpec = !dow.contains(NO_SPEC);
+
+ if (!dayOfMSpec || dayOfWSpec) {
+ if (!dayOfWSpec || dayOfMSpec) {
+ throw new ParseException(
+ "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.", 0);
+ }
+ }
+ } catch (ParseException pe) {
+ throw pe;
+ } catch (Exception e) {
+ throw new ParseException("Illegal cron expression format ("
+ + e.toString() + ")", 0);
+ }
+ }
+
+ protected int storeExpressionVals(int pos, String s, int type)
+ throws ParseException {
+
+ int incr = 0;
+ int i = skipWhiteSpace(pos, s);
+ if (i >= s.length()) {
+ return i;
+ }
+ char c = s.charAt(i);
+ if ((c >= 'A') && (c <= 'Z') && (!s.equals("L")) && (!s.equals("LW")) && (!s.matches("^L-[0-9]*[W]?"))) {
+ String sub = s.substring(i, i + 3);
+ int sval = -1;
+ int eval = -1;
+ if (type == MONTH) {
+ sval = getMonthNumber(sub) + 1;
+ if (sval <= 0) {
+ throw new ParseException("Invalid Month value: '" + sub + "'", i);
+ }
+ if (s.length() > i + 3) {
+ c = s.charAt(i + 3);
+ if (c == '-') {
+ i += 4;
+ sub = s.substring(i, i + 3);
+ eval = getMonthNumber(sub) + 1;
+ if (eval <= 0) {
+ throw new ParseException("Invalid Month value: '" + sub + "'", i);
+ }
+ }
+ }
+ } else if (type == DAY_OF_WEEK) {
+ sval = getDayOfWeekNumber(sub);
+ if (sval < 0) {
+ throw new ParseException("Invalid Day-of-Week value: '"
+ + sub + "'", i);
+ }
+ if (s.length() > i + 3) {
+ c = s.charAt(i + 3);
+ if (c == '-') {
+ i += 4;
+ sub = s.substring(i, i + 3);
+ eval = getDayOfWeekNumber(sub);
+ if (eval < 0) {
+ throw new ParseException(
+ "Invalid Day-of-Week value: '" + sub
+ + "'", i);
+ }
+ } else if (c == '#') {
+ try {
+ i += 4;
+ nthdayOfWeek = Integer.parseInt(s.substring(i));
+ if (nthdayOfWeek < 1 || nthdayOfWeek > 5) {
+ throw new Exception();
+ }
+ } catch (Exception e) {
+ throw new ParseException(
+ "A numeric value between 1 and 5 must follow the '#' option",
+ i);
+ }
+ } else if (c == 'L') {
+ lastdayOfWeek = true;
+ i++;
+ }
+ }
+
+ } else {
+ throw new ParseException(
+ "Illegal characters for this position: '" + sub + "'",
+ i);
+ }
+ if (eval != -1) {
+ incr = 1;
+ }
+ addToSet(sval, eval, incr, type);
+ return (i + 3);
+ }
+
+ if (c == '?') {
+ i++;
+ if ((i + 1) < s.length()
+ && (s.charAt(i) != ' ' && s.charAt(i + 1) != '\t')) {
+ throw new ParseException("Illegal character after '?': "
+ + s.charAt(i), i);
+ }
+ if (type != DAY_OF_WEEK && type != DAY_OF_MONTH) {
+ throw new ParseException(
+ "'?' can only be specified for Day-of-Month or Day-of-Week.",
+ i);
+ }
+ if (type == DAY_OF_WEEK && !lastdayOfMonth) {
+ int val = daysOfMonth.last();
+ if (val == NO_SPEC_INT) {
+ throw new ParseException(
+ "'?' can only be specified for Day-of-Month -OR- Day-of-Week.",
+ i);
+ }
+ }
+
+ addToSet(NO_SPEC_INT, -1, 0, type);
+ return i;
+ }
+
+ if (c == '*' || c == '/') {
+ if (c == '*' && (i + 1) >= s.length()) {
+ addToSet(ALL_SPEC_INT, -1, incr, type);
+ return i + 1;
+ } else if (c == '/'
+ && ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s
+ .charAt(i + 1) == '\t')) {
+ throw new ParseException("'/' must be followed by an integer.", i);
+ } else if (c == '*') {
+ i++;
+ }
+ c = s.charAt(i);
+ if (c == '/') { // is an increment specified?
+ i++;
+ if (i >= s.length()) {
+ throw new ParseException("Unexpected end of string.", i);
+ }
+
+ incr = getNumericValue(s, i);
+
+ i++;
+ if (incr > 10) {
+ i++;
+ }
+ checkIncrementRange(incr, type, i);
+ } else {
+ incr = 1;
+ }
+
+ addToSet(ALL_SPEC_INT, -1, incr, type);
+ return i;
+ } else if (c == 'L') {
+ i++;
+ if (type == DAY_OF_MONTH) {
+ lastdayOfMonth = true;
+ }
+ if (type == DAY_OF_WEEK) {
+ addToSet(7, 7, 0, type);
+ }
+ if(type == DAY_OF_MONTH && s.length() > i) {
+ c = s.charAt(i);
+ if(c == '-') {
+ ValueSet vs = getValue(0, s, i+1);
+ lastdayOffset = vs.value;
+ 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') {
+ nearestWeekday = true;
+ i++;
+ }
+ }
+ }
+ return i;
+ } else if (c >= '0' && c <= '9') {
+ int val = Integer.parseInt(String.valueOf(c));
+ i++;
+ if (i >= s.length()) {
+ addToSet(val, -1, -1, type);
+ } else {
+ c = s.charAt(i);
+ if (c >= '0' && c <= '9') {
+ ValueSet vs = getValue(val, s, i);
+ val = vs.value;
+ i = vs.pos;
+ }
+ i = checkNext(i, s, val, type);
+ return i;
+ }
+ } else {
+ throw new ParseException("Unexpected character: " + c, i);
+ }
+
+ return i;
+ }
+
+ private void checkIncrementRange(int incr, int type, int idxPos) throws ParseException {
+ if (incr > 59 && (type == SECOND || type == MINUTE)) {
+ throw new ParseException("Increment > 60 : " + incr, idxPos);
+ } else if (incr > 23 && (type == HOUR)) {
+ throw new ParseException("Increment > 24 : " + incr, idxPos);
+ } else if (incr > 31 && (type == DAY_OF_MONTH)) {
+ throw new ParseException("Increment > 31 : " + incr, idxPos);
+ } else if (incr > 7 && (type == DAY_OF_WEEK)) {
+ throw new ParseException("Increment > 7 : " + incr, idxPos);
+ } else if (incr > 12 && (type == MONTH)) {
+ throw new ParseException("Increment > 12 : " + incr, idxPos);
+ }
+ }
+
+ protected int checkNext(int pos, String s, int val, int type)
+ throws ParseException {
+
+ int end = -1;
+ int i = pos;
+
+ if (i >= s.length()) {
+ addToSet(val, end, -1, type);
+ return i;
+ }
+
+ char c = s.charAt(pos);
+
+ if (c == 'L') {
+ if (type == DAY_OF_WEEK) {
+ if(val < 1 || val > 7)
+ throw new ParseException("Day-of-Week values must be between 1 and 7", -1);
+ lastdayOfWeek = true;
+ } else {
+ throw new ParseException("'L' option is not valid here. (pos=" + i + ")", i);
+ }
+ TreeSet set = getSet(type);
+ set.add(val);
+ i++;
+ return i;
+ }
+
+ if (c == 'W') {
+ if (type == DAY_OF_MONTH) {
+ nearestWeekday = true;
+ } else {
+ 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);
+ TreeSet set = getSet(type);
+ set.add(val);
+ i++;
+ return i;
+ }
+
+ if (c == '#') {
+ if (type != DAY_OF_WEEK) {
+ throw new ParseException("'#' option is not valid here. (pos=" + i + ")", i);
+ }
+ i++;
+ try {
+ nthdayOfWeek = Integer.parseInt(s.substring(i));
+ if (nthdayOfWeek < 1 || nthdayOfWeek > 5) {
+ throw new Exception();
+ }
+ } catch (Exception e) {
+ throw new ParseException(
+ "A numeric value between 1 and 5 must follow the '#' option",
+ i);
+ }
+
+ TreeSet set = getSet(type);
+ set.add(val);
+ i++;
+ return i;
+ }
+
+ if (c == '-') {
+ i++;
+ c = s.charAt(i);
+ int v = Integer.parseInt(String.valueOf(c));
+ end = v;
+ i++;
+ if (i >= s.length()) {
+ addToSet(val, end, 1, type);
+ return i;
+ }
+ c = s.charAt(i);
+ if (c >= '0' && c <= '9') {
+ ValueSet vs = getValue(v, s, i);
+ end = vs.value;
+ i = vs.pos;
+ }
+ if (i < s.length() && ((c = s.charAt(i)) == '/')) {
+ i++;
+ c = s.charAt(i);
+ int v2 = Integer.parseInt(String.valueOf(c));
+ i++;
+ if (i >= s.length()) {
+ addToSet(val, end, v2, type);
+ return i;
+ }
+ c = s.charAt(i);
+ if (c >= '0' && c <= '9') {
+ ValueSet vs = getValue(v2, s, i);
+ int v3 = vs.value;
+ addToSet(val, end, v3, type);
+ i = vs.pos;
+ return i;
+ } else {
+ addToSet(val, end, v2, type);
+ return i;
+ }
+ } else {
+ addToSet(val, end, 1, type);
+ return i;
+ }
+ }
+
+ if (c == '/') {
+ if ((i + 1) >= s.length() || s.charAt(i + 1) == ' ' || s.charAt(i + 1) == '\t') {
+ throw new ParseException("'/' must be followed by an integer.", i);
+ }
+
+ i++;
+ c = s.charAt(i);
+ int v2 = Integer.parseInt(String.valueOf(c));
+ i++;
+ if (i >= s.length()) {
+ checkIncrementRange(v2, type, i);
+ addToSet(val, end, v2, type);
+ return i;
+ }
+ c = s.charAt(i);
+ if (c >= '0' && c <= '9') {
+ ValueSet vs = getValue(v2, s, i);
+ int v3 = vs.value;
+ checkIncrementRange(v3, type, i);
+ addToSet(val, end, v3, type);
+ i = vs.pos;
+ return i;
+ } else {
+ throw new ParseException("Unexpected character '" + c + "' after '/'", i);
+ }
+ }
+
+ addToSet(val, end, 0, type);
+ i++;
+ return i;
+ }
+
+ public String getCronExpression() {
+ return cronExpression;
+ }
+
+ public String getExpressionSummary() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append("seconds: ");
+ buf.append(getExpressionSetSummary(seconds));
+ buf.append("\n");
+ buf.append("minutes: ");
+ buf.append(getExpressionSetSummary(minutes));
+ buf.append("\n");
+ buf.append("hours: ");
+ buf.append(getExpressionSetSummary(hours));
+ buf.append("\n");
+ buf.append("daysOfMonth: ");
+ buf.append(getExpressionSetSummary(daysOfMonth));
+ buf.append("\n");
+ buf.append("months: ");
+ buf.append(getExpressionSetSummary(months));
+ buf.append("\n");
+ buf.append("daysOfWeek: ");
+ buf.append(getExpressionSetSummary(daysOfWeek));
+ buf.append("\n");
+ buf.append("lastdayOfWeek: ");
+ buf.append(lastdayOfWeek);
+ buf.append("\n");
+ buf.append("nearestWeekday: ");
+ buf.append(nearestWeekday);
+ buf.append("\n");
+ buf.append("NthDayOfWeek: ");
+ buf.append(nthdayOfWeek);
+ buf.append("\n");
+ buf.append("lastdayOfMonth: ");
+ buf.append(lastdayOfMonth);
+ buf.append("\n");
+ buf.append("years: ");
+ buf.append(getExpressionSetSummary(years));
+ buf.append("\n");
+
+ return buf.toString();
+ }
+
+ protected String getExpressionSetSummary(java.util.Set set) {
+
+ if (set.contains(NO_SPEC)) {
+ return "?";
+ }
+ if (set.contains(ALL_SPEC)) {
+ return "*";
+ }
+
+ StringBuilder buf = new StringBuilder();
+
+ Iterator itr = set.iterator();
+ boolean first = true;
+ while (itr.hasNext()) {
+ Integer iVal = itr.next();
+ String val = iVal.toString();
+ if (!first) {
+ buf.append(",");
+ }
+ buf.append(val);
+ first = false;
+ }
+
+ return buf.toString();
+ }
+
+ protected String getExpressionSetSummary(java.util.ArrayList list) {
+
+ if (list.contains(NO_SPEC)) {
+ return "?";
+ }
+ if (list.contains(ALL_SPEC)) {
+ return "*";
+ }
+
+ StringBuilder buf = new StringBuilder();
+
+ Iterator itr = list.iterator();
+ boolean first = true;
+ while (itr.hasNext()) {
+ Integer iVal = itr.next();
+ String val = iVal.toString();
+ if (!first) {
+ buf.append(",");
+ }
+ buf.append(val);
+ first = false;
+ }
+
+ return buf.toString();
+ }
+
+ protected int skipWhiteSpace(int i, String s) {
+ for (; i < s.length() && (s.charAt(i) == ' ' || s.charAt(i) == '\t'); i++) {
+ }
+
+ return i;
+ }
+
+ protected int findNextWhiteSpace(int i, String s) {
+ for (; i < s.length() && (s.charAt(i) != ' ' || s.charAt(i) != '\t'); i++) {
+ }
+
+ return i;
+ }
+
+ protected void addToSet(int val, int end, int incr, int type)
+ throws ParseException {
+
+ TreeSet set = getSet(type);
+
+ if (type == SECOND || type == MINUTE) {
+ if ((val < 0 || val > 59 || end > 59) && (val != ALL_SPEC_INT)) {
+ throw new ParseException(
+ "Minute and Second values must be between 0 and 59",
+ -1);
+ }
+ } else if (type == HOUR) {
+ if ((val < 0 || val > 23 || end > 23) && (val != ALL_SPEC_INT)) {
+ throw new ParseException(
+ "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)
+ && (val != NO_SPEC_INT)) {
+ throw new ParseException(
+ "Day of month values must be between 1 and 31", -1);
+ }
+ } else if (type == MONTH) {
+ if ((val < 1 || val > 12 || end > 12) && (val != ALL_SPEC_INT)) {
+ throw new ParseException(
+ "Month values must be between 1 and 12", -1);
+ }
+ } else if (type == DAY_OF_WEEK) {
+ if ((val == 0 || val > 7 || end > 7) && (val != ALL_SPEC_INT)
+ && (val != NO_SPEC_INT)) {
+ throw new ParseException(
+ "Day-of-Week values must be between 1 and 7", -1);
+ }
+ }
+
+ if ((incr == 0 || incr == -1) && val != ALL_SPEC_INT) {
+ if (val != -1) {
+ set.add(val);
+ } else {
+ set.add(NO_SPEC);
+ }
+
+ return;
+ }
+
+ int startAt = val;
+ int stopAt = end;
+
+ if (val == ALL_SPEC_INT && incr <= 0) {
+ incr = 1;
+ set.add(ALL_SPEC); // put in a marker, but also fill values
+ }
+
+ if (type == SECOND || type == MINUTE) {
+ if (stopAt == -1) {
+ stopAt = 59;
+ }
+ if (startAt == -1 || startAt == ALL_SPEC_INT) {
+ startAt = 0;
+ }
+ } else if (type == HOUR) {
+ if (stopAt == -1) {
+ stopAt = 23;
+ }
+ if (startAt == -1 || startAt == ALL_SPEC_INT) {
+ startAt = 0;
+ }
+ } else if (type == DAY_OF_MONTH) {
+ if (stopAt == -1) {
+ stopAt = 31;
+ }
+ if (startAt == -1 || startAt == ALL_SPEC_INT) {
+ startAt = 1;
+ }
+ } else if (type == MONTH) {
+ if (stopAt == -1) {
+ stopAt = 12;
+ }
+ if (startAt == -1 || startAt == ALL_SPEC_INT) {
+ startAt = 1;
+ }
+ } else if (type == DAY_OF_WEEK) {
+ if (stopAt == -1) {
+ stopAt = 7;
+ }
+ if (startAt == -1 || startAt == ALL_SPEC_INT) {
+ startAt = 1;
+ }
+ } else if (type == YEAR) {
+ if (stopAt == -1) {
+ stopAt = MAX_YEAR;
+ }
+ if (startAt == -1 || startAt == ALL_SPEC_INT) {
+ startAt = 1970;
+ }
+ }
+
+ // 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) {
+ switch (type) {
+ case SECOND : max = 60; break;
+ case MINUTE : max = 60; break;
+ case HOUR : max = 24; break;
+ case MONTH : max = 12; break;
+ case DAY_OF_WEEK : max = 7; break;
+ case DAY_OF_MONTH : max = 31; break;
+ case YEAR : throw new IllegalArgumentException("Start year must be less than stop year");
+ default : throw new IllegalArgumentException("Unexpected type encountered");
+ }
+ stopAt += max;
+ }
+
+ for (int i = startAt; i <= stopAt; i += incr) {
+ if (max == -1) {
+ // ie: there's no max to overflow over
+ set.add(i);
+ } else {
+ // take the modulus to get the real value
+ int i2 = i % max;
+
+ // 1-indexed ranges should not include 0, and should include their max
+ if (i2 == 0 && (type == MONTH || type == DAY_OF_WEEK || type == DAY_OF_MONTH) ) {
+ i2 = max;
+ }
+
+ set.add(i2);
+ }
+ }
+ }
+
+ TreeSet getSet(int type) {
+ switch (type) {
+ case SECOND:
+ return seconds;
+ case MINUTE:
+ return minutes;
+ case HOUR:
+ return hours;
+ case DAY_OF_MONTH:
+ return daysOfMonth;
+ case MONTH:
+ return months;
+ case DAY_OF_WEEK:
+ return daysOfWeek;
+ case YEAR:
+ return years;
+ default:
+ return null;
+ }
+ }
+
+ protected ValueSet getValue(int v, String s, int i) {
+ char c = s.charAt(i);
+ StringBuilder s1 = new StringBuilder(String.valueOf(v));
+ while (c >= '0' && c <= '9') {
+ s1.append(c);
+ i++;
+ if (i >= s.length()) {
+ break;
+ }
+ c = s.charAt(i);
+ }
+ ValueSet val = new ValueSet();
+
+ val.pos = (i < s.length()) ? i : i + 1;
+ val.value = Integer.parseInt(s1.toString());
+ return val;
+ }
+
+ protected int getNumericValue(String s, int i) {
+ int endOfVal = findNextWhiteSpace(i, s);
+ String val = s.substring(i, endOfVal);
+ return Integer.parseInt(val);
+ }
+
+ protected int getMonthNumber(String s) {
+ Integer integer = monthMap.get(s);
+
+ if (integer == null) {
+ return -1;
+ }
+
+ return integer;
+ }
+
+ protected int getDayOfWeekNumber(String s) {
+ Integer integer = dayMap.get(s);
+
+ if (integer == null) {
+ return -1;
+ }
+
+ return integer;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ //
+ // Computation Functions
+ //
+ ////////////////////////////////////////////////////////////////////////////
+
+ public Date getTimeAfter(Date afterTime) {
+
+ // Computation is based on Gregorian year only.
+ Calendar cl = new java.util.GregorianCalendar(getTimeZone());
+
+ // move ahead one second, since we're computing the time *after* the
+ // given time
+ afterTime = new Date(afterTime.getTime() + 1000);
+ // CronTrigger does not deal with milliseconds
+ cl.setTime(afterTime);
+ cl.set(Calendar.MILLISECOND, 0);
+
+ boolean gotOne = false;
+ // loop until we've computed the next time, or we've past the endTime
+ while (!gotOne) {
+
+ //if (endTime != null && cl.getTime().after(endTime)) return null;
+ if(cl.get(Calendar.YEAR) > 2999) { // prevent endless loop...
+ return null;
+ }
+
+ SortedSet st = null;
+ int t = 0;
+
+ int sec = cl.get(Calendar.SECOND);
+ int min = cl.get(Calendar.MINUTE);
+
+ // get second.................................................
+ st = seconds.tailSet(sec);
+ if (st != null && st.size() != 0) {
+ sec = st.first();
+ } else {
+ sec = seconds.first();
+ min++;
+ cl.set(Calendar.MINUTE, min);
+ }
+ cl.set(Calendar.SECOND, sec);
+
+ min = cl.get(Calendar.MINUTE);
+ int hr = cl.get(Calendar.HOUR_OF_DAY);
+ t = -1;
+
+ // get minute.................................................
+ st = minutes.tailSet(min);
+ if (st != null && st.size() != 0) {
+ t = min;
+ min = st.first();
+ } else {
+ min = minutes.first();
+ hr++;
+ }
+ if (min != t) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, min);
+ setCalendarHour(cl, hr);
+ continue;
+ }
+ cl.set(Calendar.MINUTE, min);
+
+ hr = cl.get(Calendar.HOUR_OF_DAY);
+ int day = cl.get(Calendar.DAY_OF_MONTH);
+ t = -1;
+
+ // get hour...................................................
+ st = hours.tailSet(hr);
+ if (st != null && st.size() != 0) {
+ t = hr;
+ hr = st.first();
+ } else {
+ hr = hours.first();
+ day++;
+ }
+ if (hr != t) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.DAY_OF_MONTH, day);
+ setCalendarHour(cl, hr);
+ continue;
+ }
+ cl.set(Calendar.HOUR_OF_DAY, hr);
+
+ day = cl.get(Calendar.DAY_OF_MONTH);
+ int mon = cl.get(Calendar.MONTH) + 1;
+ // '+ 1' because calendar is 0-based for this field, and we are
+ // 1-based
+ t = -1;
+ int tmon = mon;
+
+ // get day...................................................
+ boolean dayOfMSpec = !daysOfMonth.contains(NO_SPEC);
+ boolean dayOfWSpec = !daysOfWeek.contains(NO_SPEC);
+ if (dayOfMSpec && !dayOfWSpec) { // get day by day of month rule
+ st = daysOfMonth.tailSet(day);
+ if (lastdayOfMonth) {
+ if(!nearestWeekday) {
+ t = day;
+ day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
+ day -= lastdayOffset;
+ if(t > day) {
+ mon++;
+ if(mon > 12) {
+ mon = 1;
+ tmon = 3333; // ensure test of mon != tmon further below fails
+ cl.add(Calendar.YEAR, 1);
+ }
+ day = 1;
+ }
+ } else {
+ t = day;
+ day = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
+ day -= lastdayOffset;
+
+ 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);
+
+ if(dow == Calendar.SATURDAY && day == 1) {
+ day += 2;
+ } else if(dow == Calendar.SATURDAY) {
+ day -= 1;
+ } else if(dow == Calendar.SUNDAY && day == ldom) {
+ day -= 2;
+ } else if(dow == Calendar.SUNDAY) {
+ day += 1;
+ }
+
+ tcal.set(Calendar.SECOND, sec);
+ tcal.set(Calendar.MINUTE, min);
+ tcal.set(Calendar.HOUR_OF_DAY, hr);
+ tcal.set(Calendar.DAY_OF_MONTH, day);
+ tcal.set(Calendar.MONTH, mon - 1);
+ Date nTime = tcal.getTime();
+ if(nTime.before(afterTime)) {
+ day = 1;
+ mon++;
+ }
+ }
+ } else if(nearestWeekday) {
+ t = day;
+ day = daysOfMonth.first();
+
+ 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);
+
+ if(dow == Calendar.SATURDAY && day == 1) {
+ day += 2;
+ } else if(dow == Calendar.SATURDAY) {
+ day -= 1;
+ } else if(dow == Calendar.SUNDAY && day == ldom) {
+ day -= 2;
+ } else if(dow == Calendar.SUNDAY) {
+ day += 1;
+ }
+
+
+ tcal.set(Calendar.SECOND, sec);
+ tcal.set(Calendar.MINUTE, min);
+ tcal.set(Calendar.HOUR_OF_DAY, hr);
+ tcal.set(Calendar.DAY_OF_MONTH, day);
+ tcal.set(Calendar.MONTH, mon - 1);
+ Date nTime = tcal.getTime();
+ if(nTime.before(afterTime)) {
+ day = daysOfMonth.first();
+ mon++;
+ }
+ } else if (st != null && st.size() != 0) {
+ t = day;
+ day = st.first();
+ // make sure we don't over-run a short month, such as february
+ int lastDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
+ if (day > lastDay) {
+ day = daysOfMonth.first();
+ mon++;
+ }
+ } else {
+ day = daysOfMonth.first();
+ mon++;
+ }
+
+ if (day != t || mon != tmon) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, day);
+ cl.set(Calendar.MONTH, mon - 1);
+ // '- 1' because calendar is 0-based for this field, and we
+ // are 1-based
+ continue;
+ }
+ } else if (dayOfWSpec && !dayOfMSpec) { // get day by day of week rule
+ if (lastdayOfWeek) { // are we looking for the last XXX day of
+ // the month?
+ int dow = daysOfWeek.first(); // desired
+ // d-o-w
+ int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w
+ int daysToAdd = 0;
+ if (cDow < dow) {
+ daysToAdd = dow - cDow;
+ }
+ if (cDow > dow) {
+ daysToAdd = dow + (7 - cDow);
+ }
+
+ int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
+
+ if (day + daysToAdd > lDay) { // did we already miss the
+ // last one?
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, 1);
+ cl.set(Calendar.MONTH, mon);
+ // no '- 1' here because we are promoting the month
+ continue;
+ }
+
+ // find date of last occurrence of this day in this month...
+ while ((day + daysToAdd + 7) <= lDay) {
+ daysToAdd += 7;
+ }
+
+ day += daysToAdd;
+
+ if (daysToAdd > 0) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, day);
+ cl.set(Calendar.MONTH, mon - 1);
+ // '- 1' here because we are not promoting the month
+ continue;
+ }
+
+ } else if (nthdayOfWeek != 0) {
+ // are we looking for the Nth XXX day in the month?
+ int dow = daysOfWeek.first(); // desired
+ // d-o-w
+ int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w
+ int daysToAdd = 0;
+ if (cDow < dow) {
+ daysToAdd = dow - cDow;
+ } else if (cDow > dow) {
+ daysToAdd = dow + (7 - cDow);
+ }
+
+ boolean dayShifted = false;
+ if (daysToAdd > 0) {
+ dayShifted = true;
+ }
+
+ day += daysToAdd;
+ int weekOfMonth = day / 7;
+ if (day % 7 > 0) {
+ weekOfMonth++;
+ }
+
+ daysToAdd = (nthdayOfWeek - weekOfMonth) * 7;
+ day += daysToAdd;
+ if (daysToAdd < 0
+ || day > getLastDayOfMonth(mon, cl
+ .get(Calendar.YEAR))) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, 1);
+ cl.set(Calendar.MONTH, mon);
+ // no '- 1' here because we are promoting the month
+ continue;
+ } else if (daysToAdd > 0 || dayShifted) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, day);
+ cl.set(Calendar.MONTH, mon - 1);
+ // '- 1' here because we are NOT promoting the month
+ continue;
+ }
+ } else {
+ int cDow = cl.get(Calendar.DAY_OF_WEEK); // current d-o-w
+ int dow = daysOfWeek.first(); // desired
+ // d-o-w
+ st = daysOfWeek.tailSet(cDow);
+ if (st != null && st.size() > 0) {
+ dow = st.first();
+ }
+
+ int daysToAdd = 0;
+ if (cDow < dow) {
+ daysToAdd = dow - cDow;
+ }
+ if (cDow > dow) {
+ daysToAdd = dow + (7 - cDow);
+ }
+
+ int lDay = getLastDayOfMonth(mon, cl.get(Calendar.YEAR));
+
+ if (day + daysToAdd > lDay) { // will we pass the end of
+ // the month?
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, 1);
+ cl.set(Calendar.MONTH, mon);
+ // no '- 1' here because we are promoting the month
+ continue;
+ } else if (daysToAdd > 0) { // are we swithing days?
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, day + daysToAdd);
+ cl.set(Calendar.MONTH, mon - 1);
+ // '- 1' because calendar is 0-based for this field,
+ // and we are 1-based
+ continue;
+ }
+ }
+ } else { // dayOfWSpec && !dayOfMSpec
+ throw new UnsupportedOperationException(
+ "Support for specifying both a day-of-week AND a day-of-month parameter is not implemented.");
+ }
+ cl.set(Calendar.DAY_OF_MONTH, day);
+
+ mon = cl.get(Calendar.MONTH) + 1;
+ // '+ 1' because calendar is 0-based for this field, and we are
+ // 1-based
+ int year = cl.get(Calendar.YEAR);
+ t = -1;
+
+ // test for expressions that never generate a valid fire date,
+ // but keep looping...
+ if (year > MAX_YEAR) {
+ return null;
+ }
+
+ // get month...................................................
+ st = months.tailSet(mon);
+ if (st != null && st.size() != 0) {
+ t = mon;
+ mon = st.first();
+ } else {
+ mon = months.first();
+ year++;
+ }
+ if (mon != t) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, 1);
+ cl.set(Calendar.MONTH, mon - 1);
+ // '- 1' because calendar is 0-based for this field, and we are
+ // 1-based
+ cl.set(Calendar.YEAR, year);
+ continue;
+ }
+ cl.set(Calendar.MONTH, mon - 1);
+ // '- 1' because calendar is 0-based for this field, and we are
+ // 1-based
+
+ year = cl.get(Calendar.YEAR);
+ t = -1;
+
+ // get year...................................................
+ st = years.tailSet(year);
+ if (st != null && st.size() != 0) {
+ t = year;
+ year = st.first();
+ } else {
+ return null; // ran out of years...
+ }
+
+ if (year != t) {
+ cl.set(Calendar.SECOND, 0);
+ cl.set(Calendar.MINUTE, 0);
+ cl.set(Calendar.HOUR_OF_DAY, 0);
+ cl.set(Calendar.DAY_OF_MONTH, 1);
+ cl.set(Calendar.MONTH, 0);
+ // '- 1' because calendar is 0-based for this field, and we are
+ // 1-based
+ cl.set(Calendar.YEAR, year);
+ continue;
+ }
+ cl.set(Calendar.YEAR, year);
+
+ gotOne = true;
+ } // while( !done )
+
+ return cl.getTime();
+ }
+
+ /**
+ * 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(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);
+ }
+ }
+
+ /**
+ * NOT YET IMPLEMENTED: Returns the time before the given time
+ * that the CronExpression
matches.
+ */
+ public Date getTimeBefore(Date endTime) {
+ // FUTURE_TODO: implement QUARTZ-423
+ return null;
+ }
+
+ /**
+ * NOT YET IMPLEMENTED: Returns the final time that the
+ * CronExpression
will match.
+ */
+ public Date getFinalFireTime() {
+ // FUTURE_TODO: implement QUARTZ-423
+ return null;
+ }
+
+ protected boolean isLeapYear(int year) {
+ return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
+ }
+
+ protected int getLastDayOfMonth(int monthNum, int year) {
+
+ switch (monthNum) {
+ case 1:
+ return 31;
+ case 2:
+ return (isLeapYear(year)) ? 29 : 28;
+ case 3:
+ return 31;
+ case 4:
+ return 30;
+ case 5:
+ return 31;
+ case 6:
+ return 30;
+ case 7:
+ return 31;
+ case 8:
+ return 31;
+ case 9:
+ return 30;
+ case 10:
+ return 31;
+ case 11:
+ return 30;
+ case 12:
+ return 31;
+ default:
+ throw new IllegalArgumentException("Illegal month number: "
+ + monthNum);
+ }
+ }
+
+
+ private void readObject(java.io.ObjectInputStream stream)
+ throws java.io.IOException, ClassNotFoundException {
+
+ stream.defaultReadObject();
+ try {
+ buildExpression(cronExpression);
+ } catch (Exception ignore) {
+ } // never happens
+ }
+
+ @Override
+ @Deprecated
+ public Object clone() {
+ return new CronExpression(this);
+ }
+}
+
+class ValueSet {
+ public int value;
+
+ public int pos;
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java
new file mode 100644
index 000000000..faa6063c4
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java
@@ -0,0 +1,14 @@
+package com.xxl.job.admin.core.exception;
+
+/**
+ * @author xuxueli 2019-05-04 23:19:29
+ */
+public class XxlJobException extends RuntimeException {
+
+ public XxlJobException() {
+ }
+ public XxlJobException(String message) {
+ super(message);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java
new file mode 100644
index 000000000..dde4b3996
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java
@@ -0,0 +1,77 @@
+package com.xxl.job.admin.core.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Created by xuxueli on 16/9/30.
+ */
+public class XxlJobGroup {
+
+ private int id;
+ private String appname;
+ private String title;
+ private int addressType; // 执行器地址类型:0=自动注册、1=手动录入
+ private String addressList; // 执行器地址列表,多地址逗号分隔(手动录入)
+ private Date updateTime;
+
+ // registry list
+ private List registryList; // 执行器地址列表(系统注册)
+ public List getRegistryList() {
+ if (addressList!=null && addressList.trim().length()>0) {
+ registryList = new ArrayList(Arrays.asList(addressList.split(",")));
+ }
+ return registryList;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getAppname() {
+ return appname;
+ }
+
+ public void setAppname(String appname) {
+ this.appname = appname;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public int getAddressType() {
+ return addressType;
+ }
+
+ public void setAddressType(int addressType) {
+ this.addressType = addressType;
+ }
+
+ public String getAddressList() {
+ return addressList;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public void setAddressList(String addressList) {
+ this.addressList = addressList;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java
new file mode 100644
index 000000000..e47b6dc65
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java
@@ -0,0 +1,237 @@
+package com.xxl.job.admin.core.model;
+
+import java.util.Date;
+
+/**
+ * xxl-job info
+ *
+ * @author xuxueli 2016-1-12 18:25:49
+ */
+public class XxlJobInfo {
+
+ private int id; // 主键ID
+
+ private int jobGroup; // 执行器主键ID
+ 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名称
+ private String executorParam; // 执行器,任务参数
+ private String executorBlockStrategy; // 阻塞处理策略
+ private int executorTimeout; // 任务执行超时时间,单位秒
+ private int executorFailRetryCount; // 失败重试次数
+
+ private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum
+ private String glueSource; // GLUE源代码
+ private String glueRemark; // GLUE备注
+ private Date glueUpdatetime; // GLUE更新时间
+
+ private String childJobId; // 子任务ID,多个逗号分隔
+
+ private int triggerStatus; // 调度状态:0-停止,1-运行
+ private long triggerLastTime; // 上次调度时间
+ private long triggerNextTime; // 下次调度时间
+
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getJobGroup() {
+ return jobGroup;
+ }
+
+ public void setJobGroup(int jobGroup) {
+ this.jobGroup = jobGroup;
+ }
+
+ public String getJobDesc() {
+ return jobDesc;
+ }
+
+ public void setJobDesc(String jobDesc) {
+ this.jobDesc = jobDesc;
+ }
+
+ public Date getAddTime() {
+ return addTime;
+ }
+
+ public void setAddTime(Date addTime) {
+ this.addTime = addTime;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ this.author = author;
+ }
+
+ public String getAlarmEmail() {
+ return alarmEmail;
+ }
+
+ public void setAlarmEmail(String alarmEmail) {
+ 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;
+ }
+
+ public void setExecutorRouteStrategy(String executorRouteStrategy) {
+ this.executorRouteStrategy = executorRouteStrategy;
+ }
+
+ public String getExecutorHandler() {
+ return executorHandler;
+ }
+
+ public void setExecutorHandler(String executorHandler) {
+ this.executorHandler = executorHandler;
+ }
+
+ public String getExecutorParam() {
+ return executorParam;
+ }
+
+ public void setExecutorParam(String executorParam) {
+ this.executorParam = executorParam;
+ }
+
+ public String getExecutorBlockStrategy() {
+ return executorBlockStrategy;
+ }
+
+ public void setExecutorBlockStrategy(String executorBlockStrategy) {
+ this.executorBlockStrategy = executorBlockStrategy;
+ }
+
+ public int getExecutorTimeout() {
+ return executorTimeout;
+ }
+
+ public void setExecutorTimeout(int executorTimeout) {
+ this.executorTimeout = executorTimeout;
+ }
+
+ public int getExecutorFailRetryCount() {
+ return executorFailRetryCount;
+ }
+
+ public void setExecutorFailRetryCount(int executorFailRetryCount) {
+ this.executorFailRetryCount = executorFailRetryCount;
+ }
+
+ public String getGlueType() {
+ return glueType;
+ }
+
+ public void setGlueType(String glueType) {
+ this.glueType = glueType;
+ }
+
+ public String getGlueSource() {
+ return glueSource;
+ }
+
+ public void setGlueSource(String glueSource) {
+ this.glueSource = glueSource;
+ }
+
+ public String getGlueRemark() {
+ return glueRemark;
+ }
+
+ public void setGlueRemark(String glueRemark) {
+ this.glueRemark = glueRemark;
+ }
+
+ public Date getGlueUpdatetime() {
+ return glueUpdatetime;
+ }
+
+ public void setGlueUpdatetime(Date glueUpdatetime) {
+ this.glueUpdatetime = glueUpdatetime;
+ }
+
+ public String getChildJobId() {
+ return childJobId;
+ }
+
+ public void setChildJobId(String childJobId) {
+ this.childJobId = childJobId;
+ }
+
+ public int getTriggerStatus() {
+ return triggerStatus;
+ }
+
+ public void setTriggerStatus(int triggerStatus) {
+ this.triggerStatus = triggerStatus;
+ }
+
+ public long getTriggerLastTime() {
+ return triggerLastTime;
+ }
+
+ public void setTriggerLastTime(long triggerLastTime) {
+ this.triggerLastTime = triggerLastTime;
+ }
+
+ public long getTriggerNextTime() {
+ return triggerNextTime;
+ }
+
+ public void setTriggerNextTime(long triggerNextTime) {
+ this.triggerNextTime = triggerNextTime;
+ }
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java
new file mode 100644
index 000000000..7d3072aa6
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java
@@ -0,0 +1,157 @@
+package com.xxl.job.admin.core.model;
+
+import java.util.Date;
+
+/**
+ * xxl-job log, used to track trigger process
+ * @author xuxueli 2015-12-19 23:19:09
+ */
+public class XxlJobLog {
+
+ private long id;
+
+ // job info
+ private int jobGroup;
+ private int jobId;
+
+ // execute info
+ private String executorAddress;
+ private String executorHandler;
+ private String executorParam;
+ private String executorShardingParam;
+ private int executorFailRetryCount;
+
+ // trigger info
+ private Date triggerTime;
+ private int triggerCode;
+ private String triggerMsg;
+
+ // handle info
+ private Date handleTime;
+ private int handleCode;
+ private String handleMsg;
+
+ // alarm info
+ private int alarmStatus;
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public int getJobGroup() {
+ return jobGroup;
+ }
+
+ public void setJobGroup(int jobGroup) {
+ this.jobGroup = jobGroup;
+ }
+
+ public int getJobId() {
+ return jobId;
+ }
+
+ public void setJobId(int jobId) {
+ this.jobId = jobId;
+ }
+
+ public String getExecutorAddress() {
+ return executorAddress;
+ }
+
+ public void setExecutorAddress(String executorAddress) {
+ this.executorAddress = executorAddress;
+ }
+
+ public String getExecutorHandler() {
+ return executorHandler;
+ }
+
+ public void setExecutorHandler(String executorHandler) {
+ this.executorHandler = executorHandler;
+ }
+
+ public String getExecutorParam() {
+ return executorParam;
+ }
+
+ public void setExecutorParam(String executorParam) {
+ this.executorParam = executorParam;
+ }
+
+ public String getExecutorShardingParam() {
+ return executorShardingParam;
+ }
+
+ public void setExecutorShardingParam(String executorShardingParam) {
+ this.executorShardingParam = executorShardingParam;
+ }
+
+ public int getExecutorFailRetryCount() {
+ return executorFailRetryCount;
+ }
+
+ public void setExecutorFailRetryCount(int executorFailRetryCount) {
+ this.executorFailRetryCount = executorFailRetryCount;
+ }
+
+ public Date getTriggerTime() {
+ return triggerTime;
+ }
+
+ public void setTriggerTime(Date triggerTime) {
+ this.triggerTime = triggerTime;
+ }
+
+ public int getTriggerCode() {
+ return triggerCode;
+ }
+
+ public void setTriggerCode(int triggerCode) {
+ this.triggerCode = triggerCode;
+ }
+
+ public String getTriggerMsg() {
+ return triggerMsg;
+ }
+
+ public void setTriggerMsg(String triggerMsg) {
+ this.triggerMsg = triggerMsg;
+ }
+
+ public Date getHandleTime() {
+ return handleTime;
+ }
+
+ public void setHandleTime(Date handleTime) {
+ this.handleTime = handleTime;
+ }
+
+ public int getHandleCode() {
+ return handleCode;
+ }
+
+ public void setHandleCode(int handleCode) {
+ this.handleCode = handleCode;
+ }
+
+ public String getHandleMsg() {
+ return handleMsg;
+ }
+
+ public void setHandleMsg(String handleMsg) {
+ this.handleMsg = handleMsg;
+ }
+
+ public int getAlarmStatus() {
+ return alarmStatus;
+ }
+
+ public void setAlarmStatus(int alarmStatus) {
+ this.alarmStatus = alarmStatus;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java
new file mode 100644
index 000000000..2f59ffa84
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java
@@ -0,0 +1,75 @@
+package com.xxl.job.admin.core.model;
+
+import java.util.Date;
+
+/**
+ * xxl-job log for glue, used to track job code process
+ * @author xuxueli 2016-5-19 17:57:46
+ */
+public class XxlJobLogGlue {
+
+ private int id;
+ private int jobId; // 任务主键ID
+ private String glueType; // GLUE类型 #com.xxl.job.core.glue.GlueTypeEnum
+ private String glueSource;
+ private String glueRemark;
+ private Date addTime;
+ private Date updateTime;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getJobId() {
+ return jobId;
+ }
+
+ public void setJobId(int jobId) {
+ this.jobId = jobId;
+ }
+
+ public String getGlueType() {
+ return glueType;
+ }
+
+ public void setGlueType(String glueType) {
+ this.glueType = glueType;
+ }
+
+ public String getGlueSource() {
+ return glueSource;
+ }
+
+ public void setGlueSource(String glueSource) {
+ this.glueSource = glueSource;
+ }
+
+ public String getGlueRemark() {
+ return glueRemark;
+ }
+
+ public void setGlueRemark(String glueRemark) {
+ this.glueRemark = glueRemark;
+ }
+
+ public Date getAddTime() {
+ return addTime;
+ }
+
+ public void setAddTime(Date addTime) {
+ this.addTime = addTime;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java
new file mode 100644
index 000000000..e58ff1a9e
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java
@@ -0,0 +1,54 @@
+package com.xxl.job.admin.core.model;
+
+import java.util.Date;
+
+public class XxlJobLogReport {
+
+ private int id;
+
+ private Date triggerDay;
+
+ private int runningCount;
+ private int sucCount;
+ private int failCount;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public Date getTriggerDay() {
+ return triggerDay;
+ }
+
+ public void setTriggerDay(Date triggerDay) {
+ this.triggerDay = triggerDay;
+ }
+
+ public int getRunningCount() {
+ return runningCount;
+ }
+
+ public void setRunningCount(int runningCount) {
+ this.runningCount = runningCount;
+ }
+
+ public int getSucCount() {
+ return sucCount;
+ }
+
+ public void setSucCount(int sucCount) {
+ this.sucCount = sucCount;
+ }
+
+ public int getFailCount() {
+ return failCount;
+ }
+
+ public void setFailCount(int failCount) {
+ this.failCount = failCount;
+ }
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java
new file mode 100644
index 000000000..924d6d336
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java
@@ -0,0 +1,55 @@
+package com.xxl.job.admin.core.model;
+
+import java.util.Date;
+
+/**
+ * Created by xuxueli on 16/9/30.
+ */
+public class XxlJobRegistry {
+
+ private int id;
+ private String registryGroup;
+ private String registryKey;
+ private String registryValue;
+ private Date updateTime;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getRegistryGroup() {
+ return registryGroup;
+ }
+
+ public void setRegistryGroup(String registryGroup) {
+ this.registryGroup = registryGroup;
+ }
+
+ public String getRegistryKey() {
+ return registryKey;
+ }
+
+ public void setRegistryKey(String registryKey) {
+ this.registryKey = registryKey;
+ }
+
+ public String getRegistryValue() {
+ return registryValue;
+ }
+
+ public void setRegistryValue(String registryValue) {
+ this.registryValue = registryValue;
+ }
+
+ public Date getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(Date updateTime) {
+ this.updateTime = updateTime;
+ }
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java
new file mode 100644
index 000000000..db17327a8
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java
@@ -0,0 +1,73 @@
+package com.xxl.job.admin.core.model;
+
+import org.springframework.util.StringUtils;
+
+/**
+ * @author xuxueli 2019-05-04 16:43:12
+ */
+public class XxlJobUser {
+
+ private int id;
+ private String username; // 账号
+ private String password; // 密码
+ private int role; // 角色:0-普通用户、1-管理员
+ private String permission; // 权限:执行器ID列表,多个逗号分割
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public int getRole() {
+ return role;
+ }
+
+ public void setRole(int role) {
+ this.role = role;
+ }
+
+ public String getPermission() {
+ return permission;
+ }
+
+ public void setPermission(String permission) {
+ this.permission = permission;
+ }
+
+ // plugin
+ public boolean validPermission(int jobGroup){
+ if (this.role == 1) {
+ return true;
+ } else {
+ if (StringUtils.hasText(this.permission)) {
+ for (String permissionItem : this.permission.split(",")) {
+ if (String.valueOf(jobGroup).equals(permissionItem)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java
new file mode 100644
index 000000000..b2dd15155
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java
@@ -0,0 +1,32 @@
+//package com.xxl.job.admin.core.jobbean;
+//
+//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;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//import org.springframework.scheduling.quartz.QuartzJobBean;
+//
+///**
+// * http job bean
+// * “@DisallowConcurrentExecution” disable concurrent, thread size can not be only one, better given more
+// * @author xuxueli 2015-12-17 18:20:34
+// */
+////@DisallowConcurrentExecution
+//public class RemoteHttpJobBean extends QuartzJobBean {
+// private static Logger logger = LoggerFactory.getLogger(RemoteHttpJobBean.class);
+//
+// @Override
+// protected void executeInternal(JobExecutionContext context)
+// throws JobExecutionException {
+//
+// // load jobId
+// JobKey jobKey = context.getTrigger().getJobKey();
+// Integer jobId = Integer.valueOf(jobKey.getName());
+//
+//
+// }
+//
+//}
\ No newline at end of file
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java
new file mode 100644
index 000000000..1e62aa190
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java
@@ -0,0 +1,413 @@
+//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;
+//import com.xxl.rpc.remoting.invoker.route.LoadBalance;
+//import com.xxl.rpc.remoting.net.NetEnum;
+//import com.xxl.rpc.remoting.net.impl.servlet.server.ServletServerHandler;
+//import com.xxl.rpc.remoting.provider.XxlRpcProviderFactory;
+//import com.xxl.rpc.serialize.Serializer;
+//import org.quartz.*;
+//import org.quartz.Trigger.TriggerState;
+//import org.quartz.impl.triggers.CronTriggerImpl;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;
+//import org.springframework.util.Assert;
+//
+//import javax.servlet.ServletException;
+//import javax.servlet.http.HttpServletRequest;
+//import javax.servlet.http.HttpServletResponse;
+//import java.io.IOException;
+//import java.util.Date;
+//import java.util.concurrent.ConcurrentHashMap;
+//
+///**
+// * base quartz scheduler util
+// * @author xuxueli 2015-12-19 16:13:53
+// */
+//public final class XxlJobDynamicScheduler {
+// private static final Logger logger = LoggerFactory.getLogger(XxlJobDynamicScheduler_old.class);
+//
+// // ---------------------- param ----------------------
+//
+// // scheduler
+// private static Scheduler scheduler;
+// public void setScheduler(Scheduler scheduler) {
+// XxlJobDynamicScheduler_old.scheduler = scheduler;
+// }
+//
+//
+// // ---------------------- init + destroy ----------------------
+// public void start() throws Exception {
+// // valid
+// Assert.notNull(scheduler, "quartz scheduler is null");
+//
+// // init i18n
+// initI18n();
+//
+// // admin registry monitor run
+// JobRegistryMonitorHelper.getInstance().start();
+//
+// // admin monitor run
+// JobFailMonitorHelper.getInstance().start();
+//
+// // admin-server
+// initRpcProvider();
+//
+// logger.info(">>>>>>>>> init xxl-job admin success.");
+// }
+//
+//
+// public void destroy() throws Exception {
+// // admin trigger pool stop
+// JobTriggerPoolHelper.toStop();
+//
+// // admin registry stop
+// JobRegistryMonitorHelper.getInstance().toStop();
+//
+// // admin monitor stop
+// JobFailMonitorHelper.getInstance().toStop();
+//
+// // admin-server
+// stopRpcProvider();
+// }
+//
+//
+// // ---------------------- I18n ----------------------
+//
+// private void initI18n(){
+// for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {
+// item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name())));
+// }
+// }
+//
+//
+// // ---------------------- admin rpc provider (no server version) ----------------------
+// private static ServletServerHandler servletServerHandler;
+// private void initRpcProvider(){
+// // init
+// XxlRpcProviderFactory xxlRpcProviderFactory = new XxlRpcProviderFactory();
+// xxlRpcProviderFactory.initConfig(
+// NetEnum.NETTY_HTTP,
+// Serializer.SerializeEnum.HESSIAN.getSerializer(),
+// null,
+// 0,
+// XxlJobAdminConfig.getAdminConfig().getAccessToken(),
+// null,
+// null);
+//
+// // add services
+// xxlRpcProviderFactory.addService(AdminBiz.class.getName(), null, XxlJobAdminConfig.getAdminConfig().getAdminBiz());
+//
+// // servlet handler
+// servletServerHandler = new ServletServerHandler(xxlRpcProviderFactory);
+// }
+// private void stopRpcProvider() throws Exception {
+// XxlRpcInvokerFactory.getInstance().stop();
+// }
+// public static void invokeAdminService(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+// servletServerHandler.handle(null, request, response);
+// }
+//
+//
+// // ---------------------- executor-client ----------------------
+// private static ConcurrentHashMap executorBizRepository = new ConcurrentHashMap();
+// public static ExecutorBiz getExecutorBiz(String address) throws Exception {
+// // valid
+// if (address==null || address.trim().length()==0) {
+// return null;
+// }
+//
+// // load-cache
+// address = address.trim();
+// ExecutorBiz executorBiz = executorBizRepository.get(address);
+// if (executorBiz != null) {
+// return executorBiz;
+// }
+//
+// // set-cache
+// executorBiz = (ExecutorBiz) new XxlRpcReferenceBean(
+// NetEnum.NETTY_HTTP,
+// Serializer.SerializeEnum.HESSIAN.getSerializer(),
+// CallType.SYNC,
+// LoadBalance.ROUND,
+// ExecutorBiz.class,
+// null,
+// 5000,
+// address,
+// XxlJobAdminConfig.getAdminConfig().getAccessToken(),
+// null,
+// null).getObject();
+//
+// executorBizRepository.put(address, executorBiz);
+// return executorBiz;
+// }
+//
+//
+// // ---------------------- schedule util ----------------------
+//
+// /**
+// * fill job info
+// *
+// * @param jobInfo
+// */
+// public static void fillJobInfo(XxlJobInfo jobInfo) {
+//
+// String name = String.valueOf(jobInfo.getId());
+//
+// // trigger key
+// TriggerKey triggerKey = TriggerKey.triggerKey(name);
+// try {
+//
+// // trigger cron
+// Trigger trigger = scheduler.getTrigger(triggerKey);
+// if (trigger!=null && trigger instanceof CronTriggerImpl) {
+// String cronExpression = ((CronTriggerImpl) trigger).getCronExpression();
+// jobInfo.setJobCron(cronExpression);
+// }
+//
+// // trigger state
+// TriggerState triggerState = scheduler.getTriggerState(triggerKey);
+// if (triggerState!=null) {
+// jobInfo.setJobStatus(triggerState.name());
+// }
+//
+// //JobKey jobKey = new JobKey(jobInfo.getJobName(), String.valueOf(jobInfo.getJobGroup()));
+// //JobDetail jobDetail = scheduler.getJobDetail(jobKey);
+// //String jobClass = jobDetail.getJobClass().getName();
+//
+// } catch (SchedulerException e) {
+// logger.error(e.getMessage(), e);
+// }
+// }
+//
+//
+// /**
+// * add trigger + job
+// *
+// * @param jobName
+// * @param cronExpression
+// * @return
+// * @throws SchedulerException
+// */
+// public static boolean addJob(String jobName, String cronExpression) throws SchedulerException {
+// // 1、job key
+// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
+// JobKey jobKey = new JobKey(jobName);
+//
+// // 2、valid
+// if (scheduler.checkExists(triggerKey)) {
+// return true; // PASS
+// }
+//
+// // 3、corn trigger
+// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing(); // withMisfireHandlingInstructionDoNothing 忽略掉调度终止过程中忽略的调度
+// CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
+//
+// // 4、job detail
+// Class extends Job> jobClass_ = RemoteHttpJobBean.class; // Class.forName(jobInfo.getJobClass());
+// JobDetail jobDetail = JobBuilder.newJob(jobClass_).withIdentity(jobKey).build();
+//
+// /*if (jobInfo.getJobData()!=null) {
+// JobDataMap jobDataMap = jobDetail.getJobDataMap();
+// jobDataMap.putAll(JacksonUtil.readValue(jobInfo.getJobData(), Map.class));
+// // JobExecutionContext context.getMergedJobDataMap().get("mailGuid");
+// }*/
+//
+// // 5、schedule job
+// Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
+//
+// logger.info(">>>>>>>>>>> addJob success(quartz), jobDetail:{}, cronTrigger:{}, date:{}", jobDetail, cronTrigger, date);
+// return true;
+// }
+//
+//
+// /**
+// * remove trigger + job
+// *
+// * @param jobName
+// * @return
+// * @throws SchedulerException
+// */
+// public static boolean removeJob(String jobName) throws SchedulerException {
+//
+// JobKey jobKey = new JobKey(jobName);
+// scheduler.deleteJob(jobKey);
+//
+// /*TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
+// if (scheduler.checkExists(triggerKey)) {
+// scheduler.unscheduleJob(triggerKey); // trigger + job
+// }*/
+//
+// logger.info(">>>>>>>>>>> removeJob success(quartz), jobKey:{}", jobKey);
+// return true;
+// }
+//
+//
+// /**
+// * updateJobCron
+// *
+// * @param jobName
+// * @param cronExpression
+// * @return
+// * @throws SchedulerException
+// */
+// public static boolean updateJobCron(String jobName, String cronExpression) throws SchedulerException {
+//
+// // 1、job key
+// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
+//
+// // 2、valid
+// if (!scheduler.checkExists(triggerKey)) {
+// return true; // PASS
+// }
+//
+// CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
+//
+// // 3、avoid repeat cron
+// String oldCron = oldTrigger.getCronExpression();
+// if (oldCron.equals(cronExpression)){
+// return true; // PASS
+// }
+//
+// // 4、new cron trigger
+// CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression).withMisfireHandlingInstructionDoNothing();
+// oldTrigger = oldTrigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
+//
+// // 5、rescheduleJob
+// scheduler.rescheduleJob(triggerKey, oldTrigger);
+//
+// /*
+// JobKey jobKey = new JobKey(jobName);
+//
+// // old job detail
+// JobDetail jobDetail = scheduler.getJobDetail(jobKey);
+//
+// // new trigger
+// HashSet triggerSet = new HashSet();
+// triggerSet.add(cronTrigger);
+// // cover trigger of job detail
+// scheduler.scheduleJob(jobDetail, triggerSet, true);*/
+//
+// logger.info(">>>>>>>>>>> resumeJob success, JobName:{}", jobName);
+// return true;
+// }
+//
+//
+// /**
+// * pause
+// *
+// * @param jobName
+// * @return
+// * @throws SchedulerException
+// */
+// /*public static boolean pauseJob(String jobName) throws SchedulerException {
+//
+// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
+//
+// boolean result = false;
+// if (scheduler.checkExists(triggerKey)) {
+// scheduler.pauseTrigger(triggerKey);
+// result = true;
+// }
+//
+// logger.info(">>>>>>>>>>> pauseJob {}, triggerKey:{}", (result?"success":"fail"),triggerKey);
+// return result;
+// }*/
+//
+//
+// /**
+// * resume
+// *
+// * @param jobName
+// * @return
+// * @throws SchedulerException
+// */
+// /*public static boolean resumeJob(String jobName) throws SchedulerException {
+//
+// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
+//
+// boolean result = false;
+// if (scheduler.checkExists(triggerKey)) {
+// scheduler.resumeTrigger(triggerKey);
+// result = true;
+// }
+//
+// logger.info(">>>>>>>>>>> resumeJob {}, triggerKey:{}", (result?"success":"fail"), triggerKey);
+// return result;
+// }*/
+//
+//
+// /**
+// * run
+// *
+// * @param jobName
+// * @return
+// * @throws SchedulerException
+// */
+// /*public static boolean triggerJob(String jobName) throws SchedulerException {
+// // TriggerKey : name + group
+// JobKey jobKey = new JobKey(jobName);
+// TriggerKey triggerKey = TriggerKey.triggerKey(jobName);
+//
+// boolean result = false;
+// if (scheduler.checkExists(triggerKey)) {
+// scheduler.triggerJob(jobKey);
+// result = true;
+// logger.info(">>>>>>>>>>> runJob success, jobKey:{}", jobKey);
+// } else {
+// logger.info(">>>>>>>>>>> runJob fail, jobKey:{}", jobKey);
+// }
+// return result;
+// }*/
+//
+//
+// /**
+// * finaAllJobList
+// *
+// * @return
+// *//*
+// @Deprecated
+// public static List> finaAllJobList(){
+// List> jobList = new ArrayList>();
+//
+// try {
+// if (scheduler.getJobGroupNames()==null || scheduler.getJobGroupNames().size()==0) {
+// return null;
+// }
+// String groupName = scheduler.getJobGroupNames().get(0);
+// Set jobKeys = scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName));
+// if (jobKeys!=null && jobKeys.size()>0) {
+// for (JobKey jobKey : jobKeys) {
+// TriggerKey triggerKey = TriggerKey.triggerKey(jobKey.getName(), Scheduler.DEFAULT_GROUP);
+// Trigger trigger = scheduler.getTrigger(triggerKey);
+// JobDetail jobDetail = scheduler.getJobDetail(jobKey);
+// TriggerState triggerState = scheduler.getTriggerState(triggerKey);
+// Map jobMap = new HashMap();
+// jobMap.put("TriggerKey", triggerKey);
+// jobMap.put("Trigger", trigger);
+// jobMap.put("JobDetail", jobDetail);
+// jobMap.put("TriggerState", triggerState);
+// jobList.add(jobMap);
+// }
+// }
+//
+// } catch (SchedulerException e) {
+// logger.error(e.getMessage(), e);
+// return null;
+// }
+// return jobList;
+// }*/
+//
+//}
\ No newline at end of file
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java
new file mode 100644
index 000000000..ad0743079
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java
@@ -0,0 +1,58 @@
+//package com.xxl.job.admin.core.quartz;
+//
+//import org.quartz.SchedulerConfigException;
+//import org.quartz.spi.ThreadPool;
+//
+///**
+// * single thread pool, for async trigger
+// *
+// * @author xuxueli 2019-03-06
+// */
+//public class XxlJobThreadPool implements ThreadPool {
+//
+// @Override
+// public boolean runInThread(Runnable runnable) {
+//
+// // async run
+// runnable.run();
+// return true;
+//
+// //return false;
+// }
+//
+// @Override
+// public int blockForAvailableThreads() {
+// return 1;
+// }
+//
+// @Override
+// public void initialize() throws SchedulerConfigException {
+//
+// }
+//
+// @Override
+// public void shutdown(boolean waitForJobsToComplete) {
+//
+// }
+//
+// @Override
+// public int getPoolSize() {
+// return 1;
+// }
+//
+// @Override
+// public void setInstanceId(String schedInstId) {
+//
+// }
+//
+// @Override
+// public void setInstanceName(String schedName) {
+//
+// }
+//
+// // support
+// public void setThreadCount(int count) {
+// //
+// }
+//
+//}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java
new file mode 100644
index 000000000..7fff93a9d
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java
@@ -0,0 +1,48 @@
+package com.xxl.job.admin.core.route;
+
+import com.xxl.job.admin.core.route.strategy.*;
+import com.xxl.job.admin.core.util.I18nUtil;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public enum ExecutorRouteStrategyEnum {
+
+ FIRST(I18nUtil.getString("jobconf_route_first"), new ExecutorRouteFirst()),
+ LAST(I18nUtil.getString("jobconf_route_last"), new ExecutorRouteLast()),
+ ROUND(I18nUtil.getString("jobconf_route_round"), new ExecutorRouteRound()),
+ RANDOM(I18nUtil.getString("jobconf_route_random"), new ExecutorRouteRandom()),
+ CONSISTENT_HASH(I18nUtil.getString("jobconf_route_consistenthash"), new ExecutorRouteConsistentHash()),
+ LEAST_FREQUENTLY_USED(I18nUtil.getString("jobconf_route_lfu"), new ExecutorRouteLFU()),
+ LEAST_RECENTLY_USED(I18nUtil.getString("jobconf_route_lru"), new ExecutorRouteLRU()),
+ FAILOVER(I18nUtil.getString("jobconf_route_failover"), new ExecutorRouteFailover()),
+ BUSYOVER(I18nUtil.getString("jobconf_route_busyover"), new ExecutorRouteBusyover()),
+ SHARDING_BROADCAST(I18nUtil.getString("jobconf_route_shard"), null);
+
+ ExecutorRouteStrategyEnum(String title, ExecutorRouter router) {
+ this.title = title;
+ this.router = router;
+ }
+
+ private String title;
+ private ExecutorRouter router;
+
+ public String getTitle() {
+ return title;
+ }
+ public ExecutorRouter getRouter() {
+ return router;
+ }
+
+ public static ExecutorRouteStrategyEnum match(String name, ExecutorRouteStrategyEnum defaultItem){
+ if (name != null) {
+ for (ExecutorRouteStrategyEnum item: ExecutorRouteStrategyEnum.values()) {
+ if (item.name().equals(name)) {
+ return item;
+ }
+ }
+ }
+ return defaultItem;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java
new file mode 100644
index 000000000..5de9a1d08
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java
@@ -0,0 +1,24 @@
+package com.xxl.job.admin.core.route;
+
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public abstract class ExecutorRouter {
+ protected static Logger logger = LoggerFactory.getLogger(ExecutorRouter.class);
+
+ /**
+ * route address
+ *
+ * @param addressList
+ * @return ReturnT.content=address
+ */
+ public abstract ReturnT route(TriggerParam triggerParam, List addressList);
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java
new file mode 100644
index 000000000..868560fc2
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java
@@ -0,0 +1,48 @@
+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.IdleBeatParam;
+import com.xxl.job.core.biz.model.ReturnT;
+import com.xxl.job.core.biz.model.TriggerParam;
+
+import java.util.List;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteBusyover extends ExecutorRouter {
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+ StringBuffer idleBeatResultSB = new StringBuffer();
+ for (String address : addressList) {
+ // beat
+ ReturnT idleBeatResult = null;
+ try {
+ ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
+ idleBeatResult = executorBiz.idleBeat(new IdleBeatParam(triggerParam.getJobId()));
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ idleBeatResult = new ReturnT(ReturnT.FAIL_CODE, ""+e );
+ }
+ idleBeatResultSB.append( (idleBeatResultSB.length()>0)?"
":"")
+ .append(I18nUtil.getString("jobconf_idleBeat") + ":")
+ .append("
address:").append(address)
+ .append("
code:").append(idleBeatResult.getCode())
+ .append("
msg:").append(idleBeatResult.getMsg());
+
+ // beat success
+ if (idleBeatResult.getCode() == ReturnT.SUCCESS_CODE) {
+ idleBeatResult.setMsg(idleBeatResultSB.toString());
+ idleBeatResult.setContent(address);
+ return idleBeatResult;
+ }
+ }
+
+ return new ReturnT(ReturnT.FAIL_CODE, idleBeatResultSB.toString());
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java
new file mode 100644
index 000000000..41ac671c6
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java
@@ -0,0 +1,85 @@
+package com.xxl.job.admin.core.route.strategy;
+
+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;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * 分组下机器地址相同,不同JOB均匀散列在不同机器上,保证分组下机器分配JOB平均;且每个JOB固定调度其中一台机器;
+ * a、virtual node:解决不均衡问题
+ * b、hash method replace hashCode:String的hashCode可能重复,需要进一步扩大hashCode的取值范围
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteConsistentHash extends ExecutorRouter {
+
+ private static int VIRTUAL_NODE_NUM = 100;
+
+ /**
+ * get hash code on 2^32 ring (md5散列的方式计算hash值)
+ * @param key
+ * @return
+ */
+ private static long hash(String key) {
+
+ // md5 byte
+ MessageDigest md5;
+ try {
+ md5 = MessageDigest.getInstance("MD5");
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("MD5 not supported", e);
+ }
+ md5.reset();
+ byte[] keyBytes = null;
+ try {
+ keyBytes = key.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("Unknown string :" + key, e);
+ }
+
+ md5.update(keyBytes);
+ byte[] digest = md5.digest();
+
+ // hash code, Truncate to 32-bits
+ long hashCode = ((long) (digest[3] & 0xFF) << 24)
+ | ((long) (digest[2] & 0xFF) << 16)
+ | ((long) (digest[1] & 0xFF) << 8)
+ | (digest[0] & 0xFF);
+
+ long truncateHashCode = hashCode & 0xffffffffL;
+ return truncateHashCode;
+ }
+
+ public String hashJob(int jobId, List addressList) {
+
+ // ------A1------A2-------A3------
+ // -----------J1------------------
+ TreeMap addressRing = new TreeMap();
+ for (String address: addressList) {
+ for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
+ long addressHash = hash("SHARD-" + address + "-NODE-" + i);
+ addressRing.put(addressHash, address);
+ }
+ }
+
+ long jobHash = hash(String.valueOf(jobId));
+ SortedMap lastRing = addressRing.tailMap(jobHash);
+ if (!lastRing.isEmpty()) {
+ return lastRing.get(lastRing.firstKey());
+ }
+ return addressRing.firstEntry().getValue();
+ }
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+ String address = hashJob(triggerParam.getJobId(), addressList);
+ return new ReturnT(address);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java
new file mode 100644
index 000000000..a2e4c909a
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java
@@ -0,0 +1,48 @@
+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;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteFailover extends ExecutorRouter {
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+
+ StringBuffer beatResultSB = new StringBuffer();
+ for (String address : addressList) {
+ // beat
+ ReturnT beatResult = null;
+ try {
+ ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
+ beatResult = executorBiz.beat();
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ beatResult = new ReturnT(ReturnT.FAIL_CODE, ""+e );
+ }
+ beatResultSB.append( (beatResultSB.length()>0)?"
":"")
+ .append(I18nUtil.getString("jobconf_beat") + ":")
+ .append("
address:").append(address)
+ .append("
code:").append(beatResult.getCode())
+ .append("
msg:").append(beatResult.getMsg());
+
+ // beat success
+ if (beatResult.getCode() == ReturnT.SUCCESS_CODE) {
+
+ beatResult.setMsg(beatResultSB.toString());
+ beatResult.setContent(address);
+ return beatResult;
+ }
+ }
+ return new ReturnT(ReturnT.FAIL_CODE, beatResultSB.toString());
+
+ }
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java
new file mode 100644
index 000000000..de4d7afb0
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java
@@ -0,0 +1,19 @@
+package com.xxl.job.admin.core.route.strategy;
+
+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;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteFirst extends ExecutorRouter {
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList){
+ return new ReturnT(addressList.get(0));
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java
new file mode 100644
index 000000000..9df197262
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java
@@ -0,0 +1,79 @@
+package com.xxl.job.admin.core.route.strategy;
+
+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;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * 单个JOB对应的每个执行器,使用频率最低的优先被选举
+ * a(*)、LFU(Least Frequently Used):最不经常使用,频率/次数
+ * b、LRU(Least Recently Used):最近最久未使用,时间
+ *
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteLFU extends ExecutorRouter {
+
+ private static ConcurrentMap> jobLfuMap = new ConcurrentHashMap>();
+ private static long CACHE_VALID_TIME = 0;
+
+ public String route(int jobId, List addressList) {
+
+ // cache clear
+ if (System.currentTimeMillis() > CACHE_VALID_TIME) {
+ jobLfuMap.clear();
+ CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
+ }
+
+ // lfu item init
+ HashMap lfuItemMap = jobLfuMap.get(jobId); // Key排序可以用TreeMap+构造入参Compare;Value排序暂时只能通过ArrayList;
+ if (lfuItemMap == null) {
+ lfuItemMap = new HashMap();
+ jobLfuMap.putIfAbsent(jobId, lfuItemMap); // 避免重复覆盖
+ }
+
+ // put new
+ for (String address: addressList) {
+ if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) >1000000 ) {
+ lfuItemMap.put(address, new Random().nextInt(addressList.size())); // 初始化时主动Random一次,缓解首次压力
+ }
+ }
+ // remove old
+ List delKeys = new ArrayList<>();
+ for (String existKey: lfuItemMap.keySet()) {
+ if (!addressList.contains(existKey)) {
+ delKeys.add(existKey);
+ }
+ }
+ if (delKeys.size() > 0) {
+ for (String delKey: delKeys) {
+ lfuItemMap.remove(delKey);
+ }
+ }
+
+ // load least userd count address
+ List> lfuItemList = new ArrayList>(lfuItemMap.entrySet());
+ Collections.sort(lfuItemList, new Comparator>() {
+ @Override
+ public int compare(Map.Entry o1, Map.Entry o2) {
+ return o1.getValue().compareTo(o2.getValue());
+ }
+ });
+
+ Map.Entry addressItem = lfuItemList.get(0);
+ String minAddress = addressItem.getKey();
+ addressItem.setValue(addressItem.getValue() + 1);
+
+ return addressItem.getKey();
+ }
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+ String address = route(triggerParam.getJobId(), addressList);
+ return new ReturnT(address);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java
new file mode 100644
index 000000000..2d5400677
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java
@@ -0,0 +1,76 @@
+package com.xxl.job.admin.core.route.strategy;
+
+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;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * 单个JOB对应的每个执行器,最久为使用的优先被选举
+ * a、LFU(Least Frequently Used):最不经常使用,频率/次数
+ * b(*)、LRU(Least Recently Used):最近最久未使用,时间
+ *
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteLRU extends ExecutorRouter {
+
+ private static ConcurrentMap> jobLRUMap = new ConcurrentHashMap>();
+ private static long CACHE_VALID_TIME = 0;
+
+ public String route(int jobId, List addressList) {
+
+ // cache clear
+ if (System.currentTimeMillis() > CACHE_VALID_TIME) {
+ jobLRUMap.clear();
+ CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
+ }
+
+ // init lru
+ LinkedHashMap lruItem = jobLRUMap.get(jobId);
+ if (lruItem == null) {
+ /**
+ * LinkedHashMap
+ * a、accessOrder:true=访问顺序排序(get/put时排序);false=插入顺序排期;
+ * b、removeEldestEntry:新增元素时将会调用,返回true时会删除最老元素;可封装LinkedHashMap并重写该方法,比如定义最大容量,超出是返回true即可实现固定长度的LRU算法;
+ */
+ lruItem = new LinkedHashMap(16, 0.75f, true);
+ jobLRUMap.putIfAbsent(jobId, lruItem);
+ }
+
+ // put new
+ for (String address: addressList) {
+ if (!lruItem.containsKey(address)) {
+ lruItem.put(address, address);
+ }
+ }
+ // remove old
+ List delKeys = new ArrayList<>();
+ for (String existKey: lruItem.keySet()) {
+ if (!addressList.contains(existKey)) {
+ delKeys.add(existKey);
+ }
+ }
+ if (delKeys.size() > 0) {
+ for (String delKey: delKeys) {
+ lruItem.remove(delKey);
+ }
+ }
+
+ // load
+ String eldestKey = lruItem.entrySet().iterator().next().getKey();
+ String eldestValue = lruItem.get(eldestKey);
+ return eldestValue;
+ }
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+ String address = route(triggerParam.getJobId(), addressList);
+ return new ReturnT(address);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java
new file mode 100644
index 000000000..4ff3cf6ba
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java
@@ -0,0 +1,19 @@
+package com.xxl.job.admin.core.route.strategy;
+
+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;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteLast extends ExecutorRouter {
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+ return new ReturnT(addressList.get(addressList.size()-1));
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java
new file mode 100644
index 000000000..5ea4a3841
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java
@@ -0,0 +1,23 @@
+package com.xxl.job.admin.core.route.strategy;
+
+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;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteRandom extends ExecutorRouter {
+
+ private static Random localRandom = new Random();
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+ String address = addressList.get(localRandom.nextInt(addressList.size()));
+ return new ReturnT(address);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java
new file mode 100644
index 000000000..d0ea2baab
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java
@@ -0,0 +1,46 @@
+package com.xxl.job.admin.core.route.strategy;
+
+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;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Created by xuxueli on 17/3/10.
+ */
+public class ExecutorRouteRound extends ExecutorRouter {
+
+ private static ConcurrentMap routeCountEachJob = new ConcurrentHashMap<>();
+ private static long CACHE_VALID_TIME = 0;
+
+ private static int count(int jobId) {
+ // cache clear
+ if (System.currentTimeMillis() > CACHE_VALID_TIME) {
+ routeCountEachJob.clear();
+ CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
+ }
+
+ AtomicInteger count = routeCountEachJob.get(jobId);
+ if (count == null || count.get() > 1000000) {
+ // 初始化时主动Random一次,缓解首次压力
+ count = new AtomicInteger(new Random().nextInt(100));
+ } else {
+ // count++
+ count.addAndGet(1);
+ }
+ routeCountEachJob.put(jobId, count);
+ return count.get();
+ }
+
+ @Override
+ public ReturnT route(TriggerParam triggerParam, List addressList) {
+ String address = addressList.get(count(triggerParam.getJobId())%addressList.size());
+ return new ReturnT(address);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java
new file mode 100644
index 000000000..0b9b4a9c8
--- /dev/null
+++ b/ruoyi-extend/ruoyi-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;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java
new file mode 100644
index 000000000..aa334fda0
--- /dev/null
+++ b/ruoyi-extend/ruoyi-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;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java
new file mode 100644
index 000000000..bb2cda8bc
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java
@@ -0,0 +1,101 @@
+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;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * @author xuxueli 2018-10-28 00:18:17
+ */
+
+public class XxlJobScheduler {
+ private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class);
+
+
+ public void init() throws Exception {
+ // init i18n
+ initI18n();
+
+ // admin trigger pool start
+ JobTriggerPoolHelper.toStart();
+
+ // admin registry monitor run
+ JobRegistryHelper.getInstance().start();
+
+ // admin fail-monitor run
+ JobFailMonitorHelper.getInstance().start();
+
+ // admin lose-monitor run ( depend on JobTriggerPoolHelper )
+ JobCompleteHelper.getInstance().start();
+
+ // admin log report start
+ JobLogReportHelper.getInstance().start();
+
+ // start-schedule ( depend on JobTriggerPoolHelper )
+ JobScheduleHelper.getInstance().start();
+
+ logger.info(">>>>>>>>> init xxl-job admin success.");
+ }
+
+
+ public void destroy() throws Exception {
+
+ // stop-schedule
+ JobScheduleHelper.getInstance().toStop();
+
+ // admin log report stop
+ JobLogReportHelper.getInstance().toStop();
+
+ // admin lose-monitor stop
+ JobCompleteHelper.getInstance().toStop();
+
+ // admin fail-monitor stop
+ JobFailMonitorHelper.getInstance().toStop();
+
+ // admin registry stop
+ JobRegistryHelper.getInstance().toStop();
+
+ // admin trigger pool stop
+ JobTriggerPoolHelper.toStop();
+
+ }
+
+ // ---------------------- I18n ----------------------
+
+ private void initI18n(){
+ for (ExecutorBlockStrategyEnum item:ExecutorBlockStrategyEnum.values()) {
+ item.setTitle(I18nUtil.getString("jobconf_block_".concat(item.name())));
+ }
+ }
+
+ // ---------------------- executor-client ----------------------
+ private static ConcurrentMap executorBizRepository = new ConcurrentHashMap();
+ public static ExecutorBiz getExecutorBiz(String address) throws Exception {
+ // valid
+ if (address==null || address.trim().length()==0) {
+ return null;
+ }
+
+ // load-cache
+ address = address.trim();
+ ExecutorBiz executorBiz = executorBizRepository.get(address);
+ if (executorBiz != null) {
+ return executorBiz;
+ }
+
+ // set-cache
+ executorBiz = new ExecutorBizClient(address, XxlJobAdminConfig.getAdminConfig().getAccessToken());
+
+ executorBizRepository.put(address, executorBiz);
+ return executorBiz;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java
new file mode 100644
index 000000000..5698926a2
--- /dev/null
+++ b/ruoyi-extend/ruoyi-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(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 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 callback(List callbackParamList) {
+
+ callbackThreadPool.execute(new Runnable() {
+ @Override
+ public void run() {
+ for (HandleCallbackParam handleCallbackParam: callbackParamList) {
+ ReturnT callbackResult = callback(handleCallbackParam);
+ logger.debug(">>>>>>>>> JobApiController.callback {}, handleCallbackParam={}, callbackResult={}",
+ (callbackResult.getCode()== ReturnT.SUCCESS_CODE?"success":"fail"), handleCallbackParam, callbackResult);
+ }
+ }
+ });
+
+ return ReturnT.SUCCESS;
+ }
+
+ private ReturnT callback(HandleCallbackParam handleCallbackParam) {
+ // valid log item
+ XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(handleCallbackParam.getLogId());
+ if (log == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, "log item not found.");
+ }
+ if (log.getHandleCode() > 0) {
+ return new ReturnT(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("
");
+ }
+ 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;
+ }
+
+
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java
new file mode 100644
index 000000000..33e4d250d
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java
@@ -0,0 +1,110 @@
+package com.xxl.job.admin.core.thread;
+
+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;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * job monitor instance
+ *
+ * @author xuxueli 2015-9-1 18:05:56
+ */
+public class JobFailMonitorHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobFailMonitorHelper.class);
+
+ private static JobFailMonitorHelper instance = new JobFailMonitorHelper();
+ public static JobFailMonitorHelper 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 {
+
+ List failLogIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findFailJobLogIds(1000);
+ if (failLogIds!=null && !failLogIds.isEmpty()) {
+ for (long failLogId: failLogIds) {
+
+ // lock log
+ int lockRet = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, 0, -1);
+ if (lockRet < 1) {
+ continue;
+ }
+ XxlJobLog log = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().load(failLogId);
+ XxlJobInfo info = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(log.getJobId());
+
+ // 1、fail retry monitor
+ if (log.getExecutorFailRetryCount() > 0) {
+ JobTriggerPoolHelper.trigger(log.getJobId(), TriggerTypeEnum.RETRY, (log.getExecutorFailRetryCount()-1), log.getExecutorShardingParam(), log.getExecutorParam(), null);
+ String retryMsg = "
>>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_type_retry") +"<<<<<<<<<<<
";
+ log.setTriggerMsg(log.getTriggerMsg() + retryMsg);
+ XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(log);
+ }
+
+ // 2、fail alarm monitor
+ int newAlarmStatus = 0; // 告警状态:0-默认、-1=锁定状态、1-无需告警、2-告警成功、3-告警失败
+ if (info!=null && info.getAlarmEmail()!=null && info.getAlarmEmail().trim().length()>0) {
+ boolean alarmResult = XxlJobAdminConfig.getAdminConfig().getJobAlarmer().alarm(info, log);
+ newAlarmStatus = alarmResult?2:3;
+ } else {
+ newAlarmStatus = 1;
+ }
+
+ XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateAlarmStatus(failLogId, -1, newAlarmStatus);
+ }
+ }
+
+ } catch (Exception e) {
+ if (!toStop) {
+ logger.error(">>>>>>>>>>> xxl-job, job fail monitor thread error:{}", e);
+ }
+ }
+
+ try {
+ TimeUnit.SECONDS.sleep(10);
+ } catch (Exception e) {
+ if (!toStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ }
+
+ logger.info(">>>>>>>>>>> xxl-job, job fail monitor thread stop");
+
+ }
+ });
+ monitorThread.setDaemon(true);
+ monitorThread.setName("xxl-job, admin JobFailMonitorHelper");
+ monitorThread.start();
+ }
+
+ public void toStop(){
+ toStop = true;
+ // interrupt and wait
+ monitorThread.interrupt();
+ try {
+ monitorThread.join();
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java
new file mode 100644
index 000000000..2387a0c42
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java
@@ -0,0 +1,152 @@
+package com.xxl.job.admin.core.thread;
+
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import com.xxl.job.admin.core.model.XxlJobLogReport;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * job log report helper
+ *
+ * @author xuxueli 2019-11-22
+ */
+public class JobLogReportHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobLogReportHelper.class);
+
+ private static JobLogReportHelper instance = new JobLogReportHelper();
+ public static JobLogReportHelper getInstance(){
+ return instance;
+ }
+
+
+ private Thread logrThread;
+ private volatile boolean toStop = false;
+ public void start(){
+ logrThread = new Thread(new Runnable() {
+
+ @Override
+ public void run() {
+
+ // last clean log time
+ long lastCleanLogTime = 0;
+
+
+ while (!toStop) {
+
+ // 1、log-report refresh: refresh log report in 3 days
+ try {
+
+ for (int i = 0; i < 3; i++) {
+
+ // today
+ Calendar itemDay = Calendar.getInstance();
+ itemDay.add(Calendar.DAY_OF_MONTH, -i);
+ itemDay.set(Calendar.HOUR_OF_DAY, 0);
+ itemDay.set(Calendar.MINUTE, 0);
+ itemDay.set(Calendar.SECOND, 0);
+ itemDay.set(Calendar.MILLISECOND, 0);
+
+ Date todayFrom = itemDay.getTime();
+
+ itemDay.set(Calendar.HOUR_OF_DAY, 23);
+ itemDay.set(Calendar.MINUTE, 59);
+ itemDay.set(Calendar.SECOND, 59);
+ itemDay.set(Calendar.MILLISECOND, 999);
+
+ Date todayTo = itemDay.getTime();
+
+ // refresh log-report every minute
+ XxlJobLogReport xxlJobLogReport = new XxlJobLogReport();
+ xxlJobLogReport.setTriggerDay(todayFrom);
+ xxlJobLogReport.setRunningCount(0);
+ xxlJobLogReport.setSucCount(0);
+ xxlJobLogReport.setFailCount(0);
+
+ Map triggerCountMap = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findLogReport(todayFrom, todayTo);
+ if (triggerCountMap!=null && triggerCountMap.size()>0) {
+ int triggerDayCount = triggerCountMap.containsKey("triggerDayCount")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCount"))):0;
+ int triggerDayCountRunning = triggerCountMap.containsKey("triggerDayCountRunning")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountRunning"))):0;
+ int triggerDayCountSuc = triggerCountMap.containsKey("triggerDayCountSuc")?Integer.valueOf(String.valueOf(triggerCountMap.get("triggerDayCountSuc"))):0;
+ int triggerDayCountFail = triggerDayCount - triggerDayCountRunning - triggerDayCountSuc;
+
+ xxlJobLogReport.setRunningCount(triggerDayCountRunning);
+ xxlJobLogReport.setSucCount(triggerDayCountSuc);
+ xxlJobLogReport.setFailCount(triggerDayCountFail);
+ }
+
+ // do refresh
+ int ret = XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().update(xxlJobLogReport);
+ if (ret < 1) {
+ XxlJobAdminConfig.getAdminConfig().getXxlJobLogReportDao().save(xxlJobLogReport);
+ }
+ }
+
+ } catch (Exception e) {
+ if (!toStop) {
+ logger.error(">>>>>>>>>>> xxl-job, job log report thread error:{}", e);
+ }
+ }
+
+ // 2、log-clean: switch open & once each day
+ if (XxlJobAdminConfig.getAdminConfig().getLogretentiondays()>0
+ && System.currentTimeMillis() - lastCleanLogTime > 24*60*60*1000) {
+
+ // expire-time
+ Calendar expiredDay = Calendar.getInstance();
+ expiredDay.add(Calendar.DAY_OF_MONTH, -1 * XxlJobAdminConfig.getAdminConfig().getLogretentiondays());
+ expiredDay.set(Calendar.HOUR_OF_DAY, 0);
+ expiredDay.set(Calendar.MINUTE, 0);
+ expiredDay.set(Calendar.SECOND, 0);
+ expiredDay.set(Calendar.MILLISECOND, 0);
+ Date clearBeforeTime = expiredDay.getTime();
+
+ // clean expired log
+ List logIds = null;
+ do {
+ logIds = XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().findClearLogIds(0, 0, clearBeforeTime, 0, 1000);
+ if (logIds!=null && logIds.size()>0) {
+ XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().clearLog(logIds);
+ }
+ } while (logIds!=null && logIds.size()>0);
+
+ // update clean time
+ lastCleanLogTime = System.currentTimeMillis();
+ }
+
+ try {
+ TimeUnit.MINUTES.sleep(1);
+ } catch (Exception e) {
+ if (!toStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ }
+
+ logger.info(">>>>>>>>>>> xxl-job, job log report thread stop");
+
+ }
+ });
+ logrThread.setDaemon(true);
+ logrThread.setName("xxl-job, admin JobLogReportHelper");
+ logrThread.start();
+ }
+
+ public void toStop(){
+ toStop = true;
+ // interrupt and wait
+ logrThread.interrupt();
+ try {
+ logrThread.join();
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java
new file mode 100644
index 000000000..37edfd985
--- /dev/null
+++ b/ruoyi-extend/ruoyi-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(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 groupList = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0);
+ if (groupList!=null && !groupList.isEmpty()) {
+
+ // remove dead address (admin/executor)
+ List 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> appAddressMap = new HashMap>();
+ List 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 registryList = appAddressMap.get(appname);
+ if (registryList == null) {
+ registryList = new ArrayList();
+ }
+
+ if (!registryList.contains(item.getRegistryValue())) {
+ registryList.add(item.getRegistryValue());
+ }
+ appAddressMap.put(appname, registryList);
+ }
+ }
+ }
+
+ // fresh group address
+ for (XxlJobGroup group: groupList) {
+ List 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 registry(RegistryParam registryParam) {
+
+ // valid
+ if (!StringUtils.hasText(registryParam.getRegistryGroup())
+ || !StringUtils.hasText(registryParam.getRegistryKey())
+ || !StringUtils.hasText(registryParam.getRegistryValue())) {
+ return new ReturnT(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 registryRemove(RegistryParam registryParam) {
+
+ // valid
+ if (!StringUtils.hasText(registryParam.getRegistryGroup())
+ || !StringUtils.hasText(registryParam.getRegistryKey())
+ || !StringUtils.hasText(registryParam.getRegistryValue())) {
+ return new ReturnT(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
+ }
+
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java
new file mode 100644
index 000000000..831bcf6a6
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java
@@ -0,0 +1,369 @@
+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.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author xuxueli 2019-05-21
+ */
+public class JobScheduleHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobScheduleHelper.class);
+
+ private static JobScheduleHelper instance = new JobScheduleHelper();
+ public static JobScheduleHelper getInstance(){
+ return instance;
+ }
+
+ public static final long PRE_READ_MS = 5000; // pre read
+
+ private Thread scheduleThread;
+ private Thread ringThread;
+ private volatile boolean scheduleThreadToStop = false;
+ private volatile boolean ringThreadToStop = false;
+ private volatile static Map> ringData = new ConcurrentHashMap<>();
+
+ public void start(){
+
+ // schedule thread
+ scheduleThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+
+ try {
+ TimeUnit.MILLISECONDS.sleep(5000 - System.currentTimeMillis()%1000 );
+ } catch (InterruptedException e) {
+ if (!scheduleThreadToStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ logger.info(">>>>>>>>> init xxl-job admin scheduler success.");
+
+ // pre-read count: treadpool-size * trigger-qps (each trigger cost 50ms, qps = 1000/50 = 20)
+ int preReadCount = (XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax() + XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax()) * 20;
+
+ while (!scheduleThreadToStop) {
+
+ // Scan Job
+ long start = System.currentTimeMillis();
+
+ Connection conn = null;
+ Boolean connAutoCommit = null;
+ PreparedStatement preparedStatement = null;
+
+ boolean preReadSuc = true;
+ try {
+
+ conn = XxlJobAdminConfig.getAdminConfig().getDataSource().getConnection();
+ connAutoCommit = conn.getAutoCommit();
+ conn.setAutoCommit(false);
+
+ preparedStatement = conn.prepareStatement( "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" );
+ preparedStatement.execute();
+
+ // tx start
+
+ // 1、pre read
+ long nowTime = System.currentTimeMillis();
+ List scheduleList = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleJobQuery(nowTime + PRE_READ_MS, preReadCount);
+ if (scheduleList!=null && scheduleList.size()>0) {
+ // 2、push time-ring
+ for (XxlJobInfo jobInfo: scheduleList) {
+
+ // time-ring jump
+ if (nowTime > jobInfo.getTriggerNextTime() + PRE_READ_MS) {
+ // 2.1、trigger-expire > 5s:pass && make next-trigger-time
+ logger.warn(">>>>>>>>>>> xxl-job, schedule misfire, jobId = " + jobInfo.getId());
+
+ // 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()) {
+ // 2.2、trigger-expire < 5s:direct-trigger && make next-trigger-time
+
+ // 1、trigger
+ JobTriggerPoolHelper.trigger(jobInfo.getId(), TriggerTypeEnum.CRON, -1, null, null, null);
+ logger.debug(">>>>>>>>>>> xxl-job, schedule push trigger : jobId = " + jobInfo.getId() );
+
+ // 2、fresh next
+ refreshNextValidTime(jobInfo, new Date());
+
+ // next-trigger-time in 5s, pre-read again
+ if (jobInfo.getTriggerStatus()==1 && nowTime + PRE_READ_MS > jobInfo.getTriggerNextTime()) {
+
+ // 1、make ring second
+ int ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);
+
+ // 2、push time ring
+ pushTimeRing(ringSecond, jobInfo.getId());
+
+ // 3、fresh next
+ refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));
+
+ }
+
+ } else {
+ // 2.3、trigger-pre-read:time-ring trigger && make next-trigger-time
+
+ // 1、make ring second
+ int ringSecond = (int)((jobInfo.getTriggerNextTime()/1000)%60);
+
+ // 2、push time ring
+ pushTimeRing(ringSecond, jobInfo.getId());
+
+ // 3、fresh next
+ refreshNextValidTime(jobInfo, new Date(jobInfo.getTriggerNextTime()));
+
+ }
+
+ }
+
+ // 3、update trigger info
+ for (XxlJobInfo jobInfo: scheduleList) {
+ XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().scheduleUpdate(jobInfo);
+ }
+
+ } else {
+ preReadSuc = false;
+ }
+
+ // tx stop
+
+
+ } catch (Exception e) {
+ if (!scheduleThreadToStop) {
+ logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread error:{}", e);
+ }
+ } finally {
+
+ // commit
+ if (conn != null) {
+ try {
+ conn.commit();
+ } catch (SQLException e) {
+ if (!scheduleThreadToStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ try {
+ conn.setAutoCommit(connAutoCommit);
+ } catch (SQLException e) {
+ if (!scheduleThreadToStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ try {
+ conn.close();
+ } catch (SQLException e) {
+ if (!scheduleThreadToStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ // close PreparedStatement
+ if (null != preparedStatement) {
+ try {
+ preparedStatement.close();
+ } catch (SQLException e) {
+ if (!scheduleThreadToStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ long cost = System.currentTimeMillis()-start;
+
+
+ // Wait seconds, align second
+ if (cost < 1000) { // scan-overtime, not wait
+ try {
+ // pre-read period: success > scan each second; fail > skip this period;
+ TimeUnit.MILLISECONDS.sleep((preReadSuc?1000:PRE_READ_MS) - System.currentTimeMillis()%1000);
+ } catch (InterruptedException e) {
+ if (!scheduleThreadToStop) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+ }
+
+ }
+
+ logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#scheduleThread stop");
+ }
+ });
+ scheduleThread.setDaemon(true);
+ scheduleThread.setName("xxl-job, admin JobScheduleHelper#scheduleThread");
+ scheduleThread.start();
+
+
+ // ring thread
+ ringThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+
+ 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 ringItemData = new ArrayList<>();
+ int nowSecond = Calendar.getInstance().get(Calendar.SECOND); // 避免处理耗时太长,跨过刻度,向前校验一个刻度;
+ for (int i = 0; i < 2; i++) {
+ List tmpData = ringData.remove( (nowSecond+60-i)%60 );
+ if (tmpData != null) {
+ ringItemData.addAll(tmpData);
+ }
+ }
+
+ // ring trigger
+ logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + Arrays.asList(ringItemData) );
+ if (ringItemData.size() > 0) {
+ // do trigger
+ for (int jobId: ringItemData) {
+ // do trigger
+ JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null, null);
+ }
+ // clear
+ ringItemData.clear();
+ }
+ } catch (Exception e) {
+ if (!ringThreadToStop) {
+ logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e);
+ }
+ }
+ }
+ logger.info(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread stop");
+ }
+ });
+ ringThread.setDaemon(true);
+ ringThread.setName("xxl-job, admin JobScheduleHelper#ringThread");
+ ringThread.start();
+ }
+
+ 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());
+ } else {
+ 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, int jobId){
+ // push async ring
+ List ringItemData = ringData.get(ringSecond);
+ if (ringItemData == null) {
+ ringItemData = new ArrayList();
+ ringData.put(ringSecond, ringItemData);
+ }
+ ringItemData.add(jobId);
+
+ logger.debug(">>>>>>>>>>> xxl-job, schedule push time-ring : " + ringSecond + " = " + Arrays.asList(ringItemData) );
+ }
+
+ public void toStop(){
+
+ // 1、stop schedule
+ scheduleThreadToStop = true;
+ try {
+ TimeUnit.SECONDS.sleep(1); // wait
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage(), e);
+ }
+ if (scheduleThread.getState() != Thread.State.TERMINATED){
+ // interrupt and wait
+ scheduleThread.interrupt();
+ try {
+ scheduleThread.join();
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ // if has ring data
+ boolean hasRingData = false;
+ if (!ringData.isEmpty()) {
+ for (int second : ringData.keySet()) {
+ List tmpData = ringData.get(second);
+ if (tmpData!=null && tmpData.size()>0) {
+ hasRingData = true;
+ break;
+ }
+ }
+ }
+ if (hasRingData) {
+ try {
+ TimeUnit.SECONDS.sleep(8);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ // stop ring (wait job-in-memory stop)
+ ringThreadToStop = true;
+ try {
+ TimeUnit.SECONDS.sleep(1);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage(), e);
+ }
+ if (ringThread.getState() != Thread.State.TERMINATED){
+ // interrupt and wait
+ ringThread.interrupt();
+ try {
+ ringThread.join();
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+ 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;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java
new file mode 100644
index 000000000..398713dd9
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java
@@ -0,0 +1,150 @@
+package com.xxl.job.admin.core.thread;
+
+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;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * job trigger thread pool helper
+ *
+ * @author xuxueli 2018-07-03 21:08:07
+ */
+public class JobTriggerPoolHelper {
+ private static Logger logger = LoggerFactory.getLogger(JobTriggerPoolHelper.class);
+
+
+ // ---------------------- trigger pool ----------------------
+
+ // fast/slow thread pool
+ private ThreadPoolExecutor fastTriggerPool = null;
+ private ThreadPoolExecutor slowTriggerPool = null;
+
+ public void start(){
+ fastTriggerPool = new ThreadPoolExecutor(
+ 10,
+ XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax(),
+ 60L,
+ TimeUnit.SECONDS,
+ new LinkedBlockingQueue(1000),
+ new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode());
+ }
+ });
+
+ slowTriggerPool = new ThreadPoolExecutor(
+ 10,
+ XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax(),
+ 60L,
+ TimeUnit.SECONDS,
+ new LinkedBlockingQueue(2000),
+ new ThreadFactory() {
+ @Override
+ public Thread newThread(Runnable r) {
+ return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode());
+ }
+ });
+ }
+
+
+ public void stop() {
+ //triggerPool.shutdown();
+ fastTriggerPool.shutdownNow();
+ slowTriggerPool.shutdownNow();
+ logger.info(">>>>>>>>> xxl-job trigger thread pool shutdown success.");
+ }
+
+
+ // job timeout count
+ private volatile long minTim = System.currentTimeMillis()/60000; // ms > min
+ private volatile ConcurrentMap jobTimeoutCountMap = new ConcurrentHashMap<>();
+
+
+ /**
+ * add trigger
+ */
+ public void addTrigger(final int jobId,
+ final TriggerTypeEnum triggerType,
+ final int failRetryCount,
+ final String executorShardingParam,
+ final String executorParam,
+ final String addressList) {
+
+ // choose thread pool
+ ThreadPoolExecutor triggerPool_ = fastTriggerPool;
+ AtomicInteger jobTimeoutCount = jobTimeoutCountMap.get(jobId);
+ if (jobTimeoutCount!=null && jobTimeoutCount.get() > 10) { // job-timeout 10 times in 1 min
+ triggerPool_ = slowTriggerPool;
+ }
+
+ // trigger
+ triggerPool_.execute(new Runnable() {
+ @Override
+ public void run() {
+
+ long start = System.currentTimeMillis();
+
+ try {
+ // do trigger
+ XxlJobTrigger.trigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ } finally {
+
+ // check timeout-count-map
+ long minTim_now = System.currentTimeMillis()/60000;
+ if (minTim != minTim_now) {
+ minTim = minTim_now;
+ jobTimeoutCountMap.clear();
+ }
+
+ // incr timeout-count-map
+ long cost = System.currentTimeMillis()-start;
+ if (cost > 500) { // ob-timeout threshold 500ms
+ AtomicInteger timeoutCount = jobTimeoutCountMap.putIfAbsent(jobId, new AtomicInteger(1));
+ if (timeoutCount != null) {
+ timeoutCount.incrementAndGet();
+ }
+ }
+
+ }
+
+ }
+ });
+ }
+
+
+
+ // ---------------------- helper ----------------------
+
+ private static JobTriggerPoolHelper helper = new JobTriggerPoolHelper();
+
+ public static void toStart() {
+ helper.start();
+ }
+ public static void toStop() {
+ helper.stop();
+ }
+
+ /**
+ * @param jobId
+ * @param triggerType
+ * @param failRetryCount
+ * >=0: use this param
+ * <0: use param from job info config
+ * @param executorShardingParam
+ * @param executorParam
+ * null: use job param
+ * not null: cover job param
+ */
+ public static void trigger(int jobId, TriggerTypeEnum triggerType, int failRetryCount, String executorShardingParam, String executorParam, String addressList) {
+ helper.addTrigger(jobId, triggerType, failRetryCount, executorShardingParam, executorParam, addressList);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java
new file mode 100644
index 000000000..446c90e91
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java
@@ -0,0 +1,27 @@
+package com.xxl.job.admin.core.trigger;
+
+import com.xxl.job.admin.core.util.I18nUtil;
+
+/**
+ * trigger type enum
+ *
+ * @author xuxueli 2018-09-16 04:56:41
+ */
+public enum TriggerTypeEnum {
+
+ MANUAL(I18nUtil.getString("jobconf_trigger_type_manual")),
+ 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")),
+ MISFIRE(I18nUtil.getString("jobconf_trigger_type_misfire"));
+
+ private TriggerTypeEnum(String title){
+ this.title = title;
+ }
+ private String title;
+ public String getTitle() {
+ return title;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java
new file mode 100644
index 000000000..748befc6b
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java
@@ -0,0 +1,226 @@
+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;
+
+import java.util.Date;
+
+/**
+ * xxl-job trigger
+ * Created by xuxueli on 17/7/13.
+ */
+public class XxlJobTrigger {
+ private static Logger logger = LoggerFactory.getLogger(XxlJobTrigger.class);
+
+ /**
+ * trigger job
+ *
+ * @param jobId
+ * @param triggerType
+ * @param failRetryCount
+ * >=0: use this param
+ * <0: use param from job info config
+ * @param executorShardingParam
+ * @param executorParam
+ * null: use job param
+ * not null: cover job param
+ * @param addressList
+ * null: use executor addressList
+ * not null: cover
+ */
+ public static void trigger(int jobId,
+ TriggerTypeEnum triggerType,
+ int failRetryCount,
+ String executorShardingParam,
+ String executorParam,
+ String addressList) {
+
+ // load data
+ XxlJobInfo jobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(jobId);
+ if (jobInfo == null) {
+ logger.warn(">>>>>>>>>>>> trigger fail, jobId invalid,jobId={}", jobId);
+ return;
+ }
+ if (executorParam != null) {
+ jobInfo.setExecutorParam(executorParam);
+ }
+ int finalFailRetryCount = failRetryCount>=0?failRetryCount:jobInfo.getExecutorFailRetryCount();
+ XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(jobInfo.getJobGroup());
+
+ // cover addressList
+ if (addressList!=null && addressList.trim().length()>0) {
+ group.setAddressType(1);
+ group.setAddressList(addressList.trim());
+ }
+
+ // sharding param
+ int[] shardingParam = null;
+ if (executorShardingParam!=null){
+ String[] shardingArr = executorShardingParam.split("/");
+ if (shardingArr.length==2 && isNumeric(shardingArr[0]) && isNumeric(shardingArr[1])) {
+ shardingParam = new int[2];
+ shardingParam[0] = Integer.valueOf(shardingArr[0]);
+ shardingParam[1] = Integer.valueOf(shardingArr[1]);
+ }
+ }
+ if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null)
+ && group.getRegistryList()!=null && !group.getRegistryList().isEmpty()
+ && shardingParam==null) {
+ for (int i = 0; i < group.getRegistryList().size(); i++) {
+ processTrigger(group, jobInfo, finalFailRetryCount, triggerType, i, group.getRegistryList().size());
+ }
+ } else {
+ if (shardingParam == null) {
+ shardingParam = new int[]{0, 1};
+ }
+ processTrigger(group, jobInfo, finalFailRetryCount, triggerType, shardingParam[0], shardingParam[1]);
+ }
+
+ }
+
+ private static boolean isNumeric(String str){
+ try {
+ int result = Integer.valueOf(str);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ /**
+ * @param group job group, registry list may be empty
+ * @param jobInfo
+ * @param finalFailRetryCount
+ * @param triggerType
+ * @param index sharding index
+ * @param total sharding index
+ */
+ private static void processTrigger(XxlJobGroup group, XxlJobInfo jobInfo, int finalFailRetryCount, TriggerTypeEnum triggerType, int index, int total){
+
+ // param
+ ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), ExecutorBlockStrategyEnum.SERIAL_EXECUTION); // block strategy
+ ExecutorRouteStrategyEnum executorRouteStrategyEnum = ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null); // route strategy
+ String shardingParam = (ExecutorRouteStrategyEnum.SHARDING_BROADCAST==executorRouteStrategyEnum)?String.valueOf(index).concat("/").concat(String.valueOf(total)):null;
+
+ // 1、save log-id
+ XxlJobLog jobLog = new XxlJobLog();
+ jobLog.setJobGroup(jobInfo.getJobGroup());
+ jobLog.setJobId(jobInfo.getId());
+ jobLog.setTriggerTime(new Date());
+ XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().save(jobLog);
+ logger.debug(">>>>>>>>>>> xxl-job trigger start, jobId:{}", jobLog.getId());
+
+ // 2、init trigger-param
+ TriggerParam triggerParam = new TriggerParam();
+ triggerParam.setJobId(jobInfo.getId());
+ triggerParam.setExecutorHandler(jobInfo.getExecutorHandler());
+ triggerParam.setExecutorParams(jobInfo.getExecutorParam());
+ triggerParam.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
+ triggerParam.setExecutorTimeout(jobInfo.getExecutorTimeout());
+ triggerParam.setLogId(jobLog.getId());
+ triggerParam.setLogDateTime(jobLog.getTriggerTime().getTime());
+ triggerParam.setGlueType(jobInfo.getGlueType());
+ triggerParam.setGlueSource(jobInfo.getGlueSource());
+ triggerParam.setGlueUpdatetime(jobInfo.getGlueUpdatetime().getTime());
+ triggerParam.setBroadcastIndex(index);
+ triggerParam.setBroadcastTotal(total);
+
+ // 3、init address
+ String address = null;
+ ReturnT routeAddressResult = null;
+ if (group.getRegistryList()!=null && !group.getRegistryList().isEmpty()) {
+ if (ExecutorRouteStrategyEnum.SHARDING_BROADCAST == executorRouteStrategyEnum) {
+ if (index < group.getRegistryList().size()) {
+ address = group.getRegistryList().get(index);
+ } else {
+ address = group.getRegistryList().get(0);
+ }
+ } else {
+ routeAddressResult = executorRouteStrategyEnum.getRouter().route(triggerParam, group.getRegistryList());
+ if (routeAddressResult.getCode() == ReturnT.SUCCESS_CODE) {
+ address = routeAddressResult.getContent();
+ }
+ }
+ } else {
+ routeAddressResult = new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("jobconf_trigger_address_empty"));
+ }
+
+ // 4、trigger remote executor
+ ReturnT triggerResult = null;
+ if (address != null) {
+ triggerResult = runExecutor(triggerParam, address);
+ } else {
+ triggerResult = new ReturnT(ReturnT.FAIL_CODE, null);
+ }
+
+ // 5、collection trigger info
+ StringBuffer triggerMsgSb = new StringBuffer();
+ triggerMsgSb.append(I18nUtil.getString("jobconf_trigger_type")).append(":").append(triggerType.getTitle());
+ triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_admin_adress")).append(":").append(IpUtil.getIp());
+ triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_exe_regtype")).append(":")
+ .append( (group.getAddressType() == 0)?I18nUtil.getString("jobgroup_field_addressType_0"):I18nUtil.getString("jobgroup_field_addressType_1") );
+ triggerMsgSb.append("
").append(I18nUtil.getString("jobconf_trigger_exe_regaddress")).append(":").append(group.getRegistryList());
+ triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorRouteStrategy")).append(":").append(executorRouteStrategyEnum.getTitle());
+ if (shardingParam != null) {
+ triggerMsgSb.append("("+shardingParam+")");
+ }
+ triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorBlockStrategy")).append(":").append(blockStrategy.getTitle());
+ triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_timeout")).append(":").append(jobInfo.getExecutorTimeout());
+ triggerMsgSb.append("
").append(I18nUtil.getString("jobinfo_field_executorFailRetryCount")).append(":").append(finalFailRetryCount);
+
+ triggerMsgSb.append("
>>>>>>>>>>>"+ I18nUtil.getString("jobconf_trigger_run") +"<<<<<<<<<<<
")
+ .append((routeAddressResult!=null&&routeAddressResult.getMsg()!=null)?routeAddressResult.getMsg()+"
":"").append(triggerResult.getMsg()!=null?triggerResult.getMsg():"");
+
+ // 6、save log trigger-info
+ jobLog.setExecutorAddress(address);
+ jobLog.setExecutorHandler(jobInfo.getExecutorHandler());
+ jobLog.setExecutorParam(jobInfo.getExecutorParam());
+ jobLog.setExecutorShardingParam(shardingParam);
+ jobLog.setExecutorFailRetryCount(finalFailRetryCount);
+ //jobLog.setTriggerTime();
+ jobLog.setTriggerCode(triggerResult.getCode());
+ jobLog.setTriggerMsg(triggerMsgSb.toString());
+ XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateTriggerInfo(jobLog);
+
+ logger.debug(">>>>>>>>>>> xxl-job trigger end, jobId:{}", jobLog.getId());
+ }
+
+ /**
+ * run executor
+ * @param triggerParam
+ * @param address
+ * @return
+ */
+ public static ReturnT runExecutor(TriggerParam triggerParam, String address){
+ ReturnT runResult = null;
+ try {
+ ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(address);
+ runResult = executorBiz.run(triggerParam);
+ } catch (Exception e) {
+ logger.error(">>>>>>>>>>> xxl-job trigger error, please check if the executor[{}] is running.", address, e);
+ runResult = new ReturnT(ReturnT.FAIL_CODE, ThrowableUtil.toString(e));
+ }
+
+ StringBuffer runResultSB = new StringBuffer(I18nUtil.getString("jobconf_trigger_run") + ":");
+ runResultSB.append("
address:").append(address);
+ runResultSB.append("
code:").append(runResult.getCode());
+ runResultSB.append("
msg:").append(runResult.getMsg());
+
+ runResult.setMsg(runResultSB.toString());
+ return runResult;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java
new file mode 100644
index 000000000..a1523aa47
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java
@@ -0,0 +1,98 @@
+package com.xxl.job.admin.core.util;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Cookie.Util
+ *
+ * @author xuxueli 2015-12-12 18:01:06
+ */
+public class CookieUtil {
+
+ // 默认缓存时间,单位/秒, 2H
+ private static final int COOKIE_MAX_AGE = Integer.MAX_VALUE;
+ // 保存路径,根路径
+ private static final String COOKIE_PATH = "/";
+
+ /**
+ * 保存
+ *
+ * @param response
+ * @param key
+ * @param value
+ * @param ifRemember
+ */
+ public static void set(HttpServletResponse response, String key, String value, boolean ifRemember) {
+ int age = ifRemember?COOKIE_MAX_AGE:-1;
+ set(response, key, value, null, COOKIE_PATH, age, true);
+ }
+
+ /**
+ * 保存
+ *
+ * @param response
+ * @param key
+ * @param value
+ * @param maxAge
+ */
+ private static void set(HttpServletResponse response, String key, String value, String domain, String path, int maxAge, boolean isHttpOnly) {
+ Cookie cookie = new Cookie(key, value);
+ if (domain != null) {
+ cookie.setDomain(domain);
+ }
+ cookie.setPath(path);
+ cookie.setMaxAge(maxAge);
+ cookie.setHttpOnly(isHttpOnly);
+ response.addCookie(cookie);
+ }
+
+ /**
+ * 查询value
+ *
+ * @param request
+ * @param key
+ * @return
+ */
+ public static String getValue(HttpServletRequest request, String key) {
+ Cookie cookie = get(request, key);
+ if (cookie != null) {
+ return cookie.getValue();
+ }
+ return null;
+ }
+
+ /**
+ * 查询Cookie
+ *
+ * @param request
+ * @param key
+ */
+ private static Cookie get(HttpServletRequest request, String key) {
+ Cookie[] arr_cookie = request.getCookies();
+ if (arr_cookie != null && arr_cookie.length > 0) {
+ for (Cookie cookie : arr_cookie) {
+ if (cookie.getName().equals(key)) {
+ return cookie;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 删除Cookie
+ *
+ * @param request
+ * @param response
+ * @param key
+ */
+ public static void remove(HttpServletRequest request, HttpServletResponse response, String key) {
+ Cookie cookie = get(request, key);
+ if (cookie != null) {
+ set(response, key, "", null, COOKIE_PATH, 0, true);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java
new file mode 100644
index 000000000..e90af434f
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java
@@ -0,0 +1,31 @@
+package com.xxl.job.admin.core.util;
+
+import freemarker.ext.beans.BeansWrapper;
+import freemarker.ext.beans.BeansWrapperBuilder;
+import freemarker.template.Configuration;
+import freemarker.template.TemplateHashModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ftl util
+ *
+ * @author xuxueli 2018-01-17 20:37:48
+ */
+public class FtlUtil {
+ private static Logger logger = LoggerFactory.getLogger(FtlUtil.class);
+
+ private static BeansWrapper wrapper = new BeansWrapperBuilder(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS).build(); //BeansWrapper.getDefaultInstance();
+
+ public static TemplateHashModel generateStaticModel(String packageName) {
+ try {
+ TemplateHashModel staticModels = wrapper.getStaticModels();
+ TemplateHashModel fileStatics = (TemplateHashModel) staticModels.get(packageName);
+ return fileStatics;
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java
new file mode 100644
index 000000000..772a96ec0
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java
@@ -0,0 +1,79 @@
+package com.xxl.job.admin.core.util;
+
+import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.EncodedResource;
+import org.springframework.core.io.support.PropertiesLoaderUtils;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * i18n util
+ *
+ * @author xuxueli 2018-01-17 20:39:06
+ */
+public class I18nUtil {
+ private static Logger logger = LoggerFactory.getLogger(I18nUtil.class);
+
+ private static Properties prop = null;
+ public static Properties loadI18nProp(){
+ if (prop != null) {
+ return prop;
+ }
+ try {
+ // build i18n prop
+ String i18n = XxlJobAdminConfig.getAdminConfig().getI18n();
+ String i18nFile = MessageFormat.format("i18n/message_{0}.properties", i18n);
+
+ // load prop
+ Resource resource = new ClassPathResource(i18nFile);
+ EncodedResource encodedResource = new EncodedResource(resource,"UTF-8");
+ prop = PropertiesLoaderUtils.loadProperties(encodedResource);
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ return prop;
+ }
+
+ /**
+ * get val of i18n key
+ *
+ * @param key
+ * @return
+ */
+ public static String getString(String key) {
+ return loadI18nProp().getProperty(key);
+ }
+
+ /**
+ * get mult val of i18n mult key, as json
+ *
+ * @param keys
+ * @return
+ */
+ public static String getMultString(String... keys) {
+ Map map = new HashMap();
+
+ Properties prop = loadI18nProp();
+ if (keys!=null && keys.length>0) {
+ for (String key: keys) {
+ map.put(key, prop.getProperty(key));
+ }
+ } else {
+ for (String key: prop.stringPropertyNames()) {
+ map.put(key, prop.getProperty(key));
+ }
+ }
+
+ String json = JacksonUtil.writeValueAsString(map);
+ return json;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java
new file mode 100644
index 000000000..4f4ea3ccb
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java
@@ -0,0 +1,92 @@
+package com.xxl.job.admin.core.util;
+
+import com.fasterxml.jackson.core.JsonGenerationException;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+/**
+ * Jackson util
+ *
+ * 1、obj need private and set/get;
+ * 2、do not support inner class;
+ *
+ * @author xuxueli 2015-9-25 18:02:56
+ */
+public class JacksonUtil {
+ private static Logger logger = LoggerFactory.getLogger(JacksonUtil.class);
+
+ private final static ObjectMapper objectMapper = new ObjectMapper();
+ public static ObjectMapper getInstance() {
+ return objectMapper;
+ }
+
+ /**
+ * bean、array、List、Map --> json
+ *
+ * @param obj
+ * @return json string
+ * @throws Exception
+ */
+ public static String writeValueAsString(Object obj) {
+ try {
+ return getInstance().writeValueAsString(obj);
+ } catch (JsonGenerationException e) {
+ logger.error(e.getMessage(), e);
+ } catch (JsonMappingException e) {
+ logger.error(e.getMessage(), e);
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * string --> bean、Map、List(array)
+ *
+ * @param jsonStr
+ * @param clazz
+ * @return obj
+ * @throws Exception
+ */
+ public static T readValue(String jsonStr, Class clazz) {
+ try {
+ return getInstance().readValue(jsonStr, clazz);
+ } catch (JsonParseException e) {
+ logger.error(e.getMessage(), e);
+ } catch (JsonMappingException e) {
+ logger.error(e.getMessage(), e);
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ return null;
+ }
+
+ /**
+ * string --> List...
+ *
+ * @param jsonStr
+ * @param parametrized
+ * @param parameterClasses
+ * @param
+ * @return
+ */
+ public static T readValue(String jsonStr, Class> parametrized, Class>... parameterClasses) {
+ try {
+ JavaType javaType = getInstance().getTypeFactory().constructParametricType(parametrized, parameterClasses);
+ return getInstance().readValue(jsonStr, javaType);
+ } catch (JsonParseException e) {
+ logger.error(e.getMessage(), e);
+ } catch (JsonMappingException e) {
+ logger.error(e.getMessage(), e);
+ } catch (IOException e) {
+ logger.error(e.getMessage(), e);
+ }
+ return null;
+ }
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java
new file mode 100644
index 000000000..fbab0613f
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java
@@ -0,0 +1,133 @@
+package com.xxl.job.admin.core.util;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * local cache tool
+ *
+ * @author xuxueli 2018-01-22 21:37:34
+ */
+public class LocalCacheUtil {
+
+ private static ConcurrentMap cacheRepository = new ConcurrentHashMap(); // 类型建议用抽象父类,兼容性更好;
+ private static class LocalCacheData{
+ private String key;
+ private Object val;
+ private long timeoutTime;
+
+ public LocalCacheData() {
+ }
+
+ public LocalCacheData(String key, Object val, long timeoutTime) {
+ this.key = key;
+ this.val = val;
+ this.timeoutTime = timeoutTime;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public Object getVal() {
+ return val;
+ }
+
+ public void setVal(Object val) {
+ this.val = val;
+ }
+
+ public long getTimeoutTime() {
+ return timeoutTime;
+ }
+
+ public void setTimeoutTime(long timeoutTime) {
+ this.timeoutTime = timeoutTime;
+ }
+ }
+
+
+ /**
+ * set cache
+ *
+ * @param key
+ * @param val
+ * @param cacheTime
+ * @return
+ */
+ public static boolean set(String key, Object val, long cacheTime){
+
+ // clean timeout cache, before set new cache (avoid cache too much)
+ cleanTimeoutCache();
+
+ // set new cache
+ if (key==null || key.trim().length()==0) {
+ return false;
+ }
+ if (val == null) {
+ remove(key);
+ }
+ if (cacheTime <= 0) {
+ remove(key);
+ }
+ long timeoutTime = System.currentTimeMillis() + cacheTime;
+ LocalCacheData localCacheData = new LocalCacheData(key, val, timeoutTime);
+ cacheRepository.put(localCacheData.getKey(), localCacheData);
+ return true;
+ }
+
+ /**
+ * remove cache
+ *
+ * @param key
+ * @return
+ */
+ public static boolean remove(String key){
+ if (key==null || key.trim().length()==0) {
+ return false;
+ }
+ cacheRepository.remove(key);
+ return true;
+ }
+
+ /**
+ * get cache
+ *
+ * @param key
+ * @return
+ */
+ public static Object get(String key){
+ if (key==null || key.trim().length()==0) {
+ return null;
+ }
+ LocalCacheData localCacheData = cacheRepository.get(key);
+ if (localCacheData!=null && System.currentTimeMillis()=localCacheData.getTimeoutTime()) {
+ cacheRepository.remove(key);
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java
new file mode 100644
index 000000000..b608d9fbc
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java
@@ -0,0 +1,37 @@
+package com.xxl.job.admin.dao;
+
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Created by xuxueli on 16/9/30.
+ */
+@Mapper
+public interface XxlJobGroupDao {
+
+ public List findAll();
+
+ public List findByAddressType(@Param("addressType") int addressType);
+
+ public int save(XxlJobGroup xxlJobGroup);
+
+ public int update(XxlJobGroup xxlJobGroup);
+
+ public int remove(@Param("id") int id);
+
+ public XxlJobGroup load(@Param("id") int id);
+
+ public List pageList(@Param("offset") int offset,
+ @Param("pagesize") int pagesize,
+ @Param("appname") String appname,
+ @Param("title") String title);
+
+ public int pageListCount(@Param("offset") int offset,
+ @Param("pagesize") int pagesize,
+ @Param("appname") String appname,
+ @Param("title") String title);
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java
new file mode 100644
index 000000000..d640efffe
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java
@@ -0,0 +1,49 @@
+package com.xxl.job.admin.dao;
+
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+
+/**
+ * job info
+ * @author xuxueli 2016-1-12 18:03:45
+ */
+@Mapper
+public interface XxlJobInfoDao {
+
+ public List pageList(@Param("offset") int offset,
+ @Param("pagesize") int pagesize,
+ @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") int jobGroup,
+ @Param("triggerStatus") int triggerStatus,
+ @Param("jobDesc") String jobDesc,
+ @Param("executorHandler") String executorHandler,
+ @Param("author") String author);
+
+ public int save(XxlJobInfo info);
+
+ public XxlJobInfo loadById(@Param("id") int id);
+
+ public int update(XxlJobInfo xxlJobInfo);
+
+ public int delete(@Param("id") long id);
+
+ public List getJobsByGroup(@Param("jobGroup") int jobGroup);
+
+ public int findAllCount();
+
+ public List scheduleJobQuery(@Param("maxNextTime") long maxNextTime, @Param("pagesize") int pagesize );
+
+ public int scheduleUpdate(XxlJobInfo xxlJobInfo);
+
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java
new file mode 100644
index 000000000..62fa3b4f9
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java
@@ -0,0 +1,62 @@
+package com.xxl.job.admin.dao;
+
+import com.xxl.job.admin.core.model.XxlJobLog;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * job log
+ * @author xuxueli 2016-1-12 18:03:06
+ */
+@Mapper
+public interface XxlJobLogDao {
+
+ // exist jobId not use jobGroup, not exist use jobGroup
+ public List pageList(@Param("offset") int offset,
+ @Param("pagesize") int pagesize,
+ @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") int jobGroup,
+ @Param("jobId") int jobId,
+ @Param("triggerTimeStart") Date triggerTimeStart,
+ @Param("triggerTimeEnd") Date triggerTimeEnd,
+ @Param("logStatus") int logStatus);
+
+ public XxlJobLog load(@Param("id") long id);
+
+ public long save(XxlJobLog xxlJobLog);
+
+ public int updateTriggerInfo(XxlJobLog xxlJobLog);
+
+ public int updateHandleInfo(XxlJobLog xxlJobLog);
+
+ public int delete(@Param("jobId") int jobId);
+
+ public Map findLogReport(@Param("from") Date from,
+ @Param("to") Date to);
+
+ public List findClearLogIds(@Param("jobGroup") int jobGroup,
+ @Param("jobId") int jobId,
+ @Param("clearBeforeTime") Date clearBeforeTime,
+ @Param("clearBeforeNum") int clearBeforeNum,
+ @Param("pagesize") int pagesize);
+ public int clearLog(@Param("logIds") List logIds);
+
+ public List findFailJobLogIds(@Param("pagesize") int pagesize);
+
+ public int updateAlarmStatus(@Param("logId") long logId,
+ @Param("oldAlarmStatus") int oldAlarmStatus,
+ @Param("newAlarmStatus") int newAlarmStatus);
+
+ public List findLostJobIds(@Param("losedTime") Date losedTime);
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java
new file mode 100644
index 000000000..3028aed22
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java
@@ -0,0 +1,24 @@
+package com.xxl.job.admin.dao;
+
+import com.xxl.job.admin.core.model.XxlJobLogGlue;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * job log for glue
+ * @author xuxueli 2016-5-19 18:04:56
+ */
+@Mapper
+public interface XxlJobLogGlueDao {
+
+ public int save(XxlJobLogGlue xxlJobLogGlue);
+
+ public List findByJobId(@Param("jobId") int jobId);
+
+ public int removeOld(@Param("jobId") int jobId, @Param("limit") int limit);
+
+ public int deleteByJobId(@Param("jobId") int jobId);
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java
new file mode 100644
index 000000000..f4b3dc81e
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java
@@ -0,0 +1,26 @@
+package com.xxl.job.admin.dao;
+
+import com.xxl.job.admin.core.model.XxlJobLogReport;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * job log
+ * @author xuxueli 2019-11-22
+ */
+@Mapper
+public interface XxlJobLogReportDao {
+
+ public int save(XxlJobLogReport xxlJobLogReport);
+
+ public int update(XxlJobLogReport xxlJobLogReport);
+
+ public List queryLogReport(@Param("triggerDayFrom") Date triggerDayFrom,
+ @Param("triggerDayTo") Date triggerDayTo);
+
+ public XxlJobLogReport queryLogReportTotal();
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java
new file mode 100644
index 000000000..1005c46c9
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java
@@ -0,0 +1,38 @@
+package com.xxl.job.admin.dao;
+
+import com.xxl.job.admin.core.model.XxlJobRegistry;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Created by xuxueli on 16/9/30.
+ */
+@Mapper
+public interface XxlJobRegistryDao {
+
+ public List findDead(@Param("timeout") int timeout,
+ @Param("nowTime") Date nowTime);
+
+ public int removeDead(@Param("ids") List ids);
+
+ public List findAll(@Param("timeout") int timeout,
+ @Param("nowTime") Date nowTime);
+
+ public int registryUpdate(@Param("registryGroup") String registryGroup,
+ @Param("registryKey") String registryKey,
+ @Param("registryValue") String registryValue,
+ @Param("updateTime") Date updateTime);
+
+ public int registrySave(@Param("registryGroup") String registryGroup,
+ @Param("registryKey") String registryKey,
+ @Param("registryValue") String registryValue,
+ @Param("updateTime") Date updateTime);
+
+ public int registryDelete(@Param("registryGroup") String registryGroup,
+ @Param("registryKey") String registryKey,
+ @Param("registryValue") String registryValue);
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java
new file mode 100644
index 000000000..e84049475
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java
@@ -0,0 +1,31 @@
+package com.xxl.job.admin.dao;
+
+import com.xxl.job.admin.core.model.XxlJobUser;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import java.util.List;
+
+/**
+ * @author xuxueli 2019-05-04 16:44:59
+ */
+@Mapper
+public interface XxlJobUserDao {
+
+ public List pageList(@Param("offset") int offset,
+ @Param("pagesize") int pagesize,
+ @Param("username") String username,
+ @Param("role") int role);
+ public int pageListCount(@Param("offset") int offset,
+ @Param("pagesize") int pagesize,
+ @Param("username") String username,
+ @Param("role") int role);
+
+ public XxlJobUser loadByUserName(@Param("username") String username);
+
+ public int save(XxlJobUser xxlJobUser);
+
+ public int update(XxlJobUser xxlJobUser);
+
+ public int delete(@Param("id") int id);
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java
new file mode 100644
index 000000000..960aedd9c
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java
@@ -0,0 +1,110 @@
+package com.xxl.job.admin.service;
+
+import com.xxl.job.admin.core.model.XxlJobUser;
+import com.xxl.job.admin.core.util.CookieUtil;
+import com.xxl.job.admin.core.util.I18nUtil;
+import com.xxl.job.admin.core.util.JacksonUtil;
+import com.xxl.job.admin.dao.XxlJobUserDao;
+import com.xxl.job.core.biz.model.ReturnT;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.DigestUtils;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.math.BigInteger;
+
+/**
+ * @author xuxueli 2019-05-04 22:13:264
+ */
+@Configuration
+public class LoginService {
+
+ public static final String LOGIN_IDENTITY_KEY = "XXL_JOB_LOGIN_IDENTITY";
+
+ @Resource
+ private XxlJobUserDao xxlJobUserDao;
+
+
+ private String makeToken(XxlJobUser xxlJobUser){
+ String tokenJson = JacksonUtil.writeValueAsString(xxlJobUser);
+ String tokenHex = new BigInteger(tokenJson.getBytes()).toString(16);
+ return tokenHex;
+ }
+ private XxlJobUser parseToken(String tokenHex){
+ XxlJobUser xxlJobUser = null;
+ if (tokenHex != null) {
+ String tokenJson = new String(new BigInteger(tokenHex, 16).toByteArray()); // username_password(md5)
+ xxlJobUser = JacksonUtil.readValue(tokenJson, XxlJobUser.class);
+ }
+ return xxlJobUser;
+ }
+
+
+ public ReturnT login(HttpServletRequest request, HttpServletResponse response, String username, String password, boolean ifRemember){
+
+ // param
+ if (username==null || username.trim().length()==0 || password==null || password.trim().length()==0){
+ return new ReturnT(500, I18nUtil.getString("login_param_empty"));
+ }
+
+ // valid passowrd
+ XxlJobUser xxlJobUser = xxlJobUserDao.loadByUserName(username);
+ if (xxlJobUser == null) {
+ return new ReturnT(500, I18nUtil.getString("login_param_unvalid"));
+ }
+ String passwordMd5 = DigestUtils.md5DigestAsHex(password.getBytes());
+ if (!passwordMd5.equals(xxlJobUser.getPassword())) {
+ return new ReturnT(500, I18nUtil.getString("login_param_unvalid"));
+ }
+
+ String loginToken = makeToken(xxlJobUser);
+
+ // do login
+ CookieUtil.set(response, LOGIN_IDENTITY_KEY, loginToken, ifRemember);
+ return ReturnT.SUCCESS;
+ }
+
+ /**
+ * logout
+ *
+ * @param request
+ * @param response
+ */
+ public ReturnT logout(HttpServletRequest request, HttpServletResponse response){
+ CookieUtil.remove(request, response, LOGIN_IDENTITY_KEY);
+ return ReturnT.SUCCESS;
+ }
+
+ /**
+ * logout
+ *
+ * @param request
+ * @return
+ */
+ public XxlJobUser ifLogin(HttpServletRequest request, HttpServletResponse response){
+ String cookieToken = CookieUtil.getValue(request, LOGIN_IDENTITY_KEY);
+ if (cookieToken != null) {
+ XxlJobUser cookieUser = null;
+ try {
+ cookieUser = parseToken(cookieToken);
+ } catch (Exception e) {
+ logout(request, response);
+ }
+ if (cookieUser != null) {
+ XxlJobUser dbUser = xxlJobUserDao.loadByUserName(cookieUser.getUsername());
+ if (dbUser != null) {
+ if (cookieUser.getPassword().equals(dbUser.getPassword())) {
+ return dbUser;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ public static void main(String[] args) {
+ System.out.println("121312");
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java
new file mode 100644
index 000000000..61da3a27c
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java
@@ -0,0 +1,86 @@
+package com.xxl.job.admin.service;
+
+
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.core.biz.model.ReturnT;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * core job action for xxl-job
+ *
+ * @author xuxueli 2016-5-28 15:30:33
+ */
+public interface XxlJobService {
+
+ /**
+ * page list
+ *
+ * @param start
+ * @param length
+ * @param jobGroup
+ * @param jobDesc
+ * @param executorHandler
+ * @param author
+ * @return
+ */
+ public Map pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author);
+
+ /**
+ * add job
+ *
+ * @param jobInfo
+ * @return
+ */
+ public ReturnT add(XxlJobInfo jobInfo);
+
+ /**
+ * update job
+ *
+ * @param jobInfo
+ * @return
+ */
+ public ReturnT update(XxlJobInfo jobInfo);
+
+ /**
+ * remove job
+ * *
+ * @param id
+ * @return
+ */
+ public ReturnT remove(int id);
+
+ /**
+ * start job
+ *
+ * @param id
+ * @return
+ */
+ public ReturnT start(int id);
+
+ /**
+ * stop job
+ *
+ * @param id
+ * @return
+ */
+ public ReturnT stop(int id);
+
+ /**
+ * dashboard info
+ *
+ * @return
+ */
+ public Map dashboardInfo();
+
+ /**
+ * chart info
+ *
+ * @param startDate
+ * @param endDate
+ * @return
+ */
+ public ReturnT> chartInfo(Date startDate, Date endDate);
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java
new file mode 100644
index 000000000..3c01e94dc
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java
@@ -0,0 +1,35 @@
+package com.xxl.job.admin.service.impl;
+
+import com.xxl.job.admin.core.thread.JobCompleteHelper;
+import com.xxl.job.admin.core.thread.JobRegistryHelper;
+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 org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author xuxueli 2017-07-27 21:54:20
+ */
+@Service
+public class AdminBizImpl implements AdminBiz {
+
+
+ @Override
+ public ReturnT callback(List callbackParamList) {
+ return JobCompleteHelper.getInstance().callback(callbackParamList);
+ }
+
+ @Override
+ public ReturnT registry(RegistryParam registryParam) {
+ return JobRegistryHelper.getInstance().registry(registryParam);
+ }
+
+ @Override
+ public ReturnT registryRemove(RegistryParam registryParam) {
+ return JobRegistryHelper.getInstance().registryRemove(registryParam);
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java
new file mode 100644
index 000000000..530ee41c8
--- /dev/null
+++ b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java
@@ -0,0 +1,434 @@
+package com.xxl.job.admin.service.impl;
+
+import com.xxl.job.admin.core.cron.CronExpression;
+import com.xxl.job.admin.core.model.XxlJobGroup;
+import com.xxl.job.admin.core.model.XxlJobInfo;
+import com.xxl.job.admin.core.model.XxlJobLogReport;
+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.util.I18nUtil;
+import com.xxl.job.admin.dao.*;
+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.Service;
+
+import javax.annotation.Resource;
+import java.text.MessageFormat;
+import java.util.*;
+
+/**
+ * core job action for xxl-job
+ * @author xuxueli 2016-5-28 15:30:33
+ */
+@Service
+public class XxlJobServiceImpl implements XxlJobService {
+ private static Logger logger = LoggerFactory.getLogger(XxlJobServiceImpl.class);
+
+ @Resource
+ private XxlJobGroupDao xxlJobGroupDao;
+ @Resource
+ private XxlJobInfoDao xxlJobInfoDao;
+ @Resource
+ public XxlJobLogDao xxlJobLogDao;
+ @Resource
+ private XxlJobLogGlueDao xxlJobLogGlueDao;
+ @Resource
+ private XxlJobLogReportDao xxlJobLogReportDao;
+
+ @Override
+ public Map pageList(int start, int length, int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
+
+ // page list
+ List list = xxlJobInfoDao.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
+ int list_count = xxlJobInfoDao.pageListCount(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
+
+ // package result
+ Map maps = new HashMap();
+ maps.put("recordsTotal", list_count); // 总记录数
+ maps.put("recordsFiltered", list_count); // 过滤后的总记录数
+ maps.put("data", list); // 分页列表
+ return maps;
+ }
+
+ @Override
+ public ReturnT add(XxlJobInfo jobInfo) {
+
+ // valid base
+ XxlJobGroup group = xxlJobGroupDao.load(jobInfo.getJobGroup());
+ if (group == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_choose")+I18nUtil.getString("jobinfo_field_jobgroup")) );
+ }
+ if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
+ }
+ if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
+ }
+
+ // valid trigger
+ ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
+ if (scheduleTypeEnum == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
+ }
+ if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
+ if (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
+ return new ReturnT(ReturnT.FAIL_CODE, "Cron"+I18nUtil.getString("system_unvalid"));
+ }
+ } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE/* || scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {
+ if (jobInfo.getScheduleConf() == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")) );
+ }
+ try {
+ int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
+ if (fixSecond < 1) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
+ }
+ } catch (Exception e) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
+ }
+ }
+
+ // valid job
+ if (GlueTypeEnum.match(jobInfo.getGlueType()) == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_gluetype")+I18nUtil.getString("system_unvalid")) );
+ }
+ if (GlueTypeEnum.BEAN==GlueTypeEnum.match(jobInfo.getGlueType()) && (jobInfo.getExecutorHandler()==null || jobInfo.getExecutorHandler().trim().length()==0) ) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+"JobHandler") );
+ }
+ // 》fix "\r" in shell
+ if (GlueTypeEnum.GLUE_SHELL==GlueTypeEnum.match(jobInfo.getGlueType()) && jobInfo.getGlueSource()!=null) {
+ jobInfo.setGlueSource(jobInfo.getGlueSource().replaceAll("\r", ""));
+ }
+
+ // valid advanced
+ if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
+ }
+ if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy")+I18nUtil.getString("system_unvalid")) );
+ }
+ if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
+ }
+
+ // 》ChildJobId valid
+ if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
+ String[] childJobIds = jobInfo.getChildJobId().split(",");
+ for (String childJobIdItem: childJobIds) {
+ if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
+ XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));
+ if (childJobInfo==null) {
+ return new ReturnT(ReturnT.FAIL_CODE,
+ MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
+ }
+ } else {
+ return new ReturnT(ReturnT.FAIL_CODE,
+ MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
+ }
+ }
+
+ // join , avoid "xxx,,"
+ String temp = "";
+ for (String item:childJobIds) {
+ temp += item + ",";
+ }
+ temp = temp.substring(0, temp.length()-1);
+
+ jobInfo.setChildJobId(temp);
+ }
+
+ // add in db
+ jobInfo.setAddTime(new Date());
+ jobInfo.setUpdateTime(new Date());
+ jobInfo.setGlueUpdatetime(new Date());
+ xxlJobInfoDao.save(jobInfo);
+ if (jobInfo.getId() < 1) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_add")+I18nUtil.getString("system_fail")) );
+ }
+
+ return new ReturnT(String.valueOf(jobInfo.getId()));
+ }
+
+ private boolean isNumeric(String str){
+ try {
+ int result = Integer.valueOf(str);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public ReturnT update(XxlJobInfo jobInfo) {
+
+ // valid base
+ if (jobInfo.getJobDesc()==null || jobInfo.getJobDesc().trim().length()==0) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_jobdesc")) );
+ }
+ if (jobInfo.getAuthor()==null || jobInfo.getAuthor().trim().length()==0) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("system_please_input")+I18nUtil.getString("jobinfo_field_author")) );
+ }
+
+ // valid trigger
+ ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(jobInfo.getScheduleType(), null);
+ if (scheduleTypeEnum == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
+ }
+ if (scheduleTypeEnum == ScheduleTypeEnum.CRON) {
+ if (jobInfo.getScheduleConf()==null || !CronExpression.isValidExpression(jobInfo.getScheduleConf())) {
+ return new ReturnT(ReturnT.FAIL_CODE, "Cron"+I18nUtil.getString("system_unvalid") );
+ }
+ } else if (scheduleTypeEnum == ScheduleTypeEnum.FIX_RATE /*|| scheduleTypeEnum == ScheduleTypeEnum.FIX_DELAY*/) {
+ if (jobInfo.getScheduleConf() == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
+ }
+ try {
+ int fixSecond = Integer.valueOf(jobInfo.getScheduleConf());
+ if (fixSecond < 1) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
+ }
+ } catch (Exception e) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type")+I18nUtil.getString("system_unvalid")) );
+ }
+ }
+
+ // valid advanced
+ if (ExecutorRouteStrategyEnum.match(jobInfo.getExecutorRouteStrategy(), null) == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorRouteStrategy")+I18nUtil.getString("system_unvalid")) );
+ }
+ if (MisfireStrategyEnum.match(jobInfo.getMisfireStrategy(), null) == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("misfire_strategy")+I18nUtil.getString("system_unvalid")) );
+ }
+ if (ExecutorBlockStrategyEnum.match(jobInfo.getExecutorBlockStrategy(), null) == null) {
+ return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_executorBlockStrategy")+I18nUtil.getString("system_unvalid")) );
+ }
+
+ // 》ChildJobId valid
+ if (jobInfo.getChildJobId()!=null && jobInfo.getChildJobId().trim().length()>0) {
+ String[] childJobIds = jobInfo.getChildJobId().split(",");
+ for (String childJobIdItem: childJobIds) {
+ if (childJobIdItem!=null && childJobIdItem.trim().length()>0 && isNumeric(childJobIdItem)) {
+ XxlJobInfo childJobInfo = xxlJobInfoDao.loadById(Integer.parseInt(childJobIdItem));
+ if (childJobInfo==null) {
+ return new ReturnT(ReturnT.FAIL_CODE,
+ MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_not_found")), childJobIdItem));
+ }
+ } else {
+ return new ReturnT(ReturnT.FAIL_CODE,
+ MessageFormat.format((I18nUtil.getString("jobinfo_field_childJobId")+"({0})"+I18nUtil.getString("system_unvalid")), childJobIdItem));
+ }
+ }
+
+ // join , avoid "xxx,,"
+ String temp = "";
+ for (String item:childJobIds) {
+ temp += item + ",";
+ }
+ temp = temp.substring(0, temp.length()-1);
+
+ jobInfo.setChildJobId(temp);
+ }
+
+ // group valid
+ XxlJobGroup jobGroup = xxlJobGroupDao.load(jobInfo.getJobGroup());
+ if (jobGroup == null) {
+ return new ReturnT