mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2026-01-12 02:06:00 +08:00
Compare commits
27 Commits
dev
...
b6eacfa5a8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b6eacfa5a8 | ||
|
|
da4dffcfce | ||
|
|
b58085fde1 | ||
|
|
b30ffa952f | ||
|
|
fd5d028e95 | ||
|
|
64100cf1ff | ||
|
|
7e7d857ba5 | ||
|
|
d22b2a10df | ||
|
|
957a4d1fcd | ||
|
|
49ef8378fe | ||
|
|
57dd6831d3 | ||
|
|
8aa60abb1f | ||
|
|
7a9f51fc7a | ||
|
|
159e30c982 | ||
|
|
7334d91d6b | ||
|
|
95c01301f6 | ||
|
|
296466fa13 | ||
|
|
3c8d864b5f | ||
|
|
ea50a57602 | ||
|
|
7e14b98676 | ||
|
|
015b406001 | ||
|
|
098d3347a0 | ||
|
|
08d4493994 | ||
|
|
367d739e2d | ||
|
|
d6688a367d | ||
|
|
0b331796e2 | ||
|
|
456620b638 |
@@ -35,6 +35,7 @@ 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>
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -38,7 +38,7 @@
|
||||
<bouncycastle.version>1.80</bouncycastle.version>
|
||||
<justauth.version>1.16.7</justauth.version>
|
||||
<!-- 离线IP地址定位库 -->
|
||||
<ip2region.version>3.3.2</ip2region.version>
|
||||
<ip2region.version>3.3.1</ip2region.version>
|
||||
<!-- OSS 配置 -->
|
||||
<aws.sdk.version>2.28.22</aws.sdk.version>
|
||||
<!-- SMS 配置 -->
|
||||
|
||||
@@ -13,7 +13,7 @@ user.logout.success=退出成功
|
||||
length.not.valid=长度必须在{min}到{max}个字符之间
|
||||
user.username.not.blank=用户名不能为空
|
||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
|
||||
user.username.length.valid=帐户长度必须在{min}到{max}个字符之间
|
||||
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
|
||||
user.password.not.blank=用户密码不能为空
|
||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
|
||||
user.password.not.valid=* 5-50个字符
|
||||
|
||||
@@ -13,7 +13,7 @@ user.logout.success=退出成功
|
||||
length.not.valid=长度必须在{min}到{max}个字符之间
|
||||
user.username.not.blank=用户名不能为空
|
||||
user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头
|
||||
user.username.length.valid=帐户长度必须在{min}到{max}个字符之间
|
||||
user.username.length.valid=账户长度必须在{min}到{max}个字符之间
|
||||
user.password.not.blank=用户密码不能为空
|
||||
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
|
||||
user.password.not.valid=* 5-50个字符
|
||||
|
||||
@@ -23,7 +23,7 @@ public interface CacheConstants {
|
||||
String SYS_DICT_KEY = "sys_dict:";
|
||||
|
||||
/**
|
||||
* 登录帐户密码错误次数 redis key
|
||||
* 登录账户密码错误次数 redis key
|
||||
*/
|
||||
String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public interface CacheNames {
|
||||
String SYS_CLIENT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_client#30d";
|
||||
|
||||
/**
|
||||
* 用户帐户
|
||||
* 用户账户
|
||||
*/
|
||||
String SYS_USER_NAME = "sys_user_name#30d";
|
||||
|
||||
|
||||
@@ -13,15 +13,15 @@ import java.util.Map;
|
||||
public interface UserService {
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户帐户
|
||||
* 通过用户ID查询用户账户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户帐户
|
||||
* @return 用户账户
|
||||
*/
|
||||
String selectUserNameById(Long userId);
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户帐户
|
||||
* 通过用户ID查询用户账户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户名称
|
||||
@@ -29,7 +29,7 @@ public interface UserService {
|
||||
String selectNicknameById(Long userId);
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户帐户
|
||||
* 通过用户ID查询用户账户
|
||||
*
|
||||
* @param userIds 用户ID 多个用逗号隔开
|
||||
* @return 用户名称
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dromara.common.core.utils.ip;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.resource.ResourceUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.common.core.exception.ServiceException;
|
||||
@@ -8,6 +9,7 @@ import org.lionsoul.ip2region.service.Config;
|
||||
import org.lionsoul.ip2region.service.Ip2Region;
|
||||
import org.lionsoul.ip2region.xdb.Util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.time.Duration;
|
||||
|
||||
@@ -29,11 +31,6 @@ 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,请合理设置该值。
|
||||
// README:https://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 = "未知";
|
||||
|
||||
@@ -46,18 +43,20 @@ public class RegionUtils {
|
||||
// 注意:Ip2Region 的xdb文件加载策略 CachePolicy 有三种,分别是:BufferCache(全量读取xdb到内存中)、VIndexCache(默认策略,按需读取并缓存)、NoCache(实时读取)
|
||||
// 本项目工具使用的 CachePolicy 为 BufferCache,BufferCache会加载整个xdb文件到内存中,setXdbInputStream 仅支持 BufferCache 策略。
|
||||
// 因为加载整个xdb文件会耗费非常大的内存,如果你不希望加载整个xdb到内存中,更推荐使用 VIndexCache 或 NoCache(即实时读取文件)策略和 setXdbPath/setXdbFile 加载方法(需要注意的一点,setXdbPath 和 setXdbFile 不支持读取ClassPath(即源码和resource目录)中的文件)。
|
||||
// 一般而言,更建议把xdb数据库放到一个指定的文件目录中(即不打包进jar包中),然后使用 VIndexCache + 配合SearcherPool的并发池读取数据,更方便随时更新xdb数据库
|
||||
// 一般而言,更建议把xdb数据库放到一个指定的文件目录中(即不打包进jar包中),然后使用 NoCache + 配合SearcherPool的并发池读取数据,更方便随时更新xdb数据库
|
||||
|
||||
InputStream v4InputStream = ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH);
|
||||
// TODO 2025年12月23日 Ip2Region封装的 InputStream 读取函数 Searcher.loadContentFromInputStream 在Linux环境下会申请过大的byte[]空间而导致OOM,这里先用临时文件的方案解决,等后续 Ip2Region 更新解决方案
|
||||
// 创建临时文件
|
||||
File v4TempXdb = FileUtil.writeFromStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH), FileUtil.createTempFile());
|
||||
|
||||
// IPv4配置
|
||||
Config v4Config = Config.custom()
|
||||
.setCachePolicy(Config.BufferCache)
|
||||
//.setXdbFile(v4TempXdb)
|
||||
.setXdbInputStream(v4InputStream)
|
||||
//
|
||||
.setCacheSliceBytes(DEFAULT_CACHE_SLICE_BYTES)
|
||||
.setXdbFile(v4TempXdb)
|
||||
// .setXdbInputStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH))
|
||||
.asV4();
|
||||
// 删除临时文件
|
||||
v4TempXdb.delete();
|
||||
|
||||
// IPv6配置
|
||||
Config v6Config = null;
|
||||
@@ -65,12 +64,17 @@ public class RegionUtils {
|
||||
if (v6XdbInputStream == null) {
|
||||
log.warn("未加载 IPv6 地址库:未在类路径下找到文件 {}。当前仅启用 IPv4 查询。如需启用 IPv6,请将 ip2region_v6.xdb 放置到 resources 目录", DEFAULT_IPV6_XDB_PATH);
|
||||
} else {
|
||||
// 创建临时文件
|
||||
File v6TempXdb = FileUtil.writeFromStream(ResourceUtil.getStream(DEFAULT_IPV4_XDB_PATH), FileUtil.createTempFile());
|
||||
|
||||
v6Config = Config.custom()
|
||||
.setCachePolicy(Config.BufferCache)
|
||||
//.setXdbFile(v6TempXdb)
|
||||
.setXdbInputStream(v6XdbInputStream)
|
||||
.setCacheSliceBytes(DEFAULT_CACHE_SLICE_BYTES)
|
||||
.setXdbFile(v6TempXdb)
|
||||
// .setXdbInputStream(v6XdbInputStream)
|
||||
.asV6();
|
||||
|
||||
// 删除临时文件
|
||||
v6TempXdb.delete();
|
||||
}
|
||||
|
||||
// 初始化Ip2Region实例
|
||||
|
||||
@@ -51,7 +51,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送文本邮件,发送给单个或多个收件人<br>
|
||||
* 使用配置文件中设置的账户发送文本邮件,发送给单个或多个收件人<br>
|
||||
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
*
|
||||
* @param to 收件人
|
||||
@@ -66,7 +66,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送HTML邮件,发送给单个或多个收件人<br>
|
||||
* 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人<br>
|
||||
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
*
|
||||
* @param to 收件人
|
||||
@@ -81,7 +81,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送单个或多个收件人<br>
|
||||
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
|
||||
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
*
|
||||
* @param to 收件人
|
||||
@@ -96,7 +96,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送单个或多个收件人<br>
|
||||
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
|
||||
* 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
*
|
||||
* @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
@@ -114,7 +114,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送文本邮件,发送给多人
|
||||
* 使用配置文件中设置的账户发送文本邮件,发送给多人
|
||||
*
|
||||
* @param tos 收件人列表
|
||||
* @param subject 标题
|
||||
@@ -127,7 +127,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送HTML邮件,发送给多人
|
||||
* 使用配置文件中设置的账户发送HTML邮件,发送给多人
|
||||
*
|
||||
* @param tos 收件人列表
|
||||
* @param subject 标题
|
||||
@@ -141,7 +141,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送给多人
|
||||
* 使用配置文件中设置的账户发送邮件,发送给多人
|
||||
*
|
||||
* @param tos 收件人列表
|
||||
* @param subject 标题
|
||||
@@ -155,7 +155,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送给多人
|
||||
* 使用配置文件中设置的账户发送邮件,发送给多人
|
||||
*
|
||||
* @param tos 收件人列表
|
||||
* @param ccs 抄送人列表,可以为null或空
|
||||
@@ -223,7 +223,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送HTML邮件,发送给单个或多个收件人<br>
|
||||
* 使用配置文件中设置的账户发送HTML邮件,发送给单个或多个收件人<br>
|
||||
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
*
|
||||
* @param to 收件人
|
||||
@@ -239,7 +239,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送单个或多个收件人<br>
|
||||
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
|
||||
* 多个收件人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
*
|
||||
* @param to 收件人
|
||||
@@ -255,7 +255,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送单个或多个收件人<br>
|
||||
* 使用配置文件中设置的账户发送邮件,发送单个或多个收件人<br>
|
||||
* 多个收件人、抄送人、密送人可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
*
|
||||
* @param to 收件人,可以使用逗号“,”分隔,也可以通过分号“;”分隔
|
||||
@@ -274,7 +274,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送HTML邮件,发送给多人
|
||||
* 使用配置文件中设置的账户发送HTML邮件,发送给多人
|
||||
*
|
||||
* @param tos 收件人列表
|
||||
* @param subject 标题
|
||||
@@ -289,7 +289,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送给多人
|
||||
* 使用配置文件中设置的账户发送邮件,发送给多人
|
||||
*
|
||||
* @param tos 收件人列表
|
||||
* @param subject 标题
|
||||
@@ -304,7 +304,7 @@ public class MailUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用配置文件中设置的帐户发送邮件,发送给多人
|
||||
* 使用配置文件中设置的账户发送邮件,发送给多人
|
||||
*
|
||||
* @param tos 收件人列表
|
||||
* @param ccs 抄送人列表,可以为null或空
|
||||
@@ -380,7 +380,7 @@ public class MailUtils {
|
||||
/**
|
||||
* 根据配置文件,获取邮件客户端会话
|
||||
*
|
||||
* @param mailAccount 邮件帐户配置
|
||||
* @param mailAccount 邮件账户配置
|
||||
* @param isSingleton 是否单例(全局共享会话)
|
||||
* @return {@link Session}
|
||||
* @since 5.5.7
|
||||
|
||||
@@ -141,8 +141,7 @@ public class OssClient {
|
||||
try {
|
||||
// 构建上传请求对象
|
||||
FileUpload fileUpload = transferManager.uploadFile(
|
||||
x -> {
|
||||
x.source(filePath).putObjectRequest(
|
||||
x -> x.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentMD5(StringUtils.isNotEmpty(md5Digest) ? md5Digest : null)
|
||||
@@ -150,13 +149,10 @@ public class OssClient {
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
//.acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build()
|
||||
);
|
||||
if (log.isDebugEnabled()) {
|
||||
x.addTransferListener(LoggingTransferListener.create());
|
||||
}
|
||||
}
|
||||
);
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
.source(filePath).build());
|
||||
|
||||
// 等待上传完成并获取上传结果
|
||||
CompletedFileUpload uploadResult = fileUpload.completionFuture().join();
|
||||
String eTag = uploadResult.response().eTag();
|
||||
@@ -196,21 +192,16 @@ public class OssClient {
|
||||
|
||||
// 使用 transferManager 进行上传
|
||||
Upload upload = transferManager.upload(
|
||||
x -> {
|
||||
x.requestBody(body).putObjectRequest(
|
||||
x -> x.requestBody(body).addTransferListener(LoggingTransferListener.create())
|
||||
.putObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.contentType(contentType)
|
||||
// 用于设置对象的访问控制列表(ACL)。不同云厂商对ACL的支持和实现方式有所不同,
|
||||
// 因此根据具体的云服务提供商,你可能需要进行不同的配置(自行开启,阿里云有acl权限配置,腾讯云没有acl权限配置)
|
||||
//.acl(getAccessPolicy().getObjectCannedACL())
|
||||
.build()
|
||||
);
|
||||
if (log.isDebugEnabled()) {
|
||||
x.addTransferListener(LoggingTransferListener.create());
|
||||
}
|
||||
}
|
||||
);
|
||||
.build())
|
||||
.build());
|
||||
|
||||
// 将输入流写入请求体
|
||||
body.writeInputStream(inputStream);
|
||||
@@ -238,17 +229,13 @@ public class OssClient {
|
||||
Path tempFilePath = FileUtils.createTempFile().toPath();
|
||||
// 使用 S3TransferManager 下载文件
|
||||
FileDownload downloadFile = transferManager.downloadFile(
|
||||
x -> {
|
||||
x.destination(tempFilePath).getObjectRequest(
|
||||
x -> x.getObjectRequest(
|
||||
y -> y.bucket(properties.getBucketName())
|
||||
.key(removeBaseUrl(path))
|
||||
.build()
|
||||
);
|
||||
if (log.isDebugEnabled()) {
|
||||
x.addTransferListener(LoggingTransferListener.create());
|
||||
}
|
||||
}
|
||||
);
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
.destination(tempFilePath)
|
||||
.build());
|
||||
// 等待文件下载操作完成
|
||||
downloadFile.completionFuture().join();
|
||||
return tempFilePath;
|
||||
@@ -257,8 +244,8 @@ public class OssClient {
|
||||
/**
|
||||
* 下载文件从 Amazon S3 到 输出流
|
||||
*
|
||||
* @param key 文件在 Amazon S3 中的对象键
|
||||
* @param out 输出流
|
||||
* @param key 文件在 Amazon S3 中的对象键
|
||||
* @param out 输出流
|
||||
* @param consumer 自定义处理逻辑
|
||||
* @throws OssException 如果下载失败,抛出自定义异常
|
||||
*/
|
||||
@@ -273,24 +260,26 @@ 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.TypedBuilder<ResponsePublisher<GetObjectResponse>> typedBuilder = DownloadRequest.builder()
|
||||
// 构建下载请求
|
||||
DownloadRequest<ResponsePublisher<GetObjectResponse>> publisherDownloadRequest = DownloadRequest.builder()
|
||||
// 文件对象
|
||||
.getObjectRequest(y -> y.bucket(properties.getBucketName())
|
||||
.key(key)
|
||||
.build())
|
||||
.addTransferListener(LoggingTransferListener.create())
|
||||
// 使用发布订阅转换器
|
||||
.responseTransformer(AsyncResponseTransformer.toPublisher())
|
||||
// 文件对象
|
||||
.getObjectRequest(y -> y.bucket(properties.getBucketName()).key(key).build());
|
||||
if (log.isDebugEnabled()) {
|
||||
typedBuilder.addTransferListener(LoggingTransferListener.create());
|
||||
}
|
||||
.build();
|
||||
|
||||
// 使用 S3TransferManager 下载文件
|
||||
Download<ResponsePublisher<GetObjectResponse>> publisherDownload = transferManager.download(typedBuilder.build());
|
||||
Download<ResponsePublisher<GetObjectResponse>> publisherDownload = transferManager.download(publisherDownloadRequest);
|
||||
// 获取下载发布订阅转换器
|
||||
ResponsePublisher<GetObjectResponse> publisher = publisherDownload.completionFuture().join().result();
|
||||
// 执行文件大小消费者函数
|
||||
@@ -300,7 +289,7 @@ public class OssClient {
|
||||
// 构建写出订阅器对象
|
||||
return out -> {
|
||||
// 创建可写入的字节通道
|
||||
try (WritableByteChannel channel = Channels.newChannel(out)) {
|
||||
try(WritableByteChannel channel = Channels.newChannel(out)){
|
||||
// 订阅数据
|
||||
publisher.subscribe(byteBuffer -> {
|
||||
while (byteBuffer.hasRemaining()) {
|
||||
@@ -358,7 +347,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
|
||||
|
||||
@@ -99,7 +99,7 @@ public class LoginHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户帐户
|
||||
* 获取用户账户
|
||||
*/
|
||||
public static String getUsername() {
|
||||
return Convert.toStr(getExtra(USER_NAME_KEY));
|
||||
|
||||
@@ -14,7 +14,6 @@ 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;
|
||||
@@ -26,7 +25,6 @@ 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;
|
||||
|
||||
@@ -193,16 +191,6 @@ 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 格式出错时抛出)
|
||||
* 可能是请求体格式非法,也可能是服务端反序列化失败
|
||||
|
||||
@@ -8,7 +8,6 @@ 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;
|
||||
@@ -34,7 +33,7 @@ public class PlusWebSocketHandler extends AbstractWebSocketHandler {
|
||||
log.info("[connect] invalid token received. sessionId: {}", session.getId());
|
||||
return;
|
||||
}
|
||||
WebSocketSessionHolder.addSession(loginUser.getUserId(), new ConcurrentWebSocketSessionDecorator(session, 10 * 1000, 64000));
|
||||
WebSocketSessionHolder.addSession(loginUser.getUserId(), session);
|
||||
log.info("[connect] sessionId: {},userId:{},userType:{}", session.getId(), loginUser.getUserId(), loginUser.getUserType());
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ public class WebSocketUtils {
|
||||
* @param session WebSocket会话
|
||||
* @param message 要发送的WebSocket消息对象
|
||||
*/
|
||||
private static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
|
||||
private synchronized static void sendMessage(WebSocketSession session, WebSocketMessage<?> message) {
|
||||
if (session == null || !session.isOpen()) {
|
||||
log.warn("[send] session会话已经关闭");
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
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");
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class SysLogininforController extends BaseController {
|
||||
}
|
||||
|
||||
@SaCheckPermission("monitor:logininfor:unlock")
|
||||
@Log(title = "帐户解锁", businessType = BusinessType.OTHER)
|
||||
@Log(title = "账户解锁", businessType = BusinessType.OTHER)
|
||||
@RepeatSubmit()
|
||||
@GetMapping("/unlock/{userName}")
|
||||
public R<Void> unlock(@PathVariable("userName") String userName) {
|
||||
|
||||
@@ -137,8 +137,6 @@ 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));
|
||||
}
|
||||
@@ -158,8 +156,6 @@ 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));
|
||||
}
|
||||
|
||||
@@ -130,11 +130,11 @@ public class SysMenu extends BaseEntity {
|
||||
public String getRouterPath() {
|
||||
String routerPath = this.path;
|
||||
// 内链打开外网方式
|
||||
if (!Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) {
|
||||
if (getParentId() != 0L && isInnerLink()) {
|
||||
routerPath = innerLinkReplaceEach(routerPath);
|
||||
}
|
||||
// 非外链并且是一级目录(类型为目录)
|
||||
if (Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(getMenuType())
|
||||
if (0L == 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) && !Constants.TOP_PARENT_ID.equals(getParentId()) && isInnerLink()) {
|
||||
} else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && 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 Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_MENU.equals(menuType) && isFrame.equals(SystemConstants.NO_FRAME);
|
||||
return getParentId() == 0L && 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 !Constants.TOP_PARENT_ID.equals(getParentId()) && SystemConstants.TYPE_DIR.equals(menuType);
|
||||
return getParentId() != 0L && SystemConstants.TYPE_DIR.equals(menuType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -160,13 +160,4 @@ public interface ISysMenuService {
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkMenuNameUnique(SysMenuBo menu);
|
||||
|
||||
/**
|
||||
* 校验路由组合是否唯一
|
||||
*
|
||||
* @param menu 菜单信息
|
||||
* @return 结果
|
||||
*/
|
||||
boolean checkRouteConfigUnique(SysMenuBo menu);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ 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;
|
||||
@@ -30,17 +29,13 @@ import org.dromara.system.service.ISysMenuService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 菜单 业务层处理
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class SysMenuServiceImpl implements ISysMenuService {
|
||||
@@ -358,43 +353,6 @@ 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));
|
||||
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获取所有子节点
|
||||
*
|
||||
|
||||
@@ -580,10 +580,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户帐户
|
||||
* 通过用户ID查询用户账户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户帐户
|
||||
* @return 用户账户
|
||||
*/
|
||||
@Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId")
|
||||
@Override
|
||||
@@ -594,10 +594,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户帐户
|
||||
* 通过用户ID查询用户账户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户帐户
|
||||
* @return 用户账户
|
||||
*/
|
||||
@Override
|
||||
@Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId")
|
||||
@@ -608,10 +608,10 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户帐户
|
||||
* 通过用户ID查询用户账户
|
||||
*
|
||||
* @param userIds 用户ID 多个用逗号隔开
|
||||
* @return 用户帐户
|
||||
* @return 用户账户
|
||||
*/
|
||||
@Override
|
||||
public String selectNicknameByIds(String userIds) {
|
||||
|
||||
@@ -74,7 +74,7 @@ public class WorkflowGlobalListener implements GlobalListener {
|
||||
String ext = listenerVariable.getNode().getExt();
|
||||
if (StringUtils.isNotBlank(ext)) {
|
||||
Map<String, Object> variable = listenerVariable.getVariable();
|
||||
if (CollUtil.isEmpty(variable)) {
|
||||
if (CollUtil.isNotEmpty(variable)) {
|
||||
variable = new HashMap<>();
|
||||
}
|
||||
NodeExtVo nodeExt = nodeExtService.parseNodeExt(ext, variable);
|
||||
|
||||
@@ -518,7 +518,7 @@ insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', 1,
|
||||
insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, sysdate, null, null, '');
|
||||
insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, sysdate, null, null, '');
|
||||
insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, sysdate, null, null, '');
|
||||
insert into sys_menu values('1050', '帐户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate, null, null, '');
|
||||
insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate, null, null, '');
|
||||
-- 在线用户按钮
|
||||
insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 103, 1, sysdate, null, null, '');
|
||||
insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate, null, null, '');
|
||||
|
||||
@@ -519,7 +519,7 @@ insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', '1'
|
||||
insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, now(), null, null, '');
|
||||
insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, now(), null, null, '');
|
||||
insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, now(), null, null, '');
|
||||
insert into sys_menu values('1050', '帐户解锁', '501', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, now(), null, null, '');
|
||||
insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, now(), null, null, '');
|
||||
-- 在线用户按钮
|
||||
insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:query', '#', 103, 1, now(), null, null, '');
|
||||
insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', '1', '0', 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, now(), null, null, '');
|
||||
|
||||
@@ -353,7 +353,7 @@ insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', '', 1,
|
||||
insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 103, 1, sysdate(), null, null, '');
|
||||
insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 103, 1, sysdate(), null, null, '');
|
||||
insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 103, 1, sysdate(), null, null, '');
|
||||
insert into sys_menu values('1050', '帐户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate(), null, null, '');
|
||||
insert into sys_menu values('1050', '账户解锁', '501', '4', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 103, 1, sysdate(), null, null, '');
|
||||
-- 在线用户按钮
|
||||
insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 103, 1, sysdate(), null, null, '');
|
||||
insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 103, 1, sysdate(), null, null, '');
|
||||
|
||||
@@ -1801,7 +1801,7 @@ INSERT sys_menu VALUES (1044, N'登录删除', 501, 2, N'#', N'', N'', 1, 0, N'F
|
||||
GO
|
||||
INSERT sys_menu VALUES (1045, N'日志导出', 501, 3, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:export', N'#', 103, 1, getdate(), NULL, NULL, N'')
|
||||
GO
|
||||
INSERT sys_menu VALUES (1050, N'帐户解锁', 501, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:unlock', N'#', 103, 1, getdate(), NULL, NULL, N'')
|
||||
INSERT sys_menu VALUES (1050, N'账户解锁', 501, 4, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:logininfor:unlock', N'#', 103, 1, getdate(), NULL, NULL, N'')
|
||||
GO
|
||||
INSERT sys_menu VALUES (1046, N'在线查询', 109, 1, N'#', N'', N'', 1, 0, N'F', N'0', N'0', N'monitor:online:query', N'#', 103, 1, getdate(), NULL, NULL, N'')
|
||||
GO
|
||||
|
||||
Reference in New Issue
Block a user