mirror of
https://gitee.com/dromara/RuoYi-Vue-Plus.git
synced 2026-09-19 01:48:47 +08:00
Merge remote-tracking branch 'origin/dev' into warm-flow-future
# Conflicts: # ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java # ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java # ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java
This commit is contained in:
commit
b04c9bee21
@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
<configuration default="false" name="ruoyi-monitor-admin" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||||
<deployment type="dockerfile">
|
<deployment type="dockerfile">
|
||||||
<settings>
|
<settings>
|
||||||
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.2" />
|
<option name="imageTag" value="ruoyi/ruoyi-monitor-admin:5.2.3" />
|
||||||
<option name="buildOnly" value="true" />
|
<option name="buildOnly" value="true" />
|
||||||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
|
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-monitor-admin/Dockerfile" />
|
||||||
</settings>
|
</settings>
|
||||||
|
|||||||
@ -2,11 +2,11 @@
|
|||||||
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="演示机">
|
<configuration default="false" name="ruoyi-server" type="docker-deploy" factoryName="dockerfile" server-name="演示机">
|
||||||
<deployment type="dockerfile">
|
<deployment type="dockerfile">
|
||||||
<settings>
|
<settings>
|
||||||
<option name="imageTag" value="ruoyi/ruoyi-server:5.2.2" />
|
<option name="imageTag" value="ruoyi/ruoyi-server:5.2.3" />
|
||||||
<option name="buildOnly" value="true" />
|
<option name="buildOnly" value="true" />
|
||||||
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
|
<option name="sourceFilePath" value="ruoyi-admin/Dockerfile" />
|
||||||
</settings>
|
</settings>
|
||||||
</deployment>
|
</deployment>
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
<configuration default="false" name="ruoyi-snailjob-server" type="docker-deploy" factoryName="dockerfile" server-name="Docker">
|
||||||
<deployment type="dockerfile">
|
<deployment type="dockerfile">
|
||||||
<settings>
|
<settings>
|
||||||
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.2" />
|
<option name="imageTag" value="ruoyi/ruoyi-snailjob-server:5.2.3" />
|
||||||
<option name="buildOnly" value="true" />
|
<option name="buildOnly" value="true" />
|
||||||
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
|
<option name="sourceFilePath" value="ruoyi-extend/ruoyi-snailjob-server/Dockerfile" />
|
||||||
</settings>
|
</settings>
|
||||||
|
|||||||
@ -6,11 +6,12 @@
|
|||||||
|
|
||||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||||
[](https://github.com/dromara/RuoYi-Vue-Plus)
|
[](https://github.com/dromara/RuoYi-Vue-Plus)
|
||||||
|
[](https://gitcode.com/dromara/RuoYi-Vue-Plus)
|
||||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
|
[](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE)
|
||||||
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
[](https://www.jetbrains.com/?from=RuoYi-Vue-Plus)
|
||||||
<br>
|
<br>
|
||||||
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
[](https://gitee.com/dromara/RuoYi-Vue-Plus)
|
||||||
[]()
|
[]()
|
||||||
[]()
|
[]()
|
||||||
[]()
|
[]()
|
||||||
|
|
||||||
|
|||||||
20
pom.xml
20
pom.xml
@ -13,8 +13,8 @@
|
|||||||
<description>RuoYi-Vue-Plus多租户管理系统</description>
|
<description>RuoYi-Vue-Plus多租户管理系统</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<revision>5.2.2</revision>
|
<revision>5.2.3</revision>
|
||||||
<spring-boot.version>3.2.10</spring-boot.version>
|
<spring-boot.version>3.3.5</spring-boot.version>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<java.version>17</java.version>
|
<java.version>17</java.version>
|
||||||
@ -24,15 +24,15 @@
|
|||||||
<easyexcel.version>4.0.3</easyexcel.version>
|
<easyexcel.version>4.0.3</easyexcel.version>
|
||||||
<velocity.version>2.3</velocity.version>
|
<velocity.version>2.3</velocity.version>
|
||||||
<satoken.version>1.39.0</satoken.version>
|
<satoken.version>1.39.0</satoken.version>
|
||||||
<mybatis-plus.version>3.5.8</mybatis-plus.version>
|
<mybatis-plus.version>3.5.9</mybatis-plus.version>
|
||||||
<p6spy.version>3.9.1</p6spy.version>
|
<p6spy.version>3.9.1</p6spy.version>
|
||||||
<hutool.version>5.8.31</hutool.version>
|
<hutool.version>5.8.31</hutool.version>
|
||||||
<spring-boot-admin.version>3.2.3</spring-boot-admin.version>
|
<spring-boot-admin.version>3.3.4</spring-boot-admin.version>
|
||||||
<redisson.version>3.36.0</redisson.version>
|
<redisson.version>3.37.0</redisson.version>
|
||||||
<lock4j.version>2.2.7</lock4j.version>
|
<lock4j.version>2.2.7</lock4j.version>
|
||||||
<dynamic-ds.version>4.3.1</dynamic-ds.version>
|
<dynamic-ds.version>4.3.1</dynamic-ds.version>
|
||||||
<snailjob.version>1.1.2</snailjob.version>
|
<snailjob.version>1.1.2</snailjob.version>
|
||||||
<mapstruct-plus.version>1.4.4</mapstruct-plus.version>
|
<mapstruct-plus.version>1.4.5</mapstruct-plus.version>
|
||||||
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
|
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
|
||||||
<lombok.version>1.18.34</lombok.version>
|
<lombok.version>1.18.34</lombok.version>
|
||||||
<bouncycastle.version>1.76</bouncycastle.version>
|
<bouncycastle.version>1.76</bouncycastle.version>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
<!-- 限制框架中的fastjson版本 -->
|
<!-- 限制框架中的fastjson版本 -->
|
||||||
<fastjson.version>1.2.83</fastjson.version>
|
<fastjson.version>1.2.83</fastjson.version>
|
||||||
<!-- 面向运行时的D-ORM依赖 -->
|
<!-- 面向运行时的D-ORM依赖 -->
|
||||||
<anyline.version>8.7.2-20240930</anyline.version>
|
<anyline.version>8.7.2-20241022</anyline.version>
|
||||||
<!--工作流配置-->
|
<!--工作流配置-->
|
||||||
<warm-flow.version>1.3.0</warm-flow.version>
|
<warm-flow.version>1.3.0</warm-flow.version>
|
||||||
|
|
||||||
@ -226,6 +226,12 @@
|
|||||||
<version>${mybatis-plus.version}</version>
|
<version>${mybatis-plus.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||||
|
<version>${mybatis-plus.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>mybatis-plus-annotation</artifactId>
|
<artifactId>mybatis-plus-annotation</artifactId>
|
||||||
|
|||||||
@ -84,11 +84,11 @@ public class SysRegisterService {
|
|||||||
String captcha = RedisUtils.getCacheObject(verifyKey);
|
String captcha = RedisUtils.getCacheObject(verifyKey);
|
||||||
RedisUtils.deleteObject(verifyKey);
|
RedisUtils.deleteObject(verifyKey);
|
||||||
if (captcha == null) {
|
if (captcha == null) {
|
||||||
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.expire"));
|
recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"));
|
||||||
throw new CaptchaExpireException();
|
throw new CaptchaExpireException();
|
||||||
}
|
}
|
||||||
if (!code.equalsIgnoreCase(captcha)) {
|
if (!code.equalsIgnoreCase(captcha)) {
|
||||||
recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.jcaptcha.error"));
|
recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"));
|
||||||
throw new CaptchaException();
|
throw new CaptchaException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -110,15 +110,12 @@ sa-token:
|
|||||||
security:
|
security:
|
||||||
# 排除路径
|
# 排除路径
|
||||||
excludes:
|
excludes:
|
||||||
# 静态资源
|
|
||||||
- /*.html
|
- /*.html
|
||||||
- /**/*.html
|
- /**/*.html
|
||||||
- /**/*.css
|
- /**/*.css
|
||||||
- /**/*.js
|
- /**/*.js
|
||||||
# 公共路径
|
|
||||||
- /favicon.ico
|
- /favicon.ico
|
||||||
- /error
|
- /error
|
||||||
# swagger 文档配置
|
|
||||||
- /*/api-docs
|
- /*/api-docs
|
||||||
- /*/api-docs/**
|
- /*/api-docs/**
|
||||||
# warm-flow-ui
|
# warm-flow-ui
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<revision>5.2.2</revision>
|
<revision>5.2.3</revision>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
|||||||
@ -43,6 +43,23 @@ public class TreeBuildUtils extends TreeUtil {
|
|||||||
return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser);
|
return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建树形结构
|
||||||
|
*
|
||||||
|
* @param <T> 输入节点的类型
|
||||||
|
* @param <K> 节点ID的类型
|
||||||
|
* @param parentId 顶级节点
|
||||||
|
* @param list 节点列表,其中包含了要构建树形结构的所有节点
|
||||||
|
* @param nodeParser 解析器,用于将输入节点转换为树节点
|
||||||
|
* @return 构建好的树形结构列表
|
||||||
|
*/
|
||||||
|
public static <T, K> List<Tree<K>> build(List<T> list, K parentId, NodeParser<T, K> nodeParser) {
|
||||||
|
if (CollUtil.isEmpty(list)) {
|
||||||
|
return CollUtil.newArrayList();
|
||||||
|
}
|
||||||
|
return TreeUtil.build(list, parentId, DEFAULT_CONFIG, nodeParser);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取节点列表中所有节点的叶子节点
|
* 获取节点列表中所有节点的叶子节点
|
||||||
*
|
*
|
||||||
|
|||||||
@ -55,6 +55,7 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|||||||
* 下拉可选项
|
* 下拉可选项
|
||||||
*/
|
*/
|
||||||
private final List<DropDownOptions> dropDownOptions;
|
private final List<DropDownOptions> dropDownOptions;
|
||||||
|
private final DictService dictService;
|
||||||
/**
|
/**
|
||||||
* 当前单选进度
|
* 当前单选进度
|
||||||
*/
|
*/
|
||||||
@ -63,7 +64,6 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|||||||
* 当前联动选择进度
|
* 当前联动选择进度
|
||||||
*/
|
*/
|
||||||
private int currentLinkedOptionsSheetIndex;
|
private int currentLinkedOptionsSheetIndex;
|
||||||
private final DictService dictService;
|
|
||||||
|
|
||||||
public ExcelDownHandler(List<DropDownOptions> options) {
|
public ExcelDownHandler(List<DropDownOptions> options) {
|
||||||
this.dropDownOptions = options;
|
this.dropDownOptions = options;
|
||||||
@ -139,8 +139,8 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|||||||
} else if (everyOptions.getOptions().size() > 10) {
|
} else if (everyOptions.getOptions().size() > 10) {
|
||||||
// 当一级选项参数个数大于10,使用额外表的形式
|
// 当一级选项参数个数大于10,使用额外表的形式
|
||||||
dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions());
|
dropDownWithSheet(helper, workbook, sheet, everyOptions.getIndex(), everyOptions.getOptions());
|
||||||
} else if (everyOptions.getOptions().size() != 0) {
|
} else {
|
||||||
// 当一级选项个数不为空,使用默认形式
|
// 否则使用默认形式
|
||||||
dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions());
|
dropDownWithSimple(helper, sheet, everyOptions.getIndex(), everyOptions.getOptions());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -171,10 +171,24 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|||||||
Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName));
|
Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName));
|
||||||
// 将下拉表隐藏
|
// 将下拉表隐藏
|
||||||
workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true);
|
workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true);
|
||||||
// 完善横向的一级选项数据表
|
// 选项数据
|
||||||
List<String> firstOptions = options.getOptions();
|
List<String> firstOptions = options.getOptions();
|
||||||
Map<String, List<String>> secoundOptionsMap = options.getNextOptions();
|
Map<String, List<String>> secoundOptionsMap = options.getNextOptions();
|
||||||
|
|
||||||
|
// 采用按行填充数据的方式,避免EasyExcel出现数据无法写入的问题
|
||||||
|
// Attempting to write a row in the range that is already written to disk
|
||||||
|
|
||||||
|
// 使用ArrayList记载数据,防止乱序
|
||||||
|
List<String> columnNames = new ArrayList<>();
|
||||||
|
// 写入第一行,即第一级的数据
|
||||||
|
Row firstRow = linkedOptionsDataSheet.createRow(0);
|
||||||
|
for (int columnIndex = 0; columnIndex < firstOptions.size(); columnIndex++) {
|
||||||
|
String columnName = firstOptions.get(columnIndex);
|
||||||
|
firstRow.createCell(columnIndex)
|
||||||
|
.setCellValue(columnName);
|
||||||
|
columnNames.add(columnName);
|
||||||
|
}
|
||||||
|
|
||||||
// 创建名称管理器
|
// 创建名称管理器
|
||||||
Name name = workbook.createName();
|
Name name = workbook.createName();
|
||||||
// 设置名称管理器的别名
|
// 设置名称管理器的别名
|
||||||
@ -190,28 +204,12 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|||||||
// 设置数据校验为序列模式,引用的是名称管理器中的别名
|
// 设置数据校验为序列模式,引用的是名称管理器中的别名
|
||||||
this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName));
|
this.markOptionsToSheet(helper, sheet, options.getIndex(), helper.createFormulaListConstraint(linkedOptionsSheetName));
|
||||||
|
|
||||||
for (int columIndex = 0; columIndex < firstOptions.size(); columIndex++) {
|
// 创建二级选项的名称管理器
|
||||||
// 先提取主表中一级下拉的列名
|
for (int columIndex = 0; columIndex < columnNames.size(); columIndex++) {
|
||||||
|
// 列名
|
||||||
String firstOptionsColumnName = getExcelColumnName(columIndex);
|
String firstOptionsColumnName = getExcelColumnName(columIndex);
|
||||||
// 一次循环是每一个一级选项
|
// 对应的一级值
|
||||||
int finalI = columIndex;
|
String thisFirstOptionsValue = columnNames.get(columIndex);
|
||||||
// 本次循环的一级选项值
|
|
||||||
String thisFirstOptionsValue = firstOptions.get(columIndex);
|
|
||||||
// 创建第一行的数据
|
|
||||||
Optional.ofNullable(linkedOptionsDataSheet.getRow(0))
|
|
||||||
// 如果不存在则创建第一行
|
|
||||||
.orElseGet(() -> linkedOptionsDataSheet.createRow(finalI))
|
|
||||||
// 第一行当前列
|
|
||||||
.createCell(columIndex)
|
|
||||||
// 设置值为当前一级选项值
|
|
||||||
.setCellValue(thisFirstOptionsValue);
|
|
||||||
|
|
||||||
// 第二行开始,设置第二级别选项参数
|
|
||||||
List<String> secondOptions = secoundOptionsMap.get(thisFirstOptionsValue);
|
|
||||||
if (CollUtil.isEmpty(secondOptions)) {
|
|
||||||
// 必须保证至少有一个关联选项,否则将导致Excel解析错误
|
|
||||||
secondOptions = Collections.singletonList("暂无_0");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 以该一级选项值创建子名称管理器
|
// 以该一级选项值创建子名称管理器
|
||||||
Name sonName = workbook.createName();
|
Name sonName = workbook.createName();
|
||||||
@ -222,7 +220,9 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|||||||
linkedOptionsSheetName,
|
linkedOptionsSheetName,
|
||||||
firstOptionsColumnName,
|
firstOptionsColumnName,
|
||||||
firstOptionsColumnName,
|
firstOptionsColumnName,
|
||||||
secondOptions.size() + 1
|
// 二级选项存在则设置为(选项个数+1)行,否则设置为2行
|
||||||
|
Math.max(Optional.ofNullable(secoundOptionsMap.get(thisFirstOptionsValue))
|
||||||
|
.orElseGet(ArrayList::new).size(), 1) + 1
|
||||||
);
|
);
|
||||||
// 设置名称管理器的引用位置
|
// 设置名称管理器的引用位置
|
||||||
sonName.setRefersToFormula(sonFunction);
|
sonName.setRefersToFormula(sonFunction);
|
||||||
@ -235,25 +235,51 @@ public class ExcelDownHandler implements SheetWriteHandler {
|
|||||||
// 二级只能主表每一行的每一列添加二级校验
|
// 二级只能主表每一行的每一列添加二级校验
|
||||||
markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction));
|
markLinkedOptionsToSheet(helper, sheet, i, options.getNextIndex(), helper.createFormulaListConstraint(secondOptionsFunction));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int rowIndex = 0; rowIndex < secondOptions.size(); rowIndex++) {
|
// 将二级数据处理为按行区分
|
||||||
// 从第二行开始填充二级选项
|
Map<Integer, List<String>> columnValueMap = new HashMap<>();
|
||||||
int finalRowIndex = rowIndex + 1;
|
int currentRow = 1;
|
||||||
int finalColumIndex = columIndex;
|
while (currentRow >= 0) {
|
||||||
|
boolean flag = false;
|
||||||
Row row = Optional.ofNullable(linkedOptionsDataSheet.getRow(finalRowIndex))
|
List<String> rowData = new ArrayList<>();
|
||||||
// 没有则创建
|
for (String columnName : columnNames) {
|
||||||
.orElseGet(() -> linkedOptionsDataSheet.createRow(finalRowIndex));
|
List<String> data = secoundOptionsMap.get(columnName);
|
||||||
Optional
|
if (CollUtil.isEmpty(data)) {
|
||||||
// 在本级一级选项所在的列
|
// 添加空字符串填充位置
|
||||||
.ofNullable(row.getCell(finalColumIndex))
|
rowData.add(" ");
|
||||||
// 不存在则创建
|
continue;
|
||||||
.orElseGet(() -> row.createCell(finalColumIndex))
|
}
|
||||||
// 设置二级选项值
|
// 取第一个
|
||||||
.setCellValue(secondOptions.get(rowIndex));
|
String str = data.get(0);
|
||||||
|
rowData.add(str);
|
||||||
|
// 通过移除的方式避免重复
|
||||||
|
data.remove(0);
|
||||||
|
// 设置可以继续
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
columnValueMap.put(currentRow, rowData);
|
||||||
|
// 可以继续,则增加行数,否则置为负数跳出循环
|
||||||
|
if (flag) {
|
||||||
|
currentRow++;
|
||||||
|
} else {
|
||||||
|
currentRow = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 填充第二级选项数据
|
||||||
|
columnValueMap.forEach((rowIndex, rowValues) -> {
|
||||||
|
Row row = linkedOptionsDataSheet.createRow(rowIndex);
|
||||||
|
for (int columnIndex = 0; columnIndex < rowValues.size(); columnIndex++) {
|
||||||
|
String rowValue = rowValues.get(columnIndex);
|
||||||
|
// 填充位置的部分不渲染
|
||||||
|
if (StrUtil.isNotBlank(rowValue)) {
|
||||||
|
row.createCell(columnIndex)
|
||||||
|
.setCellValue(rowValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
currentLinkedOptionsSheetIndex++;
|
currentLinkedOptionsSheetIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,11 @@
|
|||||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.baomidou</groupId>
|
||||||
|
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- sql性能分析插件 -->
|
<!-- sql性能分析插件 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>p6spy</groupId>
|
<groupId>p6spy</groupId>
|
||||||
|
|||||||
@ -0,0 +1,50 @@
|
|||||||
|
package org.dromara.common.mybatis.aspect;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.AfterThrowing;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Before;
|
||||||
|
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||||
|
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据权限处理
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Aspect
|
||||||
|
public class DataPermissionAspect {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理请求前执行
|
||||||
|
*/
|
||||||
|
@Before(value = "@annotation(dataPermission)")
|
||||||
|
public void doBefore(JoinPoint joinPoint, DataPermission dataPermission) {
|
||||||
|
DataPermissionHelper.setPermission(dataPermission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理完请求后执行
|
||||||
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
|
*/
|
||||||
|
@AfterReturning(pointcut = "@annotation(dataPermission)")
|
||||||
|
public void doAfterReturning(JoinPoint joinPoint, DataPermission dataPermission) {
|
||||||
|
DataPermissionHelper.removePermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拦截异常操作
|
||||||
|
*
|
||||||
|
* @param joinPoint 切点
|
||||||
|
* @param e 异常
|
||||||
|
*/
|
||||||
|
@AfterThrowing(value = "@annotation(dataPermission)", throwing = "e")
|
||||||
|
public void doAfterThrowing(JoinPoint joinPoint, DataPermission dataPermission, Exception e) {
|
||||||
|
DataPermissionHelper.removePermission();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerIntercept
|
|||||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||||
import org.dromara.common.core.factory.YmlPropertySourceFactory;
|
import org.dromara.common.core.factory.YmlPropertySourceFactory;
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
import org.dromara.common.core.utils.SpringUtils;
|
||||||
|
import org.dromara.common.mybatis.aspect.DataPermissionAspect;
|
||||||
import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
|
import org.dromara.common.mybatis.handler.InjectionMetaObjectHandler;
|
||||||
import org.dromara.common.mybatis.handler.MybatisExceptionHandler;
|
import org.dromara.common.mybatis.handler.MybatisExceptionHandler;
|
||||||
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
|
import org.dromara.common.mybatis.interceptor.PlusDataPermissionInterceptor;
|
||||||
@ -51,7 +52,15 @@ public class MybatisPlusConfig {
|
|||||||
* 数据权限拦截器
|
* 数据权限拦截器
|
||||||
*/
|
*/
|
||||||
public PlusDataPermissionInterceptor dataPermissionInterceptor() {
|
public PlusDataPermissionInterceptor dataPermissionInterceptor() {
|
||||||
return new PlusDataPermissionInterceptor(SpringUtils.getProperty("mybatis-plus.mapperPackage"));
|
return new PlusDataPermissionInterceptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数据权限切面处理器
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public DataPermissionAspect dataPermissionAspect() {
|
||||||
|
return new DataPermissionAspect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
package org.dromara.common.mybatis.handler;
|
package org.dromara.common.mybatis.handler;
|
||||||
|
|
||||||
import cn.hutool.core.annotation.AnnotationUtil;
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -9,7 +8,6 @@ import net.sf.jsqlparser.expression.Expression;
|
|||||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||||
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
|
import net.sf.jsqlparser.expression.operators.relational.ParenthesedExpressionList;
|
||||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||||
import org.apache.ibatis.io.Resources;
|
|
||||||
import org.dromara.common.core.domain.dto.RoleDTO;
|
import org.dromara.common.core.domain.dto.RoleDTO;
|
||||||
import org.dromara.common.core.domain.model.LoginUser;
|
import org.dromara.common.core.domain.model.LoginUser;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
@ -21,27 +19,17 @@ import org.dromara.common.mybatis.annotation.DataPermission;
|
|||||||
import org.dromara.common.mybatis.enums.DataScopeType;
|
import org.dromara.common.mybatis.enums.DataScopeType;
|
||||||
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
import org.dromara.common.mybatis.helper.DataPermissionHelper;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
|
||||||
import org.springframework.context.expression.BeanFactoryResolver;
|
import org.springframework.context.expression.BeanFactoryResolver;
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
|
||||||
import org.springframework.core.type.ClassMetadata;
|
|
||||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
|
||||||
import org.springframework.expression.BeanResolver;
|
import org.springframework.expression.BeanResolver;
|
||||||
import org.springframework.expression.ExpressionParser;
|
import org.springframework.expression.ExpressionParser;
|
||||||
import org.springframework.expression.ParserContext;
|
import org.springframework.expression.ParserContext;
|
||||||
import org.springframework.expression.common.TemplateParserContext;
|
import org.springframework.expression.common.TemplateParserContext;
|
||||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,11 +41,6 @@ import java.util.function.Function;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class PlusDataPermissionHandler {
|
public class PlusDataPermissionHandler {
|
||||||
|
|
||||||
/**
|
|
||||||
* 方法或类(名称) 与 注解的映射关系缓存
|
|
||||||
*/
|
|
||||||
private final Map<String, DataPermission> dataPermissionCacheMap = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spel 解析器
|
* spel 解析器
|
||||||
*/
|
*/
|
||||||
@ -68,15 +51,6 @@ public class PlusDataPermissionHandler {
|
|||||||
*/
|
*/
|
||||||
private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
|
private final BeanResolver beanResolver = new BeanFactoryResolver(SpringUtils.getBeanFactory());
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造方法,扫描指定包下的 Mapper 类并初始化缓存
|
|
||||||
*
|
|
||||||
* @param mapperPackage Mapper 类所在的包路径
|
|
||||||
*/
|
|
||||||
public PlusDataPermissionHandler(String mapperPackage) {
|
|
||||||
scanMapperClasses(mapperPackage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取数据过滤条件的 SQL 片段
|
* 获取数据过滤条件的 SQL 片段
|
||||||
*
|
*
|
||||||
@ -86,24 +60,24 @@ public class PlusDataPermissionHandler {
|
|||||||
* @return 数据过滤条件的 SQL 片段
|
* @return 数据过滤条件的 SQL 片段
|
||||||
*/
|
*/
|
||||||
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
|
public Expression getSqlSegment(Expression where, String mappedStatementId, boolean isSelect) {
|
||||||
// 获取数据权限配置
|
|
||||||
DataPermission dataPermission = getDataPermission(mappedStatementId);
|
|
||||||
// 获取当前登录用户信息
|
|
||||||
LoginUser currentUser = DataPermissionHelper.getVariable("user");
|
|
||||||
if (ObjectUtil.isNull(currentUser)) {
|
|
||||||
currentUser = LoginHelper.getLoginUser();
|
|
||||||
DataPermissionHelper.setVariable("user", currentUser);
|
|
||||||
}
|
|
||||||
// 如果是超级管理员或租户管理员,则不过滤数据
|
|
||||||
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
|
||||||
return where;
|
|
||||||
}
|
|
||||||
// 构造数据过滤条件的 SQL 片段
|
|
||||||
String dataFilterSql = buildDataFilter(dataPermission, isSelect);
|
|
||||||
if (StringUtils.isBlank(dataFilterSql)) {
|
|
||||||
return where;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
|
// 获取数据权限配置
|
||||||
|
DataPermission dataPermission = DataPermissionHelper.getPermission();
|
||||||
|
// 获取当前登录用户信息
|
||||||
|
LoginUser currentUser = DataPermissionHelper.getVariable("user");
|
||||||
|
if (ObjectUtil.isNull(currentUser)) {
|
||||||
|
currentUser = LoginHelper.getLoginUser();
|
||||||
|
DataPermissionHelper.setVariable("user", currentUser);
|
||||||
|
}
|
||||||
|
// 如果是超级管理员或租户管理员,则不过滤数据
|
||||||
|
if (LoginHelper.isSuperAdmin() || LoginHelper.isTenantAdmin()) {
|
||||||
|
return where;
|
||||||
|
}
|
||||||
|
// 构造数据过滤条件的 SQL 片段
|
||||||
|
String dataFilterSql = buildDataFilter(dataPermission, isSelect);
|
||||||
|
if (StringUtils.isBlank(dataFilterSql)) {
|
||||||
|
return where;
|
||||||
|
}
|
||||||
Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
|
Expression expression = CCJSqlParserUtil.parseExpression(dataFilterSql);
|
||||||
// 数据权限使用单独的括号 防止与其他条件冲突
|
// 数据权限使用单独的括号 防止与其他条件冲突
|
||||||
ParenthesedExpressionList<Expression> parenthesis = new ParenthesedExpressionList<>(expression);
|
ParenthesedExpressionList<Expression> parenthesis = new ParenthesedExpressionList<>(expression);
|
||||||
@ -114,6 +88,8 @@ public class PlusDataPermissionHandler {
|
|||||||
}
|
}
|
||||||
} catch (JSQLParserException e) {
|
} catch (JSQLParserException e) {
|
||||||
throw new ServiceException("数据权限解析异常 => " + e.getMessage());
|
throw new ServiceException("数据权限解析异常 => " + e.getMessage());
|
||||||
|
} finally {
|
||||||
|
DataPermissionHelper.removePermission();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,8 +146,11 @@ public class PlusDataPermissionHandler {
|
|||||||
context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
|
context.setVariable(dataColumn.key()[i], dataColumn.value()[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 忽略数据权限 防止spel表达式内有其他sql查询导致死循环调用
|
||||||
|
String sql = DataPermissionHelper.ignore(() ->
|
||||||
|
parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class)
|
||||||
|
);
|
||||||
// 解析sql模板并填充
|
// 解析sql模板并填充
|
||||||
String sql = parser.parseExpression(type.getSqlTemplate(), parserContext).getValue(context, String.class);
|
|
||||||
conditions.add(joinStr + sql);
|
conditions.add(joinStr + sql);
|
||||||
isSuccess = true;
|
isSuccess = true;
|
||||||
}
|
}
|
||||||
@ -188,87 +167,12 @@ public class PlusDataPermissionHandler {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 扫描指定包下的 Mapper 类,并查找其中带有特定注解的方法或类
|
|
||||||
*
|
|
||||||
* @param mapperPackage Mapper 类所在的包路径
|
|
||||||
*/
|
|
||||||
private void scanMapperClasses(String mapperPackage) {
|
|
||||||
// 创建资源解析器和元数据读取工厂
|
|
||||||
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
|
||||||
CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
|
|
||||||
// 将 Mapper 包路径按分隔符拆分为数组
|
|
||||||
String[] packagePatternArray = StringUtils.splitPreserveAllTokens(mapperPackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
|
|
||||||
String classpath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX;
|
|
||||||
try {
|
|
||||||
for (String packagePattern : packagePatternArray) {
|
|
||||||
// 将包路径转换为资源路径
|
|
||||||
String path = ClassUtils.convertClassNameToResourcePath(packagePattern);
|
|
||||||
// 获取指定路径下的所有 .class 文件资源
|
|
||||||
Resource[] resources = resolver.getResources(classpath + path + "/*.class");
|
|
||||||
for (Resource resource : resources) {
|
|
||||||
// 获取资源的类元数据
|
|
||||||
ClassMetadata classMetadata = factory.getMetadataReader(resource).getClassMetadata();
|
|
||||||
// 获取资源对应的类对象
|
|
||||||
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
|
|
||||||
// 查找类中的特定注解
|
|
||||||
findAnnotation(clazz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("初始化数据安全缓存时出错:{}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在指定的类中查找特定的注解 DataPermission,并将带有这个注解的方法或类存储到 dataPermissionCacheMap 中
|
|
||||||
*
|
|
||||||
* @param clazz 要查找的类
|
|
||||||
*/
|
|
||||||
private void findAnnotation(Class<?> clazz) {
|
|
||||||
DataPermission dataPermission;
|
|
||||||
for (Method method : clazz.getMethods()) {
|
|
||||||
if (method.isDefault() || method.isVarArgs()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String mappedStatementId = clazz.getName() + "." + method.getName();
|
|
||||||
if (AnnotationUtil.hasAnnotation(method, DataPermission.class)) {
|
|
||||||
dataPermission = AnnotationUtil.getAnnotation(method, DataPermission.class);
|
|
||||||
dataPermissionCacheMap.put(mappedStatementId, dataPermission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (AnnotationUtil.hasAnnotation(clazz, DataPermission.class)) {
|
|
||||||
dataPermission = AnnotationUtil.getAnnotation(clazz, DataPermission.class);
|
|
||||||
dataPermissionCacheMap.put(clazz.getName(), dataPermission);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据映射语句 ID 或类名获取对应的 DataPermission 注解对象
|
|
||||||
*
|
|
||||||
* @param mapperId 映射语句 ID
|
|
||||||
* @return DataPermission 注解对象,如果不存在则返回 null
|
|
||||||
*/
|
|
||||||
public DataPermission getDataPermission(String mapperId) {
|
|
||||||
// 检查缓存中是否包含映射语句 ID 对应的 DataPermission 注解对象
|
|
||||||
if (dataPermissionCacheMap.containsKey(mapperId)) {
|
|
||||||
return dataPermissionCacheMap.get(mapperId);
|
|
||||||
}
|
|
||||||
// 如果缓存中不包含映射语句 ID 对应的 DataPermission 注解对象,则尝试使用类名作为键查找
|
|
||||||
String clazzName = mapperId.substring(0, mapperId.lastIndexOf("."));
|
|
||||||
if (dataPermissionCacheMap.containsKey(clazzName)) {
|
|
||||||
return dataPermissionCacheMap.get(clazzName);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象
|
* 检查给定的映射语句 ID 是否有效,即是否能够找到对应的 DataPermission 注解对象
|
||||||
*
|
*
|
||||||
* @param mapperId 映射语句 ID
|
|
||||||
* @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
|
* @return 如果找到对应的 DataPermission 注解对象,则返回 false;否则返回 true
|
||||||
*/
|
*/
|
||||||
public boolean invalid(String mapperId) {
|
public boolean invalid() {
|
||||||
return getDataPermission(mapperId) == null;
|
return DataPermissionHelper.getPermission() == null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,8 +62,8 @@ public class DataBaseHelper {
|
|||||||
// charindex(',100,' , ',0,100,101,') <> 0
|
// charindex(',100,' , ',0,100,101,') <> 0
|
||||||
return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2);
|
return "charindex(',%s,' , ','+%s+',') <> 0".formatted(var, var2);
|
||||||
} else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
|
} else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
|
||||||
// (select position(',100,' in ',0,100,101,')) <> 0
|
// (select strpos(',0,100,101,' , ',100,')) <> 0
|
||||||
return "(select position(',%s,' in ','||%s||',')) <> 0".formatted(var, var2);
|
return "(select strpos(','||%s||',' , ',%s,')) <> 0".formatted(var2, var);
|
||||||
} else if (dataBasyType == DataBaseType.ORACLE) {
|
} else if (dataBasyType == DataBaseType.ORACLE) {
|
||||||
// instr(',0,100,101,' , ',100,') <> 0
|
// instr(',0,100,101,' , ',100,') <> 0
|
||||||
return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var);
|
return "instr(','||%s||',' , ',%s,') <> 0".formatted(var2, var);
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;
|
|||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.dromara.common.core.utils.reflect.ReflectUtils;
|
import org.dromara.common.core.utils.reflect.ReflectUtils;
|
||||||
|
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -29,6 +30,33 @@ public class DataPermissionHelper {
|
|||||||
|
|
||||||
private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
|
private static final ThreadLocal<Stack<Integer>> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new);
|
||||||
|
|
||||||
|
private static final ThreadLocal<DataPermission> PERMISSION_CACHE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前执行mapper权限注解
|
||||||
|
*
|
||||||
|
* @return 返回当前执行mapper权限注解
|
||||||
|
*/
|
||||||
|
public static DataPermission getPermission() {
|
||||||
|
return PERMISSION_CACHE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置当前执行mapper权限注解
|
||||||
|
*
|
||||||
|
* @param dataPermission 数据权限注解
|
||||||
|
*/
|
||||||
|
public static void setPermission(DataPermission dataPermission) {
|
||||||
|
PERMISSION_CACHE.set(dataPermission);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除当前执行mapper权限注解
|
||||||
|
*/
|
||||||
|
public static void removePermission() {
|
||||||
|
PERMISSION_CACHE.remove();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从上下文中获取指定键的变量值,并将其转换为指定的类型
|
* 从上下文中获取指定键的变量值,并将其转换为指定的类型
|
||||||
*
|
*
|
||||||
|
|||||||
@ -39,11 +39,9 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造函数,初始化 PlusDataPermissionHandler 实例
|
* 构造函数,初始化 PlusDataPermissionHandler 实例
|
||||||
*
|
|
||||||
* @param mapperPackage 扫描的映射器包
|
|
||||||
*/
|
*/
|
||||||
public PlusDataPermissionInterceptor(String mapperPackage) {
|
public PlusDataPermissionInterceptor() {
|
||||||
this.dataPermissionHandler = new PlusDataPermissionHandler(mapperPackage);
|
this.dataPermissionHandler = new PlusDataPermissionHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,7 +62,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 检查是否缺少有效的数据权限注解
|
// 检查是否缺少有效的数据权限注解
|
||||||
if (dataPermissionHandler.invalid(ms.getId())) {
|
if (dataPermissionHandler.invalid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 解析 sql 分配对应方法
|
// 解析 sql 分配对应方法
|
||||||
@ -92,7 +90,7 @@ public class PlusDataPermissionInterceptor extends BaseMultiTableInnerIntercepto
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 检查是否缺少有效的数据权限注解
|
// 检查是否缺少有效的数据权限注解
|
||||||
if (dataPermissionHandler.invalid(ms.getId())) {
|
if (dataPermissionHandler.invalid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
|
PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import org.dromara.common.core.utils.file.FileUtils;
|
|||||||
import org.dromara.common.oss.constant.OssConstant;
|
import org.dromara.common.oss.constant.OssConstant;
|
||||||
import org.dromara.common.oss.entity.UploadResult;
|
import org.dromara.common.oss.entity.UploadResult;
|
||||||
import org.dromara.common.oss.enumd.AccessPolicyType;
|
import org.dromara.common.oss.enumd.AccessPolicyType;
|
||||||
import org.dromara.common.oss.enumd.PolicyType;
|
|
||||||
import org.dromara.common.oss.exception.OssException;
|
import org.dromara.common.oss.exception.OssException;
|
||||||
import org.dromara.common.oss.properties.OssProperties;
|
import org.dromara.common.oss.properties.OssProperties;
|
||||||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
|
||||||
@ -22,8 +21,6 @@ import software.amazon.awssdk.services.s3.S3AsyncClient;
|
|||||||
import software.amazon.awssdk.services.s3.S3Configuration;
|
import software.amazon.awssdk.services.s3.S3Configuration;
|
||||||
import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
|
import software.amazon.awssdk.services.s3.crt.S3CrtHttpConfiguration;
|
||||||
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
|
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
|
||||||
import software.amazon.awssdk.services.s3.model.NoSuchBucketException;
|
|
||||||
import software.amazon.awssdk.services.s3.model.S3Exception;
|
|
||||||
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
|
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
|
||||||
import software.amazon.awssdk.transfer.s3.S3TransferManager;
|
import software.amazon.awssdk.transfer.s3.S3TransferManager;
|
||||||
import software.amazon.awssdk.transfer.s3.model.*;
|
import software.amazon.awssdk.transfer.s3.model.*;
|
||||||
@ -83,10 +80,10 @@ public class OssClient {
|
|||||||
StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
|
StaticCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
|
||||||
AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
|
AwsBasicCredentials.create(properties.getAccessKey(), properties.getSecretKey()));
|
||||||
|
|
||||||
//使用对象存储服务时要求明确配置访问样式(路径样式或虚拟托管样式)。需要启用路径样式访问
|
// MinIO 使用 HTTPS 限制使用域名访问,站点填域名。需要启用路径样式访问
|
||||||
boolean isStyle = true;
|
boolean isStyle = !StringUtils.containsAny(properties.getEndpoint(), OssConstant.CLOUD_SERVICE);
|
||||||
|
|
||||||
//创建AWS基于 CRT 的 S3 客户端
|
// 创建AWS基于 CRT 的 S3 客户端
|
||||||
this.client = S3AsyncClient.crtBuilder()
|
this.client = S3AsyncClient.crtBuilder()
|
||||||
.credentialsProvider(credentialsProvider)
|
.credentialsProvider(credentialsProvider)
|
||||||
.endpointOverride(URI.create(getEndpoint()))
|
.endpointOverride(URI.create(getEndpoint()))
|
||||||
@ -115,8 +112,6 @@ public class OssClient {
|
|||||||
.serviceConfiguration(config)
|
.serviceConfiguration(config)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// 创建存储桶
|
|
||||||
createBucket();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (e instanceof OssException) {
|
if (e instanceof OssException) {
|
||||||
throw e;
|
throw e;
|
||||||
@ -125,43 +120,6 @@ public class OssClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 同步创建存储桶
|
|
||||||
* 如果存储桶不存在,会进行创建;如果存储桶存在,不执行任何操作
|
|
||||||
*
|
|
||||||
* @throws OssException 当创建存储桶时发生异常时抛出
|
|
||||||
*/
|
|
||||||
public void createBucket() {
|
|
||||||
String bucketName = properties.getBucketName();
|
|
||||||
try {
|
|
||||||
// 尝试获取存储桶的信息
|
|
||||||
client.headBucket(
|
|
||||||
x -> x.bucket(bucketName)
|
|
||||||
.build())
|
|
||||||
.join();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
if (ex.getCause() instanceof NoSuchBucketException) {
|
|
||||||
try {
|
|
||||||
// 存储桶不存在,尝试创建存储桶
|
|
||||||
client.createBucket(
|
|
||||||
x -> x.bucket(bucketName))
|
|
||||||
.join();
|
|
||||||
|
|
||||||
// 设置存储桶的访问策略(Bucket Policy)
|
|
||||||
client.putBucketPolicy(
|
|
||||||
x -> x.bucket(bucketName)
|
|
||||||
.policy(getPolicy(bucketName, getAccessPolicy().getPolicyType())))
|
|
||||||
.join();
|
|
||||||
} catch (S3Exception e) {
|
|
||||||
// 存储桶创建或策略设置失败
|
|
||||||
throw new OssException("创建Bucket失败, 请核对配置信息:[" + e.getMessage() + "]");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new OssException("判断Bucket是否存在失败,请核对配置信息:[" + ex.getMessage() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传文件到 Amazon S3,并返回上传结果
|
* 上传文件到 Amazon S3,并返回上传结果
|
||||||
*
|
*
|
||||||
@ -529,77 +487,4 @@ public class OssClient {
|
|||||||
return AccessPolicyType.getByType(properties.getAccessPolicy());
|
return AccessPolicyType.getByType(properties.getAccessPolicy());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成 AWS S3 存储桶访问策略
|
|
||||||
*
|
|
||||||
* @param bucketName 存储桶
|
|
||||||
* @param policyType 桶策略类型
|
|
||||||
* @return 符合 AWS S3 存储桶访问策略格式的字符串
|
|
||||||
*/
|
|
||||||
private static String getPolicy(String bucketName, PolicyType policyType) {
|
|
||||||
String policy = switch (policyType) {
|
|
||||||
case WRITE -> """
|
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": []
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
case READ_WRITE -> """
|
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Principal": "*",
|
|
||||||
"Action": [
|
|
||||||
"s3:GetBucketLocation",
|
|
||||||
"s3:ListBucket",
|
|
||||||
"s3:ListBucketMultipartUploads"
|
|
||||||
],
|
|
||||||
"Resource": "arn:aws:s3:::bucketName"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Principal": "*",
|
|
||||||
"Action": [
|
|
||||||
"s3:AbortMultipartUpload",
|
|
||||||
"s3:DeleteObject",
|
|
||||||
"s3:GetObject",
|
|
||||||
"s3:ListMultipartUploadParts",
|
|
||||||
"s3:PutObject"
|
|
||||||
],
|
|
||||||
"Resource": "arn:aws:s3:::bucketName/*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
case READ -> """
|
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Principal": "*",
|
|
||||||
"Action": ["s3:GetBucketLocation"],
|
|
||||||
"Resource": "arn:aws:s3:::bucketName"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Deny",
|
|
||||||
"Principal": "*",
|
|
||||||
"Action": ["s3:ListBucket"],
|
|
||||||
"Resource": "arn:aws:s3:::bucketName"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Principal": "*",
|
|
||||||
"Action": "s3:GetObject",
|
|
||||||
"Resource": "arn:aws:s3:::bucketName/*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
""";
|
|
||||||
};
|
|
||||||
return policy.replaceAll("bucketName", bucketName);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,17 +17,17 @@ public enum AccessPolicyType {
|
|||||||
/**
|
/**
|
||||||
* private
|
* private
|
||||||
*/
|
*/
|
||||||
PRIVATE("0", BucketCannedACL.PRIVATE, ObjectCannedACL.PRIVATE, PolicyType.WRITE),
|
PRIVATE("0", BucketCannedACL.PRIVATE, ObjectCannedACL.PRIVATE),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* public
|
* public
|
||||||
*/
|
*/
|
||||||
PUBLIC("1", BucketCannedACL.PUBLIC_READ_WRITE, ObjectCannedACL.PUBLIC_READ_WRITE, PolicyType.READ_WRITE),
|
PUBLIC("1", BucketCannedACL.PUBLIC_READ_WRITE, ObjectCannedACL.PUBLIC_READ_WRITE),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* custom
|
* custom
|
||||||
*/
|
*/
|
||||||
CUSTOM("2", BucketCannedACL.PUBLIC_READ, ObjectCannedACL.PUBLIC_READ, PolicyType.READ);
|
CUSTOM("2", BucketCannedACL.PUBLIC_READ, ObjectCannedACL.PUBLIC_READ);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 桶 权限类型(数据库值)
|
* 桶 权限类型(数据库值)
|
||||||
@ -44,11 +44,6 @@ public enum AccessPolicyType {
|
|||||||
*/
|
*/
|
||||||
private final ObjectCannedACL objectCannedACL;
|
private final ObjectCannedACL objectCannedACL;
|
||||||
|
|
||||||
/**
|
|
||||||
* 桶策略类型
|
|
||||||
*/
|
|
||||||
private final PolicyType policyType;
|
|
||||||
|
|
||||||
public static AccessPolicyType getByType(String type) {
|
public static AccessPolicyType getByType(String type) {
|
||||||
for (AccessPolicyType value : values()) {
|
for (AccessPolicyType value : values()) {
|
||||||
if (value.getType().equals(type)) {
|
if (value.getType().equals(type)) {
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
package org.dromara.common.oss.enumd;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* minio策略配置
|
|
||||||
*
|
|
||||||
* @author Lion Li
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
public enum PolicyType {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只读
|
|
||||||
*/
|
|
||||||
READ("read-only"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只写
|
|
||||||
*/
|
|
||||||
WRITE("write-only"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读写
|
|
||||||
*/
|
|
||||||
READ_WRITE("read-write");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类型
|
|
||||||
*/
|
|
||||||
private final String type;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -38,4 +38,10 @@ public @interface RateLimiter {
|
|||||||
* 提示消息 支持国际化 格式为 {code}
|
* 提示消息 支持国际化 格式为 {code}
|
||||||
*/
|
*/
|
||||||
String message() default "{rate.limiter.message}";
|
String message() default "{rate.limiter.message}";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流策略超时时间 默认一天(策略存活时间 会清除已存在的策略数据)
|
||||||
|
*/
|
||||||
|
int timeout() default 86400;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,13 +54,14 @@ public class RateLimiterAspect {
|
|||||||
public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
|
public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
|
||||||
int time = rateLimiter.time();
|
int time = rateLimiter.time();
|
||||||
int count = rateLimiter.count();
|
int count = rateLimiter.count();
|
||||||
|
int timeout = rateLimiter.timeout();
|
||||||
try {
|
try {
|
||||||
String combineKey = getCombineKey(rateLimiter, point);
|
String combineKey = getCombineKey(rateLimiter, point);
|
||||||
RateType rateType = RateType.OVERALL;
|
RateType rateType = RateType.OVERALL;
|
||||||
if (rateLimiter.limitType() == LimitType.CLUSTER) {
|
if (rateLimiter.limitType() == LimitType.CLUSTER) {
|
||||||
rateType = RateType.PER_CLIENT;
|
rateType = RateType.PER_CLIENT;
|
||||||
}
|
}
|
||||||
long number = RedisUtils.rateLimiter(combineKey, rateType, count, time);
|
long number = RedisUtils.rateLimiter(combineKey, rateType, count, time, timeout);
|
||||||
if (number == -1) {
|
if (number == -1) {
|
||||||
String message = rateLimiter.message();
|
String message = rateLimiter.message();
|
||||||
if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
|
if (StringUtils.startsWith(message, "{") && StringUtils.endsWith(message, "}")) {
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import lombok.AccessLevel;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
import org.dromara.common.core.utils.SpringUtils;
|
||||||
import org.redisson.api.*;
|
import org.redisson.api.*;
|
||||||
|
import org.redisson.api.options.KeysScanOptions;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -36,8 +37,22 @@ public class RedisUtils {
|
|||||||
* @return -1 表示失败
|
* @return -1 表示失败
|
||||||
*/
|
*/
|
||||||
public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
|
public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval) {
|
||||||
|
return rateLimiter(key, rateType, rate, rateInterval, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流
|
||||||
|
*
|
||||||
|
* @param key 限流key
|
||||||
|
* @param rateType 限流类型
|
||||||
|
* @param rate 速率
|
||||||
|
* @param rateInterval 速率间隔
|
||||||
|
* @param timeout 超时时间
|
||||||
|
* @return -1 表示失败
|
||||||
|
*/
|
||||||
|
public static long rateLimiter(String key, RateType rateType, int rate, int rateInterval, int timeout) {
|
||||||
RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
|
RRateLimiter rateLimiter = CLIENT.getRateLimiter(key);
|
||||||
rateLimiter.trySetRate(rateType, rate, rateInterval, RateIntervalUnit.SECONDS);
|
rateLimiter.trySetRate(rateType, rate, Duration.ofSeconds(rateInterval), Duration.ofSeconds(timeout));
|
||||||
if (rateLimiter.tryAcquire()) {
|
if (rateLimiter.tryAcquire()) {
|
||||||
return rateLimiter.availablePermits();
|
return rateLimiter.availablePermits();
|
||||||
} else {
|
} else {
|
||||||
@ -518,13 +533,34 @@ public class RedisUtils {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获得缓存的基本对象列表(全局匹配忽略租户 自行拼接租户id)
|
* 获得缓存的基本对象列表(全局匹配忽略租户 自行拼接租户id)
|
||||||
*
|
* <P>
|
||||||
|
* limit-设置扫描的限制数量(默认为0,查询全部)
|
||||||
|
* pattern-设置键的匹配模式(默认为null)
|
||||||
|
* chunkSize-设置每次扫描的块大小(默认为0,本方法设置为1000)
|
||||||
|
* type-设置键的类型(默认为null,查询全部类型)
|
||||||
|
* </P>
|
||||||
|
* @see KeysScanOptions
|
||||||
* @param pattern 字符串前缀
|
* @param pattern 字符串前缀
|
||||||
* @return 对象列表
|
* @return 对象列表
|
||||||
*/
|
*/
|
||||||
public static Collection<String> keys(final String pattern) {
|
public static Collection<String> keys(final String pattern) {
|
||||||
Stream<String> stream = CLIENT.getKeys().getKeysStreamByPattern(pattern);
|
return keys(KeysScanOptions.defaults().pattern(pattern).chunkSize(1000));
|
||||||
return stream.collect(Collectors.toList());
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过扫描参数获取缓存的基本对象列表
|
||||||
|
* @param keysScanOptions 扫描参数
|
||||||
|
* <P>
|
||||||
|
* limit-设置扫描的限制数量(默认为0,查询全部)
|
||||||
|
* pattern-设置键的匹配模式(默认为null)
|
||||||
|
* chunkSize-设置每次扫描的块大小(默认为0)
|
||||||
|
* type-设置键的类型(默认为null,查询全部类型)
|
||||||
|
* </P>
|
||||||
|
* @see KeysScanOptions
|
||||||
|
*/
|
||||||
|
public static Collection<String> keys(final KeysScanOptions keysScanOptions) {
|
||||||
|
Stream<String> keysStream = CLIENT.getKeys().getKeysStream(keysScanOptions);
|
||||||
|
return keysStream.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -66,7 +66,7 @@ public class PlusSmsDao implements SmsDao {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void clean() {
|
public void clean() {
|
||||||
RedisUtils.deleteObject(GlobalConstants.GLOBAL_REDIS_KEY + "sms:");
|
RedisUtils.deleteKeys(GlobalConstants.GLOBAL_REDIS_KEY + "sms:*");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import cn.dev33.satoken.dao.SaTokenDao;
|
|||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||||
import org.dromara.common.core.utils.reflect.ReflectUtils;
|
import org.dromara.common.core.utils.reflect.ReflectUtils;
|
||||||
import org.dromara.common.mybatis.config.MybatisPlusConfig;
|
|
||||||
import org.dromara.common.redis.config.RedisConfig;
|
import org.dromara.common.redis.config.RedisConfig;
|
||||||
import org.dromara.common.redis.config.properties.RedissonProperties;
|
import org.dromara.common.redis.config.properties.RedissonProperties;
|
||||||
import org.dromara.common.tenant.core.TenantSaTokenDao;
|
import org.dromara.common.tenant.core.TenantSaTokenDao;
|
||||||
@ -16,7 +15,7 @@ import org.redisson.config.ClusterServersConfig;
|
|||||||
import org.redisson.config.SingleServerConfig;
|
import org.redisson.config.SingleServerConfig;
|
||||||
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.cache.CacheManager;
|
import org.springframework.cache.CacheManager;
|
||||||
@ -33,8 +32,8 @@ import org.springframework.context.annotation.Primary;
|
|||||||
@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
|
@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
|
||||||
public class TenantConfig {
|
public class TenantConfig {
|
||||||
|
|
||||||
@ConditionalOnBean(MybatisPlusConfig.class)
|
@ConditionalOnClass(TenantLineInnerInterceptor.class)
|
||||||
@AutoConfiguration(after = {MybatisPlusConfig.class})
|
@AutoConfiguration
|
||||||
static class MybatisPlusConfiguration {
|
static class MybatisPlusConfiguration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -27,8 +27,12 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
|
|||||||
if (StringUtils.isBlank(name)) {
|
if (StringUtils.isBlank(name)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
|
try {
|
||||||
return super.map(name);
|
if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
|
||||||
|
return super.map(name);
|
||||||
|
}
|
||||||
|
} catch (NoClassDefFoundError ignore) {
|
||||||
|
// 有些服务不需要mp导致类不存在 忽略即可
|
||||||
}
|
}
|
||||||
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
|
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
|
||||||
return super.map(name);
|
return super.map(name);
|
||||||
@ -54,8 +58,12 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
|
|||||||
if (StringUtils.isBlank(unmap)) {
|
if (StringUtils.isBlank(unmap)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
|
try {
|
||||||
return super.unmap(name);
|
if (InterceptorIgnoreHelper.willIgnoreTenantLine("")) {
|
||||||
|
return super.unmap(name);
|
||||||
|
}
|
||||||
|
} catch (NoClassDefFoundError ignore) {
|
||||||
|
// 有些服务不需要mp导致类不存在 忽略即可
|
||||||
}
|
}
|
||||||
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
|
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
|
||||||
return super.unmap(name);
|
return super.unmap(name);
|
||||||
|
|||||||
@ -39,7 +39,7 @@ public class TranslationHandler extends JsonSerializer<Object> implements Contex
|
|||||||
if (ObjectUtil.isNotNull(trans)) {
|
if (ObjectUtil.isNotNull(trans)) {
|
||||||
// 如果映射字段不为空 则取映射字段的值
|
// 如果映射字段不为空 则取映射字段的值
|
||||||
if (StringUtils.isNotBlank(translation.mapper())) {
|
if (StringUtils.isNotBlank(translation.mapper())) {
|
||||||
value = ReflectUtils.invokeGetter(gen.getCurrentValue(), translation.mapper());
|
value = ReflectUtils.invokeGetter(gen.currentValue(), translation.mapper());
|
||||||
}
|
}
|
||||||
// 如果为 null 直接写出
|
// 如果为 null 直接写出
|
||||||
if (ObjectUtil.isNull(value)) {
|
if (ObjectUtil.isNull(value)) {
|
||||||
|
|||||||
@ -19,23 +19,21 @@ import org.springframework.context.annotation.Bean;
|
|||||||
@EnableConfigurationProperties(XssProperties.class)
|
@EnableConfigurationProperties(XssProperties.class)
|
||||||
public class FilterConfig {
|
public class FilterConfig {
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
|
@ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
|
||||||
public FilterRegistrationBean xssFilterRegistration(XssProperties xssProperties) {
|
public FilterRegistrationBean<XssFilter> xssFilterRegistration() {
|
||||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
FilterRegistrationBean<XssFilter> registration = new FilterRegistrationBean<>();
|
||||||
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
||||||
registration.setFilter(new XssFilter());
|
registration.setFilter(new XssFilter());
|
||||||
registration.addUrlPatterns("/*");
|
registration.addUrlPatterns("/*");
|
||||||
registration.setName("xssFilter");
|
registration.setName("xssFilter");
|
||||||
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
|
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 1);
|
||||||
return registration;
|
return registration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
||||||
@Bean
|
@Bean
|
||||||
public FilterRegistrationBean someFilterRegistration() {
|
public FilterRegistrationBean<RepeatableFilter> someFilterRegistration() {
|
||||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
FilterRegistrationBean<RepeatableFilter> registration = new FilterRegistrationBean<>();
|
||||||
registration.setFilter(new RepeatableFilter());
|
registration.setFilter(new RepeatableFilter());
|
||||||
registration.addUrlPatterns("/*");
|
registration.addUrlPatterns("/*");
|
||||||
registration.setName("repeatableFilter");
|
registration.setName("repeatableFilter");
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import jakarta.servlet.http.HttpServletRequestWrapper;
|
|||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XSS过滤处理
|
* XSS过滤处理
|
||||||
@ -28,6 +29,33 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
super(request);
|
super(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getParameter(String name) {
|
||||||
|
String value = super.getParameter(name);
|
||||||
|
if (value != null) {
|
||||||
|
return HtmlUtil.cleanHtmlTag(value).trim();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String[]> getParameterMap() {
|
||||||
|
Map<String, String[]> valueMap = super.getParameterMap();
|
||||||
|
for (Map.Entry<String, String[]> entry : valueMap.entrySet()) {
|
||||||
|
String[] values = entry.getValue();
|
||||||
|
if (values != null) {
|
||||||
|
int length = values.length;
|
||||||
|
String[] escapseValues = new String[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
// 防xss攻击和过滤前后空格
|
||||||
|
escapseValues[i] = HtmlUtil.cleanHtmlTag(values[i]).trim();
|
||||||
|
}
|
||||||
|
valueMap.put(entry.getKey(), escapseValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valueMap;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getParameterValues(String name) {
|
public String[] getParameterValues(String name) {
|
||||||
String[] values = super.getParameterValues(name);
|
String[] values = super.getParameterValues(name);
|
||||||
@ -40,7 +68,7 @@ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
|
|||||||
}
|
}
|
||||||
return escapseValues;
|
return escapseValues;
|
||||||
}
|
}
|
||||||
return super.getParameterValues(name);
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package org.dromara.common.web.interceptor;
|
|||||||
|
|
||||||
import cn.hutool.core.io.IoUtil;
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -64,9 +65,11 @@ public class PlusWebInvokeTimeInterceptor implements HandlerInterceptor {
|
|||||||
@Override
|
@Override
|
||||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||||
StopWatch stopWatch = KEY_CACHE.get();
|
StopWatch stopWatch = KEY_CACHE.get();
|
||||||
stopWatch.stop();
|
if (ObjectUtil.isNotNull(stopWatch)) {
|
||||||
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
|
stopWatch.stop();
|
||||||
KEY_CACHE.remove();
|
log.info("[PLUS]结束请求 => URL[{}],耗时:[{}]毫秒", request.getMethod() + " " + request.getRequestURI(), stopWatch.getTime());
|
||||||
|
KEY_CACHE.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -34,14 +34,18 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
|
|||||||
@DataColumn(key = "deptName", value = "dept_id"),
|
@DataColumn(key = "deptName", value = "dept_id"),
|
||||||
@DataColumn(key = "userName", value = "user_id")
|
@DataColumn(key = "userName", value = "user_id")
|
||||||
})
|
})
|
||||||
List<TestDemo> selectList(IPage<TestDemo> page, @Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
|
default <P extends IPage<TestDemoVo>> P selectVoPage(IPage<TestDemo> page, Wrapper<TestDemo> wrapper) {
|
||||||
|
return selectVoPage(page, wrapper, this.currentVoClass());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DataPermission({
|
@DataPermission({
|
||||||
@DataColumn(key = "deptName", value = "dept_id"),
|
@DataColumn(key = "deptName", value = "dept_id"),
|
||||||
@DataColumn(key = "userName", value = "user_id")
|
@DataColumn(key = "userName", value = "user_id")
|
||||||
})
|
})
|
||||||
List<TestDemo> selectList(@Param(Constants.WRAPPER) Wrapper<TestDemo> queryWrapper);
|
default List<TestDemoVo> selectVoList(Wrapper<TestDemo> wrapper) {
|
||||||
|
return selectVoList(wrapper, this.currentVoClass());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@DataPermission(value = {
|
@DataPermission(value = {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package org.dromara.demo.service.impl;
|
package org.dromara.demo.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@ -121,8 +122,9 @@ public class ExportExcelServiceImpl implements IExportExcelService {
|
|||||||
List<DemoCityData> provinceList = new ArrayList<>();
|
List<DemoCityData> provinceList = new ArrayList<>();
|
||||||
|
|
||||||
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
||||||
provinceList.add(new DemoCityData(0, null, "安徽省"));
|
provinceList.add(new DemoCityData(0, null, "P100000"));
|
||||||
provinceList.add(new DemoCityData(1, null, "江苏省"));
|
provinceList.add(new DemoCityData(1, null, "P200000"));
|
||||||
|
provinceList.add(new DemoCityData(2, null, "P300000"));
|
||||||
|
|
||||||
return provinceList;
|
return provinceList;
|
||||||
}
|
}
|
||||||
@ -137,11 +139,11 @@ public class ExportExcelServiceImpl implements IExportExcelService {
|
|||||||
List<DemoCityData> cityList = new ArrayList<>();
|
List<DemoCityData> cityList = new ArrayList<>();
|
||||||
|
|
||||||
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
||||||
cityList.add(new DemoCityData(0, 0, "合肥市"));
|
cityList.add(new DemoCityData(0, 0, "C110000"));
|
||||||
cityList.add(new DemoCityData(1, 0, "芜湖市"));
|
cityList.add(new DemoCityData(1, 0, "C120000"));
|
||||||
cityList.add(new DemoCityData(2, 1, "南京市"));
|
cityList.add(new DemoCityData(2, 1, "C210000"));
|
||||||
cityList.add(new DemoCityData(3, 1, "无锡市"));
|
cityList.add(new DemoCityData(3, 1, "C220000"));
|
||||||
cityList.add(new DemoCityData(4, 1, "徐州市"));
|
cityList.add(new DemoCityData(4, 1, "C230000"));
|
||||||
|
|
||||||
selectParentData(provinceList, cityList);
|
selectParentData(provinceList, cityList);
|
||||||
|
|
||||||
@ -157,17 +159,29 @@ public class ExportExcelServiceImpl implements IExportExcelService {
|
|||||||
private List<DemoCityData> getAreaList(List<DemoCityData> cityList) {
|
private List<DemoCityData> getAreaList(List<DemoCityData> cityList) {
|
||||||
List<DemoCityData> areaList = new ArrayList<>();
|
List<DemoCityData> areaList = new ArrayList<>();
|
||||||
|
|
||||||
|
int minCount = 500;
|
||||||
|
int maxCount = 10000;
|
||||||
|
|
||||||
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
// 实际业务中一般采用数据库读取的形式,这里直接拼接创建
|
||||||
areaList.add(new DemoCityData(0, 0, "瑶海区"));
|
for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
|
||||||
areaList.add(new DemoCityData(1, 0, "庐江区"));
|
areaList.add(new DemoCityData(areaList.size(), 0, String.format("A11%04d", i)));
|
||||||
areaList.add(new DemoCityData(2, 1, "南宁县"));
|
}
|
||||||
areaList.add(new DemoCityData(3, 1, "镜湖区"));
|
|
||||||
areaList.add(new DemoCityData(4, 2, "玄武区"));
|
for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
|
||||||
areaList.add(new DemoCityData(5, 2, "秦淮区"));
|
areaList.add(new DemoCityData(areaList.size(), 1, String.format("A12%04d", i)));
|
||||||
areaList.add(new DemoCityData(6, 3, "宜兴市"));
|
}
|
||||||
areaList.add(new DemoCityData(7, 3, "新吴区"));
|
|
||||||
areaList.add(new DemoCityData(8, 4, "鼓楼区"));
|
for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
|
||||||
areaList.add(new DemoCityData(9, 4, "丰县"));
|
areaList.add(new DemoCityData(areaList.size(), 2, String.format("A21%04d", i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
|
||||||
|
areaList.add(new DemoCityData(areaList.size(), 3, String.format("A22%04d", i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < RandomUtil.randomInt(minCount, maxCount); i++) {
|
||||||
|
areaList.add(new DemoCityData(areaList.size(), 4, String.format("A23%04d", i)));
|
||||||
|
}
|
||||||
|
|
||||||
selectParentData(cityList, areaList);
|
selectParentData(cityList, areaList);
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,6 @@ import org.dromara.common.core.utils.file.FileUtils;
|
|||||||
import org.dromara.common.json.utils.JsonUtils;
|
import org.dromara.common.json.utils.JsonUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
|
||||||
import org.dromara.generator.constant.GenConstants;
|
import org.dromara.generator.constant.GenConstants;
|
||||||
import org.dromara.generator.domain.GenTable;
|
import org.dromara.generator.domain.GenTable;
|
||||||
import org.dromara.generator.domain.GenTableColumn;
|
import org.dromara.generator.domain.GenTableColumn;
|
||||||
@ -106,7 +105,8 @@ public class GenTableServiceImpl implements IGenTableService {
|
|||||||
.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
|
.like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
|
||||||
.like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
|
.like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
|
||||||
.between(params.get("beginTime") != null && params.get("endTime") != null,
|
.between(params.get("beginTime") != null && params.get("endTime") != null,
|
||||||
"create_time", params.get("beginTime"), params.get("endTime"));
|
"create_time", params.get("beginTime"), params.get("endTime"))
|
||||||
|
.orderByAsc("table_id");
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,11 +269,10 @@ public class GenTableServiceImpl implements IGenTableService {
|
|||||||
@DSTransactional
|
@DSTransactional
|
||||||
@Override
|
@Override
|
||||||
public void importGenTable(List<GenTable> tableList, String dataName) {
|
public void importGenTable(List<GenTable> tableList, String dataName) {
|
||||||
Long operId = LoginHelper.getUserId();
|
|
||||||
try {
|
try {
|
||||||
for (GenTable table : tableList) {
|
for (GenTable table : tableList) {
|
||||||
String tableName = table.getTableName();
|
String tableName = table.getTableName();
|
||||||
GenUtils.initTable(table, operId);
|
GenUtils.initTable(table);
|
||||||
table.setDataName(dataName);
|
table.setDataName(dataName);
|
||||||
int row = baseMapper.insert(table);
|
int row = baseMapper.insert(table);
|
||||||
if (row > 0) {
|
if (row > 0) {
|
||||||
|
|||||||
@ -22,14 +22,13 @@ public class GenUtils {
|
|||||||
/**
|
/**
|
||||||
* 初始化表信息
|
* 初始化表信息
|
||||||
*/
|
*/
|
||||||
public static void initTable(GenTable genTable, Long operId) {
|
public static void initTable(GenTable genTable) {
|
||||||
genTable.setClassName(convertClassName(genTable.getTableName()));
|
genTable.setClassName(convertClassName(genTable.getTableName()));
|
||||||
genTable.setPackageName(GenConfig.getPackageName());
|
genTable.setPackageName(GenConfig.getPackageName());
|
||||||
genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
|
genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
|
||||||
genTable.setBusinessName(getBusinessName(genTable.getTableName()));
|
genTable.setBusinessName(getBusinessName(genTable.getTableName()));
|
||||||
genTable.setFunctionName(replaceText(genTable.getTableComment()));
|
genTable.setFunctionName(replaceText(genTable.getTableComment()));
|
||||||
genTable.setFunctionAuthor(GenConfig.getAuthor());
|
genTable.setFunctionAuthor(GenConfig.getAuthor());
|
||||||
genTable.setCreateBy(operId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -128,13 +128,9 @@ public class SysUserController extends BaseController {
|
|||||||
@SaCheckPermission("system:user:query")
|
@SaCheckPermission("system:user:query")
|
||||||
@GetMapping(value = {"/", "/{userId}"})
|
@GetMapping(value = {"/", "/{userId}"})
|
||||||
public R<SysUserInfoVo> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
|
public R<SysUserInfoVo> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
|
||||||
userService.checkUserDataScope(userId);
|
|
||||||
SysUserInfoVo userInfoVo = new SysUserInfoVo();
|
SysUserInfoVo userInfoVo = new SysUserInfoVo();
|
||||||
SysRoleBo roleBo = new SysRoleBo();
|
|
||||||
roleBo.setStatus(UserConstants.ROLE_NORMAL);
|
|
||||||
List<SysRoleVo> roles = roleService.selectRoleList(roleBo);
|
|
||||||
userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
|
|
||||||
if (ObjectUtil.isNotNull(userId)) {
|
if (ObjectUtil.isNotNull(userId)) {
|
||||||
|
userService.checkUserDataScope(userId);
|
||||||
SysUserVo sysUser = userService.selectUserById(userId);
|
SysUserVo sysUser = userService.selectUserById(userId);
|
||||||
userInfoVo.setUser(sysUser);
|
userInfoVo.setUser(sysUser);
|
||||||
userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId));
|
userInfoVo.setRoleIds(roleService.selectRoleListByUserId(userId));
|
||||||
@ -146,6 +142,10 @@ public class SysUserController extends BaseController {
|
|||||||
userInfoVo.setPostIds(postService.selectPostListByUserId(userId));
|
userInfoVo.setPostIds(postService.selectPostListByUserId(userId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
SysRoleBo roleBo = new SysRoleBo();
|
||||||
|
roleBo.setStatus(UserConstants.ROLE_NORMAL);
|
||||||
|
List<SysRoleVo> roles = roleService.selectRoleList(roleBo);
|
||||||
|
userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
|
||||||
return R.ok(userInfoVo);
|
return R.ok(userInfoVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
package org.dromara.system.mapper;
|
package org.dromara.system.mapper;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.dromara.common.mybatis.annotation.DataColumn;
|
import org.dromara.common.mybatis.annotation.DataColumn;
|
||||||
import org.dromara.common.mybatis.annotation.DataPermission;
|
import org.dromara.common.mybatis.annotation.DataPermission;
|
||||||
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
||||||
|
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||||
import org.dromara.system.domain.SysDept;
|
import org.dromara.system.domain.SysDept;
|
||||||
import org.dromara.system.domain.vo.SysDeptVo;
|
import org.dromara.system.domain.vo.SysDeptVo;
|
||||||
|
|
||||||
@ -46,6 +48,12 @@ public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
|
|||||||
})
|
})
|
||||||
long countDeptById(Long deptId);
|
long countDeptById(Long deptId);
|
||||||
|
|
||||||
|
default List<SysDept> selectListByParentId(Long parentId) {
|
||||||
|
return this.selectList(new LambdaQueryWrapper<SysDept>()
|
||||||
|
.select(SysDept::getDeptId)
|
||||||
|
.apply(DataBaseHelper.findInSet(parentId, "ancestors")));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据角色ID查询部门树信息
|
* 根据角色ID查询部门树信息
|
||||||
*
|
*
|
||||||
|
|||||||
@ -197,4 +197,6 @@ public interface ISysRoleService {
|
|||||||
|
|
||||||
void cleanOnlineUserByRole(Long roleId);
|
void cleanOnlineUserByRole(Long roleId);
|
||||||
|
|
||||||
|
void cleanOnlineUser(List<Long> userIds);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import cn.hutool.core.util.ObjectUtil;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.dromara.common.core.utils.StreamUtils;
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
|
||||||
import org.dromara.system.domain.SysDept;
|
import org.dromara.system.domain.SysDept;
|
||||||
import org.dromara.system.domain.SysRoleDept;
|
import org.dromara.system.domain.SysRoleDept;
|
||||||
import org.dromara.system.mapper.SysDeptMapper;
|
import org.dromara.system.mapper.SysDeptMapper;
|
||||||
@ -63,9 +62,7 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
|
|||||||
if (ObjectUtil.isNull(deptId)) {
|
if (ObjectUtil.isNull(deptId)) {
|
||||||
return "-1";
|
return "-1";
|
||||||
}
|
}
|
||||||
List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
List<SysDept> deptList = deptMapper.selectListByParentId(deptId);
|
||||||
.select(SysDept::getDeptId)
|
|
||||||
.apply(DataBaseHelper.findInSet(deptId, "ancestors")));
|
|
||||||
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
|
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||||
ids.add(deptId);
|
ids.add(deptId);
|
||||||
if (CollUtil.isNotEmpty(ids)) {
|
if (CollUtil.isNotEmpty(ids)) {
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import org.dromara.common.core.service.DeptService;
|
|||||||
import org.dromara.common.core.utils.MapstructUtils;
|
import org.dromara.common.core.utils.MapstructUtils;
|
||||||
import org.dromara.common.core.utils.SpringUtils;
|
import org.dromara.common.core.utils.SpringUtils;
|
||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
|
import org.dromara.common.core.utils.StreamUtils;
|
||||||
import org.dromara.common.core.utils.TreeBuildUtils;
|
import org.dromara.common.core.utils.TreeBuildUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
||||||
@ -109,11 +110,22 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
if (CollUtil.isEmpty(depts)) {
|
if (CollUtil.isEmpty(depts)) {
|
||||||
return CollUtil.newArrayList();
|
return CollUtil.newArrayList();
|
||||||
}
|
}
|
||||||
return TreeBuildUtils.build(depts, (dept, tree) ->
|
// 获取当前列表中每一个节点的parentId,然后在列表中查找是否有id与其parentId对应,若无对应,则表明此时节点列表中,该节点在当前列表中属于顶级节点
|
||||||
tree.setId(dept.getDeptId())
|
List<Tree<Long>> treeList = CollUtil.newArrayList();
|
||||||
.setParentId(dept.getParentId())
|
for (SysDeptVo d : depts) {
|
||||||
.setName(dept.getDeptName())
|
Long parentId = d.getParentId();
|
||||||
.setWeight(dept.getOrderNum()));
|
SysDeptVo sysDeptVo = StreamUtils.findFirst(depts, it -> it.getDeptId().longValue() == parentId);
|
||||||
|
if (ObjectUtil.isNull(sysDeptVo)) {
|
||||||
|
List<Tree<Long>> trees = TreeBuildUtils.build(depts, parentId, (dept, tree) ->
|
||||||
|
tree.setId(dept.getDeptId())
|
||||||
|
.setParentId(dept.getParentId())
|
||||||
|
.setName(dept.getDeptName())
|
||||||
|
.setWeight(dept.getOrderNum()));
|
||||||
|
Tree<Long> tree = trees.stream().filter(it -> it.getId().longValue() == d.getDeptId()).findFirst().get();
|
||||||
|
treeList.add(tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return treeList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -328,11 +340,14 @@ public class SysDeptServiceImpl implements ISysDeptService, DeptService {
|
|||||||
public int updateDept(SysDeptBo bo) {
|
public int updateDept(SysDeptBo bo) {
|
||||||
SysDept dept = MapstructUtils.convert(bo, SysDept.class);
|
SysDept dept = MapstructUtils.convert(bo, SysDept.class);
|
||||||
SysDept oldDept = baseMapper.selectById(dept.getDeptId());
|
SysDept oldDept = baseMapper.selectById(dept.getDeptId());
|
||||||
|
if (ObjectUtil.isNull(oldDept)) {
|
||||||
|
throw new ServiceException("部门不存在,无法修改");
|
||||||
|
}
|
||||||
if (!oldDept.getParentId().equals(dept.getParentId())) {
|
if (!oldDept.getParentId().equals(dept.getParentId())) {
|
||||||
// 如果是新父部门 则校验是否具有新父部门权限 避免越权
|
// 如果是新父部门 则校验是否具有新父部门权限 避免越权
|
||||||
this.checkDeptDataScope(dept.getParentId());
|
this.checkDeptDataScope(dept.getParentId());
|
||||||
SysDept newParentDept = baseMapper.selectById(dept.getParentId());
|
SysDept newParentDept = baseMapper.selectById(dept.getParentId());
|
||||||
if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) {
|
if (ObjectUtil.isNotNull(newParentDept)) {
|
||||||
String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId();
|
String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId();
|
||||||
String oldAncestors = oldDept.getAncestors();
|
String oldAncestors = oldDept.getAncestors();
|
||||||
dept.setAncestors(newAncestors);
|
dept.setAncestors(newAncestors);
|
||||||
|
|||||||
@ -16,7 +16,6 @@ import org.dromara.common.core.utils.StreamUtils;
|
|||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
|
||||||
import org.dromara.system.domain.SysDept;
|
import org.dromara.system.domain.SysDept;
|
||||||
import org.dromara.system.domain.SysPost;
|
import org.dromara.system.domain.SysPost;
|
||||||
import org.dromara.system.domain.SysUserPost;
|
import org.dromara.system.domain.SysUserPost;
|
||||||
@ -82,12 +81,8 @@ public class SysPostServiceImpl implements ISysPostService, PostService {
|
|||||||
} else if (ObjectUtil.isNotNull(bo.getBelongDeptId())) {
|
} else if (ObjectUtil.isNotNull(bo.getBelongDeptId())) {
|
||||||
//部门树搜索
|
//部门树搜索
|
||||||
wrapper.and(x -> {
|
wrapper.and(x -> {
|
||||||
List<Long> deptIds = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
List<SysDept> deptList = deptMapper.selectListByParentId(bo.getBelongDeptId());
|
||||||
.select(SysDept::getDeptId)
|
List<Long> deptIds = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||||
.apply(DataBaseHelper.findInSet(bo.getBelongDeptId(), "ancestors")))
|
|
||||||
.stream()
|
|
||||||
.map(SysDept::getDeptId)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
deptIds.add(bo.getBelongDeptId());
|
deptIds.add(bo.getBelongDeptId());
|
||||||
x.in(SysPost::getDeptId, deptIds);
|
x.in(SysPost::getDeptId, deptIds);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -438,7 +438,7 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
|||||||
.eq(SysUserRole::getRoleId, userRole.getRoleId())
|
.eq(SysUserRole::getRoleId, userRole.getRoleId())
|
||||||
.eq(SysUserRole::getUserId, userRole.getUserId()));
|
.eq(SysUserRole::getUserId, userRole.getUserId()));
|
||||||
if (rows > 0) {
|
if (rows > 0) {
|
||||||
cleanOnlineUserByRole(userRole.getRoleId());
|
cleanOnlineUser(List.of(userRole.getUserId()));
|
||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
@ -452,11 +452,12 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int deleteAuthUsers(Long roleId, Long[] userIds) {
|
public int deleteAuthUsers(Long roleId, Long[] userIds) {
|
||||||
|
List<Long> ids = List.of(userIds);
|
||||||
int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
|
int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
|
||||||
.eq(SysUserRole::getRoleId, roleId)
|
.eq(SysUserRole::getRoleId, roleId)
|
||||||
.in(SysUserRole::getUserId, Arrays.asList(userIds)));
|
.in(SysUserRole::getUserId, ids));
|
||||||
if (rows > 0) {
|
if (rows > 0) {
|
||||||
cleanOnlineUserByRole(roleId);
|
cleanOnlineUser(ids);
|
||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
@ -472,7 +473,8 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
|||||||
public int insertAuthUsers(Long roleId, Long[] userIds) {
|
public int insertAuthUsers(Long roleId, Long[] userIds) {
|
||||||
// 新增用户与角色管理
|
// 新增用户与角色管理
|
||||||
int rows = 1;
|
int rows = 1;
|
||||||
List<SysUserRole> list = StreamUtils.toList(List.of(userIds), userId -> {
|
List<Long> ids = List.of(userIds);
|
||||||
|
List<SysUserRole> list = StreamUtils.toList(ids, userId -> {
|
||||||
SysUserRole ur = new SysUserRole();
|
SysUserRole ur = new SysUserRole();
|
||||||
ur.setUserId(userId);
|
ur.setUserId(userId);
|
||||||
ur.setRoleId(roleId);
|
ur.setRoleId(roleId);
|
||||||
@ -482,7 +484,7 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
|||||||
rows = userRoleMapper.insertBatch(list) ? list.size() : 0;
|
rows = userRoleMapper.insertBatch(list) ? list.size() : 0;
|
||||||
}
|
}
|
||||||
if (rows > 0) {
|
if (rows > 0) {
|
||||||
cleanOnlineUserByRole(roleId);
|
cleanOnlineUser(ids);
|
||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
@ -506,6 +508,9 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LoginUser loginUser = LoginHelper.getLoginUser(token);
|
LoginUser loginUser = LoginHelper.getLoginUser(token);
|
||||||
|
if (ObjectUtil.isNull(loginUser) || CollUtil.isEmpty(loginUser.getRoles())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) {
|
if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) {
|
||||||
try {
|
try {
|
||||||
StpUtil.logoutByTokenValue(token);
|
StpUtil.logoutByTokenValue(token);
|
||||||
@ -515,6 +520,32 @@ public class SysRoleServiceImpl implements ISysRoleService, RoleService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanOnlineUser(List<Long> userIds) {
|
||||||
|
List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
|
||||||
|
if (CollUtil.isEmpty(keys)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 角色关联的在线用户量过大会导致redis阻塞卡顿 谨慎操作
|
||||||
|
keys.parallelStream().forEach(key -> {
|
||||||
|
String token = StringUtils.substringAfterLast(key, ":");
|
||||||
|
// 如果已经过期则跳过
|
||||||
|
if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LoginUser loginUser = LoginHelper.getLoginUser(token);
|
||||||
|
if (ObjectUtil.isNull(loginUser)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (userIds.contains(loginUser.getUserId())) {
|
||||||
|
try {
|
||||||
|
StpUtil.logoutByTokenValue(token);
|
||||||
|
} catch (NotLoginException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询角色并返回任务指派的列表,支持分页
|
* 查询角色并返回任务指派的列表,支持分页
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package org.dromara.system.service.impl;
|
package org.dromara.system.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.secure.BCrypt;
|
import cn.dev33.satoken.secure.BCrypt;
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
@ -203,7 +204,7 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
|||||||
String numbers = RandomUtil.randomNumbers(6);
|
String numbers = RandomUtil.randomNumbers(6);
|
||||||
// 判断是否存在,如果存在则重新生成
|
// 判断是否存在,如果存在则重新生成
|
||||||
if (tenantIds.contains(numbers)) {
|
if (tenantIds.contains(numbers)) {
|
||||||
generateTenantId(tenantIds);
|
return generateTenantId(tenantIds);
|
||||||
}
|
}
|
||||||
return numbers;
|
return numbers;
|
||||||
}
|
}
|
||||||
@ -413,33 +414,36 @@ public class SysTenantServiceImpl implements ISysTenantService {
|
|||||||
Map<String, SysDictData> map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue);
|
Map<String, SysDictData> map = StreamUtils.toIdentityMap(dataListTenant, SysDictData::getDictValue);
|
||||||
for (SysDictData dictData : dataList) {
|
for (SysDictData dictData : dataList) {
|
||||||
if (!map.containsKey(dictData.getDictValue())) {
|
if (!map.containsKey(dictData.getDictValue())) {
|
||||||
|
SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
|
||||||
// 设置字典编码为 null
|
// 设置字典编码为 null
|
||||||
dictData.setDictCode(null);
|
data.setDictCode(null);
|
||||||
dictData.setTenantId(tenantId);
|
data.setTenantId(tenantId);
|
||||||
dictData.setCreateTime(null);
|
data.setCreateTime(null);
|
||||||
dictData.setUpdateTime(null);
|
data.setUpdateTime(null);
|
||||||
set.add(tenantId);
|
set.add(tenantId);
|
||||||
saveDataList.add(dictData);
|
saveDataList.add(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dictType.setDictId(null);
|
SysDictType type = BeanUtil.toBean(dictType, SysDictType.class);
|
||||||
dictType.setTenantId(tenantId);
|
type.setDictId(null);
|
||||||
dictType.setCreateTime(null);
|
type.setTenantId(tenantId);
|
||||||
dictType.setUpdateTime(null);
|
type.setCreateTime(null);
|
||||||
|
type.setUpdateTime(null);
|
||||||
set.add(tenantId);
|
set.add(tenantId);
|
||||||
saveTypeList.add(dictType);
|
saveTypeList.add(type);
|
||||||
if (CollUtil.isNotEmpty(dataList)) {
|
if (CollUtil.isNotEmpty(dataList)) {
|
||||||
// 筛选出 dictType 对应的 data
|
// 筛选出 dictType 对应的 data
|
||||||
for (SysDictData dictData : dataList) {
|
for (SysDictData dictData : dataList) {
|
||||||
|
SysDictData data = BeanUtil.toBean(dictData, SysDictData.class);
|
||||||
// 设置字典编码为 null
|
// 设置字典编码为 null
|
||||||
dictData.setDictCode(null);
|
data.setDictCode(null);
|
||||||
dictData.setTenantId(tenantId);
|
data.setTenantId(tenantId);
|
||||||
dictData.setCreateTime(null);
|
data.setCreateTime(null);
|
||||||
dictData.setUpdateTime(null);
|
data.setUpdateTime(null);
|
||||||
set.add(tenantId);
|
set.add(tenantId);
|
||||||
|
saveDataList.add(data);
|
||||||
}
|
}
|
||||||
saveDataList.addAll(dataList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,6 @@ import org.dromara.common.core.utils.StreamUtils;
|
|||||||
import org.dromara.common.core.utils.StringUtils;
|
import org.dromara.common.core.utils.StringUtils;
|
||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.common.mybatis.helper.DataBaseHelper;
|
|
||||||
import org.dromara.common.satoken.utils.LoginHelper;
|
import org.dromara.common.satoken.utils.LoginHelper;
|
||||||
import org.dromara.system.domain.*;
|
import org.dromara.system.domain.*;
|
||||||
import org.dromara.system.domain.bo.SysUserBo;
|
import org.dromara.system.domain.bo.SysUserBo;
|
||||||
@ -88,9 +87,7 @@ public class SysUserServiceImpl implements ISysUserService, UserService {
|
|||||||
.between(params.get("beginTime") != null && params.get("endTime") != null,
|
.between(params.get("beginTime") != null && params.get("endTime") != null,
|
||||||
"u.create_time", params.get("beginTime"), params.get("endTime"))
|
"u.create_time", params.get("beginTime"), params.get("endTime"))
|
||||||
.and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
|
.and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
|
||||||
List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
|
List<SysDept> deptList = deptMapper.selectListByParentId(user.getDeptId());
|
||||||
.select(SysDept::getDeptId)
|
|
||||||
.apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors")));
|
|
||||||
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
|
List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
|
||||||
ids.add(user.getDeptId());
|
ids.add(user.getDeptId());
|
||||||
w.in("u.dept_id", ids);
|
w.in("u.dept_id", ids);
|
||||||
|
|||||||
@ -96,7 +96,7 @@ public class WfDefinitionConfigServiceImpl implements IWfDefinitionConfigService
|
|||||||
baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, bo.getTableName()));
|
baseMapper.delete(new LambdaQueryWrapper<WfDefinitionConfig>().eq(WfDefinitionConfig::getTableName, bo.getTableName()));
|
||||||
add.setTableName(add.getTableName().toLowerCase());
|
add.setTableName(add.getTableName().toLowerCase());
|
||||||
boolean flag = baseMapper.insertOrUpdate(add);
|
boolean flag = baseMapper.insertOrUpdate(add);
|
||||||
if (baseMapper.insertOrUpdate(add)) {
|
if (flag) {
|
||||||
bo.setId(add.getId());
|
bo.setId(add.getId());
|
||||||
}
|
}
|
||||||
return flag;
|
return flag;
|
||||||
|
|||||||
@ -100,7 +100,7 @@ services:
|
|||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
ruoyi-server1:
|
ruoyi-server1:
|
||||||
image: ruoyi/ruoyi-server:5.2.2
|
image: ruoyi/ruoyi-server:5.2.3
|
||||||
container_name: ruoyi-server1
|
container_name: ruoyi-server1
|
||||||
environment:
|
environment:
|
||||||
# 时区上海
|
# 时区上海
|
||||||
@ -115,7 +115,7 @@ services:
|
|||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
ruoyi-server2:
|
ruoyi-server2:
|
||||||
image: ruoyi/ruoyi-server:5.2.2
|
image: ruoyi/ruoyi-server:5.2.3
|
||||||
container_name: ruoyi-server2
|
container_name: ruoyi-server2
|
||||||
environment:
|
environment:
|
||||||
# 时区上海
|
# 时区上海
|
||||||
@ -130,7 +130,7 @@ services:
|
|||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
ruoyi-monitor-admin:
|
ruoyi-monitor-admin:
|
||||||
image: ruoyi/ruoyi-monitor-admin:5.2.2
|
image: ruoyi/ruoyi-monitor-admin:5.2.3
|
||||||
container_name: ruoyi-monitor-admin
|
container_name: ruoyi-monitor-admin
|
||||||
environment:
|
environment:
|
||||||
# 时区上海
|
# 时区上海
|
||||||
@ -142,7 +142,7 @@ services:
|
|||||||
network_mode: "host"
|
network_mode: "host"
|
||||||
|
|
||||||
ruoyi-snailjob-server:
|
ruoyi-snailjob-server:
|
||||||
image: ruoyi/ruoyi-snailjob-server:5.2.2
|
image: ruoyi/ruoyi-snailjob-server:5.2.3
|
||||||
container_name: ruoyi-snailjob-server
|
container_name: ruoyi-snailjob-server
|
||||||
environment:
|
environment:
|
||||||
# 时区上海
|
# 时区上海
|
||||||
|
|||||||
@ -5,7 +5,7 @@ create table sys_social
|
|||||||
(
|
(
|
||||||
id number(20) not null,
|
id number(20) not null,
|
||||||
user_id number(20) not null,
|
user_id number(20) not null,
|
||||||
tenant_id varchar2(20) default null,
|
tenant_id varchar2(20) default '000000',
|
||||||
auth_id varchar2(255) not null,
|
auth_id varchar2(255) not null,
|
||||||
source varchar2(255) not null,
|
source varchar2(255) not null,
|
||||||
open_id varchar2(255) default null,
|
open_id varchar2(255) default null,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ create table sys_social
|
|||||||
(
|
(
|
||||||
id int8 not null,
|
id int8 not null,
|
||||||
user_id int8 not null,
|
user_id int8 not null,
|
||||||
tenant_id varchar(20) default null::varchar,
|
tenant_id varchar(20) default '000000'::varchar,
|
||||||
auth_id varchar(255) not null,
|
auth_id varchar(255) not null,
|
||||||
source varchar(255) not null,
|
source varchar(255) not null,
|
||||||
open_id varchar(255) default null::varchar,
|
open_id varchar(255) default null::varchar,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ create table sys_social
|
|||||||
(
|
(
|
||||||
id bigint not null comment '主键',
|
id bigint not null comment '主键',
|
||||||
user_id bigint not null comment '用户ID',
|
user_id bigint not null comment '用户ID',
|
||||||
tenant_id varchar(20) default null comment '租户id',
|
tenant_id varchar(20) default '000000' comment '租户id',
|
||||||
auth_id varchar(255) not null comment '平台+平台唯一id',
|
auth_id varchar(255) not null comment '平台+平台唯一id',
|
||||||
source varchar(255) not null comment '用户来源',
|
source varchar(255) not null comment '用户来源',
|
||||||
open_id varchar(255) default null comment '平台编号唯一id',
|
open_id varchar(255) default null comment '平台编号唯一id',
|
||||||
|
|||||||
@ -2,7 +2,7 @@ create table sys_social
|
|||||||
(
|
(
|
||||||
id bigint NOT NULL,
|
id bigint NOT NULL,
|
||||||
user_id bigint NOT NULL,
|
user_id bigint NOT NULL,
|
||||||
tenant_id nvarchar(20) NULL,
|
tenant_id nvarchar(20) DEFAULT ('000000') NULL,
|
||||||
auth_id nvarchar(255) NOT NULL,
|
auth_id nvarchar(255) NOT NULL,
|
||||||
source nvarchar(255) NOT NULL,
|
source nvarchar(255) NOT NULL,
|
||||||
open_id nvarchar(255) NULL,
|
open_id nvarchar(255) NULL,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user