diff --git a/.run/ruoyi-monitor-admin.run.xml b/.run/ruoyi-monitor-admin.run.xml
index 11513a6f9..99630d7d8 100644
--- a/.run/ruoyi-monitor-admin.run.xml
+++ b/.run/ruoyi-monitor-admin.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-xxl-job-admin.run.xml b/.run/ruoyi-powerjob-server.run.xml
similarity index 56%
rename from .run/ruoyi-xxl-job-admin.run.xml
rename to .run/ruoyi-powerjob-server.run.xml
index be5255766..25e2ae1b6 100644
--- a/.run/ruoyi-xxl-job-admin.run.xml
+++ b/.run/ruoyi-powerjob-server.run.xml
@@ -1,10 +1,10 @@
-
+
-
+
-
+
diff --git a/.run/ruoyi-server.run.xml b/.run/ruoyi-server.run.xml
index f648cf99d..5aab5ca9f 100644
--- a/.run/ruoyi-server.run.xml
+++ b/.run/ruoyi-server.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/README.md b/README.md
index eb82295ad..421ca75c3 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
[](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
-[](https://gitee.com/dromara/RuoYi-Vue-Plus)
+[](https://gitee.com/dromara/RuoYi-Vue-Plus)
[]()
[]()
[]()
@@ -35,6 +35,7 @@
| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat |
| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 |
| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验 角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 |
+| 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 |
| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer 可同时使用异构切换 | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 |
| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 |
| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具 支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan 支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐 连接池采用 common-pool Bug多经常性出问题 |
@@ -45,6 +46,7 @@
| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤 只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展 生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 |
| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件 支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 |
| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密 支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 |
+| 接口传输加密 | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性 | 无 |
| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译 支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 |
| 多数据源框架 | 采用 dynamic-datasource 支持世面大部分数据库 通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源 支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 |
| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 |
@@ -54,10 +56,10 @@
| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 |
| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 |
| 分布式锁 | 采用 Lock4j 底层基于 Redisson | 无 |
-| 分布式任务调度 | 采用 Xxl-Job 天生支持分布式 统一的管理中心 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 |
+| 分布式任务调度 | 采用 PowerJob 天生支持分布式 统一的管理中心 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 |
| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储 支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 |
| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 |
-| 短信 | 支持 阿里、腾讯 只需在yml配置好厂家密钥即可使用 接口化支持扩展其他厂家 | 不支持 |
+| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 |
| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 |
| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释 只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 |
| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 |
@@ -75,30 +77,31 @@
## 本框架与RuoYi的业务差异
-| 业务 | 功能说明 | 本框架 | RuoYi |
-|--------|-----------------------------------------|-----|------------------|
-| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 |
-| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 |
-| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 |
-| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 |
-| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 |
-| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 |
-| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 |
-| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 |
-| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 |
-| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 |
-| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 |
-| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 |
-| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 |
-| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 |
-| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 |
-| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 |
-| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 |
-| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 |
-| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 |
-| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 |
-| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 |
-| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 |
+| 业务 | 功能说明 | 本框架 | RuoYi |
+|--------|----------------------------------------------------------------------|-----|------------------|
+| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 |
+| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 |
+| 客户端管理 | 系统内对接的所有客户端管理 如: pc端、小程序端等 支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效 | 支持 | 无 |
+| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 |
+| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 |
+| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 |
+| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 |
+| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 |
+| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 |
+| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 |
+| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 |
+| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 |
+| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 |
+| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 |
+| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 |
+| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 |
+| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 |
+| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 |
+| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 |
+| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 |
+| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 |
+| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 |
+| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 |
## 参考文档
diff --git a/pom.xml b/pom.xml
index fb909a959..181c8270c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,32 +13,33 @@
RuoYi-Vue-Plus多租户管理系统
- 5.0.0
- 3.0.7
+ 5.1.0-BETA
+ 3.1.2
UTF-8
UTF-8
17
- 3.0.1
+ 3.0.2
2.1.0
0.15.0
5.2.3
- 3.2.1
+ 3.3.2
2.3
- 1.34.0
+ 1.35.0.RC
3.5.3.1
3.9.1
- 5.8.18
+ 5.8.20
4.10.0
- 3.0.4
- 3.20.1
+ 3.1.3
+ 3.23.1
2.2.4
- 3.6.1
+ 4.1.2
2.14.2
- 2.4.0
- 1.2.3
+ 4.3.3
+ 1.3.5
0.2.0
1.18.26
1.72
+ 1.16.5
2.7.0
@@ -46,16 +47,15 @@
1.33
- 1.12.400
+ 1.12.517
- 2.0.23
- 3.1.687
+ 2.2.0
3.2.2
3.2.2
3.11.0
- 3.0.0
+ 3.1.2
1.3.0
@@ -114,6 +114,13 @@
import
+
+
+ me.zhyd.oauth
+ JustAuth
+ ${justauth.version}
+
+
org.dromara
@@ -197,7 +204,7 @@
com.baomidou
- dynamic-datasource-spring-boot-starter
+ dynamic-datasource-spring-boot3-starter
${dynamic-ds.version}
@@ -237,17 +244,11 @@
aws-java-sdk-s3
${aws-java-sdk-s3.version}
-
+
- com.aliyun
- dysmsapi20170525
- ${aliyun.sms.version}
-
-
-
- com.tencentcloudapi
- tencentcloud-sdk-java-sms
- ${tencent.sms.version}
+ org.dromara.sms4j
+ sms4j-spring-boot-starter
+ ${sms4j.version}
@@ -274,11 +275,16 @@
${lock4j.version}
-
+
- com.xuxueli
- xxl-job-core
- ${xxl-job.version}
+ tech.powerjob
+ powerjob-worker-spring-boot-starter
+ ${powerjob.version}
+
+
+ tech.powerjob
+ powerjob-official-processors
+ ${powerjob.version}
@@ -480,8 +486,8 @@
public
- aliyun nexus
- https://maven.aliyun.com/repository/public/
+ huawei nexus
+ https://mirrors.huaweicloud.com/repository/maven/
true
@@ -491,8 +497,8 @@
public
- aliyun nexus
- https://maven.aliyun.com/repository/public/
+ huawei nexus
+ https://mirrors.huaweicloud.com/repository/maven/
true
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 70241f0b5..019935899 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -43,6 +43,12 @@
ruoyi-common-doc
+
+ org.dromara
+ ruoyi-common-social
+
+
+
org.dromara
ruoyi-system
@@ -82,6 +88,11 @@
test
+
+ me.zhyd.oauth
+ JustAuth
+
+
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
index f39fd3068..3c03e4248 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java
@@ -2,27 +2,38 @@ package org.dromara.web.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthRequest;
+import me.zhyd.oauth.utils.AuthStateUtils;
import org.dromara.common.core.domain.R;
-import org.dromara.common.core.domain.model.EmailLoginBody;
import org.dromara.common.core.domain.model.LoginBody;
import org.dromara.common.core.domain.model.RegisterBody;
-import org.dromara.common.core.domain.model.SmsLoginBody;
import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.utils.SocialUtils;
import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysClient;
import org.dromara.system.domain.bo.SysTenantBo;
import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.service.ISysClientService;
import org.dromara.system.service.ISysConfigService;
+import org.dromara.system.service.ISysSocialService;
import org.dromara.system.service.ISysTenantService;
import org.dromara.web.domain.vo.LoginTenantVo;
import org.dromara.web.domain.vo.LoginVo;
import org.dromara.web.domain.vo.TenantListVo;
+import org.dromara.web.service.IAuthStrategy;
import org.dromara.web.service.SysLoginService;
import org.dromara.web.service.SysRegisterService;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.validation.constraints.NotBlank;
-import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -34,6 +45,7 @@ import java.util.List;
*
* @author Lion Li
*/
+@Slf4j
@SaIgnore
@Validated
@RequiredArgsConstructor
@@ -41,74 +53,87 @@ import java.util.List;
@RequestMapping("/auth")
public class AuthController {
+ private final SocialProperties socialProperties;
private final SysLoginService loginService;
private final SysRegisterService registerService;
private final ISysConfigService configService;
private final ISysTenantService tenantService;
+ private final ISysSocialService socialUserService;
+ private final ISysClientService clientService;
+
/**
* 登录方法
*
- * @param body 登录信息
+ * @param loginBody 登录信息
* @return 结果
*/
@PostMapping("/login")
- public R login(@Validated @RequestBody LoginBody body) {
- LoginVo loginVo = new LoginVo();
- // 生成令牌
- String token = loginService.login(
- body.getTenantId(),
- body.getUsername(), body.getPassword(),
- body.getCode(), body.getUuid());
- loginVo.setToken(token);
- return R.ok(loginVo);
+ public R login(@Validated @RequestBody LoginBody loginBody) {
+ // 授权类型和客户端id
+ String clientId = loginBody.getClientId();
+ String grantType = loginBody.getGrantType();
+ SysClient client = clientService.queryByClientId(clientId);
+ // 查询不到 client 或 client 内不包含 grantType
+ if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
+ log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType);
+ return R.fail(MessageUtils.message("auth.grant.type.error"));
+ }
+ // 校验租户
+ loginService.checkTenant(loginBody.getTenantId());
+ // 登录
+ return R.ok(IAuthStrategy.login(loginBody, client));
}
/**
- * 短信登录
+ * 第三方登录请求
*
- * @param body 登录信息
+ * @param source 登录来源
* @return 结果
*/
- @PostMapping("/smsLogin")
- public R smsLogin(@Validated @RequestBody SmsLoginBody body) {
- LoginVo loginVo = new LoginVo();
- // 生成令牌
- String token = loginService.smsLogin(body.getTenantId(), body.getPhonenumber(), body.getSmsCode());
- loginVo.setToken(token);
- return R.ok(loginVo);
+ @GetMapping("/binding/{source}")
+ public R authBinding(@PathVariable("source") String source) {
+ SocialLoginConfigProperties obj = socialProperties.getType().get(source);
+ if (ObjectUtil.isNull(obj)) {
+ return R.fail(source + "平台账号暂不支持");
+ }
+ AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties);
+ String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
+ return R.ok("操作成功", authorizeUrl);
}
/**
- * 邮件登录
+ * 第三方登录回调业务处理 绑定授权
*
- * @param body 登录信息
+ * @param loginBody 请求体
* @return 结果
*/
- @PostMapping("/emailLogin")
- public R emailLogin(@Validated @RequestBody EmailLoginBody body) {
- LoginVo loginVo = new LoginVo();
- // 生成令牌
- String token = loginService.emailLogin(body.getTenantId(), body.getEmail(), body.getEmailCode());
- loginVo.setToken(token);
- return R.ok(loginVo);
+ @PostMapping("/social/callback")
+ public R socialCallback(@RequestBody LoginBody loginBody) {
+ // 获取第三方登录信息
+ AuthResponse response = SocialUtils.loginAuth(loginBody, socialProperties);
+ AuthUser authUserData = response.getData();
+ // 判断授权响应是否成功
+ if (!response.ok()) {
+ return R.fail(response.getMsg());
+ }
+ loginService.socialRegister(authUserData);
+ return R.ok();
}
+
/**
- * 小程序登录(示例)
+ * 取消授权
*
- * @param xcxCode 小程序code
- * @return 结果
+ * @param socialId socialId
*/
- @PostMapping("/xcxLogin")
- public R xcxLogin(@NotBlank(message = "{xcx.code.not.blank}") String xcxCode) {
- LoginVo loginVo = new LoginVo();
- // 生成令牌
- String token = loginService.xcxLogin(xcxCode);
- loginVo.setToken(token);
- return R.ok(loginVo);
+ @DeleteMapping(value = "/unlock/{socialId}")
+ public R unlockSocial(@PathVariable Long socialId) {
+ Boolean rows = socialUserService.deleteWithValidById(socialId);
+ return rows ? R.ok() : R.fail("取消授权失败");
}
+
/**
* 退出登录
*/
@@ -140,9 +165,17 @@ public class AuthController {
List tenantList = tenantService.queryList(new SysTenantBo());
List voList = MapstructUtils.convert(tenantList, TenantListVo.class);
// 获取域名
- String host = new URL(request.getRequestURL().toString()).getHost();
+ String host;
+ String referer = request.getHeader("referer");
+ if (StringUtils.isNotBlank(referer)) {
+ // 这里从referer中取值是为了本地使用hosts添加虚拟域名,方便本地环境调试
+ host = referer.split("//")[1].split("/")[0];
+ } else {
+ host = new URL(request.getRequestURL().toString()).getHost();
+ }
// 根据域名进行筛选
- List list = StreamUtils.filter(voList, vo -> StringUtils.equals(vo.getDomain(), host));
+ List list = StreamUtils.filter(voList, vo ->
+ StringUtils.equals(vo.getDomain(), host));
// 返回对象
LoginTenantVo vo = new LoginTenantVo();
vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
index dd9fa196e..656447e89 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java
@@ -14,11 +14,12 @@ import org.dromara.common.core.utils.reflect.ReflectUtils;
import org.dromara.common.mail.config.properties.MailProperties;
import org.dromara.common.mail.utils.MailUtils;
import org.dromara.common.redis.utils.RedisUtils;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.core.SmsTemplate;
-import org.dromara.common.sms.entity.SmsResult;
import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.common.web.enums.CaptchaType;
+import org.dromara.sms4j.api.SmsBlend;
+import org.dromara.sms4j.api.entity.SmsResponse;
+import org.dromara.sms4j.core.factory.SmsFactory;
+import org.dromara.sms4j.provider.enumerate.SupplierType;
import org.dromara.web.domain.vo.CaptchaVo;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
@@ -31,8 +32,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.LinkedHashMap;
/**
* 验证码操作处理
@@ -47,7 +47,6 @@ import java.util.Map;
public class CaptchaController {
private final CaptchaProperties captchaProperties;
- private final SmsProperties smsProperties;
private final MailProperties mailProperties;
/**
@@ -57,21 +56,18 @@ public class CaptchaController {
*/
@GetMapping("/resource/sms/code")
public R smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
- if (!smsProperties.getEnabled()) {
- return R.fail("当前系统没有开启短信功能!");
- }
String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
// 验证码模板id 自行处理 (查数据库或写死均可)
String templateId = "";
- Map map = new HashMap<>(1);
+ LinkedHashMap map = new LinkedHashMap<>(1);
map.put("code", code);
- SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class);
- SmsResult result = smsTemplate.send(phonenumber, templateId, map);
- if (!result.isSuccess()) {
- log.error("验证码短信发送异常 => {}", result);
- return R.fail(result.getMessage());
+ SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
+ SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
+ if (!"OK".equals(smsResponse.getCode())) {
+ log.error("验证码短信发送异常 => {}", smsResponse);
+ return R.fail(smsResponse.getMessage());
}
return R.ok();
}
@@ -101,7 +97,7 @@ public class CaptchaController {
/**
* 生成验证码
*/
- @GetMapping("/code")
+ @GetMapping("/auth/code")
public R getCode() {
CaptchaVo captchaVo = new CaptchaVo();
boolean captchaEnabled = captchaProperties.getEnable();
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java
index ef5dac0df..834afe5a1 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java
@@ -1,5 +1,6 @@
package org.dromara.web.domain.vo;
+import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
@@ -10,6 +11,44 @@ import lombok.Data;
@Data
public class LoginVo {
- private String token;
+ /**
+ * 授权令牌
+ */
+ @JsonProperty("access_token")
+ private String accessToken;
+
+ /**
+ * 刷新令牌
+ */
+ @JsonProperty("refresh_token")
+ private String refreshToken;
+
+ /**
+ * 授权令牌 access_token 的有效期
+ */
+ @JsonProperty("expire_in")
+ private Long expireIn;
+
+ /**
+ * 刷新令牌 refresh_token 的有效期
+ */
+ @JsonProperty("refresh_expire_in")
+ private Long refreshExpireIn;
+
+ /**
+ * 应用id
+ */
+ @JsonProperty("client_id")
+ private String clientId;
+
+ /**
+ * 令牌权限
+ */
+ private String scope;
+
+ /**
+ * 用户 openid
+ */
+ private String openid;
}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java
new file mode 100644
index 000000000..690f74024
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java
@@ -0,0 +1,45 @@
+package org.dromara.web.service;
+
+
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.system.domain.SysClient;
+import org.dromara.web.domain.vo.LoginVo;
+
+/**
+ * 授权策略
+ *
+ * @author Michelle.Chung
+ */
+public interface IAuthStrategy {
+
+ String BASE_NAME = "AuthStrategy";
+
+ /**
+ * 登录
+ */
+ static LoginVo login(LoginBody loginBody, SysClient client) {
+ // 授权类型和客户端id
+ String clientId = loginBody.getClientId();
+ String grantType = loginBody.getGrantType();
+ String beanName = grantType + BASE_NAME;
+ if (!SpringUtils.containsBean(beanName)) {
+ throw new ServiceException("授权类型不正确!");
+ }
+ IAuthStrategy instance = SpringUtils.getBean(beanName);
+ instance.validate(loginBody);
+ return instance.login(clientId, loginBody, client);
+ }
+
+ /**
+ * 参数校验
+ */
+ void validate(LoginBody loginBody);
+
+ /**
+ * 登录
+ */
+ LoginVo login(String clientId, LoginBody loginBody, SysClient client);
+
+}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
index 689a55de1..b91452cd7 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
@@ -1,39 +1,40 @@
package org.dromara.web.service;
import cn.dev33.satoken.exception.NotLoginException;
-import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthUser;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser;
-import org.dromara.common.core.domain.model.XcxLoginUser;
-import org.dromara.common.core.enums.DeviceType;
import org.dromara.common.core.enums.LoginType;
import org.dromara.common.core.enums.TenantStatus;
import org.dromara.common.core.enums.UserStatus;
-import org.dromara.common.core.exception.user.CaptchaException;
-import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException;
-import org.dromara.common.core.utils.*;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ServletUtils;
+import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.log.event.LogininforEvent;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.exception.TenantException;
import org.dromara.common.tenant.helper.TenantHelper;
-import org.dromara.common.web.config.properties.CaptchaProperties;
import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysSocialBo;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysPermissionService;
+import org.dromara.system.service.ISysSocialService;
import org.dromara.system.service.ISysTenantService;
+import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -52,107 +53,35 @@ import java.util.function.Supplier;
@Service
public class SysLoginService {
- private final SysUserMapper userMapper;
- private final CaptchaProperties captchaProperties;
- private final ISysPermissionService permissionService;
- private final ISysTenantService tenantService;
-
@Value("${user.password.maxRetryCount}")
private Integer maxRetryCount;
@Value("${user.password.lockTime}")
private Integer lockTime;
+ private final ISysTenantService tenantService;
+ private final ISysPermissionService permissionService;
+ private final ISysSocialService sysSocialService;
+ private final SysUserMapper userMapper;
+
+
/**
- * 登录验证
+ * 绑定第三方用户
*
- * @param username 用户名
- * @param password 密码
- * @param code 验证码
- * @param uuid 唯一标识
- * @return 结果
+ * @param authUserData 授权响应实体
+ * @return 统一响应实体
*/
- public String login(String tenantId, String username, String password, String code, String uuid) {
- boolean captchaEnabled = captchaProperties.getEnable();
- // 验证码开关
- if (captchaEnabled) {
- validateCaptcha(tenantId, username, code, uuid);
- }
- // 校验租户
- checkTenant(tenantId);
-
- // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
- SysUserVo user = loadUserByUsername(tenantId, username);
- checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
- // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
- LoginUser loginUser = buildLoginUser(user);
- // 生成token
- LoginHelper.loginByDevice(loginUser, DeviceType.PC);
-
- recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
- recordLoginInfo(user.getUserId());
- return StpUtil.getTokenValue();
+ public void socialRegister(AuthUser authUserData) {
+ SysSocialBo bo = new SysSocialBo();
+ bo.setUserId(LoginHelper.getUserId());
+ bo.setAuthId(authUserData.getSource() + authUserData.getUuid());
+ bo.setOpenId(authUserData.getUuid());
+ bo.setUserName(authUserData.getUsername());
+ BeanUtils.copyProperties(authUserData, bo);
+ BeanUtils.copyProperties(authUserData.getToken(), bo);
+ sysSocialService.insertByBo(bo);
}
- public String smsLogin(String tenantId, String phonenumber, String smsCode) {
- // 校验租户
- checkTenant(tenantId);
- // 通过手机号查找用户
- SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber);
-
- checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
- // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
- LoginUser loginUser = buildLoginUser(user);
- // 生成token
- LoginHelper.loginByDevice(loginUser, DeviceType.APP);
-
- recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
- recordLoginInfo(user.getUserId());
- return StpUtil.getTokenValue();
- }
-
- public String emailLogin(String tenantId, String email, String emailCode) {
- // 校验租户
- checkTenant(tenantId);
- // 通过邮箱查找用户
- SysUserVo user = loadUserByEmail(tenantId, email);
-
- checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
- // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
- LoginUser loginUser = buildLoginUser(user);
- // 生成token
- LoginHelper.loginByDevice(loginUser, DeviceType.APP);
-
- recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
- recordLoginInfo(user.getUserId());
- return StpUtil.getTokenValue();
- }
-
-
- public String xcxLogin(String xcxCode) {
- // xcxCode 为 小程序调用 wx.login 授权后获取
- // todo 以下自行实现
- // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
- String openid = "";
- // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
- SysUserVo user = loadUserByOpenid(openid);
- // 校验租户
- checkTenant(user.getTenantId());
-
- // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
- XcxLoginUser loginUser = new XcxLoginUser();
- loginUser.setTenantId(user.getTenantId());
- loginUser.setUserId(user.getUserId());
- loginUser.setUsername(user.getUserName());
- loginUser.setUserType(user.getUserType());
- loginUser.setOpenid(openid);
- // 生成token
- LoginHelper.loginByDevice(loginUser, DeviceType.XCX);
-
- recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
- recordLoginInfo(user.getUserId());
- return StpUtil.getTokenValue();
- }
/**
* 退出登录
@@ -164,9 +93,13 @@ public class SysLoginService {
// 超级管理员 登出清除动态租户
TenantHelper.clearDynamic();
}
- StpUtil.logout();
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
} catch (NotLoginException ignored) {
+ } finally {
+ try {
+ StpUtil.logout();
+ } catch (NotLoginException ignored) {
+ }
}
}
@@ -178,7 +111,7 @@ public class SysLoginService {
* @param status 状态
* @param message 消息内容
*/
- private void recordLogininfor(String tenantId, String username, String status, String message) {
+ public void recordLogininfor(String tenantId, String username, String status, String message) {
LogininforEvent logininforEvent = new LogininforEvent();
logininforEvent.setTenantId(tenantId);
logininforEvent.setUsername(username);
@@ -188,123 +121,11 @@ public class SysLoginService {
SpringUtils.context().publishEvent(logininforEvent);
}
- /**
- * 校验短信验证码
- */
- private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
- String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
- if (StringUtils.isBlank(code)) {
- recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
- throw new CaptchaExpireException();
- }
- return code.equals(smsCode);
- }
-
- /**
- * 校验邮箱验证码
- */
- private boolean validateEmailCode(String tenantId, String email, String emailCode) {
- String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
- if (StringUtils.isBlank(code)) {
- recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
- throw new CaptchaExpireException();
- }
- return code.equals(emailCode);
- }
-
- /**
- * 校验验证码
- *
- * @param username 用户名
- * @param code 验证码
- * @param uuid 唯一标识
- */
- public void validateCaptcha(String tenantId, String username, String code, String uuid) {
- String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
- String captcha = RedisUtils.getCacheObject(verifyKey);
- RedisUtils.deleteObject(verifyKey);
- if (captcha == null) {
- recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
- throw new CaptchaExpireException();
- }
- if (!code.equalsIgnoreCase(captcha)) {
- recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
- throw new CaptchaException();
- }
- }
-
- private SysUserVo loadUserByUsername(String tenantId, String username) {
- SysUser user = userMapper.selectOne(new LambdaQueryWrapper()
- .select(SysUser::getUserName, SysUser::getStatus)
- .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
- .eq(SysUser::getUserName, username));
- if (ObjectUtil.isNull(user)) {
- log.info("登录用户:{} 不存在.", username);
- throw new UserException("user.not.exists", username);
- } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
- log.info("登录用户:{} 已被停用.", username);
- throw new UserException("user.blocked", username);
- }
- if (TenantHelper.isEnable()) {
- return userMapper.selectTenantUserByUserName(username, tenantId);
- }
- return userMapper.selectUserByUserName(username);
- }
-
- private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) {
- SysUser user = userMapper.selectOne(new LambdaQueryWrapper()
- .select(SysUser::getPhonenumber, SysUser::getStatus)
- .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
- .eq(SysUser::getPhonenumber, phonenumber));
- if (ObjectUtil.isNull(user)) {
- log.info("登录用户:{} 不存在.", phonenumber);
- throw new UserException("user.not.exists", phonenumber);
- } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
- log.info("登录用户:{} 已被停用.", phonenumber);
- throw new UserException("user.blocked", phonenumber);
- }
- if (TenantHelper.isEnable()) {
- return userMapper.selectTenantUserByPhonenumber(phonenumber, tenantId);
- }
- return userMapper.selectUserByPhonenumber(phonenumber);
- }
-
- private SysUserVo loadUserByEmail(String tenantId, String email) {
- SysUser user = userMapper.selectOne(new LambdaQueryWrapper()
- .select(SysUser::getPhonenumber, SysUser::getStatus)
- .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
- .eq(SysUser::getEmail, email));
- if (ObjectUtil.isNull(user)) {
- log.info("登录用户:{} 不存在.", email);
- throw new UserException("user.not.exists", email);
- } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
- log.info("登录用户:{} 已被停用.", email);
- throw new UserException("user.blocked", email);
- }
- if (TenantHelper.isEnable()) {
- return userMapper.selectTenantUserByEmail(email, tenantId);
- }
- return userMapper.selectUserByEmail(email);
- }
-
- private SysUserVo loadUserByOpenid(String openid) {
- // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
- // todo 自行实现 userService.selectUserByOpenid(openid);
- SysUserVo user = new SysUserVo();
- if (ObjectUtil.isNull(user)) {
- log.info("登录用户:{} 不存在.", openid);
- // todo 用户不存在 业务逻辑自行实现
- } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
- log.info("登录用户:{} 已被停用.", openid);
- // todo 用户已被停用 业务逻辑自行实现
- }
- return user;
- }
/**
* 构建登录用户
*/
- private LoginUser buildLoginUser(SysUserVo user) {
+ public LoginUser buildLoginUser(SysUserVo user) {
LoginUser loginUser = new LoginUser();
loginUser.setTenantId(user.getTenantId());
loginUser.setUserId(user.getUserId());
@@ -336,29 +157,28 @@ public class SysLoginService {
/**
* 登录校验
*/
- private void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) {
+ public void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) {
String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL;
- // 获取用户登录错误次数(可自定义限制策略 例如: key + username + ip)
- Integer errorNumber = RedisUtils.getCacheObject(errorKey);
+ // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip)
+ int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0);
// 锁定时间内登录 则踢出
- if (ObjectUtil.isNotNull(errorNumber) && errorNumber.equals(maxRetryCount)) {
+ if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
}
if (supplier.get()) {
- // 是否第一次
- errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
+ // 错误次数递增
+ errorNumber++;
+ RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
// 达到规定错误次数 则锁定登录
- if (errorNumber.equals(maxRetryCount)) {
- RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime));
+ if (errorNumber >= maxRetryCount) {
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime));
throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime);
} else {
- // 未达到规定错误次数 则递增
- RedisUtils.setCacheObject(errorKey, errorNumber);
+ // 未达到规定错误次数
recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber));
throw new UserException(loginType.getRetryLimitCount(), errorNumber);
}
@@ -368,7 +188,12 @@ public class SysLoginService {
RedisUtils.deleteObject(errorKey);
}
- private void checkTenant(String tenantId) {
+ /**
+ * 校验租户
+ *
+ * @param tenantId 租户ID
+ */
+ public void checkTenant(String tenantId) {
if (!TenantHelper.isEnable()) {
return;
}
@@ -383,7 +208,7 @@ public class SysLoginService {
log.info("登录租户:{} 已被停用.", tenantId);
throw new TenantException("tenant.blocked");
} else if (ObjectUtil.isNotNull(tenant.getExpireTime())
- && new Date().after(tenant.getExpireTime())) {
+ && new Date().after(tenant.getExpireTime())) {
log.info("登录租户:{} 已超过有效期.", tenantId);
throw new TenantException("tenant.expired");
}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
new file mode 100644
index 000000000..c284e3df3
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java
@@ -0,0 +1,113 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.user.CaptchaExpireException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.auth.EmailGroup;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 邮件认证策略
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("email" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class EmailAuthStrategy implements IAuthStrategy {
+
+ private final SysLoginService loginService;
+ private final SysUserMapper userMapper;
+
+ @Override
+ public void validate(LoginBody loginBody) {
+ ValidatorUtils.validate(loginBody, EmailGroup.class);
+ }
+
+ @Override
+ public LoginVo login(String clientId, LoginBody loginBody, SysClient client) {
+ String tenantId = loginBody.getTenantId();
+ String email = loginBody.getEmail();
+ String emailCode = loginBody.getEmailCode();
+
+ // 通过邮箱查找用户
+ SysUserVo user = loadUserByEmail(tenantId, email);
+
+ loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode));
+ // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
+ LoginUser loginUser = loginService.buildLoginUser(user);
+ SaLoginModel model = new SaLoginModel();
+ model.setDevice(client.getDeviceType());
+ // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
+ // 例如: 后台用户30分钟过期 app用户1天过期
+ model.setTimeout(client.getTimeout());
+ model.setActiveTimeout(client.getActiveTimeout());
+ model.setExtra(LoginHelper.CLIENT_KEY, clientId);
+ // 生成token
+ LoginHelper.login(loginUser, model);
+
+ loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
+ loginService.recordLoginInfo(user.getUserId());
+
+ LoginVo loginVo = new LoginVo();
+ loginVo.setAccessToken(StpUtil.getTokenValue());
+ loginVo.setExpireIn(StpUtil.getTokenTimeout());
+ loginVo.setClientId(clientId);
+ return loginVo;
+ }
+
+ /**
+ * 校验邮箱验证码
+ */
+ private boolean validateEmailCode(String tenantId, String email, String emailCode) {
+ String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email);
+ if (StringUtils.isBlank(code)) {
+ loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+ throw new CaptchaExpireException();
+ }
+ return code.equals(emailCode);
+ }
+
+ private SysUserVo loadUserByEmail(String tenantId, String email) {
+ SysUser user = userMapper.selectOne(new LambdaQueryWrapper()
+ .select(SysUser::getEmail, SysUser::getStatus)
+ .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
+ .eq(SysUser::getEmail, email));
+ if (ObjectUtil.isNull(user)) {
+ log.info("登录用户:{} 不存在.", email);
+ throw new UserException("user.not.exists", email);
+ } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+ log.info("登录用户:{} 已被停用.", email);
+ throw new UserException("user.blocked", email);
+ }
+ if (TenantHelper.isEnable()) {
+ return userMapper.selectTenantUserByEmail(email, tenantId);
+ }
+ return userMapper.selectUserByEmail(email);
+ }
+
+}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
new file mode 100644
index 000000000..401dfb20c
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java
@@ -0,0 +1,132 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.user.CaptchaException;
+import org.dromara.common.core.exception.user.CaptchaExpireException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.auth.PasswordGroup;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.web.config.properties.CaptchaProperties;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 密码认证策略
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("password" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class PasswordAuthStrategy implements IAuthStrategy {
+
+ private final CaptchaProperties captchaProperties;
+ private final SysLoginService loginService;
+ private final SysUserMapper userMapper;
+
+ @Override
+ public void validate(LoginBody loginBody) {
+ ValidatorUtils.validate(loginBody, PasswordGroup.class);
+ }
+
+ @Override
+ public LoginVo login(String clientId, LoginBody loginBody, SysClient client) {
+ String tenantId = loginBody.getTenantId();
+ String username = loginBody.getUsername();
+ String password = loginBody.getPassword();
+ String code = loginBody.getCode();
+ String uuid = loginBody.getUuid();
+
+ boolean captchaEnabled = captchaProperties.getEnable();
+ // 验证码开关
+ if (captchaEnabled) {
+ validateCaptcha(tenantId, username, code, uuid);
+ }
+
+ SysUserVo user = loadUserByUsername(tenantId, username);
+ loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
+ // 此处可根据登录用户的数据不同 自行创建 loginUser
+ LoginUser loginUser = loginService.buildLoginUser(user);
+ SaLoginModel model = new SaLoginModel();
+ model.setDevice(client.getDeviceType());
+ // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
+ // 例如: 后台用户30分钟过期 app用户1天过期
+ model.setTimeout(client.getTimeout());
+ model.setActiveTimeout(client.getActiveTimeout());
+ model.setExtra(LoginHelper.CLIENT_KEY, clientId);
+ // 生成token
+ LoginHelper.login(loginUser, model);
+
+ loginService.recordLogininfor(loginUser.getTenantId(), username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
+ loginService.recordLoginInfo(user.getUserId());
+
+ LoginVo loginVo = new LoginVo();
+ loginVo.setAccessToken(StpUtil.getTokenValue());
+ loginVo.setExpireIn(StpUtil.getTokenTimeout());
+ loginVo.setClientId(clientId);
+ return loginVo;
+ }
+
+ /**
+ * 校验验证码
+ *
+ * @param username 用户名
+ * @param code 验证码
+ * @param uuid 唯一标识
+ */
+ private void validateCaptcha(String tenantId, String username, String code, String uuid) {
+ String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.defaultString(uuid, "");
+ String captcha = RedisUtils.getCacheObject(verifyKey);
+ RedisUtils.deleteObject(verifyKey);
+ if (captcha == null) {
+ loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+ throw new CaptchaExpireException();
+ }
+ if (!code.equalsIgnoreCase(captcha)) {
+ loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
+ throw new CaptchaException();
+ }
+ }
+
+ private SysUserVo loadUserByUsername(String tenantId, String username) {
+ SysUser user = userMapper.selectOne(new LambdaQueryWrapper()
+ .select(SysUser::getUserName, SysUser::getStatus)
+ .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
+ .eq(SysUser::getUserName, username));
+ if (ObjectUtil.isNull(user)) {
+ log.info("登录用户:{} 不存在.", username);
+ throw new UserException("user.not.exists", username);
+ } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+ log.info("登录用户:{} 已被停用.", username);
+ throw new UserException("user.blocked", username);
+ }
+ if (TenantHelper.isEnable()) {
+ return userMapper.selectTenantUserByUserName(username, tenantId);
+ }
+ return userMapper.selectUserByUserName(username);
+ }
+
+}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
new file mode 100644
index 000000000..3fd05691d
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java
@@ -0,0 +1,113 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.LoginType;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.user.CaptchaExpireException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.auth.SmsGroup;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 短信认证策略
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("sms" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class SmsAuthStrategy implements IAuthStrategy {
+
+ private final SysLoginService loginService;
+ private final SysUserMapper userMapper;
+
+ @Override
+ public void validate(LoginBody loginBody) {
+ ValidatorUtils.validate(loginBody, SmsGroup.class);
+ }
+
+ @Override
+ public LoginVo login(String clientId, LoginBody loginBody, SysClient client) {
+ String tenantId = loginBody.getTenantId();
+ String phonenumber = loginBody.getPhonenumber();
+ String smsCode = loginBody.getSmsCode();
+
+ // 通过手机号查找用户
+ SysUserVo user = loadUserByPhonenumber(tenantId, phonenumber);
+
+ loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
+ // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
+ LoginUser loginUser = loginService.buildLoginUser(user);
+ SaLoginModel model = new SaLoginModel();
+ model.setDevice(client.getDeviceType());
+ // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
+ // 例如: 后台用户30分钟过期 app用户1天过期
+ model.setTimeout(client.getTimeout());
+ model.setActiveTimeout(client.getActiveTimeout());
+ model.setExtra(LoginHelper.CLIENT_KEY, clientId);
+ // 生成token
+ LoginHelper.login(loginUser, model);
+
+ loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
+ loginService.recordLoginInfo(user.getUserId());
+
+ LoginVo loginVo = new LoginVo();
+ loginVo.setAccessToken(StpUtil.getTokenValue());
+ loginVo.setExpireIn(StpUtil.getTokenTimeout());
+ loginVo.setClientId(clientId);
+ return loginVo;
+ }
+
+ /**
+ * 校验短信验证码
+ */
+ private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) {
+ String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber);
+ if (StringUtils.isBlank(code)) {
+ loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
+ throw new CaptchaExpireException();
+ }
+ return code.equals(smsCode);
+ }
+
+ private SysUserVo loadUserByPhonenumber(String tenantId, String phonenumber) {
+ SysUser user = userMapper.selectOne(new LambdaQueryWrapper()
+ .select(SysUser::getPhonenumber, SysUser::getStatus)
+ .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
+ .eq(SysUser::getPhonenumber, phonenumber));
+ if (ObjectUtil.isNull(user)) {
+ log.info("登录用户:{} 不存在.", phonenumber);
+ throw new UserException("user.not.exists", phonenumber);
+ } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+ log.info("登录用户:{} 已被停用.", phonenumber);
+ throw new UserException("user.blocked", phonenumber);
+ }
+ if (TenantHelper.isEnable()) {
+ return userMapper.selectTenantUserByPhonenumber(phonenumber, tenantId);
+ }
+ return userMapper.selectUserByPhonenumber(phonenumber);
+ }
+
+}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
new file mode 100644
index 000000000..d0d4b433c
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java
@@ -0,0 +1,138 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.http.Method;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.domain.model.LoginUser;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.auth.SocialGroup;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.utils.SocialUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysSocialService;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 第三方授权策略
+ *
+ * @author thiszhc is 三三
+ */
+@Slf4j
+@Service("social" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class SocialAuthStrategy implements IAuthStrategy {
+
+ private final SocialProperties socialProperties;
+ private final ISysSocialService sysSocialService;
+ private final SysUserMapper userMapper;
+ private final SysLoginService loginService;
+
+
+ @Override
+ public void validate(LoginBody loginBody) {
+ ValidatorUtils.validate(loginBody, SocialGroup.class);
+ }
+
+ /**
+ * 登录-第三方授权登录
+ *
+ * @param clientId 客户端id
+ * @param loginBody 登录信息
+ * @param client 客户端信息
+ */
+ @Override
+ public LoginVo login(String clientId, LoginBody loginBody, SysClient client) {
+ AuthResponse response = SocialUtils.loginAuth(loginBody, socialProperties);
+ if (!response.ok()) {
+ throw new ServiceException(response.getMsg());
+ }
+ AuthUser authUserData = response.getData();
+ if ("GITEE".equals(authUserData.getSource())) {
+ // 如用户使用 gitee 登录顺手 star 给作者一点支持 拒绝白嫖
+ HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Vue-Plus")
+ .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
+ .executeAsync();
+ HttpUtil.createRequest(Method.PUT, "https://gitee.com/api/v5/user/starred/dromara/RuoYi-Cloud-Plus")
+ .formStr(MapUtil.of("access_token", authUserData.getToken().getAccessToken()))
+ .executeAsync();
+ }
+
+ SysSocialVo social = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid());
+ if (!ObjectUtil.isNotNull(social)) {
+ throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!");
+ }
+ // 验证授权表里面的租户id是否包含当前租户id
+ String tenantId = social.getTenantId();
+ if (ObjectUtil.isNotNull(social) && StrUtil.isNotBlank(tenantId)
+ && !tenantId.contains(loginBody.getTenantId())) {
+ throw new ServiceException("对不起,你没有权限登录当前租户!");
+ }
+
+ // 查找用户
+ SysUserVo user = loadUser(tenantId, social.getUserId());
+
+ // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
+ LoginUser loginUser = loginService.buildLoginUser(user);
+ SaLoginModel model = new SaLoginModel();
+ model.setDevice(client.getDeviceType());
+ // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
+ // 例如: 后台用户30分钟过期 app用户1天过期
+ model.setTimeout(client.getTimeout());
+ model.setActiveTimeout(client.getActiveTimeout());
+ model.setExtra(LoginHelper.CLIENT_KEY, clientId);
+ // 生成token
+ LoginHelper.login(loginUser, model);
+
+ loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
+ loginService.recordLoginInfo(user.getUserId());
+
+ LoginVo loginVo = new LoginVo();
+ loginVo.setAccessToken(StpUtil.getTokenValue());
+ loginVo.setExpireIn(StpUtil.getTokenTimeout());
+ loginVo.setClientId(clientId);
+ return loginVo;
+ }
+
+ private SysUserVo loadUser(String tenantId, Long userId) {
+ SysUser user = userMapper.selectOne(new LambdaQueryWrapper()
+ .select(SysUser::getUserName, SysUser::getStatus)
+ .eq(TenantHelper.isEnable(), SysUser::getTenantId, tenantId)
+ .eq(SysUser::getUserId, userId));
+ if (ObjectUtil.isNull(user)) {
+ log.info("登录用户:{} 不存在.", "");
+ throw new UserException("user.not.exists", "");
+ } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+ log.info("登录用户:{} 已被停用.", "");
+ throw new UserException("user.blocked", "");
+ }
+ if (TenantHelper.isEnable()) {
+ return userMapper.selectTenantUserByUserName(user.getUserName(), tenantId);
+ }
+ return userMapper.selectUserByUserName(user.getUserName());
+ }
+
+}
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
new file mode 100644
index 000000000..5a6f43ab4
--- /dev/null
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
@@ -0,0 +1,93 @@
+package org.dromara.web.service.impl;
+
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.domain.model.XcxLoginUser;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.utils.MessageUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.core.validate.auth.WechatGroup;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.web.domain.vo.LoginVo;
+import org.dromara.web.service.IAuthStrategy;
+import org.dromara.web.service.SysLoginService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 邮件认证策略
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@Service("xcx" + IAuthStrategy.BASE_NAME)
+@RequiredArgsConstructor
+public class XcxAuthStrategy implements IAuthStrategy {
+
+ private final SysLoginService loginService;
+
+ @Override
+ public void validate(LoginBody loginBody) {
+ ValidatorUtils.validate(loginBody, WechatGroup.class);
+ }
+
+ @Override
+ public LoginVo login(String clientId, LoginBody loginBody, SysClient client) {
+ // xcxCode 为 小程序调用 wx.login 授权后获取
+ String xcxCode = loginBody.getXcxCode();
+ // todo 以下自行实现
+ // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
+ String openid = "";
+ // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
+ SysUserVo user = loadUserByOpenid(openid);
+
+ // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
+ XcxLoginUser loginUser = new XcxLoginUser();
+ loginUser.setTenantId(user.getTenantId());
+ loginUser.setUserId(user.getUserId());
+ loginUser.setUsername(user.getUserName());
+ loginUser.setUserType(user.getUserType());
+ loginUser.setOpenid(openid);
+
+ SaLoginModel model = new SaLoginModel();
+ model.setDevice(client.getDeviceType());
+ // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置
+ // 例如: 后台用户30分钟过期 app用户1天过期
+ model.setTimeout(client.getTimeout());
+ model.setActiveTimeout(client.getActiveTimeout());
+ model.setExtra(LoginHelper.CLIENT_KEY, clientId);
+ // 生成token
+ LoginHelper.login(loginUser, model);
+
+ loginService.recordLogininfor(loginUser.getTenantId(), user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
+ loginService.recordLoginInfo(user.getUserId());
+
+ LoginVo loginVo = new LoginVo();
+ loginVo.setAccessToken(StpUtil.getTokenValue());
+ loginVo.setExpireIn(StpUtil.getTokenTimeout());
+ loginVo.setClientId(clientId);
+ loginVo.setOpenid(openid);
+ return loginVo;
+ }
+
+ private SysUserVo loadUserByOpenid(String openid) {
+ // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
+ // todo 自行实现 userService.selectUserByOpenid(openid);
+ SysUserVo user = new SysUserVo();
+ if (ObjectUtil.isNull(user)) {
+ log.info("登录用户:{} 不存在.", openid);
+ // todo 用户不存在 业务逻辑自行实现
+ } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+ log.info("登录用户:{} 已被停用.", openid);
+ // todo 用户已被停用 业务逻辑自行实现
+ }
+ return user;
+ }
+
+}
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
index fef1fa054..dbe2482d2 100644
--- a/ruoyi-admin/src/main/resources/application-dev.yml
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -8,27 +8,21 @@ spring.boot.admin.client:
username: ruoyi
password: 123456
---- # xxl-job 配置
-xxl.job:
- # 执行器开关
- enabled: true
- # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
- admin-addresses: http://localhost:9100/xxl-job-admin
- # 执行器通讯TOKEN:非空时启用
- access-token: xxl-job
- executor:
- # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册
- appname: xxl-job-executor
- # 执行器端口号 执行器从9101开始往后写
- port: 9101
- # 执行器注册:默认IP:PORT
- address:
- # 执行器IP:默认自动获取IP
- ip:
- # 执行器运行日志文件存储磁盘路径
- logpath: ./logs/xxl-job
- # 执行器日志文件保存天数:大于3生效
- logretentiondays: 30
+--- # powerjob 配置
+powerjob:
+ worker:
+ # 如何开启调度中心请查看文档教程
+ enabled: false
+ # 需要先在 powerjob 登录页执行应用注册后才能使用
+ app-name: ruoyi-worker
+ enable-test-mode: false
+ max-appended-wf-context-length: 4096
+ max-result-length: 4096
+ # 28080 端口 随着主应用端口飘逸 避免集群冲突
+ port: 2${server.port}
+ protocol: http
+ server-address: 127.0.0.1:7700
+ store-strategy: disk
--- # 数据源配置
spring:
@@ -130,7 +124,7 @@ spring.data:
# 连接超时时间
timeout: 10s
# 是否开启ssl
- ssl: false
+ ssl.enabled: false
redisson:
# redis key前缀
@@ -176,14 +170,100 @@ mail:
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout: 0
---- # sms 短信
+--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
+# https://wind.kim/doc/start 文档地址 各个厂商可同时使用
sms:
- enabled: false
# 阿里云 dysmsapi.aliyuncs.com
- # 腾讯云 sms.tencentcloudapi.com
- endpoint: "dysmsapi.aliyuncs.com"
- accessKeyId: xxxxxxx
- accessKeySecret: xxxxxx
- signName: 测试
- # 腾讯专用
- sdkAppId:
+ alibaba:
+ #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
+ requestUrl: dysmsapi.aliyuncs.com
+ #阿里云的accessKey
+ accessKeyId: xxxxxxx
+ #阿里云的accessKeySecret
+ accessKeySecret: xxxxxxx
+ #短信签名
+ signature: 测试
+ tencent:
+ #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置
+ requestUrl: sms.tencentcloudapi.com
+ #腾讯云的accessKey
+ accessKeyId: xxxxxxx
+ #腾讯云的accessKeySecret
+ accessKeySecret: xxxxxxx
+ #短信签名
+ signature: 测试
+ #短信sdkAppId
+ sdkAppId: appid
+ #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
+ territory: ap-guangzhou
+
+
+--- # 三方授权
+justauth:
+ enabled: true
+ # 前端外网访问地址
+ address: http://localhost:80
+ type:
+ maxkey:
+ # maxkey 服务器地址
+ # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
+ server-url: http://sso.maxkey.top
+ client-id: 876892492581044224
+ client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
+ redirect-uri: ${justauth.address}/social-callback?source=maxkey
+ qq:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=qq
+ union-id: false
+ weibo:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=weibo
+ gitee:
+ client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
+ client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
+ redirect-uri: ${justauth.address}/social-callback?source=gitee
+ dingtalk:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=dingtalk
+ baidu:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=baidu
+ csdn:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=csdn
+ coding:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=coding
+ coding-group-name: xx
+ oschina:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=oschina
+ alipay:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=alipay
+ alipay-public-key: MIIB**************DAQAB
+ wechat_open:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_open
+ wechat_mp:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
+ wechat_enterprise:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
+ agent-id: 1000002
+ gitlab:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=gitlab
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
index fb76f2d82..59e341645 100644
--- a/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -11,27 +11,21 @@ spring.boot.admin.client:
username: ruoyi
password: 123456
---- # xxl-job 配置
-xxl.job:
- # 执行器开关
- enabled: true
- # 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
- admin-addresses: http://localhost:9100/xxl-job-admin
- # 执行器通讯TOKEN:非空时启用
- access-token: xxl-job
- executor:
- # 执行器AppName:执行器心跳注册分组依据;为空则关闭自动注册
- appname: xxl-job-executor
- # 执行器端口号 执行器从9101开始往后写
- port: 9101
- # 执行器注册:默认IP:PORT
- address:
- # 执行器IP:默认自动获取IP
- ip:
- # 执行器运行日志文件存储磁盘路径
- logpath: ./logs/xxl-job
- # 执行器日志文件保存天数:大于3生效
- logretentiondays: 30
+--- # powerjob 配置
+powerjob:
+ worker:
+ # 如何开启调度中心请查看文档教程
+ enabled: false
+ # 需要先在 powerjob 登录页执行应用注册后才能使用
+ app-name: ruoyi-worker
+ enable-test-mode: false
+ max-appended-wf-context-length: 4096
+ max-result-length: 4096
+ # 28080 端口 随着主应用端口飘逸 避免集群冲突
+ port: 2${server.port}
+ protocol: http
+ server-address: 127.0.0.1:7700
+ store-strategy: disk
--- # 数据源配置
spring:
@@ -133,7 +127,7 @@ spring.data:
# 连接超时时间
timeout: 10s
# 是否开启ssl
- ssl: false
+ ssl.enabled: false
redisson:
# redis key前缀
@@ -179,14 +173,99 @@ mail:
# Socket连接超时值,单位毫秒,缺省值不超时
connectionTimeout: 0
---- # sms 短信
+--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
+# https://wind.kim/doc/start 文档地址 各个厂商可同时使用
sms:
- enabled: false
# 阿里云 dysmsapi.aliyuncs.com
- # 腾讯云 sms.tencentcloudapi.com
- endpoint: "dysmsapi.aliyuncs.com"
- accessKeyId: xxxxxxx
- accessKeySecret: xxxxxx
- signName: 测试
- # 腾讯专用
- sdkAppId:
+ alibaba:
+ #请求地址 默认为 dysmsapi.aliyuncs.com 如无特殊改变可以不用设置
+ requestUrl: dysmsapi.aliyuncs.com
+ #阿里云的accessKey
+ accessKeyId: xxxxxxx
+ #阿里云的accessKeySecret
+ accessKeySecret: xxxxxxx
+ #短信签名
+ signature: 测试
+ tencent:
+ #请求地址默认为 sms.tencentcloudapi.com 如无特殊改变可不用设置
+ requestUrl: sms.tencentcloudapi.com
+ #腾讯云的accessKey
+ accessKeyId: xxxxxxx
+ #腾讯云的accessKeySecret
+ accessKeySecret: xxxxxxx
+ #短信签名
+ signature: 测试
+ #短信sdkAppId
+ sdkAppId: appid
+ #地域信息默认为 ap-guangzhou 如无特殊改变可不用设置
+ territory: ap-guangzhou
+
+--- # 三方授权
+justauth:
+ enabled: true
+ # 前端外网访问地址
+ address: http://localhost:80
+ type:
+ maxkey:
+ # maxkey 服务器地址
+ # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
+ server-url: http://sso.maxkey.top
+ client-id: 876892492581044224
+ client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
+ redirect-uri: ${justauth.address}/social-callback?source=maxkey
+ qq:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=qq
+ union-id: false
+ weibo:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=weibo
+ gitee:
+ client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
+ client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
+ redirect-uri: ${justauth.address}/social-callback?source=gitee
+ dingtalk:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=dingtalk
+ baidu:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=baidu
+ csdn:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=csdn
+ coding:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=coding
+ coding-group-name: xx
+ oschina:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=oschina
+ alipay:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=alipay
+ alipay-public-key: MIIB**************DAQAB
+ wechat_open:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_open
+ wechat_mp:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
+ wechat_enterprise:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
+ agent-id: 1000002
+ gitlab:
+ client-id: 10**********6
+ client-secret: 1f7d08**********5b7**********29e
+ redirect-uri: ${justauth.address}/social-callback?source=gitlab
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
index 31d0de5ff..616446d27 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -96,20 +96,15 @@ spring:
sa-token:
# token名称 (同时也是cookie名称)
token-name: Authorization
- # token有效期 设为一天 (必定过期) 单位: 秒
- timeout: 86400
- # token临时有效期 (指定时间无操作就过期) 单位: 秒
- activity-timeout: 1800
+ # token固定超时 设为七天 (必定过期) 单位: 秒
+ timeout: 604800
+ # 多端不同 token 有效期 可查看 LoginHelper.loginByDevice 方法自定义
+ # token最低活跃时间 (指定时间无操作就过期) 单位: 秒
+ active-timeout: 1800
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true
# 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false
- # 是否尝试从header里读取token
- is-read-header: true
- # 是否尝试从cookie里读取token
- is-read-cookie: false
- # token前缀
- token-prefix: "Bearer"
# jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz
@@ -145,6 +140,7 @@ tenant:
- sys_role_menu
- sys_user_post
- sys_user_role
+ - sys_client
# MyBatisPlus配置
# https://baomidou.com/config/
@@ -156,39 +152,12 @@ mybatis-plus:
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 实体扫描,多个package用逗号或者分号分隔
typeAliasesPackage: org.dromara.**.domain
- # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
- checkConfigLocation: false
- configuration:
- # 自动驼峰命名规则(camel case)映射
- mapUnderscoreToCamelCase: true
- # MyBatis 自动映射策略
- # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
- autoMappingBehavior: FULL
- # MyBatis 自动映射时未知列或未知属性处理策
- # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
- autoMappingUnknownColumnBehavior: NONE
- # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
- # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
- # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
- logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
global-config:
- # 是否打印 Logo banner
- banner: true
dbConfig:
# 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
+ # 如需改为自增 需要将数据库表全部设置为自增
idType: ASSIGN_ID
- # 逻辑已删除值
- logicDeleteValue: 2
- # 逻辑未删除值
- logicNotDeleteValue: 0
- # 字段验证策略之 insert,在 insert 的时候的字段验证策略
- # IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL
- insertStrategy: NOT_NULL
- # 字段验证策略之 update,在 update 的时候的字段验证策略
- updateStrategy: NOT_NULL
- # 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
- where-strategy: NOT_NULL
# 数据加密
mybatis-encryptor:
@@ -204,8 +173,23 @@ mybatis-encryptor:
publicKey:
privateKey:
-# Swagger配置
-swagger:
+# api接口加密
+api-decrypt:
+ # 是否开启全局接口加密
+ enabled: true
+ # AES 加密头标识
+ headerFlag: encrypt-key
+ # 公私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换
+ publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
+ privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
+
+springdoc:
+ api-docs:
+ # 是否开启接口文档
+ enabled: true
+# swagger-ui:
+# # 持久化认证数据
+# persistAuthorization: true
info:
# 标题
title: '标题:${ruoyi.name}多租户管理系统_接口文档'
@@ -225,14 +209,6 @@ swagger:
type: APIKEY
in: HEADER
name: ${sa-token.token-name}
-
-springdoc:
- api-docs:
- # 是否开启接口文档
- enabled: true
- swagger-ui:
- # 持久化认证数据
- persistAuthorization: true
#这里定义了两个分组,可定义多个,也可以不定义
group-configs:
- group: 1.演示模块
@@ -285,6 +261,6 @@ management:
websocket:
enabled: true
# 路径
- path: /websocket
+ path: /resource/websocket
# 设置访问源地址
allowedOrigins: '*'
diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties
index 4f2da28b4..5c9f42271 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -28,6 +28,9 @@ user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
+auth.grant.type.error=认证权限类型错误
+auth.grant.type.not.blank=认证权限类型不能为空
+auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小! 允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
index 0c738a37e..2ab82a667 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties
@@ -28,6 +28,9 @@ user.register.error=Register failed, please contact system administrator
user.notfound=Please login again
user.forcelogout=The administrator is forced to exit,please login again
user.unknown.error=Unknown error, please login again
+auth.grant.type.error=Auth grant type error
+auth.grant.type.not.blank=Auth grant type cannot be blank
+auth.clientid.not.blank=Auth clientid cannot be blank
##文件上传消息
upload.exceed.maxSize=The uploaded file size exceeds the limit file size! the maximum allowed file size is:{0}MB!
upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters
diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
index 4f2da28b4..5c9f42271 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
+++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties
@@ -28,6 +28,9 @@ user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录
+auth.grant.type.error=认证权限类型错误
+auth.grant.type.not.blank=认证权限类型不能为空
+auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小! 允许的文件最大大小是:{0}MB!
upload.filename.exceed.length=上传的文件名最长{0}个字符
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index 0428aea78..45493d3e9 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -11,6 +11,7 @@
ruoyi-common-bom
+ ruoyi-common-social
ruoyi-common-core
ruoyi-common-doc
ruoyi-common-excel
diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml
index ae16451ad..ef8afda50 100644
--- a/ruoyi-common/ruoyi-common-bom/pom.xml
+++ b/ruoyi-common/ruoyi-common-bom/pom.xml
@@ -14,7 +14,7 @@
- 5.0.0
+ 5.1.0-BETA
@@ -117,6 +117,12 @@
${revision}
+
+ org.dromara
+ ruoyi-common-social
+ ${revision}
+
+
org.dromara
@@ -165,6 +171,7 @@
ruoyi-common-websocket
${revision}
+
diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml
index 8f3740fd9..33f9f7fc4 100644
--- a/ruoyi-common/ruoyi-common-core/pom.xml
+++ b/ruoyi-common/ruoyi-common-core/pom.xml
@@ -34,6 +34,11 @@
spring-boot-starter-validation
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
org.apache.commons
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
index de9a9bcaa..9a32afe55 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/AsyncConfig.java
@@ -2,16 +2,14 @@ package org.dromara.common.core.config;
import cn.hutool.core.util.ArrayUtil;
import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.Arrays;
import java.util.concurrent.Executor;
-import java.util.concurrent.ScheduledExecutorService;
/**
* 异步配置
@@ -22,16 +20,12 @@ import java.util.concurrent.ScheduledExecutorService;
@AutoConfiguration
public class AsyncConfig implements AsyncConfigurer {
- @Autowired
- @Qualifier("scheduledExecutorService")
- private ScheduledExecutorService scheduledExecutorService;
-
/**
* 自定义 @Async 注解使用系统线程池
*/
@Override
public Executor getAsyncExecutor() {
- return scheduledExecutorService;
+ return SpringUtils.getBean("scheduledExecutorService");
}
/**
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java
index 00825c2fd..45c5bd13c 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java
@@ -22,18 +22,19 @@ public class ValidatorConfig {
*/
@Bean
public Validator validator(MessageSource messageSource) {
- LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
- // 国际化
- factoryBean.setValidationMessageSource(messageSource);
- // 设置使用 HibernateValidator 校验器
- factoryBean.setProviderClass(HibernateValidator.class);
- Properties properties = new Properties();
- // 设置 快速异常返回
- properties.setProperty("hibernate.validator.fail_fast", "true");
- factoryBean.setValidationProperties(properties);
- // 加载配置
- factoryBean.afterPropertiesSet();
- return factoryBean.getValidator();
+ try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
+ // 国际化
+ factoryBean.setValidationMessageSource(messageSource);
+ // 设置使用 HibernateValidator 校验器
+ factoryBean.setProviderClass(HibernateValidator.class);
+ Properties properties = new Properties();
+ // 设置 快速异常返回
+ properties.setProperty("hibernate.validator.fail_fast", "true");
+ factoryBean.setValidationProperties(properties);
+ // 加载配置
+ factoryBean.afterPropertiesSet();
+ return factoryBean.getValidator();
+ }
}
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
index 38593a33d..ae9bc2e62 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java
@@ -31,4 +31,9 @@ public interface GlobalConstants {
* 登录账户密码错误次数 redis key
*/
String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:";
+
+ /**
+ * 三方认证 redis key
+ */
+ String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java
index 73f678cc9..cdff7738b 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java
@@ -1,7 +1,9 @@
package org.dromara.common.core.domain.model;
+import jakarta.validation.constraints.Email;
import org.dromara.common.core.constant.UserConstants;
import lombok.Data;
+import org.dromara.common.core.validate.auth.*;
import org.hibernate.validator.constraints.Length;
import jakarta.validation.constraints.NotBlank;
@@ -15,6 +17,28 @@ import jakarta.validation.constraints.NotBlank;
@Data
public class LoginBody {
+ /**
+ * 客户端id
+ */
+ @NotBlank(message = "{auth.clientid.not.blank}")
+ private String clientId;
+
+ /**
+ * 客户端key
+ */
+ private String clientKey;
+
+ /**
+ * 客户端秘钥
+ */
+ private String clientSecret;
+
+ /**
+ * 授权类型
+ */
+ @NotBlank(message = "{auth.grant.type.not.blank}")
+ private String grantType;
+
/**
* 租户ID
*/
@@ -24,15 +48,15 @@ public class LoginBody {
/**
* 用户名
*/
- @NotBlank(message = "{user.username.not.blank}")
- @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}")
+ @NotBlank(message = "{user.username.not.blank}", groups = {PasswordGroup.class})
+ @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}", groups = {PasswordGroup.class})
private String username;
/**
* 用户密码
*/
- @NotBlank(message = "{user.password.not.blank}")
- @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}")
+ @NotBlank(message = "{user.password.not.blank}", groups = {PasswordGroup.class})
+ @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}", groups = {PasswordGroup.class})
private String password;
/**
@@ -45,4 +69,52 @@ public class LoginBody {
*/
private String uuid;
+ /**
+ * 手机号
+ */
+ @NotBlank(message = "{user.phonenumber.not.blank}", groups = {SmsGroup.class})
+ private String phonenumber;
+
+ /**
+ * 短信code
+ */
+ @NotBlank(message = "{sms.code.not.blank}", groups = {SmsGroup.class})
+ private String smsCode;
+
+ /**
+ * 邮箱
+ */
+ @NotBlank(message = "{user.email.not.blank}", groups = {EmailGroup.class})
+ @Email(message = "{user.email.not.valid}")
+ private String email;
+
+ /**
+ * 邮箱code
+ */
+ @NotBlank(message = "{email.code.not.blank}", groups = {EmailGroup.class})
+ private String emailCode;
+
+ /**
+ * 小程序code
+ */
+ @NotBlank(message = "{xcx.code.not.blank}", groups = {WechatGroup.class})
+ private String xcxCode;
+
+ /**
+ * 第三方登录平台
+ */
+ @NotBlank(message = "{social.source.not.blank}" , groups = {SocialGroup.class})
+ private String source;
+
+ /**
+ * 第三方登录code
+ */
+ @NotBlank(message = "{social.code.not.blank}" , groups = {SocialGroup.class})
+ private String socialCode;
+
+ /**
+ * 第三方登录socialState
+ */
+ @NotBlank(message = "{social.state.not.blank}" , groups = {SocialGroup.class})
+ private String socialState;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLogin.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLogin.java
new file mode 100644
index 000000000..5666bce56
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLogin.java
@@ -0,0 +1,21 @@
+package org.dromara.common.core.domain.model;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * 第三方登录用户身份权限
+ *
+ * @author thiszhc is 三三
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+public class SocialLogin extends LoginUser{
+
+ /**
+ * openid
+ */
+ private String openid;
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java
index 09bf44b6d..dbadfc2de 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java
@@ -26,7 +26,12 @@ public enum DeviceType {
/**
* 小程序端
*/
- XCX("xcx");
+ XCX("xcx"),
+
+ /**
+ * social第三方端
+ */
+ SOCIAL("social");
private final String device;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/GlobalException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/GlobalException.java
index 6b404e600..76b1265d7 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/GlobalException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/GlobalException.java
@@ -1,5 +1,10 @@
package org.dromara.common.core.exception;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
import java.io.Serial;
/**
@@ -7,6 +12,10 @@ import java.io.Serial;
*
* @author ruoyi
*/
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
public class GlobalException extends RuntimeException {
@Serial
@@ -22,12 +31,6 @@ public class GlobalException extends RuntimeException {
*/
private String detailMessage;
- /**
- * 空构造方法,避免反序列化问题
- */
- public GlobalException() {
- }
-
public GlobalException(String message) {
this.message = message;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
index 712e6e7e6..4fb097a88 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java
@@ -1,5 +1,10 @@
package org.dromara.common.core.exception;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
import java.io.Serial;
/**
@@ -7,6 +12,10 @@ import java.io.Serial;
*
* @author ruoyi
*/
+@Data
+@EqualsAndHashCode(callSuper = true)
+@NoArgsConstructor
+@AllArgsConstructor
public final class ServiceException extends RuntimeException {
@Serial
@@ -27,12 +36,6 @@ public final class ServiceException extends RuntimeException {
*/
private String detailMessage;
- /**
- * 空构造方法,避免反序列化问题
- */
- public ServiceException() {
- }
-
public ServiceException(String message) {
this.message = message;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java
index 28acafd15..40ce01ba8 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java
@@ -1,5 +1,6 @@
package org.dromara.common.core.exception.base;
+import lombok.AllArgsConstructor;
import org.dromara.common.core.utils.MessageUtils;
import org.dromara.common.core.utils.StringUtils;
import lombok.Data;
@@ -16,6 +17,7 @@ import java.io.Serial;
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
+@AllArgsConstructor
public class BaseException extends RuntimeException {
@Serial
@@ -41,13 +43,6 @@ public class BaseException extends RuntimeException {
*/
private 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) {
this(module, code, args, null);
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java
new file mode 100644
index 000000000..af61b90ca
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java
@@ -0,0 +1,31 @@
+package org.dromara.common.core.factory;
+
+import org.dromara.common.core.utils.StringUtils;
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.env.PropertiesPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.support.DefaultPropertySourceFactory;
+import org.springframework.core.io.support.EncodedResource;
+
+import java.io.IOException;
+
+/**
+ * yml 配置源工厂
+ *
+ * @author Lion Li
+ */
+public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
+
+ @Override
+ public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException {
+ String sourceName = resource.getResource().getFilename();
+ if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) {
+ YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
+ factory.setResources(resource.getResource());
+ factory.afterPropertiesSet();
+ return new PropertiesPropertySource(sourceName, factory.getObject());
+ }
+ return super.createPropertySource(name, resource);
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java
index 04d0f9b05..b78a7f257 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java
@@ -1,5 +1,7 @@
package org.dromara.common.core.service;
+import java.util.Map;
+
/**
* 通用 字典服务
*
@@ -54,4 +56,12 @@ public interface DictService {
*/
String getDictValue(String dictType, String dictLabel, String separator);
+ /**
+ * 获取字典下所有的字典值与标签
+ *
+ * @param dictType 字典类型
+ * @return dictValue为key,dictLabel为值组成的Map
+ */
+ Map getAllDictByDictType(String dictType);
+
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java
index 6f3729b98..48dfc08d7 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java
@@ -3,6 +3,7 @@ package org.dromara.common.core.utils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.context.MessageSource;
+import org.springframework.context.NoSuchMessageException;
import org.springframework.context.i18n.LocaleContextHolder;
/**
@@ -23,6 +24,10 @@ public class MessageUtils {
* @return 获取国际化翻译值
*/
public static String message(String code, Object... args) {
- return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
+ try {
+ return MESSAGE_SOURCE.getMessage(code, args, LocaleContextHolder.getLocale());
+ } catch (NoSuchMessageException e) {
+ return code;
+ }
}
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
index 91e2990bd..a1316eb85 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java
@@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpSession;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.http.MediaType;
+import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@@ -19,6 +20,7 @@ import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@@ -101,14 +103,22 @@ public class ServletUtils extends JakartaServletUtil {
* 获取request
*/
public static HttpServletRequest getRequest() {
- return getRequestAttributes().getRequest();
+ try {
+ return getRequestAttributes().getRequest();
+ } catch (Exception e) {
+ return null;
+ }
}
/**
* 获取response
*/
public static HttpServletResponse getResponse() {
- return getRequestAttributes().getResponse();
+ try {
+ return getRequestAttributes().getResponse();
+ } catch (Exception e) {
+ return null;
+ }
}
/**
@@ -119,8 +129,33 @@ public class ServletUtils extends JakartaServletUtil {
}
public static ServletRequestAttributes getRequestAttributes() {
- RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
- return (ServletRequestAttributes) attributes;
+ try {
+ RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+ return (ServletRequestAttributes) attributes;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static String getHeader(HttpServletRequest request, String name) {
+ String value = request.getHeader(name);
+ if (StringUtils.isEmpty(value)) {
+ return StringUtils.EMPTY;
+ }
+ return urlDecode(value);
+ }
+
+ public static Map getHeaders(HttpServletRequest request) {
+ Map map = new LinkedCaseInsensitiveMap<>();
+ Enumeration enumeration = request.getHeaderNames();
+ if (enumeration != null) {
+ while (enumeration.hasMoreElements()) {
+ String key = enumeration.nextElement();
+ String value = request.getHeader(key);
+ map.put(key, value);
+ }
+ }
+ return map;
}
/**
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
index d9dcb401b..967612ef9 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java
@@ -72,7 +72,7 @@ public class StreamUtils {
return CollUtil.newArrayList();
}
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
- return collection.stream().sorted(comparing).collect(Collectors.toList());
+ return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
}
/**
@@ -89,7 +89,7 @@ public class StreamUtils {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
- return collection.stream().collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
+ return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
}
/**
@@ -108,7 +108,7 @@ public class StreamUtils {
if (CollUtil.isEmpty(collection)) {
return MapUtil.newHashMap();
}
- return collection.stream().collect(Collectors.toMap(key, value, (l, r) -> l));
+ return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
}
/**
@@ -126,7 +126,7 @@ public class StreamUtils {
return MapUtil.newHashMap();
}
return collection
- .stream()
+ .stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
}
@@ -147,7 +147,7 @@ public class StreamUtils {
return MapUtil.newHashMap();
}
return collection
- .stream()
+ .stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
}
@@ -168,7 +168,7 @@ public class StreamUtils {
return MapUtil.newHashMap();
}
return collection
- .stream()
+ .stream().filter(Objects::nonNull)
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/EmailGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/EmailGroup.java
new file mode 100644
index 000000000..130932f4a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/EmailGroup.java
@@ -0,0 +1,7 @@
+package org.dromara.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface EmailGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/PasswordGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/PasswordGroup.java
new file mode 100644
index 000000000..1516172ad
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/PasswordGroup.java
@@ -0,0 +1,7 @@
+package org.dromara.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface PasswordGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/SmsGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/SmsGroup.java
new file mode 100644
index 000000000..d56286027
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/SmsGroup.java
@@ -0,0 +1,7 @@
+package org.dromara.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface SmsGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/SocialGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/SocialGroup.java
new file mode 100644
index 000000000..2b19ffe30
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/SocialGroup.java
@@ -0,0 +1,4 @@
+package org.dromara.common.core.validate.auth;
+
+public interface SocialGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/WechatGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/WechatGroup.java
new file mode 100644
index 000000000..b397f1870
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/auth/WechatGroup.java
@@ -0,0 +1,7 @@
+package org.dromara.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface WechatGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
similarity index 86%
rename from ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java
rename to ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
index 459941c97..069ef9ac8 100644
--- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SwaggerConfig.java
+++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java
@@ -1,13 +1,13 @@
package org.dromara.common.doc.config;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.doc.config.properties.SwaggerProperties;
-import org.dromara.common.doc.handler.OpenApiHandler;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.doc.config.properties.SpringDocProperties;
+import org.dromara.common.doc.handler.OpenApiHandler;
import org.springdoc.core.configuration.SpringDocConfiguration;
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
import org.springdoc.core.customizers.OpenApiCustomizer;
@@ -36,26 +36,26 @@ import java.util.Set;
*/
@RequiredArgsConstructor
@AutoConfiguration(before = SpringDocConfiguration.class)
-@EnableConfigurationProperties(SwaggerProperties.class)
+@EnableConfigurationProperties(SpringDocProperties.class)
@ConditionalOnProperty(name = "springdoc.api-docs.enabled", havingValue = "true", matchIfMissing = true)
-public class SwaggerConfig {
+public class SpringDocConfig {
private final ServerProperties serverProperties;
@Bean
@ConditionalOnMissingBean(OpenAPI.class)
- public OpenAPI openApi(SwaggerProperties swaggerProperties) {
+ public OpenAPI openApi(SpringDocProperties properties) {
OpenAPI openApi = new OpenAPI();
// 文档基本信息
- SwaggerProperties.InfoProperties infoProperties = swaggerProperties.getInfo();
+ SpringDocProperties.InfoProperties infoProperties = properties.getInfo();
Info info = convertInfo(infoProperties);
openApi.info(info);
// 扩展文档信息
- openApi.externalDocs(swaggerProperties.getExternalDocs());
- openApi.tags(swaggerProperties.getTags());
- openApi.paths(swaggerProperties.getPaths());
- openApi.components(swaggerProperties.getComponents());
- Set keySet = swaggerProperties.getComponents().getSecuritySchemes().keySet();
+ openApi.externalDocs(properties.getExternalDocs());
+ openApi.tags(properties.getTags());
+ openApi.paths(properties.getPaths());
+ openApi.components(properties.getComponents());
+ Set keySet = properties.getComponents().getSecuritySchemes().keySet();
List list = new ArrayList<>();
SecurityRequirement securityRequirement = new SecurityRequirement();
keySet.forEach(securityRequirement::addList);
@@ -65,7 +65,7 @@ public class SwaggerConfig {
return openApi;
}
- private Info convertInfo(SwaggerProperties.InfoProperties infoProperties) {
+ private Info convertInfo(SpringDocProperties.InfoProperties infoProperties) {
Info info = new Info();
info.setTitle(infoProperties.getTitle());
info.setDescription(infoProperties.getDescription());
diff --git a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java
similarity index 95%
rename from ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java
rename to ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java
index 9e08e7398..eae3b4c62 100644
--- a/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SwaggerProperties.java
+++ b/ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java
@@ -18,8 +18,8 @@ import java.util.List;
* @author Lion Li
*/
@Data
-@ConfigurationProperties(prefix = "swagger")
-public class SwaggerProperties {
+@ConfigurationProperties(prefix = "springdoc")
+public class SpringDocProperties {
/**
* 文档基本信息
diff --git a/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index e64b2eb3f..fe11e76e7 100644
--- a/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1 +1 @@
-org.dromara.common.doc.config.SwaggerConfig
+org.dromara.common.doc.config.SpringDocConfig
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java
index ba0b95876..d357d72a4 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java
@@ -32,7 +32,7 @@ public @interface EncryptField {
String publicKey() default "";
/**
- * 公钥。RSA、SM2需要
+ * 私钥。RSA、SM2需要
*/
String privateKey() default "";
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java
new file mode 100644
index 000000000..098f6bc8d
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java
@@ -0,0 +1,32 @@
+package org.dromara.common.encrypt.config;
+
+import jakarta.servlet.DispatcherType;
+import org.dromara.common.encrypt.filter.CryptoFilter;
+import org.dromara.common.encrypt.properties.ApiDecryptProperties;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * api 解密自动配置
+ *
+ * @author wdhcr
+ */
+@AutoConfiguration
+@EnableConfigurationProperties(ApiDecryptProperties.class)
+@ConditionalOnProperty(value = "api-decrypt.enabled", havingValue = "true")
+public class ApiDecryptAutoConfiguration {
+
+ @Bean
+ public FilterRegistrationBean cryptoFilterRegistration(ApiDecryptProperties properties) {
+ FilterRegistrationBean registration = new FilterRegistrationBean<>();
+ registration.setDispatcherTypes(DispatcherType.REQUEST);
+ registration.setFilter(new CryptoFilter(properties));
+ registration.addUrlPatterns("/*");
+ registration.setName("cryptoFilter");
+ registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
+ return registration;
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java
new file mode 100644
index 000000000..c31e025ac
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java
@@ -0,0 +1,49 @@
+package org.dromara.common.encrypt.filter;
+
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.properties.ApiDecryptProperties;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+
+import java.io.IOException;
+
+
+/**
+ * Crypto 过滤器
+ *
+ * @author wdhcr
+ */
+public class CryptoFilter implements Filter {
+ private final ApiDecryptProperties properties;
+
+ public CryptoFilter(ApiDecryptProperties properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ ServletRequest requestWrapper = null;
+ HttpServletRequest servletRequest = (HttpServletRequest) request;
+ // 是否为 json 请求
+ if (StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) {
+ // 是否为 put 或者 post 请求
+ if (HttpMethod.PUT.matches(servletRequest.getMethod()) || HttpMethod.POST.matches(servletRequest.getMethod())) {
+ // 是否存在加密标头
+ String headerValue = servletRequest.getHeader(properties.getHeaderFlag());
+ if (StringUtils.isNotBlank(headerValue)) {
+ requestWrapper = new DecryptRequestBodyWrapper(servletRequest, properties.getPublicKey(), properties.getPrivateKey(), properties.getHeaderFlag());
+ }
+ }
+ }
+
+ chain.doFilter(ObjectUtil.defaultIfNull(requestWrapper, request), response);
+ }
+
+ @Override
+ public void destroy() {
+
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java
new file mode 100644
index 000000000..fa9a31071
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java
@@ -0,0 +1,94 @@
+package org.dromara.common.encrypt.filter;
+
+import cn.hutool.core.io.IoUtil;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.encrypt.utils.EncryptUtils;
+import org.springframework.http.MediaType;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 解密请求参数工具类
+ *
+ * @author wdhcr
+ */
+public class DecryptRequestBodyWrapper extends HttpServletRequestWrapper {
+
+ private final byte[] body;
+
+ public DecryptRequestBodyWrapper(HttpServletRequest request, String publicKey, String privateKey, String headerFlag) throws IOException {
+ super(request);
+ // 获取 AES 密码 采用 RSA 加密
+ String headerRsa = request.getHeader(headerFlag);
+ String decryptAes = EncryptUtils.decryptByRsa(headerRsa, privateKey);
+ // 解密 AES 密码
+ String aesPassword = EncryptUtils.decryptByBase64(decryptAes);
+ request.setCharacterEncoding(Constants.UTF8);
+ byte[] readBytes = IoUtil.readBytes(request.getInputStream(), false);
+ String requestBody = new String(readBytes, StandardCharsets.UTF_8);
+ // 解密 body 采用 AES 加密
+ String decryptBody = EncryptUtils.decryptByAes(requestBody, aesPassword);
+ body = decryptBody.getBytes(StandardCharsets.UTF_8);
+ }
+
+ @Override
+ public BufferedReader getReader() {
+ return new BufferedReader(new InputStreamReader(getInputStream()));
+ }
+
+
+ @Override
+ public int getContentLength() {
+ return body.length;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return body.length;
+ }
+
+ @Override
+ public String getContentType() {
+ return MediaType.APPLICATION_JSON_VALUE;
+ }
+
+
+ @Override
+ public ServletInputStream getInputStream() {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(body);
+ return new ServletInputStream() {
+ @Override
+ public int read() {
+ return bais.read();
+ }
+
+ @Override
+ public int available() {
+ return body.length;
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public boolean isReady() {
+ return false;
+ }
+
+ @Override
+ public void setReadListener(ReadListener readListener) {
+
+ }
+ };
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java
index 774da8d54..7c2508f86 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java
@@ -1,6 +1,7 @@
package org.dromara.common.encrypt.interceptor;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -75,7 +76,7 @@ public class MybatisDecryptInterceptor implements Interceptor {
Set fields = encryptorManager.getFieldCache(sourceObject.getClass());
try {
for (Field field : fields) {
- field.set(sourceObject, this.decryptField(String.valueOf(field.get(sourceObject)), field));
+ field.set(sourceObject, this.decryptField(Convert.toStr(field.get(sourceObject)), field));
}
} catch (Exception e) {
log.error("处理解密字段时出错", e);
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java
index d16bc941f..152f7db40 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java
@@ -1,6 +1,7 @@
package org.dromara.common.encrypt.interceptor;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -84,7 +85,7 @@ public class MybatisEncryptInterceptor implements Interceptor {
Set fields = encryptorManager.getFieldCache(sourceObject.getClass());
try {
for (Field field : fields) {
- field.set(sourceObject, this.encryptField(String.valueOf(field.get(sourceObject)), field));
+ field.set(sourceObject, this.encryptField(Convert.toStr(field.get(sourceObject)), field));
}
} catch (Exception e) {
log.error("处理加密字段时出错", e);
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java
new file mode 100644
index 000000000..9e25b7b9a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java
@@ -0,0 +1,34 @@
+package org.dromara.common.encrypt.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * api解密属性配置类
+ * @author wdhcr
+ */
+@Data
+@ConfigurationProperties(prefix = "api-decrypt")
+public class ApiDecryptProperties {
+
+ /**
+ * 加密开关
+ */
+ private Boolean enabled;
+
+ /**
+ * 头部标识
+ */
+ private String headerFlag;
+
+
+ /**
+ * 公钥
+ */
+ private String publicKey;
+
+ /**
+ * 私钥
+ */
+ private String privateKey;
+}
diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index fe37589da..132cf295a 100644
--- a/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -1 +1,3 @@
org.dromara.common.encrypt.config.EncryptorAutoConfiguration
+org.dromara.common.encrypt.config.ApiDecryptAutoConfiguration
+
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java
index 3b5269540..b948ea7ee 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java
@@ -37,14 +37,26 @@ public class ExcelEnumConvert implements Converter {
@Override
public Object convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
- Object codeValue = cellData.getData();
+ cellData.checkEmpty();
+ // Excel中填入的是枚举中指定的描述
+ Object textValue = switch (cellData.getType()) {
+ case STRING, DIRECT_STRING, RICH_TEXT_STRING -> cellData.getStringValue();
+ case NUMBER -> cellData.getNumberValue();
+ case BOOLEAN -> cellData.getBooleanValue();
+ default -> throw new IllegalArgumentException("单元格类型异常!");
+ };
// 如果是空值
- if (ObjectUtil.isNull(codeValue)) {
+ if (ObjectUtil.isNull(textValue)) {
return null;
}
- Map enumValueMap = beforeConvert(contentProperty);
- String textValue = enumValueMap.get(codeValue);
- return Convert.convert(contentProperty.getField().getType(), textValue);
+ Map enumCodeToTextMap = beforeConvert(contentProperty);
+ // 从Java输出至Excel是code转text
+ // 因此从Excel转Java应该将text与code对调
+ Map enumTextToCodeMap = new HashMap<>();
+ enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key));
+ // 应该从text -> code中查找
+ Object codeValue = enumTextToCodeMap.get(textValue);
+ return Convert.convert(contentProperty.getField().getType(), codeValue);
}
@Override
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java
new file mode 100644
index 000000000..8b53a0ce0
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java
@@ -0,0 +1,149 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Excel下拉可选项
+ * 注意:为确保下拉框解析正确,传值务必使用createOptionValue()做为值的拼接
+ *
+ * @author Emil.Zhang
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@SuppressWarnings("unused")
+public class DropDownOptions {
+ /**
+ * 一级下拉所在列index,从0开始算
+ */
+ private int index = 0;
+ /**
+ * 二级下拉所在的index,从0开始算,不能与一级相同
+ */
+ private int nextIndex = 0;
+ /**
+ * 一级下拉所包含的数据
+ */
+ private List options = new ArrayList<>();
+ /**
+ * 二级下拉所包含的数据Map
+ * 以每一个一级选项值为Key,每个一级选项对应的二级数据为Value
+ */
+ private Map> nextOptions = new HashMap<>();
+ /**
+ * 分隔符
+ */
+ private static final String DELIMITER = "_";
+
+ /**
+ * 创建只有一级的下拉选
+ */
+ public DropDownOptions(int index, List options) {
+ this.index = index;
+ this.options = options;
+ }
+
+ /**
+ * 创建每个选项可选值
+ * 注意:不能以数字,特殊符号开头,选项中不可以包含任何运算符号
+ *
+ * @param vars 可选值内包含的参数
+ * @return 合规的可选值
+ */
+ public static String createOptionValue(Object... vars) {
+ StringBuilder stringBuffer = new StringBuilder();
+ String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$";
+ for (int i = 0; i < vars.length; i++) {
+ String var = StrUtil.trimToEmpty(String.valueOf(vars[i]));
+ if (!var.matches(regex)) {
+ throw new ServiceException("选项数据不符合规则,仅允许使用中英文字符以及数字");
+ }
+ stringBuffer.append(var);
+ if (i < vars.length - 1) {
+ // 直至最后一个前,都以_作为切割线
+ stringBuffer.append(DELIMITER);
+ }
+ }
+ if (stringBuffer.toString().matches("^\\d_*$")) {
+ throw new ServiceException("禁止以数字开头");
+ }
+ return stringBuffer.toString();
+ }
+
+ /**
+ * 将处理后合理的可选值解析为原始的参数
+ *
+ * @param option 经过处理后的合理的可选项
+ * @return 原始的参数
+ */
+ public static List analyzeOptionValue(String option) {
+ return StrUtil.split(option, DELIMITER, true, true);
+ }
+
+ /**
+ * 创建级联下拉选项
+ *
+ * @param parentList 父实体可选项原始数据
+ * @param parentIndex 父下拉选位置
+ * @param sonList 子实体可选项原始数据
+ * @param sonIndex 子下拉选位置
+ * @param parentHowToGetIdFunction 父类如何获取唯一标识
+ * @param sonHowToGetParentIdFunction 子类如何获取父类的唯一标识
+ * @param howToBuildEveryOption 如何生成下拉选内容
+ * @return 级联下拉选项
+ */
+ public static DropDownOptions buildLinkedOptions(List parentList,
+ int parentIndex,
+ List sonList,
+ int sonIndex,
+ Function parentHowToGetIdFunction,
+ Function sonHowToGetParentIdFunction,
+ Function howToBuildEveryOption) {
+ DropDownOptions parentLinkSonOptions = new DropDownOptions();
+ // 先创建父类的下拉
+ parentLinkSonOptions.setIndex(parentIndex);
+ parentLinkSonOptions.setOptions(
+ parentList.stream()
+ .map(howToBuildEveryOption)
+ .collect(Collectors.toList())
+ );
+ // 提取父-子级联下拉
+ Map> sonOptions = new HashMap<>();
+ // 父级依据自己的ID分组
+ Map> parentGroupByIdMap =
+ parentList.stream().collect(Collectors.groupingBy(parentHowToGetIdFunction));
+ // 遍历每个子集,提取到Map中
+ sonList.forEach(everySon -> {
+ if (parentGroupByIdMap.containsKey(sonHowToGetParentIdFunction.apply(everySon))) {
+ // 找到对应的上级
+ T parentObj = parentGroupByIdMap.get(sonHowToGetParentIdFunction.apply(everySon)).get(0);
+ // 提取名称和ID作为Key
+ String key = howToBuildEveryOption.apply(parentObj);
+ // Key对应的Value
+ List thisParentSonOptionList;
+ if (sonOptions.containsKey(key)) {
+ thisParentSonOptionList = sonOptions.get(key);
+ } else {
+ thisParentSonOptionList = new ArrayList<>();
+ sonOptions.put(key, thisParentSonOptionList);
+ }
+ // 往Value中添加当前子集选项
+ thisParentSonOptionList.add(howToBuildEveryOption.apply(everySon));
+ }
+ });
+ parentLinkSonOptions.setNextIndex(sonIndex);
+ parentLinkSonOptions.setNextOptions(sonOptions);
+ return parentLinkSonOptions;
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
new file mode 100644
index 000000000..db4fecca1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java
@@ -0,0 +1,373 @@
+package org.dromara.common.excel.core;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.write.handler.SheetWriteHandler;
+import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
+import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.*;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.ss.util.WorkbookUtil;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.service.DictService;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.annotation.ExcelEnumFormat;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+/**
+ * Excel表格下拉选操作
+ * 考虑到下拉选过多可能导致Excel打开缓慢的问题,只校验前1000行
+ *
+ * 即只有前1000行的数据可以用下拉框,超出的自行通过限制数据量的形式,第二次输出
+ *
+ * @author Emil.Zhang
+ */
+@Slf4j
+public class ExcelDownHandler implements SheetWriteHandler {
+
+ /**
+ * Excel表格中的列名英文
+ * 仅为了解析列英文,禁止修改
+ */
+ private static final String EXCEL_COLUMN_NAME = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ /**
+ * 单选数据Sheet名
+ */
+ private static final String OPTIONS_SHEET_NAME = "options";
+ /**
+ * 联动选择数据Sheet名的头
+ */
+ private static final String LINKED_OPTIONS_SHEET_NAME = "linkedOptions";
+ /**
+ * 下拉可选项
+ */
+ private final List dropDownOptions;
+ /**
+ * 当前单选进度
+ */
+ private int currentOptionsColumnIndex;
+ /**
+ * 当前联动选择进度
+ */
+ private int currentLinkedOptionsSheetIndex;
+ private final DictService dictService;
+
+ public ExcelDownHandler(List options) {
+ this.dropDownOptions = options;
+ this.currentOptionsColumnIndex = 0;
+ this.currentLinkedOptionsSheetIndex = 0;
+ this.dictService = SpringUtils.getBean(DictService.class);
+ }
+
+ /**
+ * 开始创建下拉数据
+ * 1.通过解析传入的@ExcelProperty同级是否标注有@DropDown选项
+ * 如果有且设置了value值,则将其直接置为下拉可选项
+ *
+ * 2.或者在调用ExcelUtil时指定了可选项,将依据传入的可选项做下拉
+ *
+ * 3.二者并存,注意调用方式
+ */
+ @Override
+ public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
+ Sheet sheet = writeSheetHolder.getSheet();
+ // 开始设置下拉框 HSSFWorkbook
+ DataValidationHelper helper = sheet.getDataValidationHelper();
+ Field[] fields = writeWorkbookHolder.getClazz().getDeclaredFields();
+ Workbook workbook = writeWorkbookHolder.getWorkbook();
+ int length = fields.length;
+ for (int i = 0; i < length; i++) {
+ // 循环实体中的每个属性
+ // 可选的下拉值
+ List options = new ArrayList<>();
+ if (fields[i].isAnnotationPresent(ExcelDictFormat.class)) {
+ // 如果指定了@ExcelDictFormat,则使用字典的逻辑
+ ExcelDictFormat format = fields[i].getDeclaredAnnotation(ExcelDictFormat.class);
+ String dictType = format.dictType();
+ String converterExp = format.readConverterExp();
+ if (StrUtil.isNotBlank(dictType)) {
+ // 如果传递了字典名,则依据字典建立下拉
+ Collection values = Optional.ofNullable(dictService.getAllDictByDictType(dictType))
+ .orElseThrow(() -> new ServiceException(String.format("字典 %s 不存在", dictType)))
+ .values();
+ options = new ArrayList<>(values);
+ } else if (StrUtil.isNotBlank(converterExp)) {
+ // 如果指定了确切的值,则直接解析确切的值
+ options = StrUtil.split(converterExp, format.separator(), true, true);
+ }
+ } else if (fields[i].isAnnotationPresent(ExcelEnumFormat.class)) {
+ // 否则如果指定了@ExcelEnumFormat,则使用枚举的逻辑
+ ExcelEnumFormat format = fields[i].getDeclaredAnnotation(ExcelEnumFormat.class);
+ List values = EnumUtil.getFieldValues(format.enumClass(), format.textField());
+ options = StreamUtils.toList(values, String::valueOf);
+ }
+ if (ObjectUtil.isNotEmpty(options)) {
+ // 仅当下拉可选项不为空时执行
+ // 获取列下标,默认为当前循环次数
+ int index = i;
+ if (fields[i].isAnnotationPresent(ExcelProperty.class)) {
+ // 如果指定了列下标,以指定的为主
+ index = fields[i].getDeclaredAnnotation(ExcelProperty.class).index();
+ }
+ if (options.size() > 20) {
+ // 这里限制如果可选项大于20,则使用额外表形式
+ dropDownWithSheet(helper, workbook, sheet, index, options);
+ } else {
+ // 否则使用固定值形式
+ dropDownWithSimple(helper, sheet, index, options);
+ }
+ }
+ }
+ if (CollUtil.isEmpty(dropDownOptions)) {
+ return;
+ }
+ dropDownOptions.forEach(everyOptions -> {
+ // 如果传递了下拉框选择器参数
+ if (!everyOptions.getNextOptions().isEmpty()) {
+ // 当二级选项不为空时,使用额外关联表的形式
+ dropDownLinkedOptions(helper, workbook, sheet, everyOptions);
+ } else if (everyOptions.getOptions().size() > 10) {
+ // 当一级选项参数个数大于10,使用额外表的形式
+ dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions());
+ } else if (everyOptions.getOptions().size() != 0) {
+ // 当一级选项个数不为空,使用默认形式
+ dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions());
+ }
+ });
+ }
+
+ /**
+ * 简单下拉框
+ * 直接将可选项拼接为指定列的数据校验值
+ *
+ * @param celIndex 列index
+ * @param value 下拉选可选值
+ */
+ private void dropDownWithSimple(DataValidationHelper helper, Sheet sheet, Integer celIndex, List value) {
+ if (ObjectUtil.isEmpty(value)) {
+ return;
+ }
+ this.markOptionsToSheet(helper, sheet, celIndex, helper.createExplicitListConstraint(ArrayUtil.toArray(value, String.class)));
+ }
+
+ /**
+ * 额外表格形式的级联下拉框
+ *
+ * @param options 额外表格形式存储的下拉可选项
+ */
+ private void dropDownLinkedOptions(DataValidationHelper helper, Workbook workbook, Sheet sheet, DropDownOptions options) {
+ String linkedOptionsSheetName = String.format("%s_%d", LINKED_OPTIONS_SHEET_NAME, currentLinkedOptionsSheetIndex);
+ // 创建联动下拉数据表
+ Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName));
+ // 将下拉表隐藏
+ workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true);
+ // 完善横向的一级选项数据表
+ List firstOptions = options.getOptions();
+ Map> secoundOptionsMap = options.getNextOptions();
+
+ // 创建名称管理器
+ Name name = workbook.createName();
+ // 设置名称管理器的别名
+ name.setNameName(linkedOptionsSheetName);
+ // 以横向第一行创建一级下拉拼接引用位置
+ String firstOptionsFunction = String.format("%s!$%s$1:$%s$1",
+ linkedOptionsSheetName,
+ getExcelColumnName(0),
+ getExcelColumnName(firstOptions.size())
+ );
+ // 设置名称管理器的引用位置
+ name.setRefersToFormula(firstOptionsFunction);
+ // 设置数据校验为序列模式,引用的是名称管理器中的别名
+ this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName));
+
+ for (int columIndex = 0; columIndex < firstOptions.size(); columIndex++) {
+ // 先提取主表中一级下拉的列名
+ String firstOptionsColumnName = getExcelColumnName(columIndex);
+ // 一次循环是每一个一级选项
+ int finalI = columIndex;
+ // 本次循环的一级选项值
+ String thisFirstOptionsValue = firstOptions.get(columIndex);
+ // 创建第一行的数据
+ Optional.ofNullable(linkedOptionsDataSheet.getRow(0))
+ // 如果不存在则创建第一行
+ .orElseGet(() -> linkedOptionsDataSheet.createRow(finalI))
+ // 第一行当前列
+ .createCell(columIndex)
+ // 设置值为当前一级选项值
+ .setCellValue(thisFirstOptionsValue);
+
+ // 第二行开始,设置第二级别选项参数
+ List secondOptions = secoundOptionsMap.get(thisFirstOptionsValue);
+ if (CollUtil.isEmpty(secondOptions)) {
+ // 必须保证至少有一个关联选项,否则将导致Excel解析错误
+ secondOptions = Collections.singletonList("暂无_0");
+ }
+
+ // 以该一级选项值创建子名称管理器
+ Name sonName = workbook.createName();
+ // 设置名称管理器的别名
+ sonName.setNameName(thisFirstOptionsValue);
+ // 以第二行该列数据拼接引用位置
+ String sonFunction = String.format("%s!$%s$2:$%s$%d",
+ linkedOptionsSheetName,
+ firstOptionsColumnName,
+ firstOptionsColumnName,
+ secondOptions.size() + 1
+ );
+ // 设置名称管理器的引用位置
+ sonName.setRefersToFormula(sonFunction);
+ // 数据验证为序列模式,引用到每一个主表中的二级选项位置
+ // 创建子项的名称管理器,只是为了使得Excel可以识别到数据
+ String mainSheetFirstOptionsColumnName = getExcelColumnName(options.getIndex());
+ for (int i = 0; i < 100; i++) {
+ // 以一级选项对应的主体所在位置创建二级下拉
+ String secondOptionsFunction = String.format("=INDIRECT(%s%d)", mainSheetFirstOptionsColumnName, i + 1);
+ // 二级只能主表每一行的每一列添加二级校验
+ markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction));
+ }
+
+ for (int rowIndex = 0; rowIndex < secondOptions.size(); rowIndex++) {
+ // 从第二行开始填充二级选项
+ int finalRowIndex = rowIndex + 1;
+ int finalColumIndex = columIndex;
+
+ Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex))
+ // 没有则创建
+ .orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex));
+ Optional
+ // 在本级一级选项所在的列
+ .ofNullable(row.getCell(finalColumIndex))
+ // 不存在则创建
+ .orElseGet(() -> row.createCell(finalColumIndex))
+ // 设置二级选项值
+ .setCellValue(secondOptions.get(rowIndex));
+ }
+ }
+
+ currentLinkedOptionsSheetIndex++;
+ }
+
+ /**
+ * 额外表格形式的普通下拉框
+ * 由于下拉框可选值数量过多,为提升Excel打开效率,使用额外表格形式做下拉
+ *
+ * @param celIndex 下拉选
+ * @param value 下拉选可选值
+ */
+ private void dropDownWithSheet(DataValidationHelper helper, Workbook workbook, Sheet sheet, Integer celIndex, List value) {
+ // 创建下拉数据表
+ Sheet simpleDataSheet = Optional.ofNullable(workbook.getSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME)))
+ .orElseGet(() -> workbook.createSheet(WorkbookUtil.createSafeSheetName(OPTIONS_SHEET_NAME)));
+ // 将下拉表隐藏
+ workbook.setSheetHidden(workbook.getSheetIndex(simpleDataSheet), true);
+ // 完善纵向的一级选项数据表
+ for (int i = 0; i < value.size(); i++) {
+ int finalI = i;
+ // 获取每一选项行,如果没有则创建
+ Row row = Optional.ofNullable(simpleDataSheet.getRow(i))
+ .orElseGet(() -> simpleDataSheet.createRow(finalI));
+ // 获取本级选项对应的选项列,如果没有则创建
+ Cell cell = Optional.ofNullable(row.getCell(currentOptionsColumnIndex))
+ .orElseGet(() -> row.createCell(currentOptionsColumnIndex));
+ // 设置值
+ cell.setCellValue(value.get(i));
+ }
+
+ // 创建名称管理器
+ Name name = workbook.createName();
+ // 设置名称管理器的别名
+ String nameName = String.format("%s_%d", OPTIONS_SHEET_NAME, celIndex);
+ name.setNameName(nameName);
+ // 以纵向第一列创建一级下拉拼接引用位置
+ String function = String.format("%s!$%s$1:$%s$%d",
+ OPTIONS_SHEET_NAME,
+ getExcelColumnName(currentOptionsColumnIndex),
+ getExcelColumnName(currentOptionsColumnIndex),
+ value.size());
+ // 设置名称管理器的引用位置
+ name.setRefersToFormula(function);
+ // 设置数据校验为序列模式,引用的是名称管理器中的别名
+ this.markOptionsToSheet(helper, sheet, celIndex, helper.createFormulaListConstraint(nameName));
+ currentOptionsColumnIndex++;
+ }
+
+ /**
+ * 挂载下拉的列,仅限一级选项
+ */
+ private void markOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer celIndex,
+ DataValidationConstraint constraint) {
+ // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
+ CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, celIndex, celIndex);
+ markDataValidationToSheet(helper, sheet, constraint, addressList);
+ }
+
+ /**
+ * 挂载下拉的列,仅限二级选项
+ */
+ private void markLinkedOptionsToSheet(DataValidationHelper helper, Sheet sheet, Integer rowIndex,
+ Integer celIndex, DataValidationConstraint constraint) {
+ // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
+ CellRangeAddressList addressList = new CellRangeAddressList(rowIndex, rowIndex, celIndex, celIndex);
+ markDataValidationToSheet(helper, sheet, constraint, addressList);
+ }
+
+ /**
+ * 应用数据校验
+ */
+ private void markDataValidationToSheet(DataValidationHelper helper, Sheet sheet,
+ DataValidationConstraint constraint, CellRangeAddressList addressList) {
+ // 数据有效性对象
+ DataValidation dataValidation = helper.createValidation(constraint, addressList);
+ // 处理Excel兼容性问题
+ if (dataValidation instanceof XSSFDataValidation) {
+ //数据校验
+ dataValidation.setSuppressDropDownArrow(true);
+ //错误提示
+ dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
+ dataValidation.createErrorBox("提示", "此值与单元格定义数据不一致");
+ dataValidation.setShowErrorBox(true);
+ //选定提示
+ dataValidation.createPromptBox("填写说明:", "填写内容只能为下拉中数据,其他数据将导致导入失败");
+ dataValidation.setShowPromptBox(true);
+ sheet.addValidationData(dataValidation);
+ } else {
+ dataValidation.setSuppressDropDownArrow(false);
+ }
+ sheet.addValidationData(dataValidation);
+ }
+
+ /**
+ * 依据列index获取列名英文
+ * 依据列index转换为Excel中的列名英文
+ * 例如第1列,index为0,解析出来为A列
+ * 第27列,index为26,解析为AA列
+ * 第28列,index为27,解析为AB列
+ *
+ * @param columnIndex 列index
+ * @return 列index所在得英文名
+ */
+ private String getExcelColumnName(int columnIndex) {
+ // 26一循环的次数
+ int columnCircleCount = columnIndex / 26;
+ // 26一循环内的位置
+ int thisCircleColumnIndex = columnIndex % 26;
+ // 26一循环的次数大于0,则视为栏名至少两位
+ String columnPrefix = columnCircleCount == 0
+ ? StrUtil.EMPTY
+ : StrUtil.subWithLength(EXCEL_COLUMN_NAME, columnCircleCount - 1, 1);
+ // 从26一循环内取对应的栏位名
+ String columnNext = StrUtil.subWithLength(EXCEL_COLUMN_NAME, thisCircleColumnIndex, 1);
+ // 将二者拼接即为最终的栏位名
+ return columnPrefix + columnNext;
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
index 3605cf25d..329911d1e 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java
@@ -10,21 +10,19 @@ import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.excel.write.metadata.fill.FillWrapper;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.core.utils.file.FileUtils;
-import org.dromara.common.excel.convert.ExcelBigNumberConvert;
-import org.dromara.common.excel.core.CellMergeStrategy;
-import org.dromara.common.excel.core.DefaultExcelListener;
-import org.dromara.common.excel.core.ExcelListener;
-import org.dromara.common.excel.core.ExcelResult;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.FileUtils;
+import org.dromara.common.excel.convert.ExcelBigNumberConvert;
+import org.dromara.common.excel.core.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -87,7 +85,26 @@ public class ExcelUtil {
try {
resetResponse(sheetName, response);
ServletOutputStream os = response.getOutputStream();
- exportExcel(list, sheetName, clazz, false, os);
+ exportExcel(list, sheetName, clazz, false, os, null);
+ } catch (IOException e) {
+ throw new RuntimeException("导出Excel异常");
+ }
+ }
+
+ /**
+ * 导出excel
+ *
+ * @param list 导出数据集合
+ * @param sheetName 工作表的名称
+ * @param clazz 实体类
+ * @param response 响应体
+ * @param options 级联下拉选
+ */
+ public static void exportExcel(List list, String sheetName, Class clazz, HttpServletResponse response, List options) {
+ try {
+ resetResponse(sheetName, response);
+ ServletOutputStream os = response.getOutputStream();
+ exportExcel(list, sheetName, clazz, false, os, options);
} catch (IOException e) {
throw new RuntimeException("导出Excel异常");
}
@@ -106,7 +123,27 @@ public class ExcelUtil {
try {
resetResponse(sheetName, response);
ServletOutputStream os = response.getOutputStream();
- exportExcel(list, sheetName, clazz, merge, os);
+ exportExcel(list, sheetName, clazz, merge, os, null);
+ } catch (IOException e) {
+ throw new RuntimeException("导出Excel异常");
+ }
+ }
+
+ /**
+ * 导出excel
+ *
+ * @param list 导出数据集合
+ * @param sheetName 工作表的名称
+ * @param clazz 实体类
+ * @param merge 是否合并单元格
+ * @param response 响应体
+ * @param options 级联下拉选
+ */
+ public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, HttpServletResponse response, List options) {
+ try {
+ resetResponse(sheetName, response);
+ ServletOutputStream os = response.getOutputStream();
+ exportExcel(list, sheetName, clazz, merge, os, options);
} catch (IOException e) {
throw new RuntimeException("导出Excel异常");
}
@@ -121,7 +158,20 @@ public class ExcelUtil {
* @param os 输出流
*/
public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os) {
- exportExcel(list, sheetName, clazz, false, os);
+ exportExcel(list, sheetName, clazz, false, os, null);
+ }
+
+ /**
+ * 导出excel
+ *
+ * @param list 导出数据集合
+ * @param sheetName 工作表的名称
+ * @param clazz 实体类
+ * @param os 输出流
+ * @param options 级联下拉选内容
+ */
+ public static void exportExcel(List list, String sheetName, Class clazz, OutputStream os, List options) {
+ exportExcel(list, sheetName, clazz, false, os, options);
}
/**
@@ -133,7 +183,8 @@ public class ExcelUtil {
* @param merge 是否合并单元格
* @param os 输出流
*/
- public static void exportExcel(List list, String sheetName, Class clazz, boolean merge, OutputStream os) {
+ public static void exportExcel(List list, String sheetName, Class clazz, boolean merge,
+ OutputStream os, List options) {
ExcelWriterSheetBuilder builder = EasyExcel.write(os, clazz)
.autoCloseStream(false)
// 自动适配
@@ -145,6 +196,8 @@ public class ExcelUtil {
// 合并处理器
builder.registerWriteHandler(new CellMergeStrategy(list, true));
}
+ // 添加下拉框操作
+ builder.registerWriteHandler(new ExcelDownHandler(options));
builder.doWrite(list);
}
@@ -253,7 +306,7 @@ public class ExcelUtil {
/**
* 重置响应体
*/
- private static void resetResponse(String sheetName, HttpServletResponse response) {
+ private static void resetResponse(String sheetName, HttpServletResponse response) throws UnsupportedEncodingException {
String filename = encodingFilename(sheetName);
FileUtils.setAttachmentResponseHeader(response, filename);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8");
@@ -275,7 +328,7 @@ public class ExcelUtil {
if (StringUtils.containsAny(propertyValue, separator)) {
for (String value : propertyValue.split(separator)) {
if (itemArray[0].equals(value)) {
- propertyString.append(itemArray[1]).append(separator);
+ propertyString.append(itemArray[1] + separator);
break;
}
}
@@ -304,7 +357,7 @@ public class ExcelUtil {
if (StringUtils.containsAny(propertyValue, separator)) {
for (String value : propertyValue.split(separator)) {
if (itemArray[1].equals(value)) {
- propertyString.append(itemArray[0]).append(separator);
+ propertyString.append(itemArray[0] + separator);
break;
}
}
diff --git a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java
index 77f26469e..016fe0fb1 100644
--- a/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java
+++ b/ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java
@@ -1,6 +1,7 @@
package org.dromara.common.idempotent.aspectj;
import cn.dev33.satoken.SaManager;
+import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import org.dromara.common.core.constant.GlobalConstants;
@@ -25,6 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.time.Duration;
import java.util.Collection;
import java.util.Map;
+import java.util.StringJoiner;
/**
* 防止重复提交(参考美团GTIS防重系统)
@@ -39,10 +41,8 @@ public class RepeatSubmitAspect {
@Before("@annotation(repeatSubmit)")
public void doBefore(JoinPoint point, RepeatSubmit repeatSubmit) throws Throwable {
// 如果注解不为0 则使用注解数值
- long interval = 0;
- if (repeatSubmit.interval() > 0) {
- interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval());
- }
+ long interval = repeatSubmit.timeUnit().toMillis(repeatSubmit.interval());
+
if (interval < 1000) {
throw new ServiceException("重复提交间隔时间不能小于'1'秒");
}
@@ -58,9 +58,7 @@ public class RepeatSubmitAspect {
submitKey = SecureUtil.md5(submitKey + ":" + nowParams);
// 唯一标识(指定key + url + 消息头)
String cacheRepeatKey = GlobalConstants.REPEAT_SUBMIT_KEY + url + submitKey;
- String key = RedisUtils.getCacheObject(cacheRepeatKey);
- if (key == null) {
- RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofMillis(interval));
+ if (RedisUtils.setObjectIfAbsent(cacheRepeatKey, "", Duration.ofMillis(interval))) {
KEY_CACHE.set(cacheRepeatKey);
} else {
String message = repeatSubmit.message();
@@ -78,7 +76,7 @@ public class RepeatSubmitAspect {
*/
@AfterReturning(pointcut = "@annotation(repeatSubmit)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, RepeatSubmit repeatSubmit, Object jsonResult) {
- if (jsonResult instanceof R r) {
+ if (jsonResult instanceof R> r) {
try {
// 成功则不删除redis数据 保证在有效时间内无法重复提交
if (r.getCode() == R.SUCCESS) {
@@ -107,19 +105,16 @@ public class RepeatSubmitAspect {
* 参数拼装
*/
private String argsArrayToString(Object[] paramsArray) {
- StringBuilder params = new StringBuilder();
- if (paramsArray != null && paramsArray.length > 0) {
- for (Object o : paramsArray) {
- if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
- try {
- params.append(JsonUtils.toJsonString(o)).append(" ");
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
+ StringJoiner params = new StringJoiner(" ");
+ if (ArrayUtil.isEmpty(paramsArray)) {
+ return params.toString();
+ }
+ for (Object o : paramsArray) {
+ if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
+ params.add(JsonUtils.toJsonString(o));
}
}
- return params.toString().trim();
+ return params.toString();
}
/**
@@ -140,13 +135,12 @@ public class RepeatSubmitAspect {
}
} else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) o;
- for (Object value : map.entrySet()) {
- Map.Entry entry = (Map.Entry) value;
- return entry.getValue() instanceof MultipartFile;
+ for (Object value : map.values()) {
+ return value instanceof MultipartFile;
}
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
- || o instanceof BindingResult;
+ || o instanceof BindingResult;
}
}
diff --git a/ruoyi-common/ruoyi-common-job/pom.xml b/ruoyi-common/ruoyi-common-job/pom.xml
index 446b4da01..b311477d0 100644
--- a/ruoyi-common/ruoyi-common-job/pom.xml
+++ b/ruoyi-common/ruoyi-common-job/pom.xml
@@ -15,17 +15,21 @@
ruoyi-common-job 定时任务
-
+
org.springframework.boot
spring-boot-autoconfigure
-
+
- com.xuxueli
- xxl-job-core
+ tech.powerjob
+ powerjob-worker-spring-boot-starter
+
+
+ tech.powerjob
+ powerjob-official-processors
diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java b/ruoyi-common/ruoyi-common-job/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java
deleted file mode 100644
index 00cd82287..000000000
--- a/ruoyi-common/ruoyi-common-job/src/main/java/com/xxl/job/core/glue/impl/SpringGlueFactory.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.xxl.job.core.glue.impl;
-
-import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
-import com.xxl.job.core.glue.GlueFactory;
-import jakarta.annotation.Resource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.core.annotation.AnnotationUtils;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-
-/**
- * @author xuxueli 2018-11-01
- */
-public class SpringGlueFactory extends GlueFactory {
- private static Logger logger = LoggerFactory.getLogger(SpringGlueFactory.class);
-
-
- /**
- * inject action of spring
- * @param instance
- */
- @Override
- public void injectService(Object instance){
- if (instance==null) {
- return;
- }
-
- if (XxlJobSpringExecutor.getApplicationContext() == null) {
- return;
- }
-
- Field[] fields = instance.getClass().getDeclaredFields();
- for (Field field : fields) {
- if (Modifier.isStatic(field.getModifiers())) {
- continue;
- }
-
- Object fieldBean = null;
- // with bean-id, bean could be found by both @Resource and @Autowired, or bean could only be found by @Autowired
-
- if (AnnotationUtils.getAnnotation(field, Resource.class) != null) {
- try {
- Resource resource = AnnotationUtils.getAnnotation(field, Resource.class);
- if (resource.name()!=null && resource.name().length()>0){
- fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(resource.name());
- } else {
- fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getName());
- }
- } catch (Exception e) {
- }
- if (fieldBean==null ) {
- fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getType());
- }
- } else if (AnnotationUtils.getAnnotation(field, Autowired.class) != null) {
- Qualifier qualifier = AnnotationUtils.getAnnotation(field, Qualifier.class);
- if (qualifier!=null && qualifier.value()!=null && qualifier.value().length()>0) {
- fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(qualifier.value());
- } else {
- fieldBean = XxlJobSpringExecutor.getApplicationContext().getBean(field.getType());
- }
- }
-
- if (fieldBean!=null) {
- field.setAccessible(true);
- try {
- field.set(instance, fieldBean);
- } catch (IllegalArgumentException e) {
- logger.error(e.getMessage(), e);
- } catch (IllegalAccessException e) {
- logger.error(e.getMessage(), e);
- }
- }
- }
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/PowerJobConfig.java b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/PowerJobConfig.java
new file mode 100644
index 000000000..67208c0e5
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/PowerJobConfig.java
@@ -0,0 +1,21 @@
+package org.dromara.common.job.config;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import tech.powerjob.worker.PowerJobWorker;
+
+/**
+ * 启动定时任务
+ * @author yhan219
+ * @since 2023/6/2
+ */
+@Configuration
+@ConditionalOnBean(PowerJobWorker.class)
+@ConditionalOnProperty(prefix = "powerjob.worker", name = "enabled", havingValue = "true")
+@EnableScheduling
+public class PowerJobConfig {
+
+
+}
diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/XxlJobConfig.java b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/XxlJobConfig.java
deleted file mode 100644
index f85c8058a..000000000
--- a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/XxlJobConfig.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.dromara.common.job.config;
-
-import org.dromara.common.job.config.properties.XxlJobProperties;
-import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-
-/**
- * xxl-job config
- *
- * @author Lion Li
- */
-@Slf4j
-@AutoConfiguration
-@EnableConfigurationProperties(XxlJobProperties.class)
-@ConditionalOnProperty(prefix = "xxl.job", name = "enabled", havingValue = "true")
-public class XxlJobConfig {
-
- @Bean
- public XxlJobSpringExecutor xxlJobExecutor(XxlJobProperties xxlJobProperties) {
- log.info(">>>>>>>>>>> xxl-job config init.");
- XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
- xxlJobSpringExecutor.setAdminAddresses(xxlJobProperties.getAdminAddresses());
- xxlJobSpringExecutor.setAccessToken(xxlJobProperties.getAccessToken());
- XxlJobProperties.Executor executor = xxlJobProperties.getExecutor();
- xxlJobSpringExecutor.setAppname(executor.getAppname());
- xxlJobSpringExecutor.setAddress(executor.getAddress());
- xxlJobSpringExecutor.setIp(executor.getIp());
- xxlJobSpringExecutor.setPort(executor.getPort());
- xxlJobSpringExecutor.setLogPath(executor.getLogPath());
- xxlJobSpringExecutor.setLogRetentionDays(executor.getLogRetentionDays());
- return xxlJobSpringExecutor;
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/properties/XxlJobProperties.java b/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/properties/XxlJobProperties.java
deleted file mode 100644
index 47cbc2c8c..000000000
--- a/ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/properties/XxlJobProperties.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.dromara.common.job.config.properties;
-
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-/**
- * xxljob配置类
- *
- * @author Lion Li
- */
-@Data
-@ConfigurationProperties(prefix = "xxl.job")
-public class XxlJobProperties {
-
- private Boolean enabled;
-
- private String adminAddresses;
-
- private String accessToken;
-
- private Executor executor;
-
- @Data
- @NoArgsConstructor
- public static class Executor {
-
- private String appname;
-
- private String address;
-
- private String ip;
-
- private int port;
-
- private String logPath;
-
- private int logRetentionDays;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
deleted file mode 100644
index 3e6fd6e59..000000000
--- a/ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ /dev/null
@@ -1 +0,0 @@
-org.dromara.common.job.config.XxlJobConfig
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
index dc3b9d03c..8c423c8a7 100644
--- a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
+++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
@@ -2,6 +2,7 @@ package org.dromara.common.log.aspect;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.ttl.TransmittableThreadLocal;
import org.dromara.common.core.utils.ServletUtils;
@@ -28,6 +29,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.util.Collection;
import java.util.Map;
+import java.util.StringJoiner;
/**
* 操作日志记录处理
@@ -170,26 +172,23 @@ public class LogAspect {
* 参数拼装
*/
private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
- StringBuilder params = new StringBuilder();
- if (paramsArray != null && paramsArray.length > 0) {
- for (Object o : paramsArray) {
- if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
- try {
- String str = JsonUtils.toJsonString(o);
- Dict dict = JsonUtils.parseMap(str);
- if (MapUtil.isNotEmpty(dict)) {
- MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);
- MapUtil.removeAny(dict, excludeParamNames);
- str = JsonUtils.toJsonString(dict);
- }
- params.append(str).append(" ");
- } catch (Exception e) {
- e.printStackTrace();
- }
+ StringJoiner params = new StringJoiner(" ");
+ if (ArrayUtil.isEmpty(paramsArray)) {
+ return params.toString();
+ }
+ for (Object o : paramsArray) {
+ if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
+ String str = JsonUtils.toJsonString(o);
+ Dict dict = JsonUtils.parseMap(str);
+ if (MapUtil.isNotEmpty(dict)) {
+ MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);
+ MapUtil.removeAny(dict, excludeParamNames);
+ str = JsonUtils.toJsonString(dict);
}
+ params.add(str);
}
}
- return params.toString().trim();
+ return params.toString();
}
/**
@@ -210,12 +209,11 @@ public class LogAspect {
}
} else if (Map.class.isAssignableFrom(clazz)) {
Map map = (Map) o;
- for (Object value : map.entrySet()) {
- Map.Entry entry = (Map.Entry) value;
- return entry.getValue() instanceof MultipartFile;
+ for (Object value : map.values()) {
+ return value instanceof MultipartFile;
}
}
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
- || o instanceof BindingResult;
+ || o instanceof BindingResult;
}
}
diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml
index 3acb608ca..51199b408 100644
--- a/ruoyi-common/ruoyi-common-mybatis/pom.xml
+++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml
@@ -29,7 +29,7 @@
com.baomidou
- dynamic-datasource-spring-boot-starter
+ dynamic-datasource-spring-boot3-starter
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaHeaderProcessor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaHeaderProcessor.java
deleted file mode 100644
index f0a50a2d9..000000000
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaHeaderProcessor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright © 2018 organization baomidou
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.baomidou.dynamic.datasource.processor.jakarta;
-
-import com.baomidou.dynamic.datasource.processor.DsProcessor;
-import jakarta.servlet.http.HttpServletRequest;
-import org.aopalliance.intercept.MethodInvocation;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-
-/**
- * @author TaoYu
- * @since 3.6.0
- */
-public class DsJakartaHeaderProcessor extends DsProcessor {
-
- /**
- * header prefix
- */
- private static final String HEADER_PREFIX = "#header";
-
- @Override
- public boolean matches(String key) {
- return key.startsWith(HEADER_PREFIX);
- }
-
- @Override
- public String doDetermineDatasource(MethodInvocation invocation, String key) {
- HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
- return request.getHeader(key.substring(8));
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaSessionProcessor.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaSessionProcessor.java
deleted file mode 100644
index 0ea8a1309..000000000
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/com/baomidou/dynamic/datasource/processor/jakarta/DsJakartaSessionProcessor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright © 2018 organization baomidou
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.baomidou.dynamic.datasource.processor.jakarta;
-
-import com.baomidou.dynamic.datasource.processor.DsProcessor;
-import jakarta.servlet.http.HttpServletRequest;
-import org.aopalliance.intercept.MethodInvocation;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-
-
-/**
- * @author TaoYu
- * @since 3.6.0
- */
-public class DsJakartaSessionProcessor extends DsProcessor {
-
- /**
- * session开头
- */
- private static final String SESSION_PREFIX = "#session";
-
- @Override
- public boolean matches(String key) {
- return key.startsWith(SESSION_PREFIX);
- }
-
- @Override
- public String doDetermineDatasource(MethodInvocation invocation, String key) {
- HttpServletRequest request = (HttpServletRequest) ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
- return request.getSession().getAttribute(key.substring(9)).toString();
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
index 1fe7834fe..c07a2bb3b 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java
@@ -7,11 +7,13 @@ import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import org.dromara.common.core.factory.YmlPropertySourceFactory;
import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
@@ -22,6 +24,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableTransactionManagement(proxyTargetClass = true)
@AutoConfiguration
@MapperScan("${mybatis-plus.mapperPackage}")
+@PropertySource(value = "classpath:common-mybatis.yml", factory = YmlPropertySourceFactory.class)
public class MybatisPlusConfig {
@Bean
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
index 4da965930..bb20f4b3a 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java
@@ -12,6 +12,9 @@ import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
/**
* 数据库助手
@@ -69,4 +72,11 @@ public class DataBaseHelper {
// find_in_set(100 , '0,100,101')
return "find_in_set('%s' , %s) <> 0".formatted(var, var2);
}
+
+ /**
+ * 获取当前加载的数据库名
+ */
+ public static List getDataSourceNameList() {
+ return new ArrayList<>(DS.getDataSources().keySet());
+ }
}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
new file mode 100644
index 000000000..f5dc63758
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml
@@ -0,0 +1,33 @@
+# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖
+# MyBatisPlus配置
+# https://baomidou.com/config/
+mybatis-plus:
+ # 启动时是否检查 MyBatis XML 文件的存在,默认不检查
+ checkConfigLocation: false
+ configuration:
+ # 自动驼峰命名规则(camel case)映射
+ mapUnderscoreToCamelCase: true
+ # MyBatis 自动映射策略
+ # NONE:不启用 PARTIAL:只对非嵌套 resultMap 自动映射 FULL:对所有 resultMap 自动映射
+ autoMappingBehavior: FULL
+ # MyBatis 自动映射时未知列或未知属性处理策
+ # NONE:不做处理 WARNING:打印相关警告 FAILING:抛出异常和详细信息
+ autoMappingUnknownColumnBehavior: NONE
+ # 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
+ # 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
+ # 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
+ logImpl: org.apache.ibatis.logging.nologging.NoLoggingImpl
+ global-config:
+ # 是否打印 Logo banner
+ banner: true
+ dbConfig:
+ # 主键类型
+ # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
+ idType: ASSIGN_ID
+ # 逻辑已删除值(框架表均使用此值 禁止随意修改)
+ logicDeleteValue: 2
+ # 逻辑未删除值
+ logicNotDeleteValue: 0
+ insertStrategy: NOT_NULL
+ updateStrategy: NOT_NULL
+ whereStrategy: NOT_NULL
diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
index 992e3d4db..53e05c927 100644
--- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
+++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
@@ -24,6 +24,7 @@ import org.dromara.common.oss.exception.OssException;
import org.dromara.common.oss.properties.OssProperties;
import java.io.ByteArrayInputStream;
+import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.Date;
@@ -115,6 +116,18 @@ public class OssClient {
return UploadResult.builder().url(getUrl() + "/" + path).filename(path).build();
}
+ public UploadResult upload(File file, String path) {
+ try {
+ PutObjectRequest putObjectRequest = new PutObjectRequest(properties.getBucketName(), path, file);
+ // 设置上传对象的 Acl 为公共读
+ putObjectRequest.setCannedAcl(getAccessPolicy().getAcl());
+ client.putObject(putObjectRequest);
+ } catch (Exception e) {
+ throw new OssException("上传文件失败,请检查配置信息:[" + e.getMessage() + "]");
+ }
+ return UploadResult.builder().url(getUrl() + "/" + path).filename(path).build();
+ }
+
public void delete(String path) {
path = path.replace(getUrl() + "/", "");
try {
@@ -132,6 +145,10 @@ public class OssClient {
return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType);
}
+ public UploadResult uploadSuffix(File file, String suffix) {
+ return upload(file, getPath(properties.getPrefix(), suffix));
+ }
+
/**
* 获取文件元数据
*
diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java
index 911d9a86a..6503eb133 100644
--- a/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java
+++ b/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java
@@ -51,13 +51,13 @@ public class OssFactory {
if (client == null) {
CLIENT_CACHE.put(key, new OssClient(configKey, properties));
log.info("创建OSS实例 key => {}", configKey);
- return CLIENT_CACHE.get(configKey);
+ return CLIENT_CACHE.get(key);
}
// 配置不相同则重新构建
if (!client.checkPropertiesSame(properties)) {
CLIENT_CACHE.put(key, new OssClient(configKey, properties));
log.info("重载OSS实例 key => {}", configKey);
- return CLIENT_CACHE.get(configKey);
+ return CLIENT_CACHE.get(key);
}
return client;
}
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
index 2a1391d0d..08ebc7826 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java
@@ -118,6 +118,10 @@ public class PlusSpringCacheManager implements CacheManager {
@Override
public Cache getCache(String name) {
+ // 重写 cacheName 支持多参数
+ String[] array = StringUtils.delimitedListToStringArray(name, "#");
+ name = array[0];
+
Cache cache = instanceMap.get(name);
if (cache != null) {
return cache;
@@ -132,9 +136,6 @@ public class PlusSpringCacheManager implements CacheManager {
configMap.put(name, config);
}
- // 重写 cacheName 支持多参数
- String[] array = StringUtils.delimitedListToStringArray(name, "#");
- name = array[0];
if (array.length > 1) {
config.setTTL(DurationStyle.detectAndParse(array[1]).toMillis());
}
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
index fd20ba09f..9f59f69f1 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java
@@ -1,8 +1,8 @@
package org.dromara.common.redis.utils;
-import org.dromara.common.core.utils.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.SpringUtils;
import org.redisson.api.*;
import java.time.Duration;
@@ -129,6 +129,18 @@ public class RedisUtils {
batch.execute();
}
+ /**
+ * 如果不存在则设置 并返回 true 如果存在则返回 false
+ *
+ * @param key 缓存的键值
+ * @param value 缓存的值
+ * @return set成功或失败
+ */
+ public static boolean setObjectIfAbsent(final String key, final T value, final Duration duration) {
+ RBucket bucket = CLIENT.getBucket(key);
+ return bucket.setIfAbsent(value, duration);
+ }
+
/**
* 注册对象监听器
*
@@ -374,6 +386,21 @@ public class RedisUtils {
return rMap.remove(hKey);
}
+ /**
+ * 删除Hash中的数据
+ *
+ * @param key Redis键
+ * @param hKeys Hash键
+ */
+ public static void delMultiCacheMapValue(final String key, final Set hKeys) {
+ RBatch batch = CLIENT.createBatch();
+ RMapAsync rMap = batch.getMap(key);
+ for (String hKey : hKeys) {
+ rMap.removeAsync(hKey);
+ }
+ batch.execute();
+ }
+
/**
* 获取多个Hash中的数据
*
diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
index 54ae2da2b..aef8a66ae 100644
--- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
+++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java
@@ -4,10 +4,12 @@ import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.jwt.StpLogicJwtForSimple;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpLogic;
+import org.dromara.common.core.factory.YmlPropertySourceFactory;
import org.dromara.common.satoken.core.dao.PlusSaTokenDao;
import org.dromara.common.satoken.core.service.SaPermissionImpl;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.PropertySource;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
@@ -16,6 +18,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
* @author Lion Li
*/
@AutoConfiguration
+@PropertySource(value = "classpath:common-satoken.yml", factory = YmlPropertySourceFactory.class)
public class SaTokenConfig implements WebMvcConfigurer {
@Bean
diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
index e79b9bacd..22c160a70 100644
--- a/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
+++ b/ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
@@ -2,17 +2,17 @@ package org.dromara.common.satoken.utils;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaStorage;
+import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.domain.model.LoginUser;
-import org.dromara.common.core.enums.DeviceType;
import org.dromara.common.core.enums.UserType;
-import lombok.AccessLevel;
-import lombok.NoArgsConstructor;
import java.util.Set;
@@ -34,31 +34,21 @@ public class LoginHelper {
public static final String LOGIN_USER_KEY = "loginUser";
public static final String TENANT_KEY = "tenantId";
public static final String USER_KEY = "userId";
-
- /**
- * 登录系统
- *
- * @param loginUser 登录用户信息
- */
- public static void login(LoginUser loginUser) {
- loginByDevice(loginUser, null);
- }
+ public static final String CLIENT_KEY = "clientid";
/**
* 登录系统 基于 设备类型
* 针对相同用户体系不同设备
*
* @param loginUser 登录用户信息
+ * @param model 配置参数
*/
- public static void loginByDevice(LoginUser loginUser, DeviceType deviceType) {
+ public static void login(LoginUser loginUser, SaLoginModel model) {
SaStorage storage = SaHolder.getStorage();
storage.set(LOGIN_USER_KEY, loginUser);
storage.set(TENANT_KEY, loginUser.getTenantId());
storage.set(USER_KEY, loginUser.getUserId());
- SaLoginModel model = new SaLoginModel();
- if (ObjectUtil.isNotNull(deviceType)) {
- model.setDevice(deviceType.getDevice());
- }
+ model = ObjectUtil.defaultIfNull(model, new SaLoginModel());
StpUtil.login(loginUser.getLoginId(),
model.setExtra(TENANT_KEY, loginUser.getTenantId())
.setExtra(USER_KEY, loginUser.getUserId()));
@@ -73,7 +63,11 @@ public class LoginHelper {
if (loginUser != null) {
return loginUser;
}
- loginUser = (LoginUser) StpUtil.getTokenSession().get(LOGIN_USER_KEY);
+ SaSession session = StpUtil.getTokenSession();
+ if (ObjectUtil.isNull(session)) {
+ return null;
+ }
+ loginUser = (LoginUser) session.get(LOGIN_USER_KEY);
SaHolder.getStorage().set(LOGIN_USER_KEY, loginUser);
return loginUser;
}
@@ -82,7 +76,11 @@ public class LoginHelper {
* 获取用户基于token
*/
public static LoginUser getLoginUser(String token) {
- return (LoginUser) StpUtil.getTokenSessionByToken(token).get(LOGIN_USER_KEY);
+ SaSession session = StpUtil.getTokenSessionByToken(token);
+ if (ObjectUtil.isNull(session)) {
+ return null;
+ }
+ return (LoginUser) session.get(LOGIN_USER_KEY);
}
/**
@@ -137,8 +135,8 @@ public class LoginHelper {
* 获取用户类型
*/
public static UserType getUserType() {
- String loginId = StpUtil.getLoginIdAsString();
- return UserType.getUserType(loginId);
+ String loginType = StpUtil.getLoginIdAsString();
+ return UserType.getUserType(loginType);
}
/**
diff --git a/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml b/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml
new file mode 100644
index 000000000..95e1b41b2
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml
@@ -0,0 +1,13 @@
+# 内置配置 不允许修改 如需修改请在 nacos 上写相同配置覆盖
+# Sa-Token配置
+sa-token:
+ # 允许动态设置 token 有效期
+ dynamic-active-timeout: true
+ # 允许从 请求参数 读取 token
+ is-read-body: true
+ # 允许从 header 读取 token
+ is-read-header: true
+ # 关闭 cookie 鉴权 从根源杜绝 csrf 漏洞风险
+ is-read-cookie: false
+ # token前缀
+ token-prefix: "Bearer"
diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
index 6936bc335..7ac920f2f 100644
--- a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
+++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java
@@ -1,9 +1,13 @@
package org.dromara.common.security.config;
+import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.interceptor.SaInterceptor;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
+import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.security.config.properties.SecurityProperties;
import org.dromara.common.security.handler.AllUrlHandler;
import lombok.RequiredArgsConstructor;
@@ -44,6 +48,18 @@ public class SecurityConfig implements WebMvcConfigurer {
// 检查是否登录 是否有token
StpUtil.checkLogin();
+ // 检查 header 里的 clientId 与 token 里的是否一致
+ String headerCid = ServletUtils.getRequest().getHeader(LoginHelper.CLIENT_KEY);
+ String clientId = StpUtil.getExtra(LoginHelper.CLIENT_KEY).toString();
+ if (!StringUtils.equals(headerCid, clientId)) {
+ // token 无效
+ throw NotLoginException.newInstance(
+ StpUtil.getLoginType(),
+ NotLoginException.INVALID_TOKEN,
+ NotLoginException.NOT_TOKEN_MESSAGE,
+ StpUtil.getTokenValue());
+ }
+
// 有效率影响 用于临时测试
// if (log.isDebugEnabled()) {
// log.debug("剩余有效时间: {}", StpUtil.getTokenTimeout());
diff --git a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/GlobalExceptionHandler.java b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/GlobalExceptionHandler.java
index ca4c3cbb4..d9ee05f45 100644
--- a/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/GlobalExceptionHandler.java
+++ b/ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/GlobalExceptionHandler.java
@@ -5,21 +5,22 @@ import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpStatus;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.DemoModeException;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StreamUtils;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
-
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.validation.ConstraintViolation;
-import jakarta.validation.ConstraintViolationException;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
/**
* 全局异常处理器
@@ -81,6 +82,26 @@ public class GlobalExceptionHandler {
return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
}
+ /**
+ * 请求路径中缺少必需的路径变量
+ */
+ @ExceptionHandler(MissingPathVariableException.class)
+ public R handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request) {
+ String requestURI = request.getRequestURI();
+ log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
+ return R.fail(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
+ }
+
+ /**
+ * 请求参数类型不匹配
+ */
+ @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+ public R handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
+ String requestURI = request.getRequestURI();
+ log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
+ return R.fail(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
+ }
+
/**
* 拦截未知的运行时异常
*/
diff --git a/ruoyi-common/ruoyi-common-sms/pom.xml b/ruoyi-common/ruoyi-common-sms/pom.xml
index b06c5caff..c50f222ac 100644
--- a/ruoyi-common/ruoyi-common-sms/pom.xml
+++ b/ruoyi-common/ruoyi-common-sms/pom.xml
@@ -16,22 +16,19 @@
-
- org.dromara
- ruoyi-common-json
-
- com.aliyun
- dysmsapi20170525
- true
+ org.dromara.sms4j
+ sms4j-spring-boot-starter
+
+
+
+ com.alibaba
+ fastjson
+
+
-
- com.tencentcloudapi
- tencentcloud-sdk-java-sms
- true
-
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java
index 86881f1d8..6b5a84442 100644
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java
+++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsConfig.java
@@ -1,15 +1,6 @@
package org.dromara.common.sms.config;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.core.AliyunSmsTemplate;
-import org.dromara.common.sms.core.SmsTemplate;
-import org.dromara.common.sms.core.TencentSmsTemplate;
import org.springframework.boot.autoconfigure.AutoConfiguration;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
/**
* 短信配置类
@@ -18,31 +9,7 @@ import org.springframework.context.annotation.Configuration;
* @version 4.2.0
*/
@AutoConfiguration
-@EnableConfigurationProperties(SmsProperties.class)
+//@EnableConfigurationProperties(SmsProperties.class)
public class SmsConfig {
- @Configuration
- @ConditionalOnProperty(value = "sms.enabled", havingValue = "true")
- @ConditionalOnClass(com.aliyun.dysmsapi20170525.Client.class)
- static class AliyunSmsConfig {
-
- @Bean
- public SmsTemplate aliyunSmsTemplate(SmsProperties smsProperties) {
- return new AliyunSmsTemplate(smsProperties);
- }
-
- }
-
- @Configuration
- @ConditionalOnProperty(value = "sms.enabled", havingValue = "true")
- @ConditionalOnClass(com.tencentcloudapi.sms.v20190711.SmsClient.class)
- static class TencentSmsConfig {
-
- @Bean
- public SmsTemplate tencentSmsTemplate(SmsProperties smsProperties) {
- return new TencentSmsTemplate(smsProperties);
- }
-
- }
-
}
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java
index da6d9400e..c7b3ef1a5 100644
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java
+++ b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/properties/SmsProperties.java
@@ -1,45 +1,19 @@
-package org.dromara.common.sms.config.properties;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-
-/**
- * SMS短信 配置属性
- *
- * @author Lion Li
- * @version 4.2.0
- */
-@Data
-@ConfigurationProperties(prefix = "sms")
-public class SmsProperties {
-
- private Boolean enabled;
-
- /**
- * 配置节点
- * 阿里云 dysmsapi.aliyuncs.com
- * 腾讯云 sms.tencentcloudapi.com
- */
- private String endpoint;
-
- /**
- * key
- */
- private String accessKeyId;
-
- /**
- * 密匙
- */
- private String accessKeySecret;
-
- /*
- * 短信签名
- */
- private String signName;
-
- /**
- * 短信应用ID (腾讯专属)
- */
- private String sdkAppId;
-
-}
+//package org.dromara.common.sms.config.properties;
+//
+//import lombok.Data;
+//import org.springframework.boot.context.properties.ConfigurationProperties;
+//
+///**
+// * SMS短信 配置属性
+// *
+// * @author Lion Li
+// * @version 4.2.0
+// */
+//@Data
+//@ConfigurationProperties(prefix = "sms")
+//public class SmsProperties {
+//
+// private Boolean enabled;
+//
+//
+//}
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java
deleted file mode 100644
index 00d81523a..000000000
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/AliyunSmsTemplate.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.dromara.common.sms.core;
-
-import com.aliyun.dysmsapi20170525.Client;
-import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
-import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
-import com.aliyun.teaopenapi.models.Config;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.json.utils.JsonUtils;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.entity.SmsResult;
-import org.dromara.common.sms.exception.SmsException;
-import lombok.SneakyThrows;
-
-import java.util.Map;
-
-/**
- * Aliyun 短信模板
- *
- * @author Lion Li
- * @version 4.2.0
- */
-public class AliyunSmsTemplate implements SmsTemplate {
-
- private SmsProperties properties;
-
- private Client client;
-
- @SneakyThrows(Exception.class)
- public AliyunSmsTemplate(SmsProperties smsProperties) {
- this.properties = smsProperties;
- Config config = new Config()
- // 您的AccessKey ID
- .setAccessKeyId(smsProperties.getAccessKeyId())
- // 您的AccessKey Secret
- .setAccessKeySecret(smsProperties.getAccessKeySecret())
- // 访问的域名
- .setEndpoint(smsProperties.getEndpoint());
- this.client = new Client(config);
- }
-
- @Override
- public SmsResult send(String phones, String templateId, Map param) {
- if (StringUtils.isBlank(phones)) {
- throw new SmsException("手机号不能为空");
- }
- if (StringUtils.isBlank(templateId)) {
- throw new SmsException("模板ID不能为空");
- }
- SendSmsRequest req = new SendSmsRequest()
- .setPhoneNumbers(phones)
- .setSignName(properties.getSignName())
- .setTemplateCode(templateId)
- .setTemplateParam(JsonUtils.toJsonString(param));
- try {
- SendSmsResponse resp = client.sendSms(req);
- return SmsResult.builder()
- .isSuccess("OK".equals(resp.getBody().getCode()))
- .message(resp.getBody().getMessage())
- .response(JsonUtils.toJsonString(resp))
- .build();
- } catch (Exception e) {
- throw new SmsException(e.getMessage());
- }
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java
deleted file mode 100644
index eba38dfff..000000000
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/SmsTemplate.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.dromara.common.sms.core;
-
-import org.dromara.common.sms.entity.SmsResult;
-
-import java.util.Map;
-
-/**
- * 短信模板
- *
- * @author Lion Li
- * @version 4.2.0
- */
-public interface SmsTemplate {
-
- /**
- * 发送短信
- *
- * @param phones 电话号(多个逗号分割)
- * @param templateId 模板id
- * @param param 模板对应参数
- * 阿里 需使用 模板变量名称对应内容 例如: code=1234
- * 腾讯 需使用 模板变量顺序对应内容 例如: 1=1234, 1为模板内第一个参数
- */
- SmsResult send(String phones, String templateId, Map param);
-
-}
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java
deleted file mode 100644
index 18d738408..000000000
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/TencentSmsTemplate.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.dromara.common.sms.core;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.ArrayUtil;
-import org.dromara.common.core.utils.StringUtils;
-import org.dromara.common.json.utils.JsonUtils;
-import org.dromara.common.sms.config.properties.SmsProperties;
-import org.dromara.common.sms.entity.SmsResult;
-import org.dromara.common.sms.exception.SmsException;
-import com.tencentcloudapi.common.Credential;
-import com.tencentcloudapi.common.profile.ClientProfile;
-import com.tencentcloudapi.common.profile.HttpProfile;
-import com.tencentcloudapi.sms.v20190711.SmsClient;
-import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
-import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
-import com.tencentcloudapi.sms.v20190711.models.SendStatus;
-import lombok.SneakyThrows;
-
-import java.util.Arrays;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Tencent 短信模板
- *
- * @author Lion Li
- * @version 4.2.0
- */
-public class TencentSmsTemplate implements SmsTemplate {
-
- private SmsProperties properties;
-
- private SmsClient client;
-
- @SneakyThrows(Exception.class)
- public TencentSmsTemplate(SmsProperties smsProperties) {
- this.properties = smsProperties;
- Credential credential = new Credential(smsProperties.getAccessKeyId(), smsProperties.getAccessKeySecret());
- HttpProfile httpProfile = new HttpProfile();
- httpProfile.setEndpoint(smsProperties.getEndpoint());
- ClientProfile clientProfile = new ClientProfile();
- clientProfile.setHttpProfile(httpProfile);
- this.client = new SmsClient(credential, "", clientProfile);
- }
-
- @Override
- public SmsResult send(String phones, String templateId, Map param) {
- if (StringUtils.isBlank(phones)) {
- throw new SmsException("手机号不能为空");
- }
- if (StringUtils.isBlank(templateId)) {
- throw new SmsException("模板ID不能为空");
- }
- SendSmsRequest req = new SendSmsRequest();
- Set set = Arrays.stream(phones.split(StringUtils.SEPARATOR)).map(p -> "+86" + p).collect(Collectors.toSet());
- req.setPhoneNumberSet(ArrayUtil.toArray(set, String.class));
- if (CollUtil.isNotEmpty(param)) {
- req.setTemplateParamSet(ArrayUtil.toArray(param.values(), String.class));
- }
- req.setTemplateID(templateId);
- req.setSign(properties.getSignName());
- req.setSmsSdkAppid(properties.getSdkAppId());
- try {
- SendSmsResponse resp = client.SendSms(req);
- SmsResult.SmsResultBuilder builder = SmsResult.builder()
- .isSuccess(true)
- .message("send success")
- .response(JsonUtils.toJsonString(resp));
- for (SendStatus sendStatus : resp.getSendStatusSet()) {
- if (!"Ok".equals(sendStatus.getCode())) {
- builder.isSuccess(false).message(sendStatus.getMessage());
- break;
- }
- }
- return builder.build();
- } catch (Exception e) {
- throw new SmsException(e.getMessage());
- }
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java
deleted file mode 100644
index 232d61201..000000000
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/entity/SmsResult.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.dromara.common.sms.entity;
-
-import lombok.Builder;
-import lombok.Data;
-
-/**
- * 上传返回体
- *
- * @author Lion Li
- */
-@Data
-@Builder
-public class SmsResult {
-
- /**
- * 是否成功
- */
- private boolean isSuccess;
-
- /**
- * 响应消息
- */
- private String message;
-
- /**
- * 实际响应体
- *
- * 可自行转换为 SDK 对应的 SendSmsResponse
- */
- private String response;
-}
diff --git a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java b/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java
deleted file mode 100644
index eb7730ae4..000000000
--- a/ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/exception/SmsException.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.dromara.common.sms.exception;
-
-import java.io.Serial;
-
-/**
- * Sms异常类
- *
- * @author Lion Li
- */
-public class SmsException extends RuntimeException {
-
- @Serial
- private static final long serialVersionUID = 1L;
-
- public SmsException(String msg) {
- super(msg);
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-social/pom.xml b/ruoyi-common/ruoyi-common-social/pom.xml
new file mode 100644
index 000000000..9f9a965e3
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/pom.xml
@@ -0,0 +1,34 @@
+
+
+
+ org.dromara
+ ruoyi-common
+ ${revision}
+
+ 4.0.0
+
+ ruoyi-common-social
+
+
+ ruoyi-common-social 授权认证
+
+
+
+
+ me.zhyd.oauth
+ JustAuth
+
+
+
+ org.dromara
+ ruoyi-common-json
+
+
+
+ org.dromara
+ ruoyi-common-redis
+
+
+
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java
new file mode 100644
index 000000000..19b39d8fb
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java
@@ -0,0 +1,23 @@
+package org.dromara.common.social.config;
+
+import me.zhyd.oauth.cache.AuthStateCache;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.utils.AuthRedisStateCache;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+
+/**
+ * Social 配置属性
+ * @author thiszhc
+ */
+@AutoConfiguration
+@EnableConfigurationProperties(SocialProperties.class)
+public class SocialAutoConfiguration {
+
+ @Bean
+ public AuthStateCache authStateCache() {
+ return new AuthRedisStateCache();
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java
new file mode 100644
index 000000000..76be234c6
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java
@@ -0,0 +1,68 @@
+package org.dromara.common.social.config.properties;
+
+import lombok.Data;
+
+/**
+ * 社交登录配置
+ *
+ * @author thiszhc
+ */
+@Data
+public class SocialLoginConfigProperties {
+
+ /**
+ * 应用 ID
+ */
+ private String clientId;
+
+ /**
+ * 应用密钥
+ */
+ private String clientSecret;
+
+ /**
+ * 回调地址
+ */
+ private String redirectUri;
+
+ /**
+ * 是否获取unionId
+ */
+ private boolean unionId;
+
+ /**
+ * Coding 企业名称
+ */
+ private String codingGroupName;
+
+ /**
+ * 支付宝公钥
+ */
+ private String alipayPublicKey;
+
+ /**
+ * 企业微信应用ID
+ */
+ private String agentId;
+
+ /**
+ * stackoverflow api key
+ */
+ private String stackOverflowKey;
+
+ /**
+ * 设备ID
+ */
+ private String deviceId;
+
+ /**
+ * 客户端系统类型
+ */
+ private String clientOsType;
+
+ /**
+ * maxkey 服务器地址
+ */
+ private String serverUrl;
+
+}
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java
new file mode 100644
index 000000000..1beb7d042
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java
@@ -0,0 +1,29 @@
+package org.dromara.common.social.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+
+/**
+ * Social 配置属性
+ *
+ * @author thiszhc
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "justauth")
+public class SocialProperties {
+
+ /**
+ * 是否启用
+ */
+ private Boolean enabled;
+
+ /**
+ * 授权类型
+ */
+ private Map type;
+
+}
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
new file mode 100644
index 000000000..e8df79e5b
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
@@ -0,0 +1,80 @@
+package org.dromara.common.social.maxkey;
+
+import cn.hutool.core.lang.Dict;
+import me.zhyd.oauth.cache.AuthStateCache;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+
+/**
+ * @author 长春叭哥 2023年03月26日
+ */
+public class AuthMaxKeyRequest extends AuthDefaultRequest {
+
+ public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.maxkey.server-url");
+
+ /**
+ * 设定归属域
+ */
+ public AuthMaxKeyRequest(AuthConfig config) {
+ super(config, AuthMaxKeySource.MAXKEY);
+ }
+
+ public AuthMaxKeyRequest(AuthConfig config, AuthStateCache authStateCache) {
+ super(config, AuthMaxKeySource.MAXKEY, authStateCache);
+ }
+
+ @Override
+ protected AuthToken getAccessToken(AuthCallback authCallback) {
+ String body = doPostAuthorizationCode(authCallback.getCode());
+ Dict object = JsonUtils.parseMap(body);
+ // oauth/token 验证异常
+ if (object.containsKey("error")) {
+ throw new AuthException(object.getStr("error_description"));
+ }
+ // user 验证异常
+ if (object.containsKey("message")) {
+ throw new AuthException(object.getStr("message"));
+ }
+ return AuthToken.builder()
+ .accessToken(object.getStr("access_token"))
+ .refreshToken(object.getStr("refresh_token"))
+ .idToken(object.getStr("id_token"))
+ .tokenType(object.getStr("token_type"))
+ .scope(object.getStr("scope"))
+ .build();
+ }
+
+ @Override
+ protected AuthUser getUserInfo(AuthToken authToken) {
+ String body = doGetUserInfo(authToken);
+ Dict object = JsonUtils.parseMap(body);
+ // oauth/token 验证异常
+ if (object.containsKey("error")) {
+ throw new AuthException(object.getStr("error_description"));
+ }
+ // user 验证异常
+ if (object.containsKey("message")) {
+ throw new AuthException(object.getStr("message"));
+ }
+ return AuthUser.builder()
+ .uuid(object.getStr("id"))
+ .username(object.getStr("username"))
+ .nickname(object.getStr("name"))
+ .avatar(object.getStr("avatar_url"))
+ .blog(object.getStr("web_url"))
+ .company(object.getStr("organization"))
+ .location(object.getStr("location"))
+ .email(object.getStr("email"))
+ .remark(object.getStr("bio"))
+ .token(authToken)
+ .source(source.toString())
+ .build();
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java
new file mode 100644
index 000000000..1ff57f7c5
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java
@@ -0,0 +1,52 @@
+package org.dromara.common.social.maxkey;
+
+import me.zhyd.oauth.config.AuthSource;
+import me.zhyd.oauth.request.AuthDefaultRequest;
+
+/**
+ * Oauth2 默认接口说明
+ *
+ * @author 长春叭哥 2023年03月26日
+ *
+ */
+public enum AuthMaxKeySource implements AuthSource {
+
+ /**
+ * 自己搭建的 maxkey 私服
+ */
+ MAXKEY {
+
+ /**
+ * 授权的api
+ */
+ @Override
+ public String authorize() {
+ return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/authorize";
+ }
+
+ /**
+ * 获取accessToken的api
+ */
+ @Override
+ public String accessToken() {
+ return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/token";
+ }
+
+ /**
+ * 获取用户信息的api
+ */
+ @Override
+ public String userInfo() {
+ return AuthMaxKeyRequest.SERVER_URL + "/sign/api/oauth/v20/me";
+ }
+
+ /**
+ * 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest}
+ */
+ @Override
+ public Class extends AuthDefaultRequest> getTargetClass() {
+ return AuthMaxKeyRequest.class;
+ }
+
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java
new file mode 100644
index 000000000..0b6ec2023
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java
@@ -0,0 +1,61 @@
+package org.dromara.common.social.utils;
+
+import lombok.AllArgsConstructor;
+import me.zhyd.oauth.cache.AuthStateCache;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.redis.utils.RedisUtils;
+
+import java.time.Duration;
+
+/**
+ * 授权状态缓存
+ */
+@AllArgsConstructor
+public class AuthRedisStateCache implements AuthStateCache {
+
+ /**
+ * 存入缓存
+ *
+ * @param key 缓存key
+ * @param value 缓存内容
+ */
+ @Override
+ public void cache(String key, String value) {
+ // 授权超时时间 默认三分钟
+ RedisUtils.setCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key, value, Duration.ofMinutes(3));
+ }
+
+ /**
+ * 存入缓存
+ *
+ * @param key 缓存key
+ * @param value 缓存内容
+ * @param timeout 指定缓存过期时间(毫秒)
+ */
+ @Override
+ public void cache(String key, String value, long timeout) {
+ RedisUtils.setCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key, value, Duration.ofMillis(timeout));
+ }
+
+ /**
+ * 获取缓存内容
+ *
+ * @param key 缓存key
+ * @return 缓存内容
+ */
+ @Override
+ public String get(String key) {
+ return RedisUtils.getCacheObject(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key);
+ }
+
+ /**
+ * 是否存在key,如果对应key的value值已过期,也返回false
+ *
+ * @param key 缓存key
+ * @return true:存在key,并且value没过期;false:key不存在或者已过期
+ */
+ @Override
+ public boolean containsKey(String key) {
+ return RedisUtils.hasKey(GlobalConstants.SOCIAL_AUTH_CODE_KEY + key);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
new file mode 100644
index 000000000..b3e801c1e
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java
@@ -0,0 +1,70 @@
+package org.dromara.common.social.utils;
+
+import cn.hutool.core.util.ObjectUtil;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.*;
+import org.dromara.common.core.domain.model.LoginBody;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
+import org.dromara.common.social.config.properties.SocialProperties;
+import org.dromara.common.social.maxkey.AuthMaxKeyRequest;
+
+/**
+ * 认证授权工具类
+ *
+ * @author thiszhc
+ */
+public class SocialUtils {
+
+ private static final AuthRedisStateCache STATE_CACHE = SpringUtils.getBean(AuthRedisStateCache.class);
+
+ @SuppressWarnings("unchecked")
+ public static AuthResponse loginAuth(LoginBody loginBody, SocialProperties socialProperties) throws AuthException {
+ AuthRequest authRequest = getAuthRequest(loginBody.getSource(), socialProperties);
+ AuthCallback callback = new AuthCallback();
+ callback.setCode(loginBody.getSocialCode());
+ callback.setState(loginBody.getSocialState());
+ return authRequest.login(callback);
+ }
+
+ public static AuthRequest getAuthRequest(String source, SocialProperties socialProperties) throws AuthException {
+ SocialLoginConfigProperties obj = socialProperties.getType().get(source);
+ if (ObjectUtil.isNull(obj)) {
+ throw new AuthException("不支持的第三方登录类型");
+ }
+ String clientId = obj.getClientId();
+ String clientSecret = obj.getClientSecret();
+ String redirectUri = obj.getRedirectUri();
+ return switch (source.toLowerCase()) {
+ case "dingtalk" -> new AuthDingTalkRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "baidu" -> new AuthBaiduRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "github" -> new AuthGithubRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "gitee" -> new AuthGiteeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "weibo" -> new AuthWeiboRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "coding" -> new AuthCodingRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "oschina" -> new AuthOschinaRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ // 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1,所以这儿的回调地址使用的局域网内的ip
+ case "alipay" -> new AuthAlipayRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), socialProperties.getType().get("alipay").getAlipayPublicKey(), STATE_CACHE);
+ case "qq" -> new AuthQqRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "wechat_open" -> new AuthWeChatOpenRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "taobao" -> new AuthTaobaoRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "douyin" -> new AuthDouyinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "linkedin" -> new AuthLinkedinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "microsoft" -> new AuthMicrosoftRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "renren" -> new AuthRenrenRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "stack_overflow" -> new AuthStackOverflowRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).stackOverflowKey("").build(), STATE_CACHE);
+ case "huawei" -> new AuthHuaweiRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "wechat_enterprise" -> new AuthWeChatEnterpriseQrcodeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).agentId("").build(), STATE_CACHE);
+ case "gitlab" -> new AuthGitlabRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "wechat_mp" -> new AuthWeChatMpRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "aliyun" -> new AuthAliyunRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ case "maxkey" -> new AuthMaxKeyRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), STATE_CACHE);
+ default -> throw new AuthException("未获取到有效的Auth配置");
+ };
+ }
+}
+
diff --git a/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..fc544a0fd
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+org.dromara.common.social.config.SocialAutoConfiguration
diff --git a/ruoyi-extend/pom.xml b/ruoyi-extend/pom.xml
index ee176e998..f5348cc13 100644
--- a/ruoyi-extend/pom.xml
+++ b/ruoyi-extend/pom.xml
@@ -13,7 +13,7 @@
ruoyi-monitor-admin
- ruoyi-xxl-job-admin
+ ruoyi-powerjob-server
diff --git a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
index 4bd37ffa9..3f5dec82c 100644
--- a/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
+++ b/ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java
@@ -3,10 +3,14 @@ package org.dromara.monitor.admin.config;
import de.codecentric.boot.admin.server.config.AdminServerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
/**
* admin 监控 安全配置
@@ -30,23 +34,23 @@ public class SecurityConfig {
successHandler.setDefaultTargetUrl(adminContextPath + "/");
return httpSecurity
- .headers().frameOptions().disable()
- .and().authorizeHttpRequests()
- .requestMatchers(adminContextPath + "/assets/**"
- , adminContextPath + "/login"
- , "/actuator"
- , "/actuator/**"
- ).permitAll()
- .anyRequest().authenticated()
- .and()
- .formLogin().loginPage(adminContextPath + "/login")
- .successHandler(successHandler).and()
- .logout().logoutUrl(adminContextPath + "/logout")
- .and()
- .httpBasic().and()
- .csrf()
- .disable()
- .build();
+ .headers((header) ->
+ header.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
+ .authorizeHttpRequests((authorize) ->
+ authorize.requestMatchers(
+ new AntPathRequestMatcher(adminContextPath + "/assets/**"),
+ new AntPathRequestMatcher(adminContextPath + "/login"),
+ new AntPathRequestMatcher("/actuator"),
+ new AntPathRequestMatcher("/actuator/**")
+ ).permitAll()
+ .anyRequest().authenticated())
+ .formLogin((formLogin) ->
+ formLogin.loginPage(adminContextPath + "/login").successHandler(successHandler))
+ .logout((logout) ->
+ logout.logoutUrl(adminContextPath + "/logout"))
+ .httpBasic(Customizer.withDefaults())
+ .csrf(AbstractHttpConfigurer::disable)
+ .build();
}
}
diff --git a/ruoyi-extend/ruoyi-powerjob-server/Dockerfile b/ruoyi-extend/ruoyi-powerjob-server/Dockerfile
new file mode 100644
index 000000000..e92de893b
--- /dev/null
+++ b/ruoyi-extend/ruoyi-powerjob-server/Dockerfile
@@ -0,0 +1,13 @@
+FROM findepi/graalvm:java17-native
+
+MAINTAINER Lion Li
+
+RUN mkdir -p /ruoyi/powerjob/logs
+
+WORKDIR /ruoyi/powerjob
+
+EXPOSE 7700
+
+ADD ./target/ruoyi-powerjob-server.jar ./app.jar
+
+ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
diff --git a/ruoyi-extend/ruoyi-powerjob-server/pom.xml b/ruoyi-extend/ruoyi-powerjob-server/pom.xml
new file mode 100644
index 000000000..60b4d27f2
--- /dev/null
+++ b/ruoyi-extend/ruoyi-powerjob-server/pom.xml
@@ -0,0 +1,68 @@
+
+
+ org.dromara
+ ruoyi-extend
+ ${revision}
+
+ 4.0.0
+ jar
+ ruoyi-powerjob-server
+
+
+ 2.7.14
+ 2.7.10
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ ${spring-boot.version}
+ pom
+ import
+
+
+
+
+
+
+
+
+ tech.powerjob
+ powerjob-server-starter
+ ${powerjob.version}
+
+
+
+ de.codecentric
+ spring-boot-admin-starter-client
+ ${spring-boot-admin.version}
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+ ${project.artifactId}
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+
diff --git a/ruoyi-extend/ruoyi-powerjob-server/src/main/java/org/dromara/powerjob/PowerJobServerApplication.java b/ruoyi-extend/ruoyi-powerjob-server/src/main/java/org/dromara/powerjob/PowerJobServerApplication.java
new file mode 100644
index 000000000..3898639cf
--- /dev/null
+++ b/ruoyi-extend/ruoyi-powerjob-server/src/main/java/org/dromara/powerjob/PowerJobServerApplication.java
@@ -0,0 +1,25 @@
+package org.dromara.powerjob;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import tech.powerjob.server.common.utils.PropertyUtils;
+
+/**
+ * powerjob 启动程序
+ *
+ * @author yhan219
+ */
+@Slf4j
+@EnableScheduling
+@SpringBootApplication(scanBasePackages = "tech.powerjob.server")
+public class PowerJobServerApplication {
+
+ public static void main(String[] args) {
+ PropertyUtils.init();
+ SpringApplication.run(tech.powerjob.server.PowerJobServerApplication.class, args);
+ log.info("文档地址: https://www.yuque.com/powerjob/guidence/problem");
+ }
+
+}
diff --git a/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application-dev.properties b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application-dev.properties
new file mode 100644
index 000000000..36dbdfc65
--- /dev/null
+++ b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application-dev.properties
@@ -0,0 +1,50 @@
+oms.env=dev
+
+####### Database properties(Configure according to the the environment) #######
+spring.datasource.core.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.core.jdbc-url=jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
+spring.datasource.core.username=root
+spring.datasource.core.password=root
+spring.datasource.core.maximum-pool-size=20
+spring.datasource.core.minimum-idle=5
+
+# 监控配置
+# 客户端开关
+spring.boot.admin.client.enabled=true
+# 设置 Spring Boot Admin Server 地址
+spring.boot.admin.client.url: http://localhost:9090/admin
+spring.boot.admin.client.instance.service-host-type=IP
+spring.boot.admin.client.username=ruoyi
+spring.boot.admin.client.password=123456
+
+####### MongoDB properties(Non-core configuration properties) #######
+####### delete mongodb config to disable mongodb #######
+oms.mongodb.enable=false
+#spring.data.mongodb.uri=mongodb+srv://zqq:No1Bug2Please3!@cluster0.wie54.gcp.mongodb.net/powerjob_daily?retryWrites=true&w=majority
+
+####### Email properties(Non-core configuration properties) #######
+####### Delete the following code to disable the mail #######
+#spring.mail.host=smtp.163.com
+#spring.mail.username=zqq@163.com
+#spring.mail.password=GOFZPNARMVKCGONV
+#spring.mail.properties.mail.smtp.auth=true
+#spring.mail.properties.mail.smtp.starttls.enable=true
+#spring.mail.properties.mail.smtp.starttls.required=true
+
+####### DingTalk properties(Non-core configuration properties) #######
+####### Delete the following code to disable the DingTalk #######
+#oms.alarm.ding.app-key=dingauqwkvxxnqskknfv
+#oms.alarm.ding.app-secret=XWrEPdAZMPgJeFtHuL0LH73LRj-74umF2_0BFcoXMfvnX0pCQvt0rpb1JOJU_HLl
+#oms.alarm.ding.agent-id=847044348
+
+####### Resource cleaning properties #######
+oms.instanceinfo.retention=1
+oms.container.retention.local=1
+oms.container.retention.remote=-1
+
+####### Cache properties #######
+oms.instance.metadata.cache.size=1024
+
+####### Threshold in precise fetching server(0~100). 100 means full detection of server, in which #######
+####### split-brain could be avoided while performance overhead would increase. #######
+oms.accurate.select.server.percentage = 50
diff --git a/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application-prod.properties b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application-prod.properties
new file mode 100644
index 000000000..e6a6052c1
--- /dev/null
+++ b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application-prod.properties
@@ -0,0 +1,50 @@
+oms.env=prod
+
+####### Database properties(Configure according to the the environment) #######
+spring.datasource.core.driver-class-name=com.mysql.cj.jdbc.Driver
+spring.datasource.core.jdbc-url=jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
+spring.datasource.core.username=root
+spring.datasource.core.password=root
+spring.datasource.core.maximum-pool-size=20
+spring.datasource.core.minimum-idle=5
+
+# 监控配置
+# 客户端开关
+spring.boot.admin.client.enabled=true
+# 设置 Spring Boot Admin Server 地址
+spring.boot.admin.client.url: http://localhost:9090/admin
+spring.boot.admin.client.instance.service-host-type=IP
+spring.boot.admin.client.username=ruoyi
+spring.boot.admin.client.password=123456
+
+####### MongoDB properties(Non-core configuration properties) #######
+####### delete mongodb config to disable mongodb #######
+oms.mongodb.enable=false
+#spring.data.mongodb.uri=mongodb+srv://zqq:No1Bug2Please3!@cluster0.wie54.gcp.mongodb.net/powerjob_daily?retryWrites=true&w=majority
+
+####### Email properties(Non-core configuration properties) #######
+####### Delete the following code to disable the mail #######
+#spring.mail.host=smtp.163.com
+#spring.mail.username=zqq@163.com
+#spring.mail.password=GOFZPNARMVKCGONV
+#spring.mail.properties.mail.smtp.auth=true
+#spring.mail.properties.mail.smtp.starttls.enable=true
+#spring.mail.properties.mail.smtp.starttls.required=true
+
+####### DingTalk properties(Non-core configuration properties) #######
+####### Delete the following code to disable the DingTalk #######
+#oms.alarm.ding.app-key=dingauqwkvxxnqskknfv
+#oms.alarm.ding.app-secret=XWrEPdAZMPgJeFtHuL0LH73LRj-74umF2_0BFcoXMfvnX0pCQvt0rpb1JOJU_HLl
+#oms.alarm.ding.agent-id=847044348
+
+####### Resource cleaning properties #######
+oms.instanceinfo.retention=7
+oms.container.retention.local=7
+oms.container.retention.remote=-1
+
+####### Cache properties #######
+oms.instance.metadata.cache.size=2048
+
+####### Threshold in precise fetching server(0~100). 100 means full detection of server, in which #######
+####### split-brain could be avoided while performance overhead would increase. #######
+oms.accurate.select.server.percentage = 50
diff --git a/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application.properties b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application.properties
new file mode 100644
index 000000000..5477c1fed
--- /dev/null
+++ b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/application.properties
@@ -0,0 +1,30 @@
+# Http server port
+server.port=7700
+
+spring.profiles.active=@profiles.active@
+spring.main.banner-mode=log
+spring.jpa.open-in-view=false
+spring.data.mongodb.repositories.type=none
+logging.level.org.mongodb=warn
+logging.config: classpath:logback-plus.xml
+
+# Configuration for uploading files.
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.file-size-threshold=0
+spring.servlet.multipart.max-file-size=209715200
+spring.servlet.multipart.max-request-size=209715200
+
+###### PowerJob transporter configuration ######
+oms.transporter.active.protocols=AKKA,HTTP
+oms.transporter.main.protocol=HTTP
+oms.akka.port=10086
+oms.http.port=10010
+# Prefix for all tables. Default empty string. Config if you have needs, i.e. pj_
+oms.table-prefix=pj_
+
+# Actuator 监控端点的配置项
+spring.application.name: ruoyi-powerjob-server
+management.endpoints.web.exposure.include=*
+management.endpoint.health.show-details=ALWAYS
+management.endpoint.logfile.external-file=./logs/ruoyi-powerjob-server.log
+management.health.mongo.enabled=${oms.mongodb.enable}
diff --git a/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/banner.txt b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/banner.txt
new file mode 100644
index 000000000..c0fac79b2
--- /dev/null
+++ b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/banner.txt
@@ -0,0 +1,11 @@
+Application Version: ${revision}
+Spring Boot Version: ${spring-boot.version}
+ _ _
+ (_) | |
+ _ __ _____ _____ _ __ _ ___ | |__ ______ ___ ___ _ ____ _____ _ __
+| '_ \ / _ \ \ /\ / / _ \ '__| |/ _ \| '_ \______/ __|/ _ \ '__\ \ / / _ \ '__|
+| |_) | (_) \ V V / __/ | | | (_) | |_) | \__ \ __/ | \ V / __/ |
+| .__/ \___/ \_/\_/ \___|_| | |\___/|_.__/ |___/\___|_| \_/ \___|_|
+| | _/ |
+|_| |__/
+
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/logback-plus.xml b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/logback-plus.xml
similarity index 93%
rename from ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/logback-plus.xml
rename to ruoyi-extend/ruoyi-powerjob-server/src/main/resources/logback-plus.xml
index 9c2e77233..ad3bfa967 100644
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/resources/logback-plus.xml
+++ b/ruoyi-extend/ruoyi-powerjob-server/src/main/resources/logback-plus.xml
@@ -2,7 +2,7 @@
logback
-
+
@@ -31,4 +31,4 @@
-
\ No newline at end of file
+
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile b/ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile
deleted file mode 100644
index 049c5c58d..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/Dockerfile
+++ /dev/null
@@ -1,16 +0,0 @@
-FROM findepi/graalvm:java17-native
-
-MAINTAINER Lion Li
-
-RUN mkdir -p /ruoyi/xxljob/logs
-
-WORKDIR /ruoyi/xxljob
-
-ENV TZ=PRC
-RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
-
-EXPOSE 9100
-
-ADD ./target/ruoyi-xxl-job-admin.jar ./app.jar
-
-ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/pom.xml b/ruoyi-extend/ruoyi-xxl-job-admin/pom.xml
deleted file mode 100644
index 10f12b5df..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/pom.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-
- 4.0.0
-
- ruoyi-extend
- org.dromara
- ${revision}
-
- ruoyi-xxl-job-admin
- jar
-
-
- 2.7.12
- 2.7.10
- 2.2.2
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter-parent
- ${spring-boot.version}
- pom
- import
-
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
-
-
- org.springframework.boot
- spring-boot-starter-freemarker
-
-
-
-
- org.springframework.boot
- spring-boot-starter-mail
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
-
- org.springframework.boot
- spring-boot-starter-aop
-
-
-
-
- org.mybatis.spring.boot
- mybatis-spring-boot-starter
- ${mybatis-spring-boot.version}
-
-
-
- com.mysql
- mysql-connector-j
-
-
-
- de.codecentric
- spring-boot-admin-starter-client
- ${spring-boot-admin.version}
-
-
-
-
- com.xuxueli
- xxl-job-core
-
-
-
-
-
- ${project.artifactId}
-
-
- org.springframework.boot
- spring-boot-maven-plugin
- ${spring-boot.version}
-
-
-
- repackage
-
-
-
-
-
-
-
-
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java
deleted file mode 100644
index 95ec1c412..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/XxlJobAdminApplication.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.xxl.job.admin;
-
-import org.springframework.boot.SpringApplication;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-/**
- * @author xuxueli 2018-10-28 00:38:13
- */
-@SpringBootApplication
-public class XxlJobAdminApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(XxlJobAdminApplication.class, args);
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java
deleted file mode 100644
index bbb25077d..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/IndexController.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.xxl.job.admin.controller;
-
-import com.xxl.job.admin.controller.annotation.PermissionLimit;
-import com.xxl.job.admin.service.LoginService;
-import com.xxl.job.admin.service.XxlJobService;
-import com.xxl.job.core.biz.model.ReturnT;
-import org.springframework.beans.propertyeditors.CustomDateEditor;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.WebDataBinder;
-import org.springframework.web.bind.annotation.InitBinder;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.view.RedirectView;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Map;
-
-/**
- * index controller
- *
- * @author xuxueli 2015-12-19 16:13:16
- */
-@Controller
-public class IndexController {
-
- @Resource
- private XxlJobService xxlJobService;
- @Resource
- private LoginService loginService;
-
-
- @RequestMapping("/")
- public String index(Model model) {
-
- Map dashboardMap = xxlJobService.dashboardInfo();
- model.addAllAttributes(dashboardMap);
-
- return "index";
- }
-
- @RequestMapping("/chartInfo")
- @ResponseBody
- public ReturnT> chartInfo(Date startDate, Date endDate) {
- ReturnT> chartInfo = xxlJobService.chartInfo(startDate, endDate);
- return chartInfo;
- }
-
- @RequestMapping("/toLogin")
- @PermissionLimit(limit = false)
- public ModelAndView toLogin(HttpServletRequest request, HttpServletResponse response, ModelAndView modelAndView) {
- if (loginService.ifLogin(request, response) != null) {
- modelAndView.setView(new RedirectView("/", true, false));
- return modelAndView;
- }
- return new ModelAndView("login");
- }
-
- @RequestMapping(value = "login", method = RequestMethod.POST)
- @ResponseBody
- @PermissionLimit(limit = false)
- public ReturnT loginDo(HttpServletRequest request, HttpServletResponse response, String userName, String password, String ifRemember) {
- boolean ifRem = (ifRemember != null && ifRemember.trim().length() > 0 && "on".equals(ifRemember)) ? true : false;
- return loginService.login(request, response, userName, password, ifRem);
- }
-
- @RequestMapping(value = "logout", method = RequestMethod.POST)
- @ResponseBody
- @PermissionLimit(limit = false)
- public ReturnT logout(HttpServletRequest request, HttpServletResponse response) {
- return loginService.logout(request, response);
- }
-
- @RequestMapping("/help")
- public String help() {
-
- /*if (!PermissionInterceptor.ifLogin(request)) {
- return "redirect:/toLogin";
- }*/
-
- return "help";
- }
-
- @InitBinder
- public void initBinder(WebDataBinder binder) {
- SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
- dateFormat.setLenient(false);
- binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java
deleted file mode 100644
index f4a37a71d..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobApiController.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.xxl.job.admin.controller;
-
-import com.xxl.job.admin.controller.annotation.PermissionLimit;
-import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
-import com.xxl.job.core.biz.AdminBiz;
-import com.xxl.job.core.biz.model.HandleCallbackParam;
-import com.xxl.job.core.biz.model.RegistryParam;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.util.GsonTool;
-import com.xxl.job.core.util.XxlJobRemotingUtil;
-import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.List;
-
-/**
- * Created by xuxueli on 17/5/10.
- */
-@Controller
-@RequestMapping("/api")
-public class JobApiController {
-
- @Resource
- private AdminBiz adminBiz;
-
- /**
- * api
- *
- * @param uri
- * @param data
- * @return
- */
- @RequestMapping("/{uri}")
- @ResponseBody
- @PermissionLimit(limit = false)
- public ReturnT api(HttpServletRequest request, @PathVariable("uri") String uri, @RequestBody(required = false) String data) {
-
- // valid
- if (!"POST".equalsIgnoreCase(request.getMethod())) {
- return new ReturnT(ReturnT.FAIL_CODE, "invalid request, HttpMethod not support.");
- }
- if (uri == null || uri.trim().length() == 0) {
- return new ReturnT(ReturnT.FAIL_CODE, "invalid request, uri-mapping empty.");
- }
- if (XxlJobAdminConfig.getAdminConfig().getAccessToken() != null
- && XxlJobAdminConfig.getAdminConfig().getAccessToken().trim().length() > 0
- && !XxlJobAdminConfig.getAdminConfig().getAccessToken().equals(request.getHeader(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN))) {
- return new ReturnT(ReturnT.FAIL_CODE, "The access token is wrong.");
- }
-
- // services mapping
- if ("callback".equals(uri)) {
- List callbackParamList = GsonTool.fromJson(data, List.class, HandleCallbackParam.class);
- return adminBiz.callback(callbackParamList);
- } else if ("registry".equals(uri)) {
- RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
- return adminBiz.registry(registryParam);
- } else if ("registryRemove".equals(uri)) {
- RegistryParam registryParam = GsonTool.fromJson(data, RegistryParam.class);
- return adminBiz.registryRemove(registryParam);
- } else {
- return new ReturnT(ReturnT.FAIL_CODE, "invalid request, uri-mapping(" + uri + ") not found.");
- }
-
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java
deleted file mode 100644
index 9185f86b4..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobCodeController.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.xxl.job.admin.controller;
-
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.model.XxlJobLogGlue;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.admin.dao.XxlJobInfoDao;
-import com.xxl.job.admin.dao.XxlJobLogGlueDao;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.glue.GlueTypeEnum;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.Date;
-import java.util.List;
-
-/**
- * job code controller
- *
- * @author xuxueli 2015-12-19 16:13:16
- */
-@Controller
-@RequestMapping("/jobcode")
-public class JobCodeController {
-
- @Resource
- private XxlJobInfoDao xxlJobInfoDao;
- @Resource
- private XxlJobLogGlueDao xxlJobLogGlueDao;
-
- @RequestMapping
- public String index(HttpServletRequest request, Model model, int jobId) {
- XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
- List jobLogGlues = xxlJobLogGlueDao.findByJobId(jobId);
-
- if (jobInfo == null) {
- throw new RuntimeException(I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
- }
- if (GlueTypeEnum.BEAN == GlueTypeEnum.match(jobInfo.getGlueType())) {
- throw new RuntimeException(I18nUtil.getString("jobinfo_glue_gluetype_unvalid"));
- }
-
- // valid permission
- JobInfoController.validPermission(request, jobInfo.getJobGroup());
-
- // Glue类型-字典
- model.addAttribute("GlueTypeEnum", GlueTypeEnum.values());
-
- model.addAttribute("jobInfo", jobInfo);
- model.addAttribute("jobLogGlues", jobLogGlues);
- return "jobcode/jobcode.index";
- }
-
- @RequestMapping("/save")
- @ResponseBody
- public ReturnT save(Model model, int id, String glueSource, String glueRemark) {
- // valid
- if (glueRemark == null) {
- return new ReturnT(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobinfo_glue_remark")));
- }
- if (glueRemark.length() < 4 || glueRemark.length() > 100) {
- return new ReturnT(500, I18nUtil.getString("jobinfo_glue_remark_limit"));
- }
- XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(id);
- if (exists_jobInfo == null) {
- return new ReturnT(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
- }
-
- // update new code
- exists_jobInfo.setGlueSource(glueSource);
- exists_jobInfo.setGlueRemark(glueRemark);
- exists_jobInfo.setGlueUpdatetime(new Date());
-
- exists_jobInfo.setUpdateTime(new Date());
- xxlJobInfoDao.update(exists_jobInfo);
-
- // log old code
- XxlJobLogGlue xxlJobLogGlue = new XxlJobLogGlue();
- xxlJobLogGlue.setJobId(exists_jobInfo.getId());
- xxlJobLogGlue.setGlueType(exists_jobInfo.getGlueType());
- xxlJobLogGlue.setGlueSource(glueSource);
- xxlJobLogGlue.setGlueRemark(glueRemark);
-
- xxlJobLogGlue.setAddTime(new Date());
- xxlJobLogGlue.setUpdateTime(new Date());
- xxlJobLogGlueDao.save(xxlJobLogGlue);
-
- // remove code backup more than 30
- xxlJobLogGlueDao.removeOld(exists_jobInfo.getId(), 30);
-
- return ReturnT.SUCCESS;
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java
deleted file mode 100644
index 5cbf87287..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobGroupController.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package com.xxl.job.admin.controller;
-
-import com.xxl.job.admin.controller.annotation.PermissionLimit;
-import com.xxl.job.admin.core.model.XxlJobGroup;
-import com.xxl.job.admin.core.model.XxlJobRegistry;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.admin.dao.XxlJobGroupDao;
-import com.xxl.job.admin.dao.XxlJobInfoDao;
-import com.xxl.job.admin.dao.XxlJobRegistryDao;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.enums.RegistryConfig;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.*;
-
-/**
- * job group controller
- *
- * @author xuxueli 2016-10-02 20:52:56
- */
-@Controller
-@RequestMapping("/jobgroup")
-public class JobGroupController {
-
- @Resource
- public XxlJobInfoDao xxlJobInfoDao;
- @Resource
- public XxlJobGroupDao xxlJobGroupDao;
- @Resource
- private XxlJobRegistryDao xxlJobRegistryDao;
-
- @RequestMapping
- @PermissionLimit(adminuser = true)
- public String index(Model model) {
- return "jobgroup/jobgroup.index";
- }
-
- @RequestMapping("/pageList")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public Map pageList(HttpServletRequest request,
- @RequestParam(required = false, defaultValue = "0") int start,
- @RequestParam(required = false, defaultValue = "10") int length,
- String appname, String title) {
-
- // page query
- List list = xxlJobGroupDao.pageList(start, length, appname, title);
- int list_count = xxlJobGroupDao.pageListCount(start, length, appname, title);
-
- // package result
- Map maps = new HashMap();
- maps.put("recordsTotal", list_count); // 总记录数
- maps.put("recordsFiltered", list_count); // 过滤后的总记录数
- maps.put("data", list); // 分页列表
- return maps;
- }
-
- @RequestMapping("/save")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public ReturnT save(XxlJobGroup xxlJobGroup) {
-
- // valid
- if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) {
- return new ReturnT(500, (I18nUtil.getString("system_please_input") + "AppName"));
- }
- if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_appname_length"));
- }
- if (xxlJobGroup.getAppname().contains(">") || xxlJobGroup.getAppname().contains("<")) {
- return new ReturnT(500, "AppName" + I18nUtil.getString("system_unvalid"));
- }
- if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) {
- return new ReturnT(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")));
- }
- if (xxlJobGroup.getTitle().contains(">") || xxlJobGroup.getTitle().contains("<")) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_title") + I18nUtil.getString("system_unvalid"));
- }
- if (xxlJobGroup.getAddressType() != 0) {
- if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_addressType_limit"));
- }
- if (xxlJobGroup.getAddressList().contains(">") || xxlJobGroup.getAddressList().contains("<")) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList") + I18nUtil.getString("system_unvalid"));
- }
-
- String[] addresss = xxlJobGroup.getAddressList().split(",");
- for (String item : addresss) {
- if (item == null || item.trim().length() == 0) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList_unvalid"));
- }
- }
- }
-
- // process
- xxlJobGroup.setUpdateTime(new Date());
-
- int ret = xxlJobGroupDao.save(xxlJobGroup);
- return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL;
- }
-
- @RequestMapping("/update")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public ReturnT update(XxlJobGroup xxlJobGroup) {
- // valid
- if (xxlJobGroup.getAppname() == null || xxlJobGroup.getAppname().trim().length() == 0) {
- return new ReturnT(500, (I18nUtil.getString("system_please_input") + "AppName"));
- }
- if (xxlJobGroup.getAppname().length() < 4 || xxlJobGroup.getAppname().length() > 64) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_appname_length"));
- }
- if (xxlJobGroup.getTitle() == null || xxlJobGroup.getTitle().trim().length() == 0) {
- return new ReturnT(500, (I18nUtil.getString("system_please_input") + I18nUtil.getString("jobgroup_field_title")));
- }
- if (xxlJobGroup.getAddressType() == 0) {
- // 0=自动注册
- List registryList = findRegistryByAppName(xxlJobGroup.getAppname());
- String addressListStr = null;
- if (registryList != null && !registryList.isEmpty()) {
- Collections.sort(registryList);
- addressListStr = "";
- for (String item : registryList) {
- addressListStr += item + ",";
- }
- addressListStr = addressListStr.substring(0, addressListStr.length() - 1);
- }
- xxlJobGroup.setAddressList(addressListStr);
- } else {
- // 1=手动录入
- if (xxlJobGroup.getAddressList() == null || xxlJobGroup.getAddressList().trim().length() == 0) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_addressType_limit"));
- }
- String[] addresss = xxlJobGroup.getAddressList().split(",");
- for (String item : addresss) {
- if (item == null || item.trim().length() == 0) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_field_registryList_unvalid"));
- }
- }
- }
-
- // process
- xxlJobGroup.setUpdateTime(new Date());
-
- int ret = xxlJobGroupDao.update(xxlJobGroup);
- return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL;
- }
-
- private List findRegistryByAppName(String appnameParam) {
- HashMap> appAddressMap = new HashMap>();
- List list = xxlJobRegistryDao.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);
- }
- }
- }
- return appAddressMap.get(appnameParam);
- }
-
- @RequestMapping("/remove")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public ReturnT remove(int id) {
-
- // valid
- int count = xxlJobInfoDao.pageListCount(0, 10, id, -1, null, null, null);
- if (count > 0) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_del_limit_0"));
- }
-
- List allList = xxlJobGroupDao.findAll();
- if (allList.size() == 1) {
- return new ReturnT(500, I18nUtil.getString("jobgroup_del_limit_1"));
- }
-
- int ret = xxlJobGroupDao.remove(id);
- return (ret > 0) ? ReturnT.SUCCESS : ReturnT.FAIL;
- }
-
- @RequestMapping("/loadById")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public ReturnT loadById(int id) {
- XxlJobGroup jobGroup = xxlJobGroupDao.load(id);
- return jobGroup != null ? new ReturnT(jobGroup) : new ReturnT(ReturnT.FAIL_CODE, null);
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java
deleted file mode 100644
index 157c60ba7..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobInfoController.java
+++ /dev/null
@@ -1,180 +0,0 @@
-package com.xxl.job.admin.controller;
-
-import com.xxl.job.admin.core.exception.XxlJobException;
-import com.xxl.job.admin.core.model.XxlJobGroup;
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.model.XxlJobUser;
-import com.xxl.job.admin.core.route.ExecutorRouteStrategyEnum;
-import com.xxl.job.admin.core.scheduler.MisfireStrategyEnum;
-import com.xxl.job.admin.core.scheduler.ScheduleTypeEnum;
-import com.xxl.job.admin.core.thread.JobScheduleHelper;
-import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
-import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.admin.dao.XxlJobGroupDao;
-import com.xxl.job.admin.service.LoginService;
-import com.xxl.job.admin.service.XxlJobService;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.enums.ExecutorBlockStrategyEnum;
-import com.xxl.job.core.glue.GlueTypeEnum;
-import com.xxl.job.core.util.DateUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.*;
-
-/**
- * index controller
- *
- * @author xuxueli 2015-12-19 16:13:16
- */
-@Controller
-@RequestMapping("/jobinfo")
-public class JobInfoController {
- private static Logger logger = LoggerFactory.getLogger(JobInfoController.class);
-
- @Resource
- private XxlJobGroupDao xxlJobGroupDao;
- @Resource
- private XxlJobService xxlJobService;
-
- @RequestMapping
- public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "-1") int jobGroup) {
-
- // 枚举-字典
- model.addAttribute("ExecutorRouteStrategyEnum", ExecutorRouteStrategyEnum.values()); // 路由策略-列表
- model.addAttribute("GlueTypeEnum", GlueTypeEnum.values()); // Glue类型-字典
- model.addAttribute("ExecutorBlockStrategyEnum", ExecutorBlockStrategyEnum.values()); // 阻塞处理策略-字典
- model.addAttribute("ScheduleTypeEnum", ScheduleTypeEnum.values()); // 调度类型
- model.addAttribute("MisfireStrategyEnum", MisfireStrategyEnum.values()); // 调度过期策略
-
- // 执行器列表
- List jobGroupList_all = xxlJobGroupDao.findAll();
-
- // filter group
- List jobGroupList = filterJobGroupByRole(request, jobGroupList_all);
- if (jobGroupList == null || jobGroupList.size() == 0) {
- throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
- }
-
- model.addAttribute("JobGroupList", jobGroupList);
- model.addAttribute("jobGroup", jobGroup);
-
- return "jobinfo/jobinfo.index";
- }
-
- public static List filterJobGroupByRole(HttpServletRequest request, List jobGroupList_all) {
- List jobGroupList = new ArrayList<>();
- if (jobGroupList_all != null && jobGroupList_all.size() > 0) {
- XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
- if (loginUser.getRole() == 1) {
- jobGroupList = jobGroupList_all;
- } else {
- List groupIdStrs = new ArrayList<>();
- if (loginUser.getPermission() != null && loginUser.getPermission().trim().length() > 0) {
- groupIdStrs = Arrays.asList(loginUser.getPermission().trim().split(","));
- }
- for (XxlJobGroup groupItem : jobGroupList_all) {
- if (groupIdStrs.contains(String.valueOf(groupItem.getId()))) {
- jobGroupList.add(groupItem);
- }
- }
- }
- }
- return jobGroupList;
- }
-
- public static void validPermission(HttpServletRequest request, int jobGroup) {
- XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
- if (!loginUser.validPermission(jobGroup)) {
- throw new RuntimeException(I18nUtil.getString("system_permission_limit") + "[username=" + loginUser.getUsername() + "]");
- }
- }
-
- @RequestMapping("/pageList")
- @ResponseBody
- public Map pageList(@RequestParam(required = false, defaultValue = "0") int start,
- @RequestParam(required = false, defaultValue = "10") int length,
- int jobGroup, int triggerStatus, String jobDesc, String executorHandler, String author) {
-
- return xxlJobService.pageList(start, length, jobGroup, triggerStatus, jobDesc, executorHandler, author);
- }
-
- @RequestMapping("/add")
- @ResponseBody
- public ReturnT add(XxlJobInfo jobInfo) {
- return xxlJobService.add(jobInfo);
- }
-
- @RequestMapping("/update")
- @ResponseBody
- public ReturnT update(XxlJobInfo jobInfo) {
- return xxlJobService.update(jobInfo);
- }
-
- @RequestMapping("/remove")
- @ResponseBody
- public ReturnT remove(int id) {
- return xxlJobService.remove(id);
- }
-
- @RequestMapping("/stop")
- @ResponseBody
- public ReturnT pause(int id) {
- return xxlJobService.stop(id);
- }
-
- @RequestMapping("/start")
- @ResponseBody
- public ReturnT start(int id) {
- return xxlJobService.start(id);
- }
-
- @RequestMapping("/trigger")
- @ResponseBody
- //@PermissionLimit(limit = false)
- public ReturnT triggerJob(int id, String executorParam, String addressList) {
- // force cover job param
- if (executorParam == null) {
- executorParam = "";
- }
-
- JobTriggerPoolHelper.trigger(id, TriggerTypeEnum.MANUAL, -1, null, executorParam, addressList);
- return ReturnT.SUCCESS;
- }
-
- @RequestMapping("/nextTriggerTime")
- @ResponseBody
- public ReturnT> nextTriggerTime(String scheduleType, String scheduleConf) {
-
- XxlJobInfo paramXxlJobInfo = new XxlJobInfo();
- paramXxlJobInfo.setScheduleType(scheduleType);
- paramXxlJobInfo.setScheduleConf(scheduleConf);
-
- List result = new ArrayList<>();
- try {
- Date lastTime = new Date();
- for (int i = 0; i < 5; i++) {
- lastTime = JobScheduleHelper.generateNextValidTime(paramXxlJobInfo, lastTime);
- if (lastTime != null) {
- result.add(DateUtil.formatDateTime(lastTime));
- } else {
- break;
- }
- }
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- return new ReturnT>(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")) + e.getMessage());
- }
- return new ReturnT>(result);
-
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java
deleted file mode 100644
index e741c174b..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java
+++ /dev/null
@@ -1,238 +0,0 @@
-package com.xxl.job.admin.controller;
-
-import com.xxl.job.admin.core.exception.XxlJobException;
-import com.xxl.job.admin.core.complete.XxlJobCompleter;
-import com.xxl.job.admin.core.model.XxlJobGroup;
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.model.XxlJobLog;
-import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.admin.dao.XxlJobGroupDao;
-import com.xxl.job.admin.dao.XxlJobInfoDao;
-import com.xxl.job.admin.dao.XxlJobLogDao;
-import com.xxl.job.core.biz.ExecutorBiz;
-import com.xxl.job.core.biz.model.KillParam;
-import com.xxl.job.core.biz.model.LogParam;
-import com.xxl.job.core.biz.model.LogResult;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.util.DateUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * index controller
- *
- * @author xuxueli 2015-12-19 16:13:16
- */
-@Controller
-@RequestMapping("/joblog")
-public class JobLogController {
- private static Logger logger = LoggerFactory.getLogger(JobLogController.class);
-
- @Resource
- private XxlJobGroupDao xxlJobGroupDao;
- @Resource
- public XxlJobInfoDao xxlJobInfoDao;
- @Resource
- public XxlJobLogDao xxlJobLogDao;
-
- @RequestMapping
- public String index(HttpServletRequest request, Model model, @RequestParam(required = false, defaultValue = "0") Integer jobId) {
-
- // 执行器列表
- List jobGroupList_all = xxlJobGroupDao.findAll();
-
- // filter group
- List jobGroupList = JobInfoController.filterJobGroupByRole(request, jobGroupList_all);
- if (jobGroupList == null || jobGroupList.size() == 0) {
- throw new XxlJobException(I18nUtil.getString("jobgroup_empty"));
- }
-
- model.addAttribute("JobGroupList", jobGroupList);
-
- // 任务
- if (jobId > 0) {
- XxlJobInfo jobInfo = xxlJobInfoDao.loadById(jobId);
- if (jobInfo == null) {
- throw new RuntimeException(I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_unvalid"));
- }
-
- model.addAttribute("jobInfo", jobInfo);
-
- // valid permission
- JobInfoController.validPermission(request, jobInfo.getJobGroup());
- }
-
- return "joblog/joblog.index";
- }
-
- @RequestMapping("/getJobsByGroup")
- @ResponseBody
- public ReturnT> getJobsByGroup(int jobGroup) {
- List list = xxlJobInfoDao.getJobsByGroup(jobGroup);
- return new ReturnT>(list);
- }
-
- @RequestMapping("/pageList")
- @ResponseBody
- public Map pageList(HttpServletRequest request,
- @RequestParam(required = false, defaultValue = "0") int start,
- @RequestParam(required = false, defaultValue = "10") int length,
- int jobGroup, int jobId, int logStatus, String filterTime) {
-
- // valid permission
- JobInfoController.validPermission(request, jobGroup); // 仅管理员支持查询全部;普通用户仅支持查询有权限的 jobGroup
-
- // parse param
- Date triggerTimeStart = null;
- Date triggerTimeEnd = null;
- if (filterTime != null && filterTime.trim().length() > 0) {
- String[] temp = filterTime.split(" - ");
- if (temp.length == 2) {
- triggerTimeStart = DateUtil.parseDateTime(temp[0]);
- triggerTimeEnd = DateUtil.parseDateTime(temp[1]);
- }
- }
-
- // page query
- List list = xxlJobLogDao.pageList(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
- int list_count = xxlJobLogDao.pageListCount(start, length, jobGroup, jobId, triggerTimeStart, triggerTimeEnd, logStatus);
-
- // package result
- Map maps = new HashMap();
- maps.put("recordsTotal", list_count); // 总记录数
- maps.put("recordsFiltered", list_count); // 过滤后的总记录数
- maps.put("data", list); // 分页列表
- return maps;
- }
-
- @RequestMapping("/logDetailPage")
- public String logDetailPage(int id, Model model) {
-
- // base check
- ReturnT logStatue = ReturnT.SUCCESS;
- XxlJobLog jobLog = xxlJobLogDao.load(id);
- if (jobLog == null) {
- throw new RuntimeException(I18nUtil.getString("joblog_logid_unvalid"));
- }
-
- model.addAttribute("triggerCode", jobLog.getTriggerCode());
- model.addAttribute("handleCode", jobLog.getHandleCode());
- model.addAttribute("logId", jobLog.getId());
- return "joblog/joblog.detail";
- }
-
- @RequestMapping("/logDetailCat")
- @ResponseBody
- public ReturnT logDetailCat(long logId, int fromLineNum) {
- try {
- // valid
- XxlJobLog jobLog = xxlJobLogDao.load(logId); // todo, need to improve performance
- if (jobLog == null) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_logid_unvalid"));
- }
-
- // log cat
- ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(jobLog.getExecutorAddress());
- ReturnT logResult = executorBiz.log(new LogParam(jobLog.getTriggerTime().getTime(), logId, fromLineNum));
-
- // is end
- if (logResult.getContent() != null && logResult.getContent().getFromLineNum() > logResult.getContent().getToLineNum()) {
- if (jobLog.getHandleCode() > 0) {
- logResult.getContent().setEnd(true);
- }
- }
-
- return logResult;
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- return new ReturnT(ReturnT.FAIL_CODE, e.getMessage());
- }
- }
-
- @RequestMapping("/logKill")
- @ResponseBody
- public ReturnT logKill(int id) {
- // base check
- XxlJobLog log = xxlJobLogDao.load(id);
- XxlJobInfo jobInfo = xxlJobInfoDao.loadById(log.getJobId());
- if (jobInfo == null) {
- return new ReturnT(500, I18nUtil.getString("jobinfo_glue_jobid_unvalid"));
- }
- if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) {
- return new ReturnT(500, I18nUtil.getString("joblog_kill_log_limit"));
- }
-
- // request of kill
- ReturnT runResult = null;
- try {
- ExecutorBiz executorBiz = XxlJobScheduler.getExecutorBiz(log.getExecutorAddress());
- runResult = executorBiz.kill(new KillParam(jobInfo.getId()));
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- runResult = new ReturnT(500, e.getMessage());
- }
-
- if (ReturnT.SUCCESS_CODE == runResult.getCode()) {
- log.setHandleCode(ReturnT.FAIL_CODE);
- log.setHandleMsg(I18nUtil.getString("joblog_kill_log_byman") + ":" + (runResult.getMsg() != null ? runResult.getMsg() : ""));
- log.setHandleTime(new Date());
- XxlJobCompleter.updateHandleInfoAndFinish(log);
- return new ReturnT(runResult.getMsg());
- } else {
- return new ReturnT(500, runResult.getMsg());
- }
- }
-
- @RequestMapping("/clearLog")
- @ResponseBody
- public ReturnT clearLog(int jobGroup, int jobId, int type) {
-
- Date clearBeforeTime = null;
- int clearBeforeNum = 0;
- if (type == 1) {
- clearBeforeTime = DateUtil.addMonths(new Date(), -1); // 清理一个月之前日志数据
- } else if (type == 2) {
- clearBeforeTime = DateUtil.addMonths(new Date(), -3); // 清理三个月之前日志数据
- } else if (type == 3) {
- clearBeforeTime = DateUtil.addMonths(new Date(), -6); // 清理六个月之前日志数据
- } else if (type == 4) {
- clearBeforeTime = DateUtil.addYears(new Date(), -1); // 清理一年之前日志数据
- } else if (type == 5) {
- clearBeforeNum = 1000; // 清理一千条以前日志数据
- } else if (type == 6) {
- clearBeforeNum = 10000; // 清理一万条以前日志数据
- } else if (type == 7) {
- clearBeforeNum = 30000; // 清理三万条以前日志数据
- } else if (type == 8) {
- clearBeforeNum = 100000; // 清理十万条以前日志数据
- } else if (type == 9) {
- clearBeforeNum = 0; // 清理所有日志数据
- } else {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("joblog_clean_type_unvalid"));
- }
-
- List logIds = null;
- do {
- logIds = xxlJobLogDao.findClearLogIds(jobGroup, jobId, clearBeforeTime, clearBeforeNum, 1000);
- if (logIds != null && logIds.size() > 0) {
- xxlJobLogDao.clearLog(logIds);
- }
- } while (logIds != null && logIds.size() > 0);
-
- return ReturnT.SUCCESS;
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java
deleted file mode 100644
index 878998d39..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/UserController.java
+++ /dev/null
@@ -1,179 +0,0 @@
-package com.xxl.job.admin.controller;
-
-import com.xxl.job.admin.controller.annotation.PermissionLimit;
-import com.xxl.job.admin.core.model.XxlJobGroup;
-import com.xxl.job.admin.core.model.XxlJobUser;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.admin.dao.XxlJobGroupDao;
-import com.xxl.job.admin.dao.XxlJobUserDao;
-import com.xxl.job.admin.service.LoginService;
-import com.xxl.job.core.biz.model.ReturnT;
-import org.springframework.stereotype.Controller;
-import org.springframework.ui.Model;
-import org.springframework.util.DigestUtils;
-import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.ResponseBody;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author xuxueli 2019-05-04 16:39:50
- */
-@Controller
-@RequestMapping("/user")
-public class UserController {
-
- @Resource
- private XxlJobUserDao xxlJobUserDao;
- @Resource
- private XxlJobGroupDao xxlJobGroupDao;
-
- @RequestMapping
- @PermissionLimit(adminuser = true)
- public String index(Model model) {
-
- // 执行器列表
- List groupList = xxlJobGroupDao.findAll();
- model.addAttribute("groupList", groupList);
-
- return "user/user.index";
- }
-
- @RequestMapping("/pageList")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public Map pageList(@RequestParam(required = false, defaultValue = "0") int start,
- @RequestParam(required = false, defaultValue = "10") int length,
- String username, int role) {
-
- // page list
- List list = xxlJobUserDao.pageList(start, length, username, role);
- int list_count = xxlJobUserDao.pageListCount(start, length, username, role);
-
- // filter
- if (list != null && list.size() > 0) {
- for (XxlJobUser item : list) {
- item.setPassword(null);
- }
- }
-
- // package result
- Map maps = new HashMap();
- maps.put("recordsTotal", list_count); // 总记录数
- maps.put("recordsFiltered", list_count); // 过滤后的总记录数
- maps.put("data", list); // 分页列表
- return maps;
- }
-
- @RequestMapping("/add")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public ReturnT add(XxlJobUser xxlJobUser) {
-
- // valid username
- if (!StringUtils.hasText(xxlJobUser.getUsername())) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_username"));
- }
- xxlJobUser.setUsername(xxlJobUser.getUsername().trim());
- if (!(xxlJobUser.getUsername().length() >= 4 && xxlJobUser.getUsername().length() <= 20)) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
- }
- // valid password
- if (!StringUtils.hasText(xxlJobUser.getPassword())) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_please_input") + I18nUtil.getString("user_password"));
- }
- xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
- if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
- }
- // md5 password
- xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
-
- // check repeat
- XxlJobUser existUser = xxlJobUserDao.loadByUserName(xxlJobUser.getUsername());
- if (existUser != null) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("user_username_repeat"));
- }
-
- // write
- xxlJobUserDao.save(xxlJobUser);
- return ReturnT.SUCCESS;
- }
-
- @RequestMapping("/update")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public ReturnT update(HttpServletRequest request, XxlJobUser xxlJobUser) {
-
- // avoid opt login seft
- XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
- if (loginUser.getUsername().equals(xxlJobUser.getUsername())) {
- return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
- }
-
- // valid password
- if (StringUtils.hasText(xxlJobUser.getPassword())) {
- xxlJobUser.setPassword(xxlJobUser.getPassword().trim());
- if (!(xxlJobUser.getPassword().length() >= 4 && xxlJobUser.getPassword().length() <= 20)) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
- }
- // md5 password
- xxlJobUser.setPassword(DigestUtils.md5DigestAsHex(xxlJobUser.getPassword().getBytes()));
- } else {
- xxlJobUser.setPassword(null);
- }
-
- // write
- xxlJobUserDao.update(xxlJobUser);
- return ReturnT.SUCCESS;
- }
-
- @RequestMapping("/remove")
- @ResponseBody
- @PermissionLimit(adminuser = true)
- public ReturnT remove(HttpServletRequest request, int id) {
-
- // avoid opt login seft
- XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
- if (loginUser.getId() == id) {
- return new ReturnT(ReturnT.FAIL.getCode(), I18nUtil.getString("user_update_loginuser_limit"));
- }
-
- xxlJobUserDao.delete(id);
- return ReturnT.SUCCESS;
- }
-
- @RequestMapping("/updatePwd")
- @ResponseBody
- public ReturnT updatePwd(HttpServletRequest request, String password) {
-
- // valid password
- if (password == null || password.trim().length() == 0) {
- return new ReturnT(ReturnT.FAIL.getCode(), "密码不可为空");
- }
- password = password.trim();
- if (!(password.length() >= 4 && password.length() <= 20)) {
- return new ReturnT(ReturnT.FAIL_CODE, I18nUtil.getString("system_lengh_limit") + "[4-20]");
- }
-
- // md5 password
- String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
-
- // update pwd
- XxlJobUser loginUser = (XxlJobUser) request.getAttribute(LoginService.LOGIN_IDENTITY_KEY);
-
- // do write
- XxlJobUser existUser = xxlJobUserDao.loadByUserName(loginUser.getUsername());
- existUser.setPassword(md5Password);
- xxlJobUserDao.update(existUser);
-
- return ReturnT.SUCCESS;
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java
deleted file mode 100644
index 054d6ef55..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/annotation/PermissionLimit.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.xxl.job.admin.controller.annotation;
-
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * 权限限制
- *
- * @author xuxueli 2015-12-12 18:29:02
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface PermissionLimit {
-
- /**
- * 登录拦截 (默认拦截)
- */
- boolean limit() default true;
-
- /**
- * 要求管理员权限
- *
- * @return
- */
- boolean adminuser() default false;
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java
deleted file mode 100644
index 228384996..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/CookieInterceptor.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.xxl.job.admin.controller.interceptor;
-
-import com.xxl.job.admin.core.util.FtlUtil;
-import com.xxl.job.admin.core.util.I18nUtil;
-import org.springframework.stereotype.Component;
-import org.springframework.web.servlet.AsyncHandlerInterceptor;
-import org.springframework.web.servlet.ModelAndView;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.util.HashMap;
-
-/**
- * push cookies to model as cookieMap
- *
- * @author xuxueli 2015-12-12 18:09:04
- */
-@Component
-public class CookieInterceptor implements AsyncHandlerInterceptor {
-
- @Override
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
- ModelAndView modelAndView) throws Exception {
-
- // cookie
- if (modelAndView != null && request.getCookies() != null && request.getCookies().length > 0) {
- HashMap cookieMap = new HashMap();
- for (Cookie ck : request.getCookies()) {
- cookieMap.put(ck.getName(), ck);
- }
- modelAndView.addObject("cookieMap", cookieMap);
- }
-
- // static method
- if (modelAndView != null) {
- modelAndView.addObject("I18nUtil", FtlUtil.generateStaticModel(I18nUtil.class.getName()));
- }
-
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java
deleted file mode 100644
index 13e53b2f1..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/PermissionInterceptor.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.xxl.job.admin.controller.interceptor;
-
-import com.xxl.job.admin.controller.annotation.PermissionLimit;
-import com.xxl.job.admin.core.model.XxlJobUser;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.admin.service.LoginService;
-import org.springframework.stereotype.Component;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.AsyncHandlerInterceptor;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * 权限拦截
- *
- * @author xuxueli 2015-12-12 18:09:04
- */
-@Component
-public class PermissionInterceptor implements AsyncHandlerInterceptor {
-
- @Resource
- private LoginService loginService;
-
- @Override
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-
- if (!(handler instanceof HandlerMethod)) {
- return true; // proceed with the next interceptor
- }
-
- // if need login
- boolean needLogin = true;
- boolean needAdminuser = false;
- HandlerMethod method = (HandlerMethod) handler;
- PermissionLimit permission = method.getMethodAnnotation(PermissionLimit.class);
- if (permission != null) {
- needLogin = permission.limit();
- needAdminuser = permission.adminuser();
- }
-
- if (needLogin) {
- XxlJobUser loginUser = loginService.ifLogin(request, response);
- if (loginUser == null) {
- response.setStatus(302);
- response.setHeader("location", request.getContextPath() + "/toLogin");
- return false;
- }
- if (needAdminuser && loginUser.getRole() != 1) {
- throw new RuntimeException(I18nUtil.getString("system_permission_limit"));
- }
- request.setAttribute(LoginService.LOGIN_IDENTITY_KEY, loginUser);
- }
-
- return true; // proceed with the next interceptor
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java
deleted file mode 100644
index 7bacf3080..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/interceptor/WebMvcConfig.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.xxl.job.admin.controller.interceptor;
-
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-import javax.annotation.Resource;
-
-/**
- * web mvc config
- *
- * @author xuxueli 2018-04-02 20:48:20
- */
-@Configuration
-public class WebMvcConfig implements WebMvcConfigurer {
-
- @Resource
- private PermissionInterceptor permissionInterceptor;
- @Resource
- private CookieInterceptor cookieInterceptor;
-
- @Override
- public void addInterceptors(InterceptorRegistry registry) {
- registry.addInterceptor(permissionInterceptor).addPathPatterns("/**");
- registry.addInterceptor(cookieInterceptor).addPathPatterns("/**");
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java
deleted file mode 100644
index d7cc0db5e..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/controller/resolver/WebExceptionResolver.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package com.xxl.job.admin.controller.resolver;
-
-import com.xxl.job.admin.core.exception.XxlJobException;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.admin.core.util.JacksonUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerExceptionResolver;
-import org.springframework.web.servlet.ModelAndView;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * common exception resolver
- *
- * @author xuxueli 2016-1-6 19:22:18
- */
-@Component
-public class WebExceptionResolver implements HandlerExceptionResolver {
- private static transient Logger logger = LoggerFactory.getLogger(WebExceptionResolver.class);
-
- @Override
- public ModelAndView resolveException(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex) {
-
- if (!(ex instanceof XxlJobException)) {
- logger.error("WebExceptionResolver:{}", ex);
- }
-
- // if json
- boolean isJson = false;
- if (handler instanceof HandlerMethod) {
- HandlerMethod method = (HandlerMethod) handler;
- ResponseBody responseBody = method.getMethodAnnotation(ResponseBody.class);
- if (responseBody != null) {
- isJson = true;
- }
- }
-
- // error result
- ReturnT errorResult = new ReturnT(ReturnT.FAIL_CODE, ex.toString().replaceAll("\n", " "));
-
- // response
- ModelAndView mv = new ModelAndView();
- if (isJson) {
- try {
- response.setContentType("application/json;charset=utf-8");
- response.getWriter().print(JacksonUtil.writeValueAsString(errorResult));
- } catch (IOException e) {
- logger.error(e.getMessage(), e);
- }
- return mv;
- } else {
-
- mv.addObject("exceptionMsg", errorResult.getMsg());
- mv.setViewName("/common/common.exception");
- return mv;
- }
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java
deleted file mode 100644
index 4165ff3a0..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarm.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.xxl.job.admin.core.alarm;
-
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.model.XxlJobLog;
-
-/**
- * @author xuxueli 2020-01-19
- */
-public interface JobAlarm {
-
- /**
- * job alarm
- *
- * @param info
- * @param jobLog
- * @return
- */
- public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog);
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java
deleted file mode 100644
index 62dac9d27..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/JobAlarmer.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.xxl.job.admin.core.alarm;
-
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.model.XxlJobLog;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-@Component
-public class JobAlarmer implements ApplicationContextAware, InitializingBean {
- private static Logger logger = LoggerFactory.getLogger(JobAlarmer.class);
-
- private ApplicationContext applicationContext;
- private List jobAlarmList;
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- Map serviceBeanMap = applicationContext.getBeansOfType(JobAlarm.class);
- if (serviceBeanMap != null && serviceBeanMap.size() > 0) {
- jobAlarmList = new ArrayList(serviceBeanMap.values());
- }
- }
-
- /**
- * job alarm
- *
- * @param info
- * @param jobLog
- * @return
- */
- public boolean alarm(XxlJobInfo info, XxlJobLog jobLog) {
-
- boolean result = false;
- if (jobAlarmList != null && jobAlarmList.size() > 0) {
- result = true; // success means all-success
- for (JobAlarm alarm : jobAlarmList) {
- boolean resultItem = false;
- try {
- resultItem = alarm.doAlarm(info, jobLog);
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- }
- if (!resultItem) {
- result = false;
- }
- }
- }
-
- return result;
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java
deleted file mode 100644
index 6ad1c0b1c..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/alarm/impl/EmailJobAlarm.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package com.xxl.job.admin.core.alarm.impl;
-
-import com.xxl.job.admin.core.alarm.JobAlarm;
-import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
-import com.xxl.job.admin.core.model.XxlJobGroup;
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.model.XxlJobLog;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.core.biz.model.ReturnT;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.mail.javamail.MimeMessageHelper;
-import org.springframework.stereotype.Component;
-
-import javax.mail.internet.MimeMessage;
-import java.text.MessageFormat;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * job alarm by email
- *
- * @author xuxueli 2020-01-19
- */
-@Component
-public class EmailJobAlarm implements JobAlarm {
- private static Logger logger = LoggerFactory.getLogger(EmailJobAlarm.class);
-
- /**
- * fail alarm
- *
- * @param jobLog
- */
- @Override
- public boolean doAlarm(XxlJobInfo info, XxlJobLog jobLog) {
- boolean alarmResult = true;
-
- // send monitor email
- if (info != null && info.getAlarmEmail() != null && info.getAlarmEmail().trim().length() > 0) {
-
- // alarmContent
- String alarmContent = "Alarm Job LogId=" + jobLog.getId();
- if (jobLog.getTriggerCode() != ReturnT.SUCCESS_CODE) {
- alarmContent += " TriggerMsg= " + jobLog.getTriggerMsg();
- }
- if (jobLog.getHandleCode() > 0 && jobLog.getHandleCode() != ReturnT.SUCCESS_CODE) {
- alarmContent += " HandleCode=" + jobLog.getHandleMsg();
- }
-
- // email info
- XxlJobGroup group = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().load(Integer.valueOf(info.getJobGroup()));
- String personal = I18nUtil.getString("admin_name_full");
- String title = I18nUtil.getString("jobconf_monitor");
- String content = MessageFormat.format(loadEmailJobAlarmTemplate(),
- group != null ? group.getTitle() : "null",
- info.getId(),
- info.getJobDesc(),
- alarmContent);
-
- Set emailSet = new HashSet(Arrays.asList(info.getAlarmEmail().split(",")));
- for (String email : emailSet) {
-
- // make mail
- try {
- MimeMessage mimeMessage = XxlJobAdminConfig.getAdminConfig().getMailSender().createMimeMessage();
-
- MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
- helper.setFrom(XxlJobAdminConfig.getAdminConfig().getEmailFrom(), personal);
- helper.setTo(email);
- helper.setSubject(title);
- helper.setText(content, true);
-
- XxlJobAdminConfig.getAdminConfig().getMailSender().send(mimeMessage);
- } catch (Exception e) {
- logger.error(">>>>>>>>>>> xxl-job, job fail alarm email send error, JobLogId:{}", jobLog.getId(), e);
-
- alarmResult = false;
- }
-
- }
- }
-
- return alarmResult;
- }
-
- /**
- * load email job alarm template
- *
- * @return
- */
- private static final String loadEmailJobAlarmTemplate() {
- String mailBodyTemplate = "" + I18nUtil.getString("jobconf_monitor_detail") + ":" +
- " \n" +
- " " +
- " \n" +
- " " + I18nUtil.getString("jobinfo_field_jobgroup") + " \n" +
- " " + I18nUtil.getString("jobinfo_field_id") + " \n" +
- " " + I18nUtil.getString("jobinfo_field_jobdesc") + " \n" +
- " " + I18nUtil.getString("jobconf_monitor_alarm_title") + " \n" +
- " " + I18nUtil.getString("jobconf_monitor_alarm_content") + " \n" +
- " \n" +
- " \n" +
- " \n" +
- " \n" +
- " {0} \n" +
- " {1} \n" +
- " {2} \n" +
- " " + I18nUtil.getString("jobconf_monitor_alarm_type") + " \n" +
- " {3} \n" +
- " \n" +
- " \n" +
- "
";
-
- return mailBodyTemplate;
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java
deleted file mode 100644
index 83399336b..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/complete/XxlJobCompleter.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package com.xxl.job.admin.core.complete;
-
-import com.xxl.job.admin.core.conf.XxlJobAdminConfig;
-import com.xxl.job.admin.core.model.XxlJobInfo;
-import com.xxl.job.admin.core.model.XxlJobLog;
-import com.xxl.job.admin.core.thread.JobTriggerPoolHelper;
-import com.xxl.job.admin.core.trigger.TriggerTypeEnum;
-import com.xxl.job.admin.core.util.I18nUtil;
-import com.xxl.job.core.biz.model.ReturnT;
-import com.xxl.job.core.context.XxlJobContext;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.text.MessageFormat;
-
-/**
- * @author xuxueli 2020-10-30 20:43:10
- */
-public class XxlJobCompleter {
- private static Logger logger = LoggerFactory.getLogger(XxlJobCompleter.class);
-
- /**
- * common fresh handle entrance (limit only once)
- *
- * @param xxlJobLog
- * @return
- */
- public static int updateHandleInfoAndFinish(XxlJobLog xxlJobLog) {
-
- // finish
- finishJob(xxlJobLog);
-
- // text最大64kb 避免长度过长
- if (xxlJobLog.getHandleMsg().length() > 15000) {
- xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg().substring(0, 15000));
- }
-
- // fresh handle
- return XxlJobAdminConfig.getAdminConfig().getXxlJobLogDao().updateHandleInfo(xxlJobLog);
- }
-
-
- /**
- * do somethind to finish job
- */
- private static void finishJob(XxlJobLog xxlJobLog) {
-
- // 1、handle success, to trigger child job
- String triggerChildMsg = null;
- if (XxlJobContext.HANDLE_CODE_SUCCESS == xxlJobLog.getHandleCode()) {
- XxlJobInfo xxlJobInfo = XxlJobAdminConfig.getAdminConfig().getXxlJobInfoDao().loadById(xxlJobLog.getJobId());
- if (xxlJobInfo != null && xxlJobInfo.getChildJobId() != null && xxlJobInfo.getChildJobId().trim().length() > 0) {
- triggerChildMsg = " >>>>>>>>>>>" + I18nUtil.getString("jobconf_trigger_child_run") + "<<<<<<<<<<< ";
-
- String[] childJobIds = xxlJobInfo.getChildJobId().split(",");
- for (int i = 0; i < childJobIds.length; i++) {
- int childJobId = (childJobIds[i] != null && childJobIds[i].trim().length() > 0 && isNumeric(childJobIds[i])) ? Integer.valueOf(childJobIds[i]) : -1;
- if (childJobId > 0) {
-
- JobTriggerPoolHelper.trigger(childJobId, TriggerTypeEnum.PARENT, -1, null, null, null);
- ReturnT triggerChildResult = ReturnT.SUCCESS;
-
- // add msg
- triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg1"),
- (i + 1),
- childJobIds.length,
- childJobIds[i],
- (triggerChildResult.getCode() == ReturnT.SUCCESS_CODE ? I18nUtil.getString("system_success") : I18nUtil.getString("system_fail")),
- triggerChildResult.getMsg());
- } else {
- triggerChildMsg += MessageFormat.format(I18nUtil.getString("jobconf_callback_child_msg2"),
- (i + 1),
- childJobIds.length,
- childJobIds[i]);
- }
- }
-
- }
- }
-
- if (triggerChildMsg != null) {
- xxlJobLog.setHandleMsg(xxlJobLog.getHandleMsg() + triggerChildMsg);
- }
-
- // 2、fix_delay trigger next
- // on the way
-
- }
-
- private static boolean isNumeric(String str) {
- try {
- int result = Integer.valueOf(str);
- return true;
- } catch (NumberFormatException e) {
- return false;
- }
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java
deleted file mode 100644
index 6e40cb760..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/conf/XxlJobAdminConfig.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package com.xxl.job.admin.core.conf;
-
-import com.xxl.job.admin.core.alarm.JobAlarmer;
-import com.xxl.job.admin.core.scheduler.XxlJobScheduler;
-import com.xxl.job.admin.dao.*;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.mail.javamail.JavaMailSender;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import javax.sql.DataSource;
-import java.util.Arrays;
-
-/**
- * xxl-job config
- *
- * @author xuxueli 2017-04-28
- */
-
-@Component
-public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
-
- private static XxlJobAdminConfig adminConfig = null;
-
- public static XxlJobAdminConfig getAdminConfig() {
- return adminConfig;
- }
-
-
- // ---------------------- XxlJobScheduler ----------------------
-
- private XxlJobScheduler xxlJobScheduler;
-
- @Override
- public void afterPropertiesSet() throws Exception {
- adminConfig = this;
-
- xxlJobScheduler = new XxlJobScheduler();
- xxlJobScheduler.init();
- }
-
- @Override
- public void destroy() throws Exception {
- xxlJobScheduler.destroy();
- }
-
-
- // ---------------------- XxlJobScheduler ----------------------
-
- // conf
- @Value("${xxl.job.i18n}")
- private String i18n;
-
- @Value("${xxl.job.accessToken}")
- private String accessToken;
-
- @Value("${spring.mail.from}")
- private String emailFrom;
-
- @Value("${xxl.job.triggerpool.fast.max}")
- private int triggerPoolFastMax;
-
- @Value("${xxl.job.triggerpool.slow.max}")
- private int triggerPoolSlowMax;
-
- @Value("${xxl.job.logretentiondays}")
- private int logretentiondays;
-
- // dao, service
-
- @Resource
- private XxlJobLogDao xxlJobLogDao;
- @Resource
- private XxlJobInfoDao xxlJobInfoDao;
- @Resource
- private XxlJobRegistryDao xxlJobRegistryDao;
- @Resource
- private XxlJobGroupDao xxlJobGroupDao;
- @Resource
- private XxlJobLogReportDao xxlJobLogReportDao;
- @Resource
- private JavaMailSender mailSender;
- @Resource
- private DataSource dataSource;
- @Resource
- private JobAlarmer jobAlarmer;
-
-
- public String getI18n() {
- if (!Arrays.asList("zh_CN", "zh_TC", "en").contains(i18n)) {
- return "zh_CN";
- }
- return i18n;
- }
-
- public String getAccessToken() {
- return accessToken;
- }
-
- public String getEmailFrom() {
- return emailFrom;
- }
-
- public int getTriggerPoolFastMax() {
- if (triggerPoolFastMax < 200) {
- return 200;
- }
- return triggerPoolFastMax;
- }
-
- public int getTriggerPoolSlowMax() {
- if (triggerPoolSlowMax < 100) {
- return 100;
- }
- return triggerPoolSlowMax;
- }
-
- public int getLogretentiondays() {
- if (logretentiondays < 7) {
- return -1; // Limit greater than or equal to 7, otherwise close
- }
- return logretentiondays;
- }
-
- public XxlJobLogDao getXxlJobLogDao() {
- return xxlJobLogDao;
- }
-
- public XxlJobInfoDao getXxlJobInfoDao() {
- return xxlJobInfoDao;
- }
-
- public XxlJobRegistryDao getXxlJobRegistryDao() {
- return xxlJobRegistryDao;
- }
-
- public XxlJobGroupDao getXxlJobGroupDao() {
- return xxlJobGroupDao;
- }
-
- public XxlJobLogReportDao getXxlJobLogReportDao() {
- return xxlJobLogReportDao;
- }
-
- public JavaMailSender getMailSender() {
- return mailSender;
- }
-
- public DataSource getDataSource() {
- return dataSource;
- }
-
- public JobAlarmer getJobAlarmer() {
- return jobAlarmer;
- }
-
-}
diff --git a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java b/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java
deleted file mode 100644
index 1530119a9..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/cron/CronExpression.java
+++ /dev/null
@@ -1,1679 +0,0 @@
-/*
- * All content copyright Terracotta, Inc., unless otherwise indicated. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy
- * of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
-
-package com.xxl.job.admin.core.cron;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.text.ParseException;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Locale;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.StringTokenizer;
-import java.util.TimeZone;
-import java.util.TreeSet;
-
-/**
- * Provides a parser and evaluator for unix-like cron expressions. Cron
- * expressions provide the ability to specify complex time combinations such as
- * "At 8:00am every Monday through Friday" or "At 1:30am every
- * last Friday of the month".
- *
- * Cron expressions are comprised of 6 required fields and one optional field
- * separated by white space. The fields respectively are described as follows:
- *
- *
- *
- * Field Name
- *
- * Allowed Values
- *
- * Allowed Special Characters
- *
- *
- * Seconds
- *
- * 0-59
- *
- * , - * /
- *
- *
- * Minutes
- *
- * 0-59
- *
- * , - * /
- *
- *
- * Hours
- *
- * 0-23
- *
- * , - * /
- *
- *
- * Day-of-month
- *
- * 1-31
- *
- * , - * ? / L W
- *
- *
- * Month
- *
- * 0-11 or JAN-DEC
- *
- * , - * /
- *
- *
- * Day-of-Week
- *
- * 1-7 or SUN-SAT
- *
- * , - * ? / L #
- *
- *
- * Year (Optional)
- *
- * empty, 1970-2199
- *
- * , - * /
- *
- *
- *
- * The '*' character is used to specify all values. For example, "*"
- * in the minute field means "every minute".
- *
- * The '?' character is allowed for the day-of-month and day-of-week fields. It
- * is used to specify 'no specific value'. This is useful when you need to
- * specify something in one of the two fields, but not the other.
- *
- * The '-' character is used to specify ranges For example "10-12" in
- * the hour field means "the hours 10, 11 and 12".
- *
- * The ',' character is used to specify additional values. For example
- * "MON,WED,FRI" in the day-of-week field means "the days Monday,
- * Wednesday, and Friday".
- *
- * The '/' character is used to specify increments. For example "0/15"
- * in the seconds field means "the seconds 0, 15, 30, and 45". And
- * "5/15" in the seconds field means "the seconds 5, 20, 35, and
- * 50". Specifying '*' before the '/' is equivalent to specifying 0 is
- * the value to start with. Essentially, for each field in the expression, there
- * is a set of numbers that can be turned on or off. For seconds and minutes,
- * the numbers range from 0 to 59. For hours 0 to 23, for days of the month 0 to
- * 31, and for months 0 to 11 (JAN to DEC). The "/" character simply helps you turn
- * on every "nth" value in the given set. Thus "7/6" in the
- * month field only turns on month "7", it does NOT mean every 6th
- * month, please note that subtlety.
- *
- * The 'L' character is allowed for the day-of-month and day-of-week fields.
- * This character is short-hand for "last", but it has different
- * meaning in each of the two fields. For example, the value "L" in
- * the day-of-month field means "the last day of the month" - day 31
- * for January, day 28 for February on non-leap years. If used in the
- * day-of-week field by itself, it simply means "7" or
- * "SAT". But if used in the day-of-week field after another value, it
- * means "the last xxx day of the month" - for example "6L"
- * means "the last friday of the month". You can also specify an offset
- * from the last day of the month, such as "L-3" which would mean the third-to-last
- * day of the calendar month. When using the 'L' option, it is important not to
- * specify lists, or ranges of values, as you'll get confusing/unexpected results.
- *
- * The 'W' character is allowed for the day-of-month field. This character
- * is used to specify the weekday (Monday-Friday) nearest the given day. As an
- * example, if you were to specify "15W" as the value for the
- * day-of-month field, the meaning is: "the nearest weekday to the 15th of
- * the month". So if the 15th is a Saturday, the trigger will fire on
- * Friday the 14th. If the 15th is a Sunday, the trigger will fire on Monday the
- * 16th. If the 15th is a Tuesday, then it will fire on Tuesday the 15th.
- * However if you specify "1W" as the value for day-of-month, and the
- * 1st is a Saturday, the trigger will fire on Monday the 3rd, as it will not
- * 'jump' over the boundary of a month's days. The 'W' character can only be
- * specified when the day-of-month is a single day, not a range or list of days.
- *
- * The 'L' and 'W' characters can also be combined for the day-of-month
- * expression to yield 'LW', which translates to "last weekday of the
- * month".
- *
- * The '#' character is allowed for the day-of-week field. This character is
- * used to specify "the nth" XXX day of the month. For example, the
- * value of "6#3" in the day-of-week field means the third Friday of
- * the month (day 6 = Friday and "#3" = the 3rd one in the month).
- * Other examples: "2#1" = the first Monday of the month and
- * "4#5" = the fifth Wednesday of the month. Note that if you specify
- * "#5" and there is not 5 of the given day-of-week in the month, then
- * no firing will occur that month. If the '#' character is used, there can
- * only be one expression in the day-of-week field ("3#1,6#3" is
- * not valid, since there are two expressions).
- *
- *
- *
- * The legal characters and the names of months and days of the week are not
- * case sensitive.
- *
- *
- * NOTES:
- *
- * Support for specifying both a day-of-week and a day-of-month value is
- * not complete (you'll need to use the '?' character in one of these fields).
- *
- * Overflowing ranges is supported - that is, having a larger number on
- * the left hand side than the right. You might do 22-2 to catch 10 o'clock
- * at night until 2 o'clock in the morning, or you might have NOV-FEB. It is
- * very important to note that overuse of overflowing ranges creates ranges
- * that don't make sense and no effort has been made to determine which
- * interpretation CronExpression chooses. An example would be
- * "0 0 14-6 ? * FRI-MON".
- *
- *
- *
- * @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 {
-
- @Serial
- 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 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;
-
- Calendar tcal = 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();
-
- Calendar tcal = 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(Calendar.HOUR_OF_DAY, hour);
- if (cal.get(Calendar.HOUR_OF_DAY) != hour && hour != 24) {
- cal.set(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
deleted file mode 100644
index 4424277b0..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/exception/XxlJobException.java
+++ /dev/null
@@ -1,15 +0,0 @@
-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
deleted file mode 100644
index 3a9952a49..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobGroup.java
+++ /dev/null
@@ -1,78 +0,0 @@
-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
deleted file mode 100644
index ee4b02cea..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobInfo.java
+++ /dev/null
@@ -1,237 +0,0 @@
-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
deleted file mode 100644
index f3301af6c..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLog.java
+++ /dev/null
@@ -1,158 +0,0 @@
-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
deleted file mode 100644
index 2da3c2da2..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogGlue.java
+++ /dev/null
@@ -1,76 +0,0 @@
-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
deleted file mode 100644
index e58ff1a9e..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobLogReport.java
+++ /dev/null
@@ -1,54 +0,0 @@
-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
deleted file mode 100644
index 924d6d336..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobRegistry.java
+++ /dev/null
@@ -1,55 +0,0 @@
-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
deleted file mode 100644
index 6f696df2c..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/model/XxlJobUser.java
+++ /dev/null
@@ -1,73 +0,0 @@
-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
deleted file mode 100644
index 5d1f2a086..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/RemoteHttpJobBean.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.xxl.job.admin.core.old;//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());
-//
-//
-// }
-//
-//}
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
deleted file mode 100644
index 5ae81bd21..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobDynamicScheduler.java
+++ /dev/null
@@ -1,413 +0,0 @@
-package com.xxl.job.admin.core.old;//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;
-// }*/
-//
-//}
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
deleted file mode 100644
index 74f3f9db0..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/old/XxlJobThreadPool.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.xxl.job.admin.core.old;//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
deleted file mode 100644
index 1903b9333..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouteStrategyEnum.java
+++ /dev/null
@@ -1,49 +0,0 @@
-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
deleted file mode 100644
index 7ca0d46ea..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/ExecutorRouter.java
+++ /dev/null
@@ -1,24 +0,0 @@
-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
deleted file mode 100644
index a36fb4cd5..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteBusyover.java
+++ /dev/null
@@ -1,48 +0,0 @@
-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
deleted file mode 100644
index abd472476..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteConsistentHash.java
+++ /dev/null
@@ -1,86 +0,0 @@
-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
deleted file mode 100644
index a889fad8a..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFailover.java
+++ /dev/null
@@ -1,48 +0,0 @@
-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
deleted file mode 100644
index a0fe0c7ce..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteFirst.java
+++ /dev/null
@@ -1,19 +0,0 @@
-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
deleted file mode 100644
index 5eadf986c..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLFU.java
+++ /dev/null
@@ -1,79 +0,0 @@
-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
deleted file mode 100644
index 02c9424e1..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLRU.java
+++ /dev/null
@@ -1,76 +0,0 @@
-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
deleted file mode 100644
index d96059ded..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteLast.java
+++ /dev/null
@@ -1,19 +0,0 @@
-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
deleted file mode 100644
index 5ea4a3841..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRandom.java
+++ /dev/null
@@ -1,23 +0,0 @@
-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
deleted file mode 100644
index dfea0ef3f..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/route/strategy/ExecutorRouteRound.java
+++ /dev/null
@@ -1,46 +0,0 @@
-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
deleted file mode 100644
index 6abc5d577..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/MisfireStrategyEnum.java
+++ /dev/null
@@ -1,39 +0,0 @@
-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
deleted file mode 100644
index f01d1fb8a..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/ScheduleTypeEnum.java
+++ /dev/null
@@ -1,46 +0,0 @@
-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
deleted file mode 100644
index 26dba69ee..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/scheduler/XxlJobScheduler.java
+++ /dev/null
@@ -1,102 +0,0 @@
-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
deleted file mode 100644
index 37b9bf873..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobCompleteHelper.java
+++ /dev/null
@@ -1,185 +0,0 @@
-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
deleted file mode 100644
index dfebc87b0..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobFailMonitorHelper.java
+++ /dev/null
@@ -1,112 +0,0 @@
-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) {
- 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
deleted file mode 100644
index 942f7527a..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobLogReportHelper.java
+++ /dev/null
@@ -1,154 +0,0 @@
-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
deleted file mode 100644
index 681b68417..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobRegistryHelper.java
+++ /dev/null
@@ -1,206 +0,0 @@
-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
deleted file mode 100644
index 69ffdb3cc..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobScheduleHelper.java
+++ /dev/null
@@ -1,370 +0,0 @@
-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
deleted file mode 100644
index 775b916b1..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/thread/JobTriggerPoolHelper.java
+++ /dev/null
@@ -1,148 +0,0 @@
-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
deleted file mode 100644
index 0402a19ba..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/TriggerTypeEnum.java
+++ /dev/null
@@ -1,29 +0,0 @@
-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
deleted file mode 100644
index ce2914a56..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/trigger/XxlJobTrigger.java
+++ /dev/null
@@ -1,224 +0,0 @@
-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
deleted file mode 100644
index bb9abd777..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/CookieUtil.java
+++ /dev/null
@@ -1,98 +0,0 @@
-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);
- }
- }
-
-}
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
deleted file mode 100644
index e90af434f..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/FtlUtil.java
+++ /dev/null
@@ -1,31 +0,0 @@
-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
deleted file mode 100644
index 4c8cc5c08..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/I18nUtil.java
+++ /dev/null
@@ -1,80 +0,0 @@
-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
deleted file mode 100644
index 0312b7479..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/JacksonUtil.java
+++ /dev/null
@@ -1,93 +0,0 @@
-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 OBJECT_MAPPER = new ObjectMapper();
-
- public static ObjectMapper getInstance() {
- return OBJECT_MAPPER;
- }
-
- /**
- * 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
deleted file mode 100644
index 6232afac7..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/core/util/LocalCacheUtil.java
+++ /dev/null
@@ -1,134 +0,0 @@
-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()) {
- return localCacheData.getVal();
- } else {
- remove(key);
- return null;
- }
- }
-
- /**
- * clean timeout cache
- *
- * @return
- */
- public static boolean cleanTimeoutCache() {
- if (!cacheRepository.keySet().isEmpty()) {
- for (String key : cacheRepository.keySet()) {
- LocalCacheData localCacheData = cacheRepository.get(key);
- if (localCacheData != null && System.currentTimeMillis() >= localCacheData.getTimeoutTime()) {
- cacheRepository.remove(key);
- }
- }
- }
- return true;
- }
-
-}
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
deleted file mode 100644
index b608d9fbc..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobGroupDao.java
+++ /dev/null
@@ -1,37 +0,0 @@
-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
deleted file mode 100644
index e01dd1121..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobInfoDao.java
+++ /dev/null
@@ -1,51 +0,0 @@
-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
deleted file mode 100644
index 7beaf7556..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogDao.java
+++ /dev/null
@@ -1,65 +0,0 @@
-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
deleted file mode 100644
index 8b2b414ce..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogGlueDao.java
+++ /dev/null
@@ -1,25 +0,0 @@
-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
deleted file mode 100644
index d4e0381a1..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobLogReportDao.java
+++ /dev/null
@@ -1,27 +0,0 @@
-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
deleted file mode 100644
index a68e12c36..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobRegistryDao.java
+++ /dev/null
@@ -1,38 +0,0 @@
-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
deleted file mode 100644
index 064ce19f3..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/dao/XxlJobUserDao.java
+++ /dev/null
@@ -1,33 +0,0 @@
-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
deleted file mode 100644
index 0937b8e95..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/LoginService.java
+++ /dev/null
@@ -1,108 +0,0 @@
-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;
- }
-
-
-}
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
deleted file mode 100644
index 43c2eff64..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/XxlJobService.java
+++ /dev/null
@@ -1,87 +0,0 @@
-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
deleted file mode 100644
index 3c01e94dc..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/AdminBizImpl.java
+++ /dev/null
@@ -1,35 +0,0 @@
-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
deleted file mode 100644
index 454610c23..000000000
--- a/ruoyi-extend/ruoyi-xxl-job-admin/src/main/java/com/xxl/job/admin/service/impl/XxlJobServiceImpl.java
+++ /dev/null
@@ -1,435 +0,0 @@
-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(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_jobgroup") + I18nUtil.getString("system_unvalid")));
- }
-
- // stage job info
- XxlJobInfo exists_jobInfo = xxlJobInfoDao.loadById(jobInfo.getId());
- if (exists_jobInfo == null) {
- return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("jobinfo_field_id") + I18nUtil.getString("system_not_found")));
- }
-
- // next trigger time (5s后生效,避开预读周期)
- long nextTriggerTime = exists_jobInfo.getTriggerNextTime();
- boolean scheduleDataNotChanged = jobInfo.getScheduleType().equals(exists_jobInfo.getScheduleType()) && jobInfo.getScheduleConf().equals(exists_jobInfo.getScheduleConf());
- if (exists_jobInfo.getTriggerStatus() == 1 && !scheduleDataNotChanged) {
- try {
- Date nextValidTime = JobScheduleHelper.generateNextValidTime(jobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
- if (nextValidTime == null) {
- return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
- }
- nextTriggerTime = nextValidTime.getTime();
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
- }
- }
-
- exists_jobInfo.setJobGroup(jobInfo.getJobGroup());
- exists_jobInfo.setJobDesc(jobInfo.getJobDesc());
- exists_jobInfo.setAuthor(jobInfo.getAuthor());
- exists_jobInfo.setAlarmEmail(jobInfo.getAlarmEmail());
- exists_jobInfo.setScheduleType(jobInfo.getScheduleType());
- exists_jobInfo.setScheduleConf(jobInfo.getScheduleConf());
- exists_jobInfo.setMisfireStrategy(jobInfo.getMisfireStrategy());
- exists_jobInfo.setExecutorRouteStrategy(jobInfo.getExecutorRouteStrategy());
- exists_jobInfo.setExecutorHandler(jobInfo.getExecutorHandler());
- exists_jobInfo.setExecutorParam(jobInfo.getExecutorParam());
- exists_jobInfo.setExecutorBlockStrategy(jobInfo.getExecutorBlockStrategy());
- exists_jobInfo.setExecutorTimeout(jobInfo.getExecutorTimeout());
- exists_jobInfo.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
- exists_jobInfo.setChildJobId(jobInfo.getChildJobId());
- exists_jobInfo.setTriggerNextTime(nextTriggerTime);
-
- exists_jobInfo.setUpdateTime(new Date());
- xxlJobInfoDao.update(exists_jobInfo);
-
-
- return ReturnT.SUCCESS;
- }
-
- @Override
- public ReturnT remove(int id) {
- XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
- if (xxlJobInfo == null) {
- return ReturnT.SUCCESS;
- }
-
- xxlJobInfoDao.delete(id);
- xxlJobLogDao.delete(id);
- xxlJobLogGlueDao.deleteByJobId(id);
- return ReturnT.SUCCESS;
- }
-
- @Override
- public ReturnT start(int id) {
- XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
-
- // valid
- ScheduleTypeEnum scheduleTypeEnum = ScheduleTypeEnum.match(xxlJobInfo.getScheduleType(), ScheduleTypeEnum.NONE);
- if (ScheduleTypeEnum.NONE == scheduleTypeEnum) {
- return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type_none_limit_start")));
- }
-
- // next trigger time (5s后生效,避开预读周期)
- long nextTriggerTime = 0;
- try {
- Date nextValidTime = JobScheduleHelper.generateNextValidTime(xxlJobInfo, new Date(System.currentTimeMillis() + JobScheduleHelper.PRE_READ_MS));
- if (nextValidTime == null) {
- return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
- }
- nextTriggerTime = nextValidTime.getTime();
- } catch (Exception e) {
- logger.error(e.getMessage(), e);
- return new ReturnT(ReturnT.FAIL_CODE, (I18nUtil.getString("schedule_type") + I18nUtil.getString("system_unvalid")));
- }
-
- xxlJobInfo.setTriggerStatus(1);
- xxlJobInfo.setTriggerLastTime(0);
- xxlJobInfo.setTriggerNextTime(nextTriggerTime);
-
- xxlJobInfo.setUpdateTime(new Date());
- xxlJobInfoDao.update(xxlJobInfo);
- return ReturnT.SUCCESS;
- }
-
- @Override
- public ReturnT stop(int id) {
- XxlJobInfo xxlJobInfo = xxlJobInfoDao.loadById(id);
-
- xxlJobInfo.setTriggerStatus(0);
- xxlJobInfo.setTriggerLastTime(0);
- xxlJobInfo.setTriggerNextTime(0);
-
- xxlJobInfo.setUpdateTime(new Date());
- xxlJobInfoDao.update(xxlJobInfo);
- return ReturnT.SUCCESS;
- }
-
- @Override
- public Map dashboardInfo() {
-
- int jobInfoCount = xxlJobInfoDao.findAllCount();
- int jobLogCount = 0;
- int jobLogSuccessCount = 0;
- XxlJobLogReport xxlJobLogReport = xxlJobLogReportDao.queryLogReportTotal();
- if (xxlJobLogReport != null) {
- jobLogCount = xxlJobLogReport.getRunningCount() + xxlJobLogReport.getSucCount() + xxlJobLogReport.getFailCount();
- jobLogSuccessCount = xxlJobLogReport.getSucCount();
- }
-
- // executor count
- Set executorAddressSet = new HashSet();
- List groupList = xxlJobGroupDao.findAll();
-
- if (groupList != null && !groupList.isEmpty()) {
- for (XxlJobGroup group : groupList) {
- if (group.getRegistryList() != null && !group.getRegistryList().isEmpty()) {
- executorAddressSet.addAll(group.getRegistryList());
- }
- }
- }
-
- int executorCount = executorAddressSet.size();
-
- Map dashboardMap = new HashMap();
- dashboardMap.put("jobInfoCount", jobInfoCount);
- dashboardMap.put("jobLogCount", jobLogCount);
- dashboardMap.put("jobLogSuccessCount", jobLogSuccessCount);
- dashboardMap.put("executorCount", executorCount);
- return dashboardMap;
- }
-
- @Override
- public ReturnT> chartInfo(Date startDate, Date endDate) {
-
- // process
- List triggerDayList = new ArrayList();
- List triggerDayCountRunningList = new ArrayList();
- List triggerDayCountSucList = new ArrayList();
- List triggerDayCountFailList = new ArrayList();
- int triggerCountRunningTotal = 0;
- int triggerCountSucTotal = 0;
- int triggerCountFailTotal = 0;
-
- List logReportList = xxlJobLogReportDao.queryLogReport(startDate, endDate);
-
- if (logReportList != null && logReportList.size() > 0) {
- for (XxlJobLogReport item : logReportList) {
- String day = DateUtil.formatDate(item.getTriggerDay());
- int triggerDayCountRunning = item.getRunningCount();
- int triggerDayCountSuc = item.getSucCount();
- int triggerDayCountFail = item.getFailCount();
-
- triggerDayList.add(day);
- triggerDayCountRunningList.add(triggerDayCountRunning);
- triggerDayCountSucList.add(triggerDayCountSuc);
- triggerDayCountFailList.add(triggerDayCountFail);
-
- triggerCountRunningTotal += triggerDayCountRunning;
- triggerCountSucTotal += triggerDayCountSuc;
- triggerCountFailTotal += triggerDayCountFail;
- }
- } else {
- for (int i = -6; i <= 0; i++) {
- triggerDayList.add(DateUtil.formatDate(DateUtil.addDays(new Date(), i)));
- triggerDayCountRunningList.add(0);
- triggerDayCountSucList.add(0);
- triggerDayCountFailList.add(0);
- }
- }
-
- Map result = new HashMap();
- result.put("triggerDayList", triggerDayList);
- result.put("triggerDayCountRunningList", triggerDayCountRunningList);
- result.put("triggerDayCountSucList", triggerDayCountSucList);
- result.put("triggerDayCountFailList", triggerDayCountFailList);
-
- result.put("triggerCountRunningTotal", triggerCountRunningTotal);
- result.put("triggerCountSucTotal", triggerCountSucTotal);
- result.put("triggerCountFailTotal", triggerCountFailTotal);
-
- return new ReturnT