diff --git a/.run/ruoyi-auth.run.xml b/.run/ruoyi-auth.run.xml
index 0b69031f..9c84b321 100644
--- a/.run/ruoyi-auth.run.xml
+++ b/.run/ruoyi-auth.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-gateway.run.xml b/.run/ruoyi-gateway.run.xml
index d399a727..b6e5ac04 100644
--- a/.run/ruoyi-gateway.run.xml
+++ b/.run/ruoyi-gateway.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-gen.run.xml b/.run/ruoyi-gen.run.xml
index d0dc0e67..abd6d2ff 100644
--- a/.run/ruoyi-gen.run.xml
+++ b/.run/ruoyi-gen.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-job.run.xml b/.run/ruoyi-job.run.xml
index 4fa17309..ead6cdae 100644
--- a/.run/ruoyi-job.run.xml
+++ b/.run/ruoyi-job.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-monitor.run.xml b/.run/ruoyi-monitor.run.xml
index 05292ec7..fc525a25 100644
--- a/.run/ruoyi-monitor.run.xml
+++ b/.run/ruoyi-monitor.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-nacos.run.xml b/.run/ruoyi-nacos.run.xml
index 3d8030ca..03e3f236 100644
--- a/.run/ruoyi-nacos.run.xml
+++ b/.run/ruoyi-nacos.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-resource.run.xml b/.run/ruoyi-resource.run.xml
index 5092e31a..79b1f4a9 100644
--- a/.run/ruoyi-resource.run.xml
+++ b/.run/ruoyi-resource.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-seata-server.run.xml b/.run/ruoyi-seata-server.run.xml
index 9765f397..dd9b15a2 100644
--- a/.run/ruoyi-seata-server.run.xml
+++ b/.run/ruoyi-seata-server.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-sentinel-dashboard.run.xml b/.run/ruoyi-sentinel-dashboard.run.xml
index fd0ca162..41c2f518 100644
--- a/.run/ruoyi-sentinel-dashboard.run.xml
+++ b/.run/ruoyi-sentinel-dashboard.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-snailjob-server.run.xml b/.run/ruoyi-snailjob-server.run.xml
index e2d7e440..dfeb8b06 100644
--- a/.run/ruoyi-snailjob-server.run.xml
+++ b/.run/ruoyi-snailjob-server.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-system.run.xml b/.run/ruoyi-system.run.xml
index a657faef..9c75c60e 100644
--- a/.run/ruoyi-system.run.xml
+++ b/.run/ruoyi-system.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/.run/ruoyi-workflow.run.xml b/.run/ruoyi-workflow.run.xml
index 4d1d25c5..59435e9b 100644
--- a/.run/ruoyi-workflow.run.xml
+++ b/.run/ruoyi-workflow.run.xml
@@ -2,7 +2,7 @@
-
+
diff --git a/README.md b/README.md
index 406e0d61..bfb67c32 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,10 @@
[](https://gitee.com/dromara/RuoYi-Cloud-Plus/blob/master/LICENSE)
[](https://www.jetbrains.com/?from=RuoYi-Cloud-Plus)
-[](https://gitee.com/dromara/RuoYi-Cloud-Plus)
+[](https://gitee.com/dromara/RuoYi-Cloud-Plus)
[]()
[]()
-[]()
+[]()
> RuoYi-Cloud-Plus `微服务通用权限管理系统` 重写 RuoYi-Cloud 全方位升级(不兼容原框架)
@@ -66,12 +66,14 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow
| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 |
| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 |
| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 |
+| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 |
| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 |
| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 |
| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 |
| 分布式日志中心 | 采用 ELK 业界成熟解决方案 实时收集所有服务的运行日志 快速发现定位问题 | 无 |
| 分布式搜索引擎 | 采用 ElasticSearch、Easy-Es 以 Mybatis-Plus 方式操作 ElasticSearch | 无 |
| 分布式消息队列 | 采用 支持 Kafka、RocketMQ、RabbitMQ 各种 延迟消息 事务消息 流消息 | 无 |
+| 分布式消息总线 | 采用 SpringCloud Bus 实现事件总线 跨服务通知 支持 Kafka、RocketMQ、RabbitMQ | 无 |
| 分库分表功能 | 采用 Apache Sharding-Proxy 代理服务无入侵支持分库分表 只需编写分库分表规则即可 | 无 |
| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 |
| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 |
@@ -80,6 +82,7 @@ CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow
| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 |
| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 |
| Excel框架 | 采用 Alibaba EasyExcel 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 |
+| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 |
| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 |
| 服务监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 |
| 全方位监控报警 | 采用 Prometheus、Grafana 多样化采集 多模板大屏展示 实时报警监控 提供详细的搭建文档 | 无 |
diff --git a/config/nacos/application-common.yml b/config/nacos/application-common.yml
index e60c9d3e..17b26aec 100644
--- a/config/nacos/application-common.yml
+++ b/config/nacos/application-common.yml
@@ -70,12 +70,16 @@ spring:
# 允许对象忽略json中不存在的属性
fail_on_unknown_properties: false
cloud:
+ nacos:
+ discovery:
+ metadata:
+ # admin 监控账号密码
+ username: ruoyi
+ userpassword: 123456
# sentinel 配置
sentinel:
# sentinel 开关
enabled: true
- # 取消控制台懒加载
- eager: true
transport:
# dashboard控制台服务名 用于服务发现
# 如无此配置将默认使用下方 dashboard 配置直接注册
@@ -103,7 +107,8 @@ spring:
# redis 密码必须配置
password: ruoyi123
database: 0
- timeout: 10s
+ # 需要使用数字
+ timeout: 10000
ssl.enabled: false
# redisson 配置
@@ -154,6 +159,7 @@ logging:
org.springframework: warn
org.apache.dubbo: warn
com.alibaba.nacos: warn
+ com.alibaba.cloud.sentinel: warn
org.mybatis.spring.mapper: error
org.apache.dubbo.config: error
# 临时处理 spring 调整日志级别导致启动警告问题 不影响使用等待 alibaba 适配
diff --git a/config/nacos/ruoyi-gateway.yml b/config/nacos/ruoyi-gateway.yml
index b51856f7..60657ae0 100644
--- a/config/nacos/ruoyi-gateway.yml
+++ b/config/nacos/ruoyi-gateway.yml
@@ -18,6 +18,7 @@ security:
- /auth/register
- /auth/tenant/list
- /resource/sms/code
+ - /resource/sse/close
- /*/v3/api-docs
- /*/error
- /csrf
diff --git a/config/nacos/ruoyi-resource.yml b/config/nacos/ruoyi-resource.yml
index 9c539725..0352230f 100644
--- a/config/nacos/ruoyi-resource.yml
+++ b/config/nacos/ruoyi-resource.yml
@@ -24,9 +24,14 @@ spring:
# username: ${datasource.system-postgres.username}
# password: ${datasource.system-postgres.password}
+# 默认/推荐使用sse推送
+sse:
+ enabled: true
+ path: /sse
+
websocket:
# 如果关闭 需要和前端开关一起关闭
- enabled: true
+ enabled: false
# 路径
path: /websocket
# 设置访问源地址
diff --git a/config/nacos/ruoyi-snailjob-server.yml b/config/nacos/ruoyi-snailjob-server.yml
index 4440fc4f..cc9c1ed8 100644
--- a/config/nacos/ruoyi-snailjob-server.yml
+++ b/config/nacos/ruoyi-snailjob-server.yml
@@ -13,6 +13,15 @@ spring:
idle-timeout: 600000
max-lifetime: 900000
keepaliveTime: 30000
+ cloud:
+ nacos:
+ discovery:
+ metadata:
+ # 解决 er 服务有 context-path 无法监控问题
+ management.context-path: ${server.servlet.context-path}/actuator
+ # 监控账号密码
+ username: ruoyi
+ userpassword: 123456
# snail-job 服务端配置
snail-job:
diff --git a/config/nacos/ruoyi-workflow.yml b/config/nacos/ruoyi-workflow.yml
index 51cf2a6a..5933ebc3 100644
--- a/config/nacos/ruoyi-workflow.yml
+++ b/config/nacos/ruoyi-workflow.yml
@@ -26,6 +26,10 @@ spring:
# flowable配置
flowable:
+ # 开关 用于启动/停用工作流
+ enabled: true
+ process.enabled: ${flowable.enabled}
+ eventregistry.enabled: ${flowable.enabled}
# 关闭定时任务JOB
async-executor-activate: false
# 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index 66bc2dd6..21b86c01 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -2,7 +2,7 @@ version: '3'
services:
mysql:
- image: mysql:8.0.31
+ image: mysql:8.0.33
container_name: mysql
environment:
# 时区上海
@@ -29,7 +29,7 @@ services:
network_mode: "host"
nacos:
- image: ruoyi/ruoyi-nacos:2.2.0
+ image: ruoyi/ruoyi-nacos:2.2.1
container_name: nacos
ports:
- "8848:8848"
@@ -96,7 +96,7 @@ services:
network_mode: "host"
seata-server:
- image: ruoyi/ruoyi-seata-server:2.2.0
+ image: ruoyi/ruoyi-seata-server:2.2.1
container_name: seata-server
ports:
- "7091:7091"
@@ -135,7 +135,7 @@ services:
network_mode: "host"
sentinel:
- image: ruoyi/ruoyi-sentinel-dashboard:2.2.0
+ image: ruoyi/ruoyi-sentinel-dashboard:2.2.1
container_name: sentinel
environment:
TZ: Asia/Shanghai
@@ -150,7 +150,7 @@ services:
network_mode: "host"
ruoyi-monitor:
- image: ruoyi/ruoyi-monitor:2.2.0
+ image: ruoyi/ruoyi-monitor:2.2.1
container_name: ruoyi-monitor
environment:
# 时区上海
@@ -166,7 +166,7 @@ services:
network_mode: "host"
ruoyi-snailjob-server:
- image: ruoyi/ruoyi-snailjob-server:2.2.0
+ image: ruoyi/ruoyi-snailjob-server:2.2.1
container_name: ruoyi-snailjob-server
environment:
# 时区上海
@@ -180,7 +180,7 @@ services:
network_mode: "host"
ruoyi-gateway:
- image: ruoyi/ruoyi-gateway:2.2.0
+ image: ruoyi/ruoyi-gateway:2.2.1
container_name: ruoyi-gateway
environment:
# 时区上海
@@ -196,7 +196,7 @@ services:
network_mode: "host"
ruoyi-auth:
- image: ruoyi/ruoyi-auth:2.2.0
+ image: ruoyi/ruoyi-auth:2.2.1
container_name: ruoyi-auth
environment:
# 时区上海
@@ -212,7 +212,7 @@ services:
network_mode: "host"
ruoyi-system:
- image: ruoyi/ruoyi-system:2.2.0
+ image: ruoyi/ruoyi-system:2.2.1
container_name: ruoyi-system
environment:
# 时区上海
@@ -228,7 +228,7 @@ services:
network_mode: "host"
ruoyi-gen:
- image: ruoyi/ruoyi-gen:2.2.0
+ image: ruoyi/ruoyi-gen:2.2.1
container_name: ruoyi-gen
environment:
# 时区上海
@@ -244,7 +244,7 @@ services:
network_mode: "host"
ruoyi-job:
- image: ruoyi/ruoyi-job:2.2.0
+ image: ruoyi/ruoyi-job:2.2.1
container_name: ruoyi-job
environment:
# 时区上海
@@ -260,7 +260,7 @@ services:
network_mode: "host"
ruoyi-resource:
- image: ruoyi/ruoyi-resource:2.2.0
+ image: ruoyi/ruoyi-resource:2.2.1
container_name: ruoyi-resource
environment:
# 时区上海
@@ -276,7 +276,7 @@ services:
network_mode: "host"
ruoyi-workflow:
- image: ruoyi/ruoyi-workflow:2.2.0
+ image: ruoyi/ruoyi-workflow:2.2.1
container_name: ruoyi-workflow
environment:
# 时区上海
diff --git a/docker/nginx/conf/nginx.conf b/docker/nginx/conf/nginx.conf
index ed01e597..6d837c4e 100644
--- a/docker/nginx/conf/nginx.conf
+++ b/docker/nginx/conf/nginx.conf
@@ -71,10 +71,13 @@ http {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- # websocket参数
+ proxy_read_timeout 86400s;
+ # sse 与 websocket参数
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
+ proxy_buffering off;
+ proxy_cache off;
proxy_pass http://server/;
}
diff --git a/docker/skywalking/agent/config/agent.config b/docker/skywalking/agent/config/agent.config
index 45b09a35..4c9f72fe 100644
--- a/docker/skywalking/agent/config/agent.config
+++ b/docker/skywalking/agent/config/agent.config
@@ -68,7 +68,7 @@ agent.force_reconnection_period=${SW_AGENT_FORCE_RECONNECTION_PERIOD:1}
agent.operation_name_threshold=${SW_AGENT_OPERATION_NAME_THRESHOLD:150}
# Keep tracing even the backend is not available if this value is true.
-agent.keep_tracing=${SW_AGENT_KEEP_TRACING:false}
+agent.keep_tracing=${SW_AGENT_KEEP_TRACING:true}
# The agent use gRPC plain text in default.
# If true, SkyWalking agent uses TLS even no CA file detected.
diff --git a/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar b/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar
index e69de29b..d9e7895b 100644
Binary files a/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar and b/docker/skywalking/agent/plugins/apm-httpClient-4.x-plugin-9.2.0.jar differ
diff --git a/pom.xml b/pom.xml
index 3ba38fce..9c4bdf90 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,40 +13,39 @@
RuoYi-Cloud-Plus微服务系统
- 2.2.0
+ 2.2.1
UTF-8
UTF-8
17
- 3.2.6
- 2023.0.2
+ 3.2.9
+ 2023.0.3
3.2.3
3.5.16
3.5.7
3.9.1
4.3.1
2.3
- 2.2.21
- 2.5.0
+ 2.2.22
+ 2.6.0
0.15.0
- 5.2.3
- 3.3.4
- 5.8.27
- 3.31.0
+ 4.0.2
+ 5.8.31
+ 3.34.1
2.2.7
- 1.0.1
+ 1.1.2
1.38.0
- 1.18.32
+ 1.18.34
7.4
2.0.0
7.14.0
9.2.0
1.76
- 2.14.4
- 1.3.6
+ 1.4.4
0.2.0
1.16.6
2.7.0
+ 2.3.15.Final
1.2.83
@@ -56,9 +55,11 @@
4.10.0
- 3.2.1
+ 3.3.2
+
+ 8.7.2-20240808
- 7.0.0
+ 7.0.1
2.3.0
@@ -233,26 +234,10 @@
${lombok.version}
-
- org.apache.poi
- poi
- ${poi.version}
-
-
- org.apache.poi
- poi-ooxml
- ${poi.version}
-
com.alibaba
easyexcel
${easyexcel.version}
-
-
- org.apache.poi
- poi-ooxml-schemas
-
-
@@ -368,6 +353,28 @@
${ip2region.version}
+
+ io.undertow
+ undertow-core
+ ${undertow.version}
+
+
+ io.undertow
+ undertow-servlet
+ ${undertow.version}
+
+
+ io.undertow
+ undertow-websockets-jsr
+ ${undertow.version}
+
+
+
+ commons-compress
+ org.apache.commons
+ 1.26.2
+
+
com.alibaba
fastjson
@@ -381,12 +388,6 @@
5.1.0
-
- com.alibaba
- transmittable-thread-local
- ${alibaba-ttl.version}
-
-
io.github.linpeilie
mapstruct-plus-spring-boot-starter
diff --git a/ruoyi-api/ruoyi-api-bom/pom.xml b/ruoyi-api/ruoyi-api-bom/pom.xml
index 8bdae831..26889bed 100644
--- a/ruoyi-api/ruoyi-api-bom/pom.xml
+++ b/ruoyi-api/ruoyi-api-bom/pom.xml
@@ -15,7 +15,7 @@
- 2.2.0
+ 2.2.1
diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java b/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java
index 1537cb5f..82931278 100644
--- a/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java
+++ b/ruoyi-auth/src/main/java/org/dromara/auth/controller/CaptchaController.java
@@ -1,6 +1,5 @@
package org.dromara.auth.controller;
-import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
@@ -32,7 +31,6 @@ import java.time.Duration;
*
* @author Lion Li
*/
-@SaIgnore
@Slf4j
@Validated
@RequiredArgsConstructor
diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java b/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java
index c4a1a0e1..60acd9df 100644
--- a/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java
+++ b/ruoyi-auth/src/main/java/org/dromara/auth/listener/UserActionListener.java
@@ -3,6 +3,8 @@ package org.dromara.auth.listener;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.convert.Convert;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import lombok.RequiredArgsConstructor;
@@ -85,7 +87,10 @@ public class UserActionListener implements SaTokenListener {
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
- RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+ String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+ TenantHelper.dynamic(tenantId, () -> {
+ RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+ });
log.info("user doLogout, useId:{}, token:{}", loginId, tokenValue);
}
@@ -94,7 +99,10 @@ public class UserActionListener implements SaTokenListener {
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
- RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+ String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+ TenantHelper.dynamic(tenantId, () -> {
+ RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+ });
log.info("user doLogoutByLoginId, useId:{}, token:{}", loginId, tokenValue);
}
@@ -103,7 +111,10 @@ public class UserActionListener implements SaTokenListener {
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
- RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+ String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY));
+ TenantHelper.dynamic(tenantId, () -> {
+ RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
+ });
log.info("user doReplaced, useId:{}, token:{}", loginId, tokenValue);
}
diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java
index eacdc01b..d50ce975 100644
--- a/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java
+++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/SysLoginService.java
@@ -14,6 +14,7 @@ import org.apache.dubbo.config.annotation.DubboReference;
import org.dromara.auth.form.RegisterBody;
import org.dromara.auth.properties.CaptchaProperties;
import org.dromara.auth.properties.UserPasswordProperties;
+import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.TenantConstants;
@@ -205,7 +206,7 @@ public class SysLoginService {
* 登录校验
*/
public void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) {
- String errorKey = GlobalConstants.PWD_ERR_CNT_KEY + username;
+ String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username;
String loginFail = Constants.LOGIN_FAIL;
Integer maxRetryCount = userPasswordProperties.getMaxRetryCount();
Integer lockTime = userPasswordProperties.getLockTime();
diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java
index 8790fe13..a9f6d351 100644
--- a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java
+++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/EmailAuthStrategy.java
@@ -19,6 +19,7 @@ import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
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.api.RemoteUserService;
import org.dromara.system.api.domain.vo.RemoteClientVo;
import org.dromara.system.api.model.LoginUser;
@@ -46,10 +47,11 @@ public class EmailAuthStrategy implements IAuthStrategy {
String tenantId = loginBody.getTenantId();
String email = loginBody.getEmail();
String emailCode = loginBody.getEmailCode();
-
- // 通过邮箱查找用户
- LoginUser loginUser = remoteUserService.getUserInfoByEmail(email, tenantId);
- loginService.checkLogin(LoginType.EMAIL, tenantId, loginUser.getUsername(), () -> !validateEmailCode(tenantId, email, emailCode));
+ LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+ LoginUser user = remoteUserService.getUserInfoByEmail(email, tenantId);
+ loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUsername(), () -> !validateEmailCode(tenantId, email, emailCode));
+ return user;
+ });
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel();
diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java
index db4ea945..0071ea4e 100644
--- a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java
+++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/PasswordAuthStrategy.java
@@ -22,6 +22,7 @@ import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
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.api.RemoteUserService;
import org.dromara.system.api.domain.vo.RemoteClientVo;
import org.dromara.system.api.model.LoginUser;
@@ -58,9 +59,11 @@ public class PasswordAuthStrategy implements IAuthStrategy {
if (captchaProperties.getEnabled()) {
validateCaptcha(tenantId, username, code, uuid);
}
-
- LoginUser loginUser = remoteUserService.getUserInfo(username, tenantId);
- loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, loginUser.getPassword()));
+ LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+ LoginUser user = remoteUserService.getUserInfo(username, tenantId);
+ loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword()));
+ return user;
+ });
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel();
diff --git a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java
index d32b5aa1..899cafcc 100644
--- a/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java
+++ b/ruoyi-auth/src/main/java/org/dromara/auth/service/impl/SmsAuthStrategy.java
@@ -19,6 +19,7 @@ import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
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.api.RemoteUserService;
import org.dromara.system.api.domain.vo.RemoteClientVo;
import org.dromara.system.api.model.LoginUser;
@@ -46,10 +47,11 @@ public class SmsAuthStrategy implements IAuthStrategy {
String tenantId = loginBody.getTenantId();
String phonenumber = loginBody.getPhonenumber();
String smsCode = loginBody.getSmsCode();
-
- // 通过手机号查找用户
- LoginUser loginUser = remoteUserService.getUserInfoByPhonenumber(phonenumber, tenantId);
- loginService.checkLogin(LoginType.SMS, tenantId, loginUser.getUsername(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
+ LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> {
+ LoginUser user = remoteUserService.getUserInfoByPhonenumber(phonenumber, tenantId);
+ loginService.checkLogin(LoginType.SMS, tenantId, user.getUsername(), () -> !validateSmsCode(tenantId, phonenumber, smsCode));
+ return user;
+ });
loginUser.setClientKey(client.getClientKey());
loginUser.setDeviceType(client.getDeviceType());
SaLoginModel model = new SaLoginModel();
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
index ff6f5581..48e00955 100644
--- a/ruoyi-common/pom.xml
+++ b/ruoyi-common/pom.xml
@@ -44,6 +44,7 @@
ruoyi-common-social
ruoyi-common-nacos
ruoyi-common-bus
+ ruoyi-common-sse
ruoyi-common
diff --git a/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml b/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml
index e2f4f110..561e2f1b 100644
--- a/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml
+++ b/ruoyi-common/ruoyi-common-alibaba-bom/pom.xml
@@ -14,8 +14,8 @@
- 2.2.0
- 2023.0.1.0
+ 2.2.1
+ 2023.0.1.2
1.8.8
1.7.1
2.3.3
@@ -123,7 +123,7 @@
com.alibaba.csp
- sentinel-spring-webmvc-adapter
+ sentinel-spring-webmvc-v6x-adapter
${sentinel.version}
diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml
index dcafd753..8a096cd6 100644
--- a/ruoyi-common/ruoyi-common-bom/pom.xml
+++ b/ruoyi-common/ruoyi-common-bom/pom.xml
@@ -14,7 +14,7 @@
- 2.2.0
+ 2.2.1
@@ -250,6 +250,13 @@
${revision}
+
+
+ org.dromara
+ ruoyi-common-sse
+ ${revision}
+
+
diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml
index 84ab453a..01d876e7 100644
--- a/ruoyi-common/ruoyi-common-core/pom.xml
+++ b/ruoyi-common/ruoyi-common-core/pom.xml
@@ -99,11 +99,6 @@
ip2region
-
- com.alibaba
- transmittable-thread-local
-
-
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
index 67bc8e4c..ceb83704 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java
@@ -22,4 +22,9 @@ public interface CacheConstants {
*/
String SYS_DICT_KEY = "sys_dict:";
+ /**
+ * 登录账户密码错误次数 redis key
+ */
+ String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
}
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 8e5a6eb9..73f62a39 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
@@ -27,11 +27,6 @@ public interface GlobalConstants {
*/
String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:";
- /**
- * 登录账户密码错误次数 redis key
- */
- String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:";
-
/**
* 三方认证 redis key
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
index 6f3b0b96..76f6dd4a 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/UserConstants.java
@@ -67,6 +67,16 @@ public interface UserConstants {
*/
String DICT_NORMAL = "0";
+ /**
+ * 通用存在标志
+ */
+ String DEL_FLAG_NORMAL = "0";
+
+ /**
+ * 通用删除标志
+ */
+ String DEL_FLAG_REMOVED = "2";
+
/**
* 是否为系统默认(是)
*/
diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java
index b2bb4186..9d6af3af 100644
--- a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java
+++ b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/apache/dubbo/metadata/store/redis/RedisMetadataReport.java
@@ -16,52 +16,27 @@
*/
package org.apache.dubbo.metadata.store.redis;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.dubbo.common.URL;
import org.apache.dubbo.common.config.configcenter.ConfigItem;
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.common.utils.ConcurrentHashMapUtils;
-import org.apache.dubbo.common.utils.ConcurrentHashSet;
-import org.apache.dubbo.common.utils.JsonUtils;
-import org.apache.dubbo.common.utils.StringUtils;
+import org.apache.dubbo.common.utils.*;
import org.apache.dubbo.metadata.MappingChangedEvent;
import org.apache.dubbo.metadata.MappingListener;
import org.apache.dubbo.metadata.MetadataInfo;
import org.apache.dubbo.metadata.ServiceNameMapping;
-import org.apache.dubbo.metadata.report.identifier.BaseMetadataIdentifier;
-import org.apache.dubbo.metadata.report.identifier.KeyTypeEnum;
-import org.apache.dubbo.metadata.report.identifier.MetadataIdentifier;
-import org.apache.dubbo.metadata.report.identifier.ServiceMetadataIdentifier;
-import org.apache.dubbo.metadata.report.identifier.SubscriberMetadataIdentifier;
+import org.apache.dubbo.metadata.report.identifier.*;
import org.apache.dubbo.metadata.report.support.AbstractMetadataReport;
import org.apache.dubbo.rpc.RpcException;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
-import redis.clients.jedis.HostAndPort;
-import redis.clients.jedis.Jedis;
-import redis.clients.jedis.JedisCluster;
-import redis.clients.jedis.JedisPool;
-import redis.clients.jedis.JedisPoolConfig;
-import redis.clients.jedis.JedisPubSub;
-import redis.clients.jedis.Transaction;
+import redis.clients.jedis.*;
import redis.clients.jedis.params.SetParams;
import redis.clients.jedis.util.JedisClusterCRC16;
-import static org.apache.dubbo.common.constants.CommonConstants.CLUSTER_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.CYCLE_REPORT_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_TIMEOUT;
-import static org.apache.dubbo.common.constants.CommonConstants.GROUP_CHAR_SEPARATOR;
-import static org.apache.dubbo.common.constants.CommonConstants.QUEUES_KEY;
-import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_KEY;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static org.apache.dubbo.common.constants.CommonConstants.*;
import static org.apache.dubbo.common.constants.LoggerCodeConstants.TRANSPORT_FAILED_RESPONSE;
import static org.apache.dubbo.metadata.MetadataConstants.META_DATA_STORE_TAG;
import static org.apache.dubbo.metadata.ServiceNameMapping.DEFAULT_MAPPING_GROUP;
@@ -479,7 +454,7 @@ public class RedisMetadataReport extends AbstractMetadataReport {
logger.info("sub from redis:" + key + " message:" + msg);
String applicationNames = getMappingData(buildMappingKey(DEFAULT_MAPPING_GROUP), msg);
MappingChangedEvent mappingChangedEvent = new MappingChangedEvent(msg, getAppNames(applicationNames));
- if (!listeners.get(msg).isEmpty()) {
+ if (!CollectionUtils.isEmpty(listeners.get(msg))) {
for (MappingListener mappingListener : listeners.get(msg)) {
mappingListener.onEvent(mappingChangedEvent);
}
diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java
index ef28564d..40ad3a2e 100644
--- a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java
+++ b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/config/CustomBeanFactoryPostProcessor.java
@@ -1,5 +1,6 @@
package org.dromara.common.dubbo.config;
+import org.dromara.common.core.utils.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -34,6 +35,10 @@ public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ String property = System.getProperty("DUBBO_IP_TO_REGISTRY");
+ if (StringUtils.isNotBlank(property)) {
+ return;
+ }
// 获取 InetUtils bean,用于获取 IP 地址
InetUtils inetUtils = beanFactory.getBean(InetUtils.class);
String ip = "127.0.0.1";
diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java
index 273155e2..5e74c65d 100644
--- a/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java
+++ b/ruoyi-common/ruoyi-common-dubbo/src/main/java/org/dromara/common/dubbo/filter/DubboRequestFilter.java
@@ -67,8 +67,8 @@ public class DubboRequestFilter implements Filter {
Result result = invoker.invoke(invocation);
// 计算调用耗时
long elapsed = System.currentTimeMillis() - startTime;
- // 如果发生异常且调用的是泛化服务,则记录异常日志
- if (result.hasException() && invoker.getInterface().equals(GenericService.class)) {
+ // 如果发生异常且调用的不是泛化服务,则记录异常日志
+ if (result.hasException() && !invoker.getInterface().equals(GenericService.class)) {
log.error("DUBBO - 服务异常: {},Exception={}", baselog, result.getException());
} else {
// 根据日志级别输出服务响应信息
diff --git a/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml b/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml
index e7035f1a..3e1199f6 100644
--- a/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml
+++ b/ruoyi-common/ruoyi-common-dubbo/src/main/resources/common-dubbo.yml
@@ -27,6 +27,7 @@ dubbo:
parameters:
namespace: ${spring.profiles.active}
database: ${spring.data.redis.database}
+ timeout: ${spring.data.redis.timeout}
# 消费者相关配置
consumer:
# 结果缓存(LRU算法)
diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml
index dd4a5eeb..14b9410b 100644
--- a/ruoyi-common/ruoyi-common-excel/pom.xml
+++ b/ruoyi-common/ruoyi-common-excel/pom.xml
@@ -25,6 +25,11 @@
com.alibaba
easyexcel
+
+ commons-compress
+ org.apache.commons
+ 1.26.2
+
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
index 7c0a48b9..7c7721c6 100644
--- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java
@@ -107,7 +107,7 @@ public class CellMergeStrategy extends AbstractMergeStrategy implements Workbook
}
if (!cellValue.equals(val)) {
- if ((i - repeatCell.getCurrent() > 1) && isMerge(list, i, field)) {
+ if ((i - repeatCell.getCurrent() > 1)) {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
}
map.put(field, new RepeatCell(val, i));
@@ -115,6 +115,11 @@ public class CellMergeStrategy extends AbstractMergeStrategy implements Workbook
if (i > repeatCell.getCurrent() && isMerge(list, i, field)) {
cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
}
+ } else if (!isMerge(list, i, field)) {
+ if ((i - repeatCell.getCurrent() > 1)) {
+ cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
+ }
+ map.put(field, new RepeatCell(val, i));
}
}
}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java
index 64101225..d8f8ef24 100644
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfiguration.java
@@ -1,6 +1,6 @@
package org.dromara.common.mail.config;
-import org.dromara.common.mail.utils.MailAccount;
+import cn.hutool.extra.mail.MailAccount;
import org.dromara.common.mail.config.properties.MailProperties;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java
deleted file mode 100644
index fdae8697..00000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.io.IORuntimeException;
-
-/**
- * 全局邮件帐户,依赖于邮件配置文件{@link MailAccount#MAIL_SETTING_PATHS}
- *
- * @author looly
- */
-public enum GlobalMailAccount {
- INSTANCE;
-
- private final MailAccount mailAccount;
-
- /**
- * 构造
- */
- GlobalMailAccount() {
- mailAccount = createDefaultAccount();
- }
-
- /**
- * 获得邮件帐户
- *
- * @return 邮件帐户
- */
- public MailAccount getAccount() {
- return this.mailAccount;
- }
-
- /**
- * 创建默认帐户
- *
- * @return MailAccount
- */
- private MailAccount createDefaultAccount() {
- for (String mailSettingPath : MailAccount.MAIL_SETTING_PATHS) {
- try {
- return new MailAccount(mailSettingPath);
- } catch (IORuntimeException ignore) {
- //ignore
- }
- }
- return null;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java
deleted file mode 100644
index b755e737..00000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.util.ArrayUtil;
-import jakarta.mail.internet.AddressException;
-import jakarta.mail.internet.InternetAddress;
-import jakarta.mail.internet.MimeUtility;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * 邮件内部工具类
- *
- * @author looly
- * @since 3.2.3
- */
-public class InternalMailUtil {
-
- /**
- * 将多个字符串邮件地址转为{@link InternetAddress}列表
- * 单个字符串地址可以是多个地址合并的字符串
- *
- * @param addrStrs 地址数组
- * @param charset 编码(主要用于中文用户名的编码)
- * @return 地址数组
- * @since 4.0.3
- */
- public static InternetAddress[] parseAddressFromStrs(String[] addrStrs, Charset charset) {
- final List resultList = new ArrayList<>(addrStrs.length);
- InternetAddress[] addrs;
- for (String addrStr : addrStrs) {
- addrs = parseAddress(addrStr, charset);
- if (ArrayUtil.isNotEmpty(addrs)) {
- Collections.addAll(resultList, addrs);
- }
- }
- return resultList.toArray(new InternetAddress[0]);
- }
-
- /**
- * 解析第一个地址
- *
- * @param address 地址字符串
- * @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码
- * @return 地址列表
- */
- public static InternetAddress parseFirstAddress(String address, Charset charset) {
- final InternetAddress[] internetAddresses = parseAddress(address, charset);
- if (ArrayUtil.isEmpty(internetAddresses)) {
- try {
- return new InternetAddress(address);
- } catch (AddressException e) {
- throw new MailException(e);
- }
- }
- return internetAddresses[0];
- }
-
- /**
- * 将一个地址字符串解析为多个地址
- * 地址间使用" "、","、";"分隔
- *
- * @param address 地址字符串
- * @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码
- * @return 地址列表
- */
- public static InternetAddress[] parseAddress(String address, Charset charset) {
- InternetAddress[] addresses;
- try {
- addresses = InternetAddress.parse(address);
- } catch (AddressException e) {
- throw new MailException(e);
- }
- //编码用户名
- if (ArrayUtil.isNotEmpty(addresses)) {
- final String charsetStr = null == charset ? null : charset.name();
- for (InternetAddress internetAddress : addresses) {
- try {
- internetAddress.setPersonal(internetAddress.getPersonal(), charsetStr);
- } catch (UnsupportedEncodingException e) {
- throw new MailException(e);
- }
- }
- }
-
- return addresses;
- }
-
- /**
- * 编码中文字符
- * 编码失败返回原字符串
- *
- * @param text 被编码的文本
- * @param charset 编码
- * @return 编码后的结果
- */
- public static String encodeText(String text, Charset charset) {
- try {
- return MimeUtility.encodeText(text, charset.name(), null);
- } catch (UnsupportedEncodingException e) {
- // ignore
- }
- return text;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java
deleted file mode 100644
index 6ca4b69e..00000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java
+++ /dev/null
@@ -1,483 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.builder.Builder;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IORuntimeException;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import jakarta.activation.DataHandler;
-import jakarta.activation.DataSource;
-import jakarta.activation.FileDataSource;
-import jakarta.activation.FileTypeMap;
-import jakarta.mail.*;
-import jakarta.mail.internet.MimeBodyPart;
-import jakarta.mail.internet.MimeMessage;
-import jakarta.mail.internet.MimeMultipart;
-import jakarta.mail.internet.MimeUtility;
-import jakarta.mail.util.ByteArrayDataSource;
-
-import java.io.*;
-import java.nio.charset.Charset;
-import java.util.Date;
-
-/**
- * 邮件发送客户端
- *
- * @author looly
- * @since 3.2.0
- */
-public class Mail implements Builder {
- @Serial
- private static final long serialVersionUID = 1L;
-
- /**
- * 邮箱帐户信息以及一些客户端配置信息
- */
- private final MailAccount mailAccount;
- /**
- * 收件人列表
- */
- private String[] tos;
- /**
- * 抄送人列表(carbon copy)
- */
- private String[] ccs;
- /**
- * 密送人列表(blind carbon copy)
- */
- private String[] bccs;
- /**
- * 回复地址(reply-to)
- */
- private String[] reply;
- /**
- * 标题
- */
- private String title;
- /**
- * 内容
- */
- private String content;
- /**
- * 是否为HTML
- */
- private boolean isHtml;
- /**
- * 正文、附件和图片的混合部分
- */
- private final Multipart multipart = new MimeMultipart();
- /**
- * 是否使用全局会话,默认为false
- */
- private boolean useGlobalSession = false;
-
- /**
- * debug输出位置,可以自定义debug日志
- */
- private PrintStream debugOutput;
-
- /**
- * 创建邮件客户端
- *
- * @param mailAccount 邮件帐号
- * @return Mail
- */
- public static Mail create(MailAccount mailAccount) {
- return new Mail(mailAccount);
- }
-
- /**
- * 创建邮件客户端,使用全局邮件帐户
- *
- * @return Mail
- */
- public static Mail create() {
- return new Mail();
- }
-
- // --------------------------------------------------------------- Constructor start
-
- /**
- * 构造,使用全局邮件帐户
- */
- public Mail() {
- this(GlobalMailAccount.INSTANCE.getAccount());
- }
-
- /**
- * 构造
- *
- * @param mailAccount 邮件帐户,如果为null使用默认配置文件的全局邮件配置
- */
- public Mail(MailAccount mailAccount) {
- mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount();
- this.mailAccount = mailAccount.defaultIfEmpty();
- }
- // --------------------------------------------------------------- Constructor end
-
- // --------------------------------------------------------------- Getters and Setters start
-
- /**
- * 设置收件人
- *
- * @param tos 收件人列表
- * @return this
- * @see #setTos(String...)
- */
- public Mail to(String... tos) {
- return setTos(tos);
- }
-
- /**
- * 设置多个收件人
- *
- * @param tos 收件人列表
- * @return this
- */
- public Mail setTos(String... tos) {
- this.tos = tos;
- return this;
- }
-
- /**
- * 设置多个抄送人(carbon copy)
- *
- * @param ccs 抄送人列表
- * @return this
- * @since 4.0.3
- */
- public Mail setCcs(String... ccs) {
- this.ccs = ccs;
- return this;
- }
-
- /**
- * 设置多个密送人(blind carbon copy)
- *
- * @param bccs 密送人列表
- * @return this
- * @since 4.0.3
- */
- public Mail setBccs(String... bccs) {
- this.bccs = bccs;
- return this;
- }
-
- /**
- * 设置多个回复地址(reply-to)
- *
- * @param reply 回复地址(reply-to)列表
- * @return this
- * @since 4.6.0
- */
- public Mail setReply(String... reply) {
- this.reply = reply;
- return this;
- }
-
- /**
- * 设置标题
- *
- * @param title 标题
- * @return this
- */
- public Mail setTitle(String title) {
- this.title = title;
- return this;
- }
-
- /**
- * 设置正文
- * 正文可以是普通文本也可以是HTML(默认普通文本),可以通过调用{@link #setHtml(boolean)} 设置是否为HTML
- *
- * @param content 正文
- * @return this
- */
- public Mail setContent(String content) {
- this.content = content;
- return this;
- }
-
- /**
- * 设置是否是HTML
- *
- * @param isHtml 是否为HTML
- * @return this
- */
- public Mail setHtml(boolean isHtml) {
- this.isHtml = isHtml;
- return this;
- }
-
- /**
- * 设置正文
- *
- * @param content 正文内容
- * @param isHtml 是否为HTML
- * @return this
- */
- public Mail setContent(String content, boolean isHtml) {
- setContent(content);
- return setHtml(isHtml);
- }
-
- /**
- * 设置文件类型附件,文件可以是图片文件,此时自动设置cid(正文中引用图片),默认cid为文件名
- *
- * @param files 附件文件列表
- * @return this
- */
- public Mail setFiles(File... files) {
- if (ArrayUtil.isEmpty(files)) {
- return this;
- }
-
- final DataSource[] attachments = new DataSource[files.length];
- for (int i = 0; i < files.length; i++) {
- attachments[i] = new FileDataSource(files[i]);
- }
- return setAttachments(attachments);
- }
-
- /**
- * 增加附件或图片,附件使用{@link DataSource} 形式表示,可以使用{@link FileDataSource}包装文件表示文件附件
- *
- * @param attachments 附件列表
- * @return this
- * @since 4.0.9
- */
- public Mail setAttachments(DataSource... attachments) {
- if (ArrayUtil.isNotEmpty(attachments)) {
- final Charset charset = this.mailAccount.getCharset();
- MimeBodyPart bodyPart;
- String nameEncoded;
- try {
- for (DataSource attachment : attachments) {
- bodyPart = new MimeBodyPart();
- bodyPart.setDataHandler(new DataHandler(attachment));
- nameEncoded = attachment.getName();
- if (this.mailAccount.isEncodefilename()) {
- nameEncoded = InternalMailUtil.encodeText(nameEncoded, charset);
- }
- // 普通附件文件名
- bodyPart.setFileName(nameEncoded);
- if (StrUtil.startWith(attachment.getContentType(), "image/")) {
- // 图片附件,用于正文中引用图片
- bodyPart.setContentID(nameEncoded);
- }
- this.multipart.addBodyPart(bodyPart);
- }
- } catch (MessagingException e) {
- throw new MailException(e);
- }
- }
- return this;
- }
-
- /**
- * 增加图片,图片的键对应到邮件模板中的占位字符串,图片类型默认为"image/jpeg"
- *
- * @param cid 图片与占位符,占位符格式为cid:${cid}
- * @param imageStream 图片文件
- * @return this
- * @since 4.6.3
- */
- public Mail addImage(String cid, InputStream imageStream) {
- return addImage(cid, imageStream, null);
- }
-
- /**
- * 增加图片,图片的键对应到邮件模板中的占位字符串
- *
- * @param cid 图片与占位符,占位符格式为cid:${cid}
- * @param imageStream 图片流,不关闭
- * @param contentType 图片类型,null赋值默认的"image/jpeg"
- * @return this
- * @since 4.6.3
- */
- public Mail addImage(String cid, InputStream imageStream, String contentType) {
- ByteArrayDataSource imgSource;
- try {
- imgSource = new ByteArrayDataSource(imageStream, ObjectUtil.defaultIfNull(contentType, "image/jpeg"));
- } catch (IOException e) {
- throw new IORuntimeException(e);
- }
- imgSource.setName(cid);
- return setAttachments(imgSource);
- }
-
- /**
- * 增加图片,图片的键对应到邮件模板中的占位字符串
- *
- * @param cid 图片与占位符,占位符格式为cid:${cid}
- * @param imageFile 图片文件
- * @return this
- * @since 4.6.3
- */
- public Mail addImage(String cid, File imageFile) {
- InputStream in = null;
- try {
- in = FileUtil.getInputStream(imageFile);
- return addImage(cid, in, FileTypeMap.getDefaultFileTypeMap().getContentType(imageFile));
- } finally {
- IoUtil.close(in);
- }
- }
-
- /**
- * 设置字符集编码
- *
- * @param charset 字符集编码
- * @return this
- * @see MailAccount#setCharset(Charset)
- */
- public Mail setCharset(Charset charset) {
- this.mailAccount.setCharset(charset);
- return this;
- }
-
- /**
- * 设置是否使用全局会话,默认为true
- *
- * @param isUseGlobalSession 是否使用全局会话,默认为true
- * @return this
- * @since 4.0.2
- */
- public Mail setUseGlobalSession(boolean isUseGlobalSession) {
- this.useGlobalSession = isUseGlobalSession;
- return this;
- }
-
- /**
- * 设置debug输出位置,可以自定义debug日志
- *
- * @param debugOutput debug输出位置
- * @return this
- * @since 5.5.6
- */
- public Mail setDebugOutput(PrintStream debugOutput) {
- this.debugOutput = debugOutput;
- return this;
- }
- // --------------------------------------------------------------- Getters and Setters end
-
- @Override
- public MimeMessage build() {
- try {
- return buildMsg();
- } catch (MessagingException e) {
- throw new MailException(e);
- }
- }
-
- /**
- * 发送
- *
- * @return message-id
- * @throws MailException 邮件发送异常
- */
- public String send() throws MailException {
- try {
- return doSend();
- } catch (MessagingException e) {
- if (e instanceof SendFailedException) {
- // 当地址无效时,显示更加详细的无效地址信息
- final Address[] invalidAddresses = ((SendFailedException) e).getInvalidAddresses();
- final String msg = StrUtil.format("Invalid Addresses: {}", ArrayUtil.toString(invalidAddresses));
- throw new MailException(msg, e);
- }
- throw new MailException(e);
- }
- }
-
- // --------------------------------------------------------------- Private method start
-
- /**
- * 执行发送
- *
- * @return message-id
- * @throws MessagingException 发送异常
- */
- private String doSend() throws MessagingException {
- final MimeMessage mimeMessage = buildMsg();
- Transport.send(mimeMessage);
- return mimeMessage.getMessageID();
- }
-
- /**
- * 构建消息
- *
- * @return {@link MimeMessage}消息
- * @throws MessagingException 消息异常
- */
- private MimeMessage buildMsg() throws MessagingException {
- final Charset charset = this.mailAccount.getCharset();
- final MimeMessage msg = new MimeMessage(getSession());
- // 发件人
- final String from = this.mailAccount.getFrom();
- if (StrUtil.isEmpty(from)) {
- // 用户未提供发送方,则从Session中自动获取
- msg.setFrom();
- } else {
- msg.setFrom(InternalMailUtil.parseFirstAddress(from, charset));
- }
- // 标题
- msg.setSubject(this.title, (null == charset) ? null : charset.name());
- // 发送时间
- msg.setSentDate(new Date());
- // 内容和附件
- msg.setContent(buildContent(charset));
- // 收件人
- msg.setRecipients(MimeMessage.RecipientType.TO, InternalMailUtil.parseAddressFromStrs(this.tos, charset));
- // 抄送人
- if (ArrayUtil.isNotEmpty(this.ccs)) {
- msg.setRecipients(MimeMessage.RecipientType.CC, InternalMailUtil.parseAddressFromStrs(this.ccs, charset));
- }
- // 密送人
- if (ArrayUtil.isNotEmpty(this.bccs)) {
- msg.setRecipients(MimeMessage.RecipientType.BCC, InternalMailUtil.parseAddressFromStrs(this.bccs, charset));
- }
- // 回复地址(reply-to)
- if (ArrayUtil.isNotEmpty(this.reply)) {
- msg.setReplyTo(InternalMailUtil.parseAddressFromStrs(this.reply, charset));
- }
-
- return msg;
- }
-
- /**
- * 构建邮件信息主体
- *
- * @param charset 编码,{@code null}则使用{@link MimeUtility#getDefaultJavaCharset()}
- * @return 邮件信息主体
- * @throws MessagingException 消息异常
- */
- private Multipart buildContent(Charset charset) throws MessagingException {
- final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset();
- // 正文
- final MimeBodyPart body = new MimeBodyPart();
- body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr));
- this.multipart.addBodyPart(body);
-
- return this.multipart;
- }
-
- /**
- * 获取默认邮件会话
- * 如果为全局单例的会话,则全局只允许一个邮件帐号,否则每次发送邮件会新建一个新的会话
- *
- * @return 邮件会话 {@link Session}
- */
- private Session getSession() {
- final Session session = MailUtils.getSession(this.mailAccount, this.useGlobalSession);
-
- if (null != this.debugOutput) {
- session.setDebugOut(debugOutput);
- }
-
- return session;
- }
- // --------------------------------------------------------------- Private method end
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java
deleted file mode 100644
index 2a732a1a..00000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java
+++ /dev/null
@@ -1,659 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.setting.Setting;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * 邮件账户对象
- *
- * @author Luxiaolei
- */
-public class MailAccount implements Serializable {
- @Serial
- private static final long serialVersionUID = -6937313421815719204L;
-
- private static final String MAIL_PROTOCOL = "mail.transport.protocol";
- private static final String SMTP_HOST = "mail.smtp.host";
- private static final String SMTP_PORT = "mail.smtp.port";
- private static final String SMTP_AUTH = "mail.smtp.auth";
- private static final String SMTP_TIMEOUT = "mail.smtp.timeout";
- private static final String SMTP_CONNECTION_TIMEOUT = "mail.smtp.connectiontimeout";
- private static final String SMTP_WRITE_TIMEOUT = "mail.smtp.writetimeout";
-
- // SSL
- private static final String STARTTLS_ENABLE = "mail.smtp.starttls.enable";
- private static final String SSL_ENABLE = "mail.smtp.ssl.enable";
- private static final String SSL_PROTOCOLS = "mail.smtp.ssl.protocols";
- private static final String SOCKET_FACTORY = "mail.smtp.socketFactory.class";
- private static final String SOCKET_FACTORY_FALLBACK = "mail.smtp.socketFactory.fallback";
- private static final String SOCKET_FACTORY_PORT = "smtp.socketFactory.port";
-
- // System Properties
- private static final String SPLIT_LONG_PARAMS = "mail.mime.splitlongparameters";
- //private static final String ENCODE_FILE_NAME = "mail.mime.encodefilename";
- //private static final String CHARSET = "mail.mime.charset";
-
- // 其他
- private static final String MAIL_DEBUG = "mail.debug";
-
- public static final String[] MAIL_SETTING_PATHS = new String[]{"config/mail.setting", "config/mailAccount.setting", "mail.setting"};
-
- /**
- * SMTP服务器域名
- */
- private String host;
- /**
- * SMTP服务端口
- */
- private Integer port;
- /**
- * 是否需要用户名密码验证
- */
- private Boolean auth;
- /**
- * 用户名
- */
- private String user;
- /**
- * 密码
- */
- private String pass;
- /**
- * 发送方,遵循RFC-822标准
- */
- private String from;
-
- /**
- * 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- */
- private boolean debug;
- /**
- * 编码用于编码邮件正文和发送人、收件人等中文
- */
- private Charset charset = CharsetUtil.CHARSET_UTF_8;
- /**
- * 对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名)
- */
- private boolean splitlongparameters = false;
- /**
- * 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
- */
- private boolean encodefilename = true;
-
- /**
- * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- */
- private boolean starttlsEnable = false;
- /**
- * 使用 SSL安全连接
- */
- private Boolean sslEnable;
-
- /**
- * SSL协议,多个协议用空格分隔
- */
- private String sslProtocols;
-
- /**
- * 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- */
- private String socketFactoryClass = "javax.net.ssl.SSLSocketFactory";
- /**
- * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- */
- private boolean socketFactoryFallback;
- /**
- * 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- */
- private int socketFactoryPort = 465;
-
- /**
- * SMTP超时时长,单位毫秒,缺省值不超时
- */
- private long timeout;
- /**
- * Socket连接超时值,单位毫秒,缺省值不超时
- */
- private long connectionTimeout;
- /**
- * Socket写出超时值,单位毫秒,缺省值不超时
- */
- private long writeTimeout;
-
- /**
- * 自定义的其他属性,此自定义属性会覆盖默认属性
- */
- private final Map customProperty = new HashMap<>();
-
- // -------------------------------------------------------------- Constructor start
-
- /**
- * 构造,所有参数需自行定义或保持默认值
- */
- public MailAccount() {
- }
-
- /**
- * 构造
- *
- * @param settingPath 配置文件路径
- */
- public MailAccount(String settingPath) {
- this(new Setting(settingPath));
- }
-
- /**
- * 构造
- *
- * @param setting 配置文件
- */
- public MailAccount(Setting setting) {
- setting.toBean(this);
- }
-
- // -------------------------------------------------------------- Constructor end
-
- /**
- * 获得SMTP服务器域名
- *
- * @return SMTP服务器域名
- */
- public String getHost() {
- return host;
- }
-
- /**
- * 设置SMTP服务器域名
- *
- * @param host SMTP服务器域名
- * @return this
- */
- public MailAccount setHost(String host) {
- this.host = host;
- return this;
- }
-
- /**
- * 获得SMTP服务端口
- *
- * @return SMTP服务端口
- */
- public Integer getPort() {
- return port;
- }
-
- /**
- * 设置SMTP服务端口
- *
- * @param port SMTP服务端口
- * @return this
- */
- public MailAccount setPort(Integer port) {
- this.port = port;
- return this;
- }
-
- /**
- * 是否需要用户名密码验证
- *
- * @return 是否需要用户名密码验证
- */
- public Boolean isAuth() {
- return auth;
- }
-
- /**
- * 设置是否需要用户名密码验证
- *
- * @param isAuth 是否需要用户名密码验证
- * @return this
- */
- public MailAccount setAuth(boolean isAuth) {
- this.auth = isAuth;
- return this;
- }
-
- /**
- * 获取用户名
- *
- * @return 用户名
- */
- public String getUser() {
- return user;
- }
-
- /**
- * 设置用户名
- *
- * @param user 用户名
- * @return this
- */
- public MailAccount setUser(String user) {
- this.user = user;
- return this;
- }
-
- /**
- * 获取密码
- *
- * @return 密码
- */
- public String getPass() {
- return pass;
- }
-
- /**
- * 设置密码
- *
- * @param pass 密码
- * @return this
- */
- public MailAccount setPass(String pass) {
- this.pass = pass;
- return this;
- }
-
- /**
- * 获取发送方,遵循RFC-822标准
- *
- * @return 发送方,遵循RFC-822标准
- */
- public String getFrom() {
- return from;
- }
-
- /**
- * 设置发送方,遵循RFC-822标准
- * 发件人可以是以下形式:
- *
- *
- * 1. user@xxx.xx
- * 2. name <user@xxx.xx>
- *
- *
- * @param from 发送方,遵循RFC-822标准
- * @return this
- */
- public MailAccount setFrom(String from) {
- this.from = from;
- return this;
- }
-
- /**
- * 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- *
- * @return 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- * @since 4.0.2
- */
- public boolean isDebug() {
- return debug;
- }
-
- /**
- * 设置是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- *
- * @param debug 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- * @return this
- * @since 4.0.2
- */
- public MailAccount setDebug(boolean debug) {
- this.debug = debug;
- return this;
- }
-
- /**
- * 获取字符集编码
- *
- * @return 编码,可能为{@code null}
- */
- public Charset getCharset() {
- return charset;
- }
-
- /**
- * 设置字符集编码,此选项不会修改全局配置,若修改全局配置,请设置此项为{@code null}并设置:
- *
- * System.setProperty("mail.mime.charset", charset);
- *
- *
- * @param charset 字符集编码,{@code null} 则表示使用全局设置的默认编码,全局编码为mail.mime.charset系统属性
- * @return this
- */
- public MailAccount setCharset(Charset charset) {
- this.charset = charset;
- return this;
- }
-
- /**
- * 对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名)
- *
- * @return 对于超长参数是否切分为多份
- */
- public boolean isSplitlongparameters() {
- return splitlongparameters;
- }
-
- /**
- * 设置对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名)
- * 注意此项为全局设置,此项会调用
- *
- * System.setProperty("mail.mime.splitlongparameters", true)
- *
- *
- * @param splitlongparameters 对于超长参数是否切分为多份
- */
- public void setSplitlongparameters(boolean splitlongparameters) {
- this.splitlongparameters = splitlongparameters;
- }
-
- /**
- * 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
- *
- * @return 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
- * @since 5.7.16
- */
- public boolean isEncodefilename() {
-
- return encodefilename;
- }
-
- /**
- * 设置对于文件名是否使用{@link #charset}编码,此选项不会修改全局配置
- * 如果此选项设置为{@code false},则是否编码取决于两个系统属性:
- *
- * - mail.mime.encodefilename 是否编码附件文件名
- * - mail.mime.charset 编码文件名的编码
- *
- *
- * @param encodefilename 对于文件名是否使用{@link #charset}编码
- * @since 5.7.16
- */
- public void setEncodefilename(boolean encodefilename) {
- this.encodefilename = encodefilename;
- }
-
- /**
- * 是否使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- *
- * @return 是否使用 STARTTLS安全连接
- */
- public boolean isStarttlsEnable() {
- return this.starttlsEnable;
- }
-
- /**
- * 设置是否使用STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- *
- * @param startttlsEnable 是否使用STARTTLS安全连接
- * @return this
- */
- public MailAccount setStarttlsEnable(boolean startttlsEnable) {
- this.starttlsEnable = startttlsEnable;
- return this;
- }
-
- /**
- * 是否使用 SSL安全连接
- *
- * @return 是否使用 SSL安全连接
- */
- public Boolean isSslEnable() {
- return this.sslEnable;
- }
-
- /**
- * 设置是否使用SSL安全连接
- *
- * @param sslEnable 是否使用SSL安全连接
- * @return this
- */
- public MailAccount setSslEnable(Boolean sslEnable) {
- this.sslEnable = sslEnable;
- return this;
- }
-
- /**
- * 获取SSL协议,多个协议用空格分隔
- *
- * @return SSL协议,多个协议用空格分隔
- * @since 5.5.7
- */
- public String getSslProtocols() {
- return sslProtocols;
- }
-
- /**
- * 设置SSL协议,多个协议用空格分隔
- *
- * @param sslProtocols SSL协议,多个协议用空格分隔
- * @since 5.5.7
- */
- public void setSslProtocols(String sslProtocols) {
- this.sslProtocols = sslProtocols;
- }
-
- /**
- * 获取指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- *
- * @return 指定实现javax.net.SocketFactory接口的类的名称, 这个类将被用于创建SMTP的套接字
- */
- public String getSocketFactoryClass() {
- return socketFactoryClass;
- }
-
- /**
- * 设置指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- *
- * @param socketFactoryClass 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- * @return this
- */
- public MailAccount setSocketFactoryClass(String socketFactoryClass) {
- this.socketFactoryClass = socketFactoryClass;
- return this;
- }
-
- /**
- * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- *
- * @return 如果设置为true, 未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- */
- public boolean isSocketFactoryFallback() {
- return socketFactoryFallback;
- }
-
- /**
- * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- *
- * @param socketFactoryFallback 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- * @return this
- */
- public MailAccount setSocketFactoryFallback(boolean socketFactoryFallback) {
- this.socketFactoryFallback = socketFactoryFallback;
- return this;
- }
-
- /**
- * 获取指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- *
- * @return 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- */
- public int getSocketFactoryPort() {
- return socketFactoryPort;
- }
-
- /**
- * 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- *
- * @param socketFactoryPort 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- * @return this
- */
- public MailAccount setSocketFactoryPort(int socketFactoryPort) {
- this.socketFactoryPort = socketFactoryPort;
- return this;
- }
-
- /**
- * 设置SMTP超时时长,单位毫秒,缺省值不超时
- *
- * @param timeout SMTP超时时长,单位毫秒,缺省值不超时
- * @return this
- * @since 4.1.17
- */
- public MailAccount setTimeout(long timeout) {
- this.timeout = timeout;
- return this;
- }
-
- /**
- * 设置Socket连接超时值,单位毫秒,缺省值不超时
- *
- * @param connectionTimeout Socket连接超时值,单位毫秒,缺省值不超时
- * @return this
- * @since 4.1.17
- */
- public MailAccount setConnectionTimeout(long connectionTimeout) {
- this.connectionTimeout = connectionTimeout;
- return this;
- }
-
- /**
- * 设置Socket写出超时值,单位毫秒,缺省值不超时
- *
- * @param writeTimeout Socket写出超时值,单位毫秒,缺省值不超时
- * @return this
- * @since 5.8.3
- */
- public MailAccount setWriteTimeout(long writeTimeout) {
- this.writeTimeout = writeTimeout;
- return this;
- }
-
- /**
- * 获取自定义属性列表
- *
- * @return 自定义参数列表
- * @since 5.6.4
- */
- public Map getCustomProperty() {
- return customProperty;
- }
-
- /**
- * 设置自定义属性,如mail.smtp.ssl.socketFactory
- *
- * @param key 属性名,空白被忽略
- * @param value 属性值, null被忽略
- * @return this
- * @since 5.6.4
- */
- public MailAccount setCustomProperty(String key, Object value) {
- if (StrUtil.isNotBlank(key) && ObjectUtil.isNotNull(value)) {
- this.customProperty.put(key, value);
- }
- return this;
- }
-
- /**
- * 获得SMTP相关信息
- *
- * @return {@link Properties}
- */
- public Properties getSmtpProps() {
- //全局系统参数
- System.setProperty(SPLIT_LONG_PARAMS, String.valueOf(this.splitlongparameters));
-
- final Properties p = new Properties();
- p.put(MAIL_PROTOCOL, "smtp");
- p.put(SMTP_HOST, this.host);
- p.put(SMTP_PORT, String.valueOf(this.port));
- p.put(SMTP_AUTH, String.valueOf(this.auth));
- if (this.timeout > 0) {
- p.put(SMTP_TIMEOUT, String.valueOf(this.timeout));
- }
- if (this.connectionTimeout > 0) {
- p.put(SMTP_CONNECTION_TIMEOUT, String.valueOf(this.connectionTimeout));
- }
- // issue#2355
- if (this.writeTimeout > 0) {
- p.put(SMTP_WRITE_TIMEOUT, String.valueOf(this.writeTimeout));
- }
-
- p.put(MAIL_DEBUG, String.valueOf(this.debug));
-
- if (this.starttlsEnable) {
- //STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- p.put(STARTTLS_ENABLE, "true");
-
- if (null == this.sslEnable) {
- //为了兼容旧版本,当用户没有此项配置时,按照starttlsEnable开启状态时对待
- this.sslEnable = true;
- }
- }
-
- // SSL
- if (null != this.sslEnable && this.sslEnable) {
- p.put(SSL_ENABLE, "true");
- p.put(SOCKET_FACTORY, socketFactoryClass);
- p.put(SOCKET_FACTORY_FALLBACK, String.valueOf(this.socketFactoryFallback));
- p.put(SOCKET_FACTORY_PORT, String.valueOf(this.socketFactoryPort));
- // issue#IZN95@Gitee,在Linux下需自定义SSL协议版本
- if (StrUtil.isNotBlank(this.sslProtocols)) {
- p.put(SSL_PROTOCOLS, this.sslProtocols);
- }
- }
-
- // 补充自定义属性,允许自定属性覆盖已经设置的值
- p.putAll(this.customProperty);
-
- return p;
- }
-
- /**
- * 如果某些值为null,使用默认值
- *
- * @return this
- */
- public MailAccount defaultIfEmpty() {
- // 去掉发件人的姓名部分
- final String fromAddress = InternalMailUtil.parseFirstAddress(this.from, this.charset).getAddress();
-
- if (StrUtil.isBlank(this.host)) {
- // 如果SMTP地址为空,默认使用smtp.<发件人邮箱后缀>
- this.host = StrUtil.format("smtp.{}", StrUtil.subSuf(fromAddress, fromAddress.indexOf('@') + 1));
- }
- if (StrUtil.isBlank(user)) {
- // 如果用户名为空,默认为发件人(issue#I4FYVY@Gitee)
- //this.user = StrUtil.subPre(fromAddress, fromAddress.indexOf('@'));
- this.user = fromAddress;
- }
- if (null == this.auth) {
- // 如果密码非空白,则使用认证模式
- this.auth = (false == StrUtil.isBlank(this.pass));
- }
- if (null == this.port) {
- // 端口在SSL状态下默认与socketFactoryPort一致,非SSL状态下默认为25
- this.port = (null != this.sslEnable && this.sslEnable) ? this.socketFactoryPort : 25;
- }
- if (null == this.charset) {
- // 默认UTF-8编码
- this.charset = CharsetUtil.CHARSET_UTF_8;
- }
-
- return this;
- }
-
- @Override
- public String toString() {
- return "MailAccount [host=" + host + ", port=" + port + ", auth=" + auth + ", user=" + user + ", pass=" + (StrUtil.isEmpty(this.pass) ? "" : "******") + ", from=" + from + ", startttlsEnable="
- + starttlsEnable + ", socketFactoryClass=" + socketFactoryClass + ", socketFactoryFallback=" + socketFactoryFallback + ", socketFactoryPort=" + socketFactoryPort + "]";
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java
deleted file mode 100644
index cc199d45..00000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.util.StrUtil;
-
-import java.io.Serial;
-
-/**
- * 邮件异常
- *
- * @author xiaoleilu
- */
-public class MailException extends RuntimeException {
- @Serial
- private static final long serialVersionUID = 8247610319171014183L;
-
- public MailException(Throwable e) {
- super(ExceptionUtil.getMessage(e), e);
- }
-
- public MailException(String message) {
- super(message);
- }
-
- public MailException(String messageTemplate, Object... params) {
- super(StrUtil.format(messageTemplate, params));
- }
-
- public MailException(String message, Throwable throwable) {
- super(message, throwable);
- }
-
- public MailException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
- super(message, throwable, enableSuppression, writableStackTrace);
- }
-
- public MailException(Throwable throwable, String messageTemplate, Object... params) {
- super(StrUtil.format(messageTemplate, params), throwable);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
index 040cc572..a28701fb 100644
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
@@ -5,6 +5,9 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.mail.JakartaMail;
+import cn.hutool.extra.mail.JakartaUserPassAuthenticator;
+import cn.hutool.extra.mail.MailAccount;
import jakarta.mail.Authenticator;
import jakarta.mail.Session;
import lombok.AccessLevel;
@@ -17,7 +20,7 @@ import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-
+import java.util.Map.Entry;
/**
* 邮件工具类
@@ -385,7 +388,7 @@ public class MailUtils {
public static Session getSession(MailAccount mailAccount, boolean isSingleton) {
Authenticator authenticator = null;
if (mailAccount.isAuth()) {
- authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
+ authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
}
return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) //
@@ -412,7 +415,7 @@ public class MailUtils {
*/
private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection tos, Collection ccs, Collection bccs, String subject, String content,
Map imageMap, boolean isHtml, File... files) {
- final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession);
+ final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession);
// 可选抄送人
if (CollUtil.isNotEmpty(ccs)) {
@@ -431,7 +434,7 @@ public class MailUtils {
// 图片
if (MapUtil.isNotEmpty(imageMap)) {
- for (Map.Entry entry : imageMap.entrySet()) {
+ for (Entry entry : imageMap.entrySet()) {
mail.addImage(entry.getKey(), entry.getValue());
// 关闭流
IoUtil.close(entry.getValue());
@@ -463,5 +466,4 @@ public class MailUtils {
return result;
}
// ------------------------------------------------------------------------------------------------------------------------ Private method end
-
}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java
deleted file mode 100644
index fbbe5e37..00000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import jakarta.mail.Authenticator;
-import jakarta.mail.PasswordAuthentication;
-
-/**
- * 用户名密码验证器
- *
- * @author looly
- * @since 3.1.2
- */
-public class UserPassAuthenticator extends Authenticator {
-
- private final String user;
- private final String pass;
-
- /**
- * 构造
- *
- * @param user 用户名
- * @param pass 密码
- */
- public UserPassAuthenticator(String user, String pass) {
- this.user = user;
- this.pass = pass;
- }
-
- @Override
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(this.user, this.pass);
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-mybatis/pom.xml b/ruoyi-common/ruoyi-common-mybatis/pom.xml
index d25f4f4d..7fe7e3bb 100644
--- a/ruoyi-common/ruoyi-common-mybatis/pom.xml
+++ b/ruoyi-common/ruoyi-common-mybatis/pom.xml
@@ -50,21 +50,26 @@
com.mysql
mysql-connector-j
-
-
- com.oracle.database.jdbc
- ojdbc8
-
-
-
- org.postgresql
- postgresql
-
-
-
- com.microsoft.sqlserver
- mssql-jdbc
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
index f8c5cd00..bca638f7 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java
@@ -30,4 +30,12 @@ public @interface DataColumn {
*/
String[] value() default "dept_id";
+ /**
+ * 权限标识符 用于通过菜单权限标识符来获取数据权限
+ * 拥有此标识符的角色 将不会拼接此角色的数据过滤sql
+ *
+ * @return 权限标识符
+ */
+ String permission() default "";
+
}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
index 6fd3c3e0..f5f22d59 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java
@@ -20,4 +20,11 @@ public @interface DataPermission {
*/
DataColumn[] value();
+ /**
+ * 权限拼接标识符(用于指定连接语句的sql符号)
+ * 如不填 默认 select 用 OR 其他语句用 AND
+ * 内容 OR 或者 AND
+ */
+ String joinStr() default "";
+
}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
index a67395fa..5a30d687 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
@@ -4,7 +4,6 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.helper.DataPermissionHelper;
-import org.dromara.common.mybatis.service.SysDataScopeService;
import org.dromara.system.api.model.LoginUser;
/**
@@ -14,9 +13,9 @@ import org.dromara.system.api.model.LoginUser;
* 内置数据:
* - {@code user}: 当前登录用户信息,参考 {@link LoginUser}
* 内置服务:
- * - {@code sdss}: 系统数据权限服务,参考 {@link SysDataScopeService}
+ * - {@code sdss}: 系统数据权限服务,参考 SysDataScopeService
* 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作
- * 如需扩展服务,可以通过 {@link SysDataScopeService} 自行编写
+ * 如需扩展服务,可以通过 SysDataScopeService 自行编写
*
*
* @author Lion Li
@@ -33,29 +32,21 @@ public enum DataScopeType {
/**
* 自定数据权限
- * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} )`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
/**
* 部门数据权限
- * 使用 SpEL 表达式:`#{#deptName} = #{#user.deptId}`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
/**
* 部门及以下数据权限
- * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )}`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
/**
* 仅本人数据权限
- * 使用 SpEL 表达式:`#{#userName} = #{#user.userId}`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
index f6b2b121..c0e650c6 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java
@@ -47,6 +47,10 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
? baseEntity.getCreateDept() : loginUser.getDeptId());
}
}
+ } else {
+ Date date = new Date();
+ this.strictInsertFill(metaObject, "createTime", Date.class, date);
+ this.strictInsertFill(metaObject, "updateTime", Date.class, date);
}
} catch (Exception e) {
throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
@@ -71,6 +75,8 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler {
if (ObjectUtil.isNotNull(userId)) {
baseEntity.setUpdateBy(userId);
}
+ } else {
+ this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
}
} catch (Exception e) {
throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED);
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
index 200006ff..5171e563 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java
@@ -99,7 +99,7 @@ public class PlusDataPermissionHandler {
return where;
}
// 构造数据过滤条件的 SQL 片段
- String dataFilterSql = buildDataFilter(dataPermission.value(), isSelect);
+ String dataFilterSql = buildDataFilter(dataPermission, isSelect);
if (StringUtils.isBlank(dataFilterSql)) {
return where;
}
@@ -120,14 +120,17 @@ public class PlusDataPermissionHandler {
/**
* 构建数据过滤条件的 SQL 语句
*
- * @param dataColumns 数据权限注解中的列信息
- * @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式
+ * @param dataPermission 数据权限注解
+ * @param isSelect 标志当前操作是否为查询操作,查询操作和更新或删除操作在处理过滤条件时会有不同的处理方式
* @return 构建的数据过滤条件的 SQL 语句
* @throws ServiceException 如果角色的数据范围异常或者 key 与 value 的长度不匹配,则抛出 ServiceException 异常
*/
- private String buildDataFilter(DataColumn[] dataColumns, boolean isSelect) {
+ private String buildDataFilter(DataPermission dataPermission, boolean isSelect) {
// 更新或删除需满足所有条件
String joinStr = isSelect ? " OR " : " AND ";
+ if (StringUtils.isNotBlank(dataPermission.joinStr())) {
+ joinStr = " " + dataPermission.joinStr() + " ";
+ }
LoginUser user = DataPermissionHelper.getVariable("user");
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(beanResolver);
@@ -145,7 +148,7 @@ public class PlusDataPermissionHandler {
return "";
}
boolean isSuccess = false;
- for (DataColumn dataColumn : dataColumns) {
+ for (DataColumn dataColumn : dataPermission.value()) {
if (dataColumn.key().length != dataColumn.value().length) {
throw new ServiceException("角色数据范围异常 => key与value长度不匹配");
}
@@ -155,6 +158,13 @@ public class PlusDataPermissionHandler {
)) {
continue;
}
+ // 包含权限标识符 这直接跳过
+ if (StringUtils.isNotBlank(dataColumn.permission()) &&
+ CollUtil.contains(user.getMenuPermission(), dataColumn.permission())
+ ) {
+ isSuccess = true;
+ continue;
+ }
// 设置注解变量 key 为表达式变量 value 为变量值
for (int i = 0; i < dataColumn.key().length; i++) {
context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
index 4650a5a1..39fad6e8 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java
@@ -2,14 +2,17 @@ package org.dromara.common.mybatis.helper;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaStorage;
+import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy;
import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
+import org.dromara.common.core.utils.reflect.ReflectUtils;
import java.util.HashMap;
import java.util.Map;
+import java.util.Stack;
import java.util.function.Supplier;
/**
@@ -24,6 +27,8 @@ public class DataPermissionHelper {
public static final String DATA_PERMISSION_KEY = "data:permission";
+ private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
+
/**
* 从上下文中获取指定键的变量值,并将其转换为指定的类型
*
@@ -66,23 +71,54 @@ public class DataPermissionHelper {
throw new NullPointerException("data permission context type exception");
}
+ private static IgnoreStrategy getIgnoreStrategy() {
+ Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL"));
+ if (ignoreStrategyLocal instanceof ThreadLocal> IGNORE_STRATEGY_LOCAL) {
+ if (IGNORE_STRATEGY_LOCAL.get() instanceof IgnoreStrategy ignoreStrategy) {
+ return ignoreStrategy;
+ }
+ }
+ return null;
+ }
+
/**
* 开启忽略数据权限(开启后需手动调用 {@link #disableIgnore()} 关闭)
*/
public static void enableIgnore() {
- InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build());
+ IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+ if (ObjectUtil.isNull(ignoreStrategy)) {
+ InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().dataPermission(true).build());
+ } else {
+ ignoreStrategy.setDataPermission(true);
+ }
+ Stack reentrantStack = REENTRANT_IGNORE.get();
+ reentrantStack.push(reentrantStack.size() + 1);
}
/**
* 关闭忽略数据权限
*/
public static void disableIgnore() {
- InterceptorIgnoreHelper.clearIgnoreStrategy();
+ IgnoreStrategy ignoreStrategy = getIgnoreStrategy();
+ if (ObjectUtil.isNotNull(ignoreStrategy)) {
+ boolean noOtherIgnoreStrategy = !Boolean.TRUE.equals(ignoreStrategy.getDynamicTableName())
+ && !Boolean.TRUE.equals(ignoreStrategy.getBlockAttack())
+ && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql())
+ && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine())
+ && CollectionUtil.isEmpty(ignoreStrategy.getOthers());
+ Stack reentrantStack = REENTRANT_IGNORE.get();
+ boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1;
+ if (noOtherIgnoreStrategy && empty) {
+ InterceptorIgnoreHelper.clearIgnoreStrategy();
+ } else if (empty) {
+ ignoreStrategy.setDataPermission(false);
+ }
+
+ }
}
/**
* 在忽略数据权限中执行
- * 禁止在忽略数据权限中执行忽略数据权限
*
* @param handle 处理执行方法
*/
@@ -97,7 +133,6 @@ public class DataPermissionHelper {
/**
* 在忽略数据权限中执行
- * 禁止在忽略数据权限中执行忽略数据权限
*
* @param handle 处理执行方法
*/
diff --git a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
index 02735b07..1f4904a3 100644
--- a/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
+++ b/ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java
@@ -80,11 +80,11 @@ public class RateLimiterAspect {
private String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
String key = rateLimiter.key();
- if (StringUtils.isNotBlank(key)) {
+ // 判断 key 不为空 和 不是表达式
+ if (StringUtils.isNotBlank(key) && StringUtils.containsAny(key, "#")) {
MethodSignature signature = (MethodSignature) point.getSignature();
Method targetMethod = signature.getMethod();
Object[] args = point.getArgs();
- //noinspection DataFlowIssue
MethodBasedEvaluationContext context =
new MethodBasedEvaluationContext(null, targetMethod, args, pnd);
context.setBeanResolver(new BeanFactoryResolver(SpringUtils.getBeanFactory()));
diff --git a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
index ee1d405f..793e21f5 100644
--- a/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
+++ b/ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java
@@ -15,15 +15,17 @@ public class CaffeineCacheDecorator implements Cache {
private static final com.github.benmanes.caffeine.cache.Cache