Compare commits

25 Commits

Author SHA1 Message Date
羡民Coding
c5777c01c1 !822 fix: 文案错误
* fix: 文案错误
2026-01-12 06:01:54 +00:00
疯狂的狮子Li
459e9caf14 update 优化 兼容path大写开头搜索 2026-01-12 09:21:01 +08:00
疯狂的狮子Li
0940ba6762 update 优化 大家都认可用"账"统一改为账 2026-01-12 09:17:39 +08:00
疯狂的狮子Li
d8ed23f227 update 优化 添加菜单路由地址和名称的校验规则 2026-01-09 17:10:51 +08:00
疯狂的狮子Li
948eba6566 update 优化 添加菜单路由地址和名称的校验规则 2026-01-09 13:19:21 +08:00
疯狂的狮子Li
1a14bdf256 update 优化 统一用词 2026-01-09 11:50:28 +08:00
疯狂的狮子Li
bbc684b335 update 删除已经过期的配置类 2026-01-06 17:26:45 +08:00
疯狂的狮子Li
2b8f4e1d2c update 下架过期的赞助商 2026-01-06 17:22:44 +08:00
AprilWind
d634c2a292 update 优化oss日志侦听器打印级别 2026-01-05 14:39:40 +08:00
ColorDreams
8b97e7bc53 update ip2region version to 3.3.2 2025-12-24 19:09:36 +08:00
疯狂的狮子Li
874ad7c9b7 fix 修复 判断条件写反问题 2025-12-24 13:10:47 +08:00
miracle-bean
89d6f6f247 !815 fix websocket 多线程下IO阻塞的问题
* fix websocket 多线程下IO阻塞的问题
2025-12-23 07:55:24 +00:00
疯狂的狮子Li
1324a1cb16 update 优化 增加 HandlerMethodValidationException 参数校验异常连接 2025-12-23 15:30:32 +08:00
ColorDreams
961bca462e fix 临时修复Ip2Region InputStream读取函数导致的OOM问题 2025-12-23 14:32:48 +08:00
疯狂的狮子Li
496df8494e update 优化 翻译实现类逻辑 2025-12-23 10:38:18 +08:00
疯狂的狮子Li
2f1f9689e0 🧨🧨🧨发布 5.5.2 版本 2025年最后一版 2025-12-23 09:28:20 +08:00
疯狂的狮子Li
8110413fdf update 删除错误的配置 2025-12-23 09:22:42 +08:00
疯狂的狮子Li
c1f64d3450 update anyline 8.7.2-20250603 => 8.7.3-20251210 2025-12-22 13:11:38 +08:00
疯狂的狮子Li
cb00f4c9c1 update snailjob 1.8.0 => 1.9.0 2025-12-22 09:42:56 +08:00
疯狂的狮子Li
79512c69b2 fix 修复 创建租户同步工作流数据 在没有流程定义的情况下不会复制流程类别的问题 2025-12-19 19:38:45 +08:00
疯狂的狮子Li
a5fb128f11 update springboot 3.5.8 => 3.5.9 2025-12-19 11:31:53 +08:00
dr5hx
8a04e3c88f !811 feat(excel): 增强单元格合并处理逻辑
* feat(excel): 增强单元格合并处理逻辑
2025-12-19 01:48:31 +00:00
疯狂的狮子Li
dac447b76f fix 修复 listenerVariable.getVariable() 获取null问题 2025-12-19 09:36:22 +08:00
AprilWind
35a9e4c8e8 update 增加高安全脱敏方法 2025-12-18 19:19:01 +08:00
AprilWind
0d87c12d3c update 优化灵活脱敏方法 2025-12-18 17:30:32 +08:00
45 changed files with 259 additions and 259 deletions

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.5.1" />
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.5.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
</settings>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-server:5.5.1" />
<option name="imageTag" value="ruoyi/ruoyi-server:5.5.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
</settings>

View File

@@ -2,7 +2,7 @@
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
<deployment type="dockerfile">
<settings>
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.5.1" />
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.5.2" />
<option name="buildOnly" value="true" />
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
</settings>

View File

@@ -10,7 +10,7 @@
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE)
[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
<br>
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.1-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.4-blue.svg)]()
[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]()
[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]()
@@ -35,7 +35,6 @@ MaxKey 业界领先单点登录产品 - https://gitee.com/dromara/MaxKey <br>
CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow <br>
数舵科技 软件定制开发APP小程序等 - http://www.shuduokeji.com/ <br>
引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc <br>
<font color="red">**启山商城系统 多租户商城源码可免费商用可二次开发 - https://www.73app.cn/** </font><br>
Mall4J 高质量Java商城系统 - https://www.mall4j.com/cn/?statId=11 <br>
aizuda flowlong 工作流 - https://gitee.com/aizuda/flowlong <br>
Ruoyi-Plus-Uniapp - https://ruoyi.plus <br>

10
pom.xml
View File

@@ -13,8 +13,8 @@
<description>Dromara RuoYi-Vue-Plus多租户管理系统</description>
<properties>
<revision>5.5.1</revision>
<spring-boot.version>3.5.8</spring-boot.version>
<revision>5.5.2</revision>
<spring-boot.version>3.5.9</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version>
@@ -31,14 +31,14 @@
<redisson.version>3.52.0</redisson.version>
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version>
<snailjob.version>1.8.0</snailjob.version>
<snailjob.version>1.9.0</snailjob.version>
<mapstruct-plus.version>1.5.0</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.40</lombok.version>
<bouncycastle.version>1.80</bouncycastle.version>
<justauth.version>1.16.7</justauth.version>
<!-- 离线IP地址定位库 -->
<ip2region.version>3.3.1</ip2region.version>
<ip2region.version>3.3.2</ip2region.version>
<!-- OSS 配置 -->
<aws.sdk.version>2.28.22</aws.sdk.version>
<!-- SMS 配置 -->
@@ -46,7 +46,7 @@
<!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20250603</anyline.version>
<anyline.version>8.7.3-20251210</anyline.version>
<!-- 工作流配置 -->
<warm-flow.version>1.8.4</warm-flow.version>

View File

@@ -5,7 +5,7 @@ user.jcaptcha.expire=验证码已失效
user.not.exists=对不起, 您的账号:{0} 不存在.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,户锁定{1}分钟
user.password.retry.limit.exceed=密码输入错误{0}次,户锁定{1}分钟
user.password.delete=对不起,您的账号:{0} 已被删除
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
role.blocked=角色已封禁,请联系管理员
@@ -47,10 +47,10 @@ repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,户锁定{1}分钟
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,户锁定{1}分钟
email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,户锁定{1}分钟
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,户锁定{1}分钟
xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空

View File

@@ -5,7 +5,7 @@ user.jcaptcha.expire=验证码已失效
user.not.exists=对不起, 您的账号:{0} 不存在.
user.password.not.match=用户不存在/密码错误
user.password.retry.limit.count=密码输入错误{0}次
user.password.retry.limit.exceed=密码输入错误{0}次,户锁定{1}分钟
user.password.retry.limit.exceed=密码输入错误{0}次,户锁定{1}分钟
user.password.delete=对不起,您的账号:{0} 已被删除
user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员
role.blocked=角色已封禁,请联系管理员
@@ -47,10 +47,10 @@ repeat.submit.message=不允许重复提交,请稍候再试
rate.limiter.message=访问过于频繁,请稍候再试
sms.code.not.blank=短信验证码不能为空
sms.code.retry.limit.count=短信验证码输入错误{0}次
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,户锁定{1}分钟
sms.code.retry.limit.exceed=短信验证码输入错误{0}次,户锁定{1}分钟
email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,户锁定{1}分钟
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,户锁定{1}分钟
xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空

View File

@@ -14,7 +14,7 @@
</description>
<properties>
<revision>5.5.1</revision>
<revision>5.5.2</revision>
</properties>
<dependencyManagement>

View File

@@ -61,7 +61,7 @@ public class UserDTO implements Serializable {
private String sex;
/**
* 号状态0正常 1停用
* 号状态0正常 1停用
*/
private String status;

View File

@@ -28,27 +28,60 @@ public class DesensitizedUtils extends DesensitizedUtil {
}
int len = value.length();
int prefixMaskLimit = prefixVisible + maskLength;
int fullLimit = prefixMaskLimit + suffixVisible;
// 总长度小于等于前后可见长度 → 全掩码
if (len <= prefixVisible + suffixVisible) {
// 规则 1长度 <= 中间掩码长度 → 全掩码
if (len <= maskLength) {
return StrUtil.repeat('*', len);
}
String mask = StrUtil.repeat('*', maskLength);
// 规则 2长度 <= 前缀 + 中间掩码
if (len <= prefixMaskLimit) {
return value.substring(0, len - maskLength) + mask;
}
String prefix = value.substring(0, prefixVisible);
// 规则 3长度 <= 前缀 + 中间掩码 + 后缀
if (len <= fullLimit) {
int suffixLen = len - prefixMaskLimit;
return prefix + mask + value.substring(len - suffixLen);
}
// 规则 4标准形态
return prefix + mask + value.substring(len - suffixVisible);
}
/**
* 高安全级别脱敏方法Token / 私钥)
*
* @param value 原始字符串
* @param prefixVisible 前面可见长度推荐0~4
* @param suffixVisible 后面可见长度推荐0~4
* @return 脱敏后字符串
*/
public static String maskHighSecurity(String value, int prefixVisible, int suffixVisible) {
if (StrUtil.isBlank(value)) {
return value;
}
int len = value.length();
// 规则1长度 <= 前缀可见长度 → 全部掩码
if (len <= prefixVisible) {
return StrUtil.repeat('*', len);
}
// 可用长度 = 总长度 - 前后可见长度
int available = len - prefixVisible - suffixVisible;
// 规则2长度 <= 前缀 + 后缀可见长度 → 优先掩码后面
if (len <= prefixVisible + suffixVisible) {
return value.substring(0, len - prefixVisible) + StrUtil.repeat('*', prefixVisible);
}
// 中间掩码长度不能超过可用长度
int actualMaskLength = Math.min(maskLength, available);
// 剩余字符尽量显示在中间掩码旁
int remaining = available - actualMaskLength;
String middleChars = remaining > 0 ? value.substring(prefixVisible, prefixVisible + remaining) : "";
String middleMask = StrUtil.repeat('*', actualMaskLength);
String prefix = value.substring(0, prefixVisible);
String suffix = value.substring(len - suffixVisible);
return prefix + middleChars + middleMask + suffix;
// 规则3标准形态 → 前后可见,中间全部掩码
return value.substring(0, prefixVisible)
+ StrUtil.repeat('*', len - prefixVisible - suffixVisible)
+ value.substring(len - suffixVisible);
}
}

View File

@@ -29,6 +29,11 @@ public class RegionUtils {
// 下载地址https://gitee.com/lionsoul/ip2region/blob/master/data/ip2region_v6.xdb
public static final String DEFAULT_IPV6_XDB_PATH = "ip2region_v6.xdb";
// 默认缓存切片大小为15MB仅针对BufferCache全量读取有效如果你的xdb数据库很大合理设置该值可以有效提升BufferCache模式下的查询效率具体可以查看Ip2Region的README
// 注意设置过大的值可能会申请内存时因内存不足而导致OOM请合理设置该值。
// READMEhttps://gitee.com/lionsoul/ip2region/tree/master/binding/java
public static final int DEFAULT_CACHE_SLICE_BYTES = 1024 * 1024 * 15;
// 未知地址
public static final String UNKNOWN_ADDRESS = "未知";
@@ -41,12 +46,17 @@ public class RegionUtils {
// 注意Ip2Region 的xdb文件加载策略 CachePolicy 有三种分别是BufferCache全量读取xdb到内存中、VIndexCache默认策略按需读取并缓存、NoCache实时读取
// 本项目工具使用的 CachePolicy 为 BufferCacheBufferCache会加载整个xdb文件到内存中setXdbInputStream 仅支持 BufferCache 策略。
// 因为加载整个xdb文件会耗费非常大的内存如果你不希望加载整个xdb到内存中更推荐使用 VIndexCache 或 NoCache即实时读取文件策略和 setXdbPath/setXdbFile 加载方法需要注意的一点setXdbPath 和 setXdbFile 不支持读取ClassPath即源码和resource目录中的文件
// 一般而言更建议把xdb数据库放到一个指定的文件目录中即不打包进jar包中然后使用 NoCache + 配合SearcherPool的并发池读取数据更方便随时更新xdb数据库
// 一般而言更建议把xdb数据库放到一个指定的文件目录中即不打包进jar包中然后使用 VIndexCache + 配合SearcherPool的并发池读取数据更方便随时更新xdb数据库
InputStream v4InputStream = ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH);
// IPv4配置
Config v4Config = Config.custom()
.setCachePolicy(Config.BufferCache)
.setXdbInputStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH))
//.setXdbFile(v4TempXdb)
.setXdbInputStream(v4InputStream)
//
.setCacheSliceBytes(DEFAULT_CACHE_SLICE_BYTES)
.asV4();
// IPv6配置
@@ -57,7 +67,9 @@ public class RegionUtils {
} else {
v6Config = Config.custom()
.setCachePolicy(Config.BufferCache)
//.setXdbFile(v6TempXdb)
.setXdbInputStream(v6XdbInputStream)
.setCacheSliceBytes(DEFAULT_CACHE_SLICE_BYTES)
.asV6();
}

View File

@@ -29,7 +29,10 @@ public class CellMergeHandler {
// 行合并开始下标
this.rowIndex = hasTitle ? 1 : 0;
}
private CellMergeHandler(final boolean hasTitle, final int rowIndex) {
this.hasTitle = hasTitle;
this.rowIndex = hasTitle ? rowIndex : 0;
}
@SneakyThrows
public List<CellRangeAddress> handle(List<?> rows) {
// 如果入参为空集合则返回空集
@@ -103,6 +106,10 @@ public class CellMergeHandler {
}
if (isAddResult && i > current) {
//如果是同一行,则跳过合并
if (current + rowIndex == lastRow) {
continue;
}
result.add(new CellRangeAddress(current + rowIndex, lastRow, colNum, colNum));
}
}
@@ -177,6 +184,16 @@ public class CellMergeHandler {
return new FieldColumnIndex(colIndex, cellMerge);
}
}
/**
* 创建一个单元格合并处理器实例
*
* @param hasTitle 是否合并标题
* @param rowIndex 行索引
* @return 单元格合并处理器
*/
public static CellMergeHandler of(final boolean hasTitle, final int rowIndex) {
return new CellMergeHandler(hasTitle, rowIndex);
}
/**
* 创建一个单元格合并处理器实例

View File

@@ -31,6 +31,10 @@ public class CellMergeStrategy extends AbstractMergeStrategy implements SheetWri
this.cellList = CellMergeHandler.of(hasTitle).handle(list);
}
public CellMergeStrategy(List<?> list, boolean hasTitle, int rowIndex) {
this.cellList = CellMergeHandler.of(hasTitle, rowIndex).handle(list);
}
@Override
protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
if (CollUtil.isEmpty(cellList)) {

View File

@@ -192,7 +192,7 @@ public class MailUtils {
/**
* 发送邮件给多人
*
* @param mailAccount 邮件户信息
* @param mailAccount 邮件户信息
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
@@ -207,7 +207,7 @@ public class MailUtils {
/**
* 发送邮件给多人
*
* @param mailAccount 邮件户信息
* @param mailAccount 邮件户信息
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
@@ -343,7 +343,7 @@ public class MailUtils {
/**
* 发送邮件给多人
*
* @param mailAccount 邮件户信息
* @param mailAccount 邮件户信息
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
@@ -360,7 +360,7 @@ public class MailUtils {
/**
* 发送邮件给多人
*
* @param mailAccount 邮件户信息
* @param mailAccount 邮件户信息
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
@@ -400,7 +400,7 @@ public class MailUtils {
/**
* 发送邮件给多人
*
* @param mailAccount 邮件户信息
* @param mailAccount 邮件户信息
* @param useGlobalSession 是否全局共享Session
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空

View File

@@ -141,7 +141,8 @@ public class OssClient {
try {
// 构建上传请求对象
FileUpload fileUpload = transferManager.uploadFile(
x -> x.putObjectRequest(
x -> {
x.source(filePath).putObjectRequest(
y -> y.bucket(properties.getBucketName())
.key(key)
.contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
@@ -149,10 +150,13 @@ public class OssClient {
// 用于设置对象的访问控制列表ACL。不同云厂商对ACL的支持和实现方式有所不同
// 因此根据具体的云服务提供商你可能需要进行不同的配置自行开启阿里云有acl权限配置腾讯云没有acl权限配置
//.acl(getAccessPolicy().getObjectCannedACL())
.build())
.addTransferListener(LoggingTransferListener.create())
.source(filePath).build());
.build()
);
if (log.isDebugEnabled()) {
x.addTransferListener(LoggingTransferListener.create());
}
}
);
// 等待上传完成并获取上传结果
CompletedFileUpload uploadResult = fileUpload.completionFuture().join();
String eTag = uploadResult.response().eTag();
@@ -192,16 +196,21 @@ public class OssClient {
// 使用 transferManager 进行上传
Upload upload = transferManager.upload(
x -> x.requestBody(body).addTransferListener(LoggingTransferListener.create())
.putObjectRequest(
x -> {
x.requestBody(body).putObjectRequest(
y -> y.bucket(properties.getBucketName())
.key(key)
.contentType(contentType)
// 用于设置对象的访问控制列表ACL。不同云厂商对ACL的支持和实现方式有所不同
// 因此根据具体的云服务提供商你可能需要进行不同的配置自行开启阿里云有acl权限配置腾讯云没有acl权限配置
//.acl(getAccessPolicy().getObjectCannedACL())
.build())
.build());
.build()
);
if (log.isDebugEnabled()) {
x.addTransferListener(LoggingTransferListener.create());
}
}
);
// 将输入流写入请求体
body.writeInputStream(inputStream);
@@ -229,13 +238,17 @@ public class OssClient {
Path tempFilePath = FileUtils.createTempFile().toPath();
// 使用 S3TransferManager 下载文件
FileDownload downloadFile = transferManager.downloadFile(
x -> x.getObjectRequest(
x -> {
x.destination(tempFilePath).getObjectRequest(
y -> y.bucket(properties.getBucketName())
.key(removeBaseUrl(path))
.build())
.addTransferListener(LoggingTransferListener.create())
.destination(tempFilePath)
.build());
.build()
);
if (log.isDebugEnabled()) {
x.addTransferListener(LoggingTransferListener.create());
}
}
);
// 等待文件下载操作完成
downloadFile.completionFuture().join();
return tempFilePath;
@@ -244,8 +257,8 @@ public class OssClient {
/**
* 下载文件从 Amazon S3 到 输出流
*
* @param key 文件在 Amazon S3 中的对象键
* @param out 输出流
* @param key 文件在 Amazon S3 中的对象键
* @param out 输出流
* @param consumer 自定义处理逻辑
* @throws OssException 如果下载失败,抛出自定义异常
*/
@@ -260,26 +273,24 @@ public class OssClient {
/**
* 下载文件从 Amazon S3 到 输出流
*
* @param key 文件在 Amazon S3 中的对象键
* @param key 文件在 Amazon S3 中的对象键
* @param contentLengthConsumer 文件大小消费者函数
* @return 写出订阅器
* @throws OssException 如果下载失败,抛出自定义异常
*/
public WriteOutSubscriber<OutputStream> download(String key, Consumer<Long> contentLengthConsumer) {
try {
// 构建下载请求
DownloadRequest<ResponsePublisher<GetObjectResponse>> publisherDownloadRequest = DownloadRequest.builder()
// 文件对象
.getObjectRequest(y -> y.bucket(properties.getBucketName())
.key(key)
.build())
.addTransferListener(LoggingTransferListener.create())
DownloadRequest.TypedBuilder<ResponsePublisher<GetObjectResponse>> typedBuilder = DownloadRequest.builder()
// 使用发布订阅转换器
.responseTransformer(AsyncResponseTransformer.toPublisher())
.build();
// 文件对象
.getObjectRequest(y -> y.bucket(properties.getBucketName()).key(key).build());
if (log.isDebugEnabled()) {
typedBuilder.addTransferListener(LoggingTransferListener.create());
}
// 使用 S3TransferManager 下载文件
Download<ResponsePublisher<GetObjectResponse>> publisherDownload = transferManager.download(publisherDownloadRequest);
Download<ResponsePublisher<GetObjectResponse>> publisherDownload = transferManager.download(typedBuilder.build());
// 获取下载发布订阅转换器
ResponsePublisher<GetObjectResponse> publisher = publisherDownload.completionFuture().join().result();
// 执行文件大小消费者函数
@@ -289,7 +300,7 @@ public class OssClient {
// 构建写出订阅器对象
return out -> {
// 创建可写入的字节通道
try(WritableByteChannel channel = Channels.newChannel(out)){
try (WritableByteChannel channel = Channels.newChannel(out)) {
// 订阅数据
publisher.subscribe(byteBuffer -> {
while (byteBuffer.hasRemaining()) {
@@ -347,7 +358,7 @@ public class OssClient {
*
* @param objectKey 对象KEY
* @param expiredTime 链接授权到期时间
* @param metadata 元数据
* @param metadata 元数据
*/
public String createPresignedPutUrl(String objectKey, Duration expiredTime, Map<String, String> metadata) {
// 使用 AWS S3 预签名 URL 的生成器 获取上传文件对象的预签名 URL

View File

@@ -88,6 +88,11 @@ public enum SensitiveStrategy {
*/
STRING_MASK(s -> DesensitizedUtils.mask(s, 4, 4, 4)),
/**
* 高安全级别脱敏Token / 私钥前2位可见后2位可见中间全部掩码
*/
MASK_HIGH_SECURITY(s -> DesensitizedUtils.maskHighSecurity(s, 2, 2)),
/**
* 清空为""
*/

View File

@@ -20,7 +20,7 @@ public class NicknameTranslationImpl implements TranslationInterface<String> {
@Override
public String translation(Object key, String other) {
if (key instanceof Long id) {
return userService.selectNicknameByIds(id.toString());
return userService.selectNicknameById(id);
} else if (key instanceof String ids) {
return userService.selectNicknameByIds(ids);
}

View File

@@ -1,5 +1,6 @@
package org.dromara.common.translation.core.impl;
import cn.hutool.core.convert.Convert;
import org.dromara.common.core.service.UserService;
import org.dromara.common.translation.annotation.TranslationType;
import org.dromara.common.translation.constant.TransConstant;
@@ -19,9 +20,6 @@ public class UserNameTranslationImpl implements TranslationInterface<String> {
@Override
public String translation(Object key, String other) {
if (key instanceof Long id) {
return userService.selectUserNameById(id);
}
return null;
return userService.selectUserNameById(Convert.toLong(key));
}
}

View File

@@ -14,6 +14,7 @@ import org.dromara.common.core.exception.SseException;
import org.dromara.common.core.exception.base.BaseException;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.expression.ExpressionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
@@ -25,6 +26,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;
@@ -191,6 +193,16 @@ public class GlobalExceptionHandler {
return R.fail(message);
}
/**
* 方法参数校验异常 用于处理 @Validated 注解
*/
@ExceptionHandler(HandlerMethodValidationException.class)
public R<Void> handlerMethodValidationException(HandlerMethodValidationException e) {
log.error(e.getMessage());
String message = StreamUtils.join(e.getAllErrors(), MessageSourceResolvable::getDefaultMessage, ", ");
return R.fail(message);
}
/**
* JSON 解析异常Jackson 在处理 JSON 格式出错时抛出)
* 可能是请求体格式非法,也可能是服务端反序列化失败

View File

@@ -8,6 +8,7 @@ import org.dromara.common.websocket.holder.WebSocketSessionHolder;
import org.dromara.common.websocket.utils.WebSocketUtils;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;
import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;
import java.io.IOException;
import java.util.List;
@@ -33,7 +34,7 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
log.info("[connect] invalid token received. sessionId: {}", session.getId());
return;
}
WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
WebSocketSessionHolder.addSession(loginUser.getUserId(), new ConcurrentWebSocketSessionDecorator(session, 10 * 1000, 64000));
log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
}

View File

@@ -113,7 +113,7 @@ public class WebSocketUtils {
* @param session WebSocket会话
* @param message 要发送的WebSocket消息对象
*/
private synchronized static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
private static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
if (session == null || !session.isOpen()) {
log.warn("[send] session会话已经关闭");
} else {

View File

@@ -1,146 +0,0 @@
package com.aizuda.snailjob.server.common.register;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.aizuda.snailjob.common.core.enums.NodeTypeEnum;
import com.aizuda.snailjob.common.core.util.JsonUtil;
import com.aizuda.snailjob.common.core.util.NetUtil;
import com.aizuda.snailjob.common.core.util.SnailJobVersion;
import com.aizuda.snailjob.common.core.util.StreamUtils;
import com.aizuda.snailjob.common.log.SnailJobLog;
import com.aizuda.snailjob.server.common.cache.CacheConsumerGroup;
import com.aizuda.snailjob.server.common.config.SystemProperties;
import com.aizuda.snailjob.server.common.convert.RegisterNodeInfoConverter;
import com.aizuda.snailjob.server.common.dto.ServerNodeExtAttrs;
import com.aizuda.snailjob.server.common.handler.InstanceManager;
import com.aizuda.snailjob.template.datasource.persistence.po.ServerNode;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 服务端注册
*
* @author opensnail
* @date 2023-06-07
* @since 1.6.0
*/
@Component(ServerRegister.BEAN_NAME)
@RequiredArgsConstructor
public class ServerRegister extends AbstractRegister {
public static final String BEAN_NAME = "serverRegister";
private final ScheduledExecutorService serverRegisterNode = Executors.newSingleThreadScheduledExecutor(r -> new Thread(r, "server-register-node"));
public static final int DELAY_TIME = 30;
public static final String CURRENT_CID;
public static final String GROUP_NAME = "DEFAULT_SERVER";
public static final String NAMESPACE_ID = "DEFAULT_SERVER_NAMESPACE_ID";
private final InstanceManager instanceManager;
private final SystemProperties systemProperties;
private final ServerProperties serverProperties;
static {
CURRENT_CID = IdUtil.getSnowflakeNextIdStr();
}
@Override
public boolean supports(int type) {
return getNodeType().equals(type);
}
@Override
protected void beforeProcessor(RegisterContext context) {
// 新增扩展参数
ServerNodeExtAttrs serverNodeExtAttrs = new ServerNodeExtAttrs();
serverNodeExtAttrs.setWebPort(serverProperties.getPort());
serverNodeExtAttrs.setSystemVersion(SnailJobVersion.getVersion());
context.setGroupName(GROUP_NAME);
context.setHostId(CURRENT_CID);
String serverHost = systemProperties.getServerHost();
if (StrUtil.isEmptyIfStr(serverHost)) {
serverHost = NetUtil.getLocalIpStr();
}
context.setHostIp(serverHost);
context.setHostPort(systemProperties.getServerPort());
context.setContextPath(Optional.ofNullable(serverProperties.getServlet().getContextPath()).orElse(StrUtil.EMPTY));
context.setNamespaceId(NAMESPACE_ID);
context.setExtAttrs(JsonUtil.toJsonString(serverNodeExtAttrs));
}
@Override
protected LocalDateTime getExpireAt() {
return LocalDateTime.now().plusSeconds(DELAY_TIME);
}
@Override
protected boolean doRegister(RegisterContext context, ServerNode serverNode) {
refreshExpireAt(Lists.newArrayList(serverNode));
return Boolean.TRUE;
}
@Override
protected void afterProcessor(final ServerNode serverNode) {
try {
// 同步当前POD消费的组的节点信息
// netty的client只会注册到一个服务端若组分配的和client连接的不是一个POD则会导致当前POD没有其他客户端的注册信息
ConcurrentMap<String /*groupName*/, Set<String>/*namespaceId*/> allConsumerGroupName = CacheConsumerGroup.getAllConsumerGroupName();
if (CollUtil.isNotEmpty(allConsumerGroupName)) {
Set<String> namespaceIdSets = StreamUtils.toSetByFlatMap(allConsumerGroupName.values(), Set::stream);
if (CollUtil.isEmpty(namespaceIdSets)) {
return;
}
List<ServerNode> serverNodes = serverNodeMapper.selectList(
new LambdaQueryWrapper<ServerNode>()
.eq(ServerNode::getNodeType, NodeTypeEnum.CLIENT.getType())
.in(ServerNode::getNamespaceId, namespaceIdSets)
.in(ServerNode::getGroupName, allConsumerGroupName.keySet()));
for (final ServerNode node : serverNodes) {
// 刷新全量本地缓存
instanceManager.registerOrUpdate(RegisterNodeInfoConverter.INSTANCE.toRegisterNodeInfo(node));
// 刷新过期时间
CacheConsumerGroup.addOrUpdate(node.getGroupName(), node.getNamespaceId());
}
}
} catch (Exception e) {
SnailJobLog.LOCAL.error("Client refresh failed", e);
}
}
@Override
protected Integer getNodeType() {
return NodeTypeEnum.SERVER.getType();
}
@Override
public void start() {
SnailJobLog.LOCAL.info("ServerRegister start");
serverRegisterNode.scheduleAtFixedRate(() -> {
try {
this.register(new RegisterContext());
} catch (Exception e) {
SnailJobLog.LOCAL.error("Server-side registration failed", e);
}
}, 0, DELAY_TIME * 2 / 3, TimeUnit.SECONDS);
}
@Override
public void close() {
SnailJobLog.LOCAL.info("ServerRegister close");
}
}

View File

@@ -137,6 +137,8 @@ public class SysMenuController extends BaseController {
return R.fail("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
} else if (SystemConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
return R.fail("新增菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
} else if (!menuService.checkRouteConfigUnique(menu)) {
return R.fail("新增菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
}
return toAjax(menuService.insertMenu(menu));
}
@@ -156,6 +158,8 @@ public class SysMenuController extends BaseController {
return R.fail("修改菜单'" + menu.getMenuName() + "'失败地址必须以http(s)://开头");
} else if (menu.getMenuId().equals(menu.getParentId())) {
return R.fail("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
} else if (!menuService.checkRouteConfigUnique(menu)) {
return R.fail("修改菜单'" + menu.getMenuName() + "'失败,路由名称或地址已存在");
}
return toAjax(menuService.updateMenu(menu));
}

View File

@@ -130,11 +130,11 @@ public class SysMenu extends BaseEntity {
public String getRouterPath() {
String routerPath = this.path;
// 内链打开外网方式
if (getParentId() != 0L && isInnerLink()) {
if (!Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) {
routerPath = innerLinkReplaceEach(routerPath);
}
// 非外链并且是一级目录(类型为目录)
if (0L == getParentId() && SystemConstants.TYPE_DIR.equals(getMenuType())
if (Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(getMenuType())
&& SystemConstants.NO_FRAME.equals(getIsFrame())) {
routerPath = "/" + this.path;
}
@@ -152,7 +152,7 @@ public class SysMenu extends BaseEntity {
String component = SystemConstants.LAYOUT;
if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) {
component = this.component;
} else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && isInnerLink()) {
} else if (StringUtils.isEmpty(this.component) && !Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) {
component = SystemConstants.INNER_LINK;
} else if (StringUtils.isEmpty(this.component) && isParentView()) {
component = SystemConstants.PARENT_VIEW;
@@ -164,7 +164,7 @@ public class SysMenu extends BaseEntity {
* 是否为菜单内部跳转
*/
public boolean isMenuFrame() {
return getParentId() == 0L && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME);
return Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME);
}
/**
@@ -178,7 +178,7 @@ public class SysMenu extends BaseEntity {
* 是否为parent_view组件
*/
public boolean isParentView() {
return getParentId() != 0L && SystemConstants.TYPE_DIR.equals(menuType);
return !Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(menuType);
}
/**

View File

@@ -78,7 +78,7 @@ public class SysUser extends TenantEntity {
private String password;
/**
* 号状态0正常 1停用
* 号状态0正常 1停用
*/
private String status;

View File

@@ -78,7 +78,7 @@ public class SysUserBo extends BaseEntity {
private String password;
/**
* 号状态0正常 1停用
* 号状态0正常 1停用
*/
private String status;

View File

@@ -63,9 +63,9 @@ public class SysUserExportVo implements Serializable {
private String sex;
/**
* 号状态0正常 1停用
* 号状态0正常 1停用
*/
@ExcelProperty(value = "号状态", converter = ExcelDictConvert.class)
@ExcelProperty(value = "号状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private String status;

View File

@@ -67,9 +67,9 @@ public class SysUserImportVo implements Serializable {
private String sex;
/**
* 号状态0正常 1停用
* 号状态0正常 1停用
*/
@ExcelProperty(value = "号状态", converter = ExcelDictConvert.class)
@ExcelProperty(value = "号状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "sys_normal_disable")
private String status;

View File

@@ -89,7 +89,7 @@ public class SysUserVo implements Serializable {
private String password;
/**
* 号状态0正常 1停用
* 号状态0正常 1停用
*/
private String status;

View File

@@ -160,4 +160,13 @@ public interface ISysMenuService {
* @return 结果
*/
boolean checkMenuNameUnique(SysMenuBo menu);
/**
* 校验路由组合是否唯一
*
* @param menu 菜单信息
* @return 结果
*/
boolean checkRouteConfigUnique(SysMenuBo menu);
}

View File

@@ -174,7 +174,7 @@ public interface ISysUserService {
* 修改用户状态
*
* @param userId 用户ID
* @param status 号状态
* @param status 号状态
* @return 结果
*/
int updateUserStatus(Long userId, String status);

View File

@@ -6,6 +6,7 @@ import cn.hutool.core.lang.tree.Tree;
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.SystemConstants;
import org.dromara.common.core.utils.MapstructUtils;
@@ -29,13 +30,17 @@ import org.dromara.system.service.ISysMenuService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
/**
* 菜单 业务层处理
*
* @author Lion Li
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class SysMenuServiceImpl implements ISysMenuService {
@@ -353,6 +358,43 @@ public class SysMenuServiceImpl implements ISysMenuService {
return !exist;
}
/**
* 校验路由名称是否唯一
*
* @param menuBo 菜单信息
* @return 结果
*/
@Override
public boolean checkRouteConfigUnique(SysMenuBo menuBo) {
SysMenu menu = MapstructUtils.convert(menuBo, SysMenu.class);
long menuId = ObjectUtil.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
Long parentId = menu.getParentId();
String path = menu.getPath();
String routeName = StringUtils.isEmpty(menu.getRouteName()) ? path : menu.getRouteName();
List<SysMenu> sysMenuList = baseMapper.selectList(
new LambdaQueryWrapper<SysMenu>()
.in(SysMenu::getMenuType, SystemConstants.TYPE_DIR, SystemConstants.TYPE_MENU)
.eq(SysMenu::getPath, path).or().eq(SysMenu::getPath, routeName));
for (SysMenu sysMenu : sysMenuList) {
if (sysMenu.getMenuId() != menuId) {
Long dbParentId = sysMenu.getParentId();
String dbPath = sysMenu.getPath();
String dbRouteName = StringUtils.isEmpty(sysMenu.getRouteName()) ? dbPath : sysMenu.getRouteName();
if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == dbParentId.longValue()) {
log.warn("[同级路由冲突] 同级下已存在相同路由路径 '{}',冲突菜单:{}", dbPath, sysMenu.getMenuName());
return false;
} else if (StringUtils.equalsAnyIgnoreCase(path, dbPath) && parentId.longValue() == Constants.TOP_PARENT_ID) {
log.warn("[根目录路由冲突] 根目录下路由 '{}' 必须唯一,已被菜单 '{}' 占用", path, sysMenu.getMenuName());
return false;
} else if (StringUtils.equalsAnyIgnoreCase(routeName, dbRouteName)) {
log.warn("[路由名称冲突] 路由名称 '{}' 需全局唯一,已被菜单 '{}' 使用", routeName, sysMenu.getMenuName());
return false;
}
}
}
return true;
}
/**
* 根据父节点的ID获取所有子节点
*

View File

@@ -375,7 +375,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
* 修改用户状态
*
* @param userId 用户ID
* @param status 号状态
* @param status 号状态
* @return 结果
*/
@Override

View File

@@ -74,6 +74,9 @@ public class WorkflowGlobalListener implements GlobalListener {
String ext = listenerVariable.getNode().getExt();
if (StringUtils.isNotBlank(ext)) {
Map<String, Object> variable = listenerVariable.getVariable();
if (CollUtil.isEmpty(variable)) {
variable = new HashMap<>();
}
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable);
Set<String> copyList = nodeExt.getCopySettings();
if (CollUtil.isNotEmpty(copyList)) {

View File

@@ -208,10 +208,6 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
@Override
@Transactional(rollbackFor = Exception.class)
public void syncDef(String tenantId) {
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID));
if (CollUtil.isEmpty(flowDefinitions)) {
return;
}
FlowCategory flowCategory = flwCategoryMapper.selectOne(new LambdaQueryWrapper<FlowCategory>()
.eq(FlowCategory::getTenantId, DEFAULT_TENANT_ID)
.eq(FlowCategory::getCategoryId, FlowConstant.FLOW_CATEGORY_ID));
@@ -223,6 +219,11 @@ public class FlwDefinitionServiceImpl implements IFlwDefinitionService {
flowCategory.setUpdateBy(null);
flowCategory.setUpdateTime(null);
flwCategoryMapper.insert(flowCategory);
List<FlowDefinition> flowDefinitions = flowDefinitionMapper.selectList(new LambdaQueryWrapper<FlowDefinition>().eq(FlowDefinition::getTenantId, DEFAULT_TENANT_ID));
if (CollUtil.isEmpty(flowDefinitions)) {
return;
}
List<Long> defIds = StreamUtils.toList(flowDefinitions, FlowDefinition::getId);
List<FlowNode> flowNodes = flowNodeMapper.selectList(new LambdaQueryWrapper<FlowNode>().in(FlowNode::getDefinitionId, defIds));
List<FlowSkip> flowSkips = flowSkipMapper.selectList(new LambdaQueryWrapper<FlowSkip>().in(FlowSkip::getDefinitionId, defIds));

View File

@@ -99,7 +99,7 @@ services:
network_mode: "host"
ruoyi-server1:
image: ruoyi/ruoyi-server:5.5.1
image: ruoyi/ruoyi-server:5.5.2
container_name: ruoyi-server1
environment:
# 时区上海
@@ -115,7 +115,7 @@ services:
network_mode: "host"
ruoyi-server2:
image: ruoyi/ruoyi-server:5.5.1
image: ruoyi/ruoyi-server:5.5.2
container_name: ruoyi-server2
environment:
# 时区上海
@@ -131,7 +131,7 @@ services:
network_mode: "host"
ruoyi-monitor-admin:
image: ruoyi/ruoyi-monitor-admin:5.5.1
image: ruoyi/ruoyi-monitor-admin:5.5.2
container_name: ruoyi-monitor-admin
environment:
# 时区上海
@@ -143,7 +143,7 @@ services:
network_mode: "host"
ruoyi-snailjob-server:
image: ruoyi/ruoyi-snailjob-server:5.5.1
image: ruoyi/ruoyi-snailjob-server:5.5.2
container_name: ruoyi-snailjob-server
environment:
# 时区上海

View File

@@ -106,11 +106,6 @@ http {
proxy_buffering off;
# 禁用代理缓存
proxy_cache off;
# 按 IP 限制连接数(防 CC 攻击) 小型站10~20 就够 中型站50~100
limit_conn perip 20;
# 按 Server 限制总并发连接数 根据服务器的最大并发处理能力来定 太小会限制合法用户访问,太大会占满服务器资源
limit_conn perserver 500;
proxy_pass http://server/;
}

View File

@@ -738,7 +738,7 @@ CREATE TABLE sj_retry_summary
id number GENERATED ALWAYS AS IDENTITY,
namespace_id varchar2(64) DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' NULL,
group_name varchar2(64) DEFAULT '' NULL,
scene_name varchar2(50) DEFAULT '' NULL,
scene_name varchar2(64) DEFAULT '' NULL,
trigger_at date DEFAULT CURRENT_TIMESTAMP NOT NULL,
running_num number DEFAULT 0 NOT NULL,
finish_num number DEFAULT 0 NOT NULL,

View File

@@ -257,7 +257,7 @@ comment on column sys_user.phonenumber is '手机号码';
comment on column sys_user.sex is '用户性别0男 1女 2未知';
comment on column sys_user.avatar is '头像路径';
comment on column sys_user.password is '密码';
comment on column sys_user.status is '号状态0正常 1停用';
comment on column sys_user.status is '号状态0正常 1停用';
comment on column sys_user.del_flag is '删除标志0代表存在 1代表删除';
comment on column sys_user.login_ip is '最后登录IP';
comment on column sys_user.login_date is '最后登录时间';

View File

@@ -684,7 +684,7 @@ CREATE TABLE sj_retry_summary
id bigserial PRIMARY KEY,
namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
group_name varchar(64) NOT NULL DEFAULT '',
scene_name varchar(50) NOT NULL DEFAULT '',
scene_name varchar(64) NOT NULL DEFAULT '',
trigger_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
running_num int NOT NULL DEFAULT 0,
finish_num int NOT NULL DEFAULT 0,

View File

@@ -258,7 +258,7 @@ comment on column sys_user.phonenumber is '手机号码';
comment on column sys_user.sex is '用户性别0男 1女 2未知';
comment on column sys_user.avatar is '头像地址';
comment on column sys_user.password is '密码';
comment on column sys_user.status is '号状态0正常 1停用';
comment on column sys_user.status is '号状态0正常 1停用';
comment on column sys_user.del_flag is '删除标志0代表存在 1代表删除';
comment on column sys_user.login_ip is '最后登陆IP';
comment on column sys_user.login_date is '最后登陆时间';

View File

@@ -423,7 +423,7 @@ CREATE TABLE `sj_retry_summary`
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
`group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称',
`scene_name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '场景名称',
`scene_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '场景名称',
`trigger_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间',
`running_num` int NOT NULL DEFAULT 0 COMMENT '重试中-日志数量',
`finish_num` int NOT NULL DEFAULT 0 COMMENT '重试完成-日志数量',

View File

@@ -148,7 +148,7 @@ create table sys_user (
sex char(1) default '0' comment '用户性别0男 1女 2未知',
avatar bigint(20) comment '头像地址',
password varchar(100) default '' comment '密码',
status char(1) default '0' comment '号状态0正常 1停用',
status char(1) default '0' comment '号状态0正常 1停用',
del_flag char(1) default '0' comment '删除标志0代表存在 1代表删除',
login_ip varchar(128) default '' comment '最后登录IP',
login_date datetime comment '最后登录时间',

View File

@@ -2248,7 +2248,7 @@ CREATE TABLE sj_retry_summary
id bigint NOT NULL PRIMARY KEY IDENTITY,
namespace_id nvarchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
group_name nvarchar(64) NOT NULL DEFAULT '',
scene_name nvarchar(50) NOT NULL DEFAULT '',
scene_name nvarchar(64) NOT NULL DEFAULT '',
trigger_at datetime2 NOT NULL DEFAULT CURRENT_TIMESTAMP,
running_num int NOT NULL DEFAULT 0,
finish_num int NOT NULL DEFAULT 0,

View File

@@ -2802,7 +2802,7 @@ EXEC sys.sp_addextendedproperty
'COLUMN', N'password'
GO
EXEC sys.sp_addextendedproperty
'MS_Description', N'号状态0正常 1停用' ,
'MS_Description', N'号状态0正常 1停用' ,
'SCHEMA', N'dbo',
'TABLE', N'sys_user',
'COLUMN', N'status'