diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java index adcc3fa50..b31a87235 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java @@ -23,6 +23,8 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { public static final String SLASH = "/"; + private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher(); + @Deprecated private StringUtils() { } @@ -233,8 +235,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { * @param url 需要匹配的url */ public static boolean isMatch(String pattern, String url) { - AntPathMatcher matcher = new AntPathMatcher(); - return matcher.match(pattern, url); + return ANT_PATH_MATCHER.match(pattern, url); } /** @@ -547,4 +548,12 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils { return Strings.CS.containsAny(cs, searchCharSequences); } + + /** + * 将一个字符串替换为较大字符串内的另一个字符串,一次 + */ + public static String replaceOnce(final String text, final String searchString, final String replacement) { + return Strings.CS.replaceOnce(text, searchString, replacement); + } + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java index 1020c81eb..18bad0fb9 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java @@ -15,7 +15,7 @@ public class SqlUtil { /** * 定义常用的 sql关键字 */ - public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()"; + public static final String SQL_REGEX = "\u000B|%0A|and |extractvalue|updatexml|sleep|information_schema|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()"; /** * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序) diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java index 71b1e8423..0f4a5310f 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java @@ -38,6 +38,9 @@ public class ExcelBigNumberConvert implements Converter { @Override public WriteCellData convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { + if (ObjectUtil.isNull(object)) { + return new WriteCellData<>(""); + } if (ObjectUtil.isNotNull(object)) { String str = Convert.toStr(object); if (str.length() > 15) { diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java index 4960ab16f..877218d90 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java @@ -16,6 +16,7 @@ import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * 枚举格式化转换处理 @@ -25,6 +26,9 @@ import java.util.Map; @Slf4j public class ExcelEnumConvert implements Converter { + private static final Map> ENUM_MAP_CACHE = new ConcurrentHashMap<>(); + private static final Map> ENUM_REVERSE_MAP_CACHE = new ConcurrentHashMap<>(); + @Override public Class supportJavaTypeKey() { return Object.class; @@ -50,10 +54,15 @@ public class ExcelEnumConvert implements Converter { return null; } Map enumCodeToTextMap = beforeConvert(contentProperty); - // 从Java输出至Excel是code转text - // 因此从Excel转Java应该将text与code对调 - Map enumTextToCodeMap = new HashMap<>(); - enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key)); + // 从Java输出至Excel是code转text,从Excel转Java应将text与code对调 + Map enumTextToCodeMap = ENUM_REVERSE_MAP_CACHE.computeIfAbsent( + contentProperty.getField(), + f -> { + Map reverseMap = new HashMap<>(); + enumCodeToTextMap.forEach((key, value) -> reverseMap.put(value, key)); + return reverseMap; + } + ); // 应该从text -> code中查找 Object codeValue = enumTextToCodeMap.get(textValue); return Convert.convert(contentProperty.getField().getType(), codeValue); @@ -70,15 +79,17 @@ public class ExcelEnumConvert implements Converter { } private Map beforeConvert(ExcelContentProperty contentProperty) { - ExcelEnumFormat anno = getAnnotation(contentProperty.getField()); - Map enumValueMap = new HashMap<>(); - Enum[] enumConstants = anno.enumClass().getEnumConstants(); - for (Enum enumConstant : enumConstants) { - Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); - String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); - enumValueMap.put(codeValue, textValue); - } - return enumValueMap; + return ENUM_MAP_CACHE.computeIfAbsent(contentProperty.getField(), field -> { + ExcelEnumFormat anno = getAnnotation(field); + Map enumValueMap = new HashMap<>(); + Enum[] enumConstants = anno.enumClass().getEnumConstants(); + for (Enum enumConstant : enumConstants) { + Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField()); + String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField()); + enumValueMap.put(codeValue, textValue); + } + return enumValueMap; + }); } private ExcelEnumFormat getAnnotation(Field field) { diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java index 4bd3e18b4..513c556a5 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java @@ -62,7 +62,7 @@ public class DefaultExcelListener extends AnalysisEventListener implements errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
", rowIndex + 1, columnIndex + 1, headMap.get(columnIndex)); if (log.isDebugEnabled()) { - log.error(errMsg); + log.warn(errMsg); } } if (exception instanceof ConstraintViolationException constraintViolationException) { @@ -70,9 +70,13 @@ public class DefaultExcelListener extends AnalysisEventListener implements String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", "); errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg); if (log.isDebugEnabled()) { - log.error(errMsg); + log.warn(errMsg); } } + if (errMsg == null) { + errMsg = StrUtil.format("第{}行数据异常: {}", context.readRowHolder().getRowIndex() + 1, exception.getMessage()); + log.warn(errMsg, exception); + } excelResult.getErrorList().add(errMsg); throw new ExcelAnalysisException(errMsg); } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java index 7373e1227..3f887ebed 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java @@ -66,7 +66,7 @@ public class DefaultExcelResult implements ExcelResult { if (errorCount == 0) { return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount); } else { - return ""; + return StrUtil.format("共{}条,成功导入{}条,错误{}条", successCount + errorCount, successCount, errorCount); } } } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java index aa9ff0bfd..00d9b98b6 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java @@ -6,13 +6,13 @@ import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.EnumUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import lombok.extern.slf4j.Slf4j; import org.apache.fesod.sheet.metadata.FieldCache; import org.apache.fesod.sheet.metadata.FieldWrapper; import org.apache.fesod.sheet.util.ClassUtils; import org.apache.fesod.sheet.write.handler.SheetWriteHandler; import org.apache.fesod.sheet.write.metadata.holder.WriteSheetHolder; import org.apache.fesod.sheet.write.metadata.holder.WriteWorkbookHolder; +import lombok.extern.slf4j.Slf4j; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddressList; import org.apache.poi.ss.util.WorkbookUtil; @@ -182,9 +182,10 @@ public class ExcelDownHandler implements SheetWriteHandler { Sheet linkedOptionsDataSheet = workbook.createSheet(WorkbookUtil.createSafeSheetName(linkedOptionsSheetName)); // 将下拉表隐藏 workbook.setSheetHidden(workbook.getSheetIndex(linkedOptionsDataSheet), true); - // 选项数据 + // 选项数据(使用副本,避免修改调用方的原始数据) List firstOptions = options.getOptions(); - Map> secoundOptionsMap = options.getNextOptions(); + Map> secoundOptionsMap = new HashMap<>(); + options.getNextOptions().forEach((k, v) -> secoundOptionsMap.put(k, new ArrayList<>(v))); // 采用按行填充数据的方式,避免出现数据无法写入的问题 // Attempting to write a row in the range that is already written to disk @@ -378,7 +379,6 @@ public class ExcelDownHandler implements SheetWriteHandler { //选定提示 dataValidation.createPromptBox("填写说明:", "填写内容只能为下拉中数据,其他数据将导致导入失败"); dataValidation.setShowPromptBox(true); - sheet.addValidationData(dataValidation); } else { dataValidation.setSuppressDropDownArrow(false); } diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java index b0d4fff87..62a03ca8b 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java @@ -99,6 +99,9 @@ public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler { } ExcelRequired excelRequired = field.getAnnotation(ExcelRequired.class); ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + if (excelProperty == null || excelProperty.value().length == 0) { + continue; + } requiredMap.put(excelProperty.value()[0], excelRequired.fontColor().getIndex()); } return requiredMap; @@ -116,6 +119,9 @@ public class DataWriteHandler implements SheetWriteHandler, CellWriteHandler { } ExcelNotation excelNotation = field.getAnnotation(ExcelNotation.class); ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class); + if (excelProperty == null || excelProperty.value().length == 0) { + continue; + } notationMap.put(excelProperty.value()[0], excelNotation.value()); } return notationMap; diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java index 97862d057..345cd24ab 100644 --- a/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java +++ b/ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java @@ -3,17 +3,17 @@ package org.dromara.common.excel.utils; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.io.resource.ClassPathResource; import cn.hutool.core.util.IdUtil; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletResponse; -import lombok.AccessLevel; -import lombok.NoArgsConstructor; -import org.apache.fesod.sheet.ExcelWriter; import org.apache.fesod.sheet.FesodSheet; +import org.apache.fesod.sheet.ExcelWriter; import org.apache.fesod.sheet.write.builder.ExcelWriterSheetBuilder; import org.apache.fesod.sheet.write.metadata.WriteSheet; import org.apache.fesod.sheet.write.metadata.fill.FillConfig; import org.apache.fesod.sheet.write.metadata.fill.FillWrapper; import org.apache.fesod.sheet.write.style.column.LongestMatchColumnWidthStyleStrategy; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletResponse; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.file.FileUtils; import org.dromara.common.excel.convert.ExcelBigNumberConvert; @@ -89,7 +89,7 @@ public class ExcelUtil { ServletOutputStream os = response.getOutputStream(); exportExcel(list, sheetName, clazz, false, os, null); } catch (IOException e) { - throw new RuntimeException("导出Excel异常"); + throw new RuntimeException("导出Excel异常", e); } } @@ -108,7 +108,7 @@ public class ExcelUtil { ServletOutputStream os = response.getOutputStream(); exportExcel(list, sheetName, clazz, false, os, options); } catch (IOException e) { - throw new RuntimeException("导出Excel异常"); + throw new RuntimeException("导出Excel异常", e); } } @@ -127,7 +127,7 @@ public class ExcelUtil { ServletOutputStream os = response.getOutputStream(); exportExcel(list, sheetName, clazz, merge, os, null); } catch (IOException e) { - throw new RuntimeException("导出Excel异常"); + throw new RuntimeException("导出Excel异常", e); } } @@ -147,7 +147,7 @@ public class ExcelUtil { ServletOutputStream os = response.getOutputStream(); exportExcel(list, sheetName, clazz, merge, os, options); } catch (IOException e) { - throw new RuntimeException("导出Excel异常"); + throw new RuntimeException("导出Excel异常", e); } } @@ -261,7 +261,7 @@ public class ExcelUtil { ServletOutputStream os = response.getOutputStream(); exportTemplate(data, templatePath, os); } catch (IOException e) { - throw new RuntimeException("导出Excel异常"); + throw new RuntimeException("导出Excel异常", e); } } @@ -283,13 +283,16 @@ public class ExcelUtil { .registerConverter(new ExcelBigNumberConvert()) .registerWriteHandler(new DataWriteHandler(data.getFirst().getClass())) .build(); - WriteSheet writeSheet = FesodSheet.writerSheet().build(); - FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); - // 单表多数据导出 模板格式为 {.属性} - for (T d : data) { - excelWriter.fill(d, fillConfig, writeSheet); + try { + WriteSheet writeSheet = FesodSheet.writerSheet().build(); + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + // 单表多数据导出 模板格式为 {.属性} + for (T d : data) { + excelWriter.fill(d, fillConfig, writeSheet); + } + } finally { + excelWriter.finish(); } - excelWriter.finish(); } /** @@ -311,7 +314,7 @@ public class ExcelUtil { ServletOutputStream os = response.getOutputStream(); exportTemplateMultiList(data, templatePath, os); } catch (IOException e) { - throw new RuntimeException("导出Excel异常"); + throw new RuntimeException("导出Excel异常", e); } } @@ -334,7 +337,7 @@ public class ExcelUtil { ServletOutputStream os = response.getOutputStream(); exportTemplateMultiSheet(data, templatePath, os); } catch (IOException e) { - throw new RuntimeException("导出Excel异常"); + throw new RuntimeException("导出Excel异常", e); } } @@ -355,18 +358,21 @@ public class ExcelUtil { // 大数值自动转换 防止失真 .registerConverter(new ExcelBigNumberConvert()) .build(); - WriteSheet writeSheet = FesodSheet.writerSheet().build(); - for (Map.Entry map : data.entrySet()) { - // 设置列表后续还有数据 - FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); - if (map.getValue() instanceof Collection) { - // 多表导出必须使用 FillWrapper - excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); - } else { - excelWriter.fill(map.getValue(), fillConfig, writeSheet); + try { + WriteSheet writeSheet = FesodSheet.writerSheet().build(); + for (Map.Entry map : data.entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), fillConfig, writeSheet); + } } + } finally { + excelWriter.finish(); } - excelWriter.finish(); } /** @@ -386,20 +392,23 @@ public class ExcelUtil { // 大数值自动转换 防止失真 .registerConverter(new ExcelBigNumberConvert()) .build(); - for (int i = 0; i < data.size(); i++) { - WriteSheet writeSheet = FesodSheet.writerSheet(i).build(); - for (Map.Entry map : data.get(i).entrySet()) { - // 设置列表后续还有数据 - FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); - if (map.getValue() instanceof Collection) { - // 多表导出必须使用 FillWrapper - excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); - } else { - excelWriter.fill(map.getValue(), writeSheet); + try { + for (int i = 0; i < data.size(); i++) { + WriteSheet writeSheet = FesodSheet.writerSheet(i).build(); + for (Map.Entry map : data.get(i).entrySet()) { + // 设置列表后续还有数据 + FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); + if (map.getValue() instanceof Collection) { + // 多表导出必须使用 FillWrapper + excelWriter.fill(new FillWrapper(map.getKey(), (Collection) map.getValue()), fillConfig, writeSheet); + } else { + excelWriter.fill(map.getValue(), writeSheet); + } } } + } finally { + excelWriter.finish(); } - excelWriter.finish(); } /** diff --git a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java index e13795a25..4db1c9ad7 100644 --- a/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java +++ b/ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java @@ -31,7 +31,7 @@ public class BigNumberSerializer extends NumberSerializer { @Override public void serialize(Number value, JsonGenerator gen, SerializationContext provider) { // 超出范围 序列化为字符串 - if (value.longValue() > MIN_SAFE_INTEGER && value.longValue() < MAX_SAFE_INTEGER) { + if (value.longValue() >= MIN_SAFE_INTEGER && value.longValue() <= MAX_SAFE_INTEGER) { super.serialize(value, gen, provider); } else { gen.writeString(value.toString()); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java index 7a735a953..431c212dd 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java @@ -33,7 +33,7 @@ public enum DataScopeType { /** * 自定数据权限 */ - CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "), + CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #roleId )} ) ", " 1 = 0 "), /** * 部门数据权限 diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java index 0d0c5d04e..52ae4618d 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java @@ -17,6 +17,7 @@ import java.util.Date; * MP注入处理器 * * @author Lion Li + * @date 2021/4/25 */ @Slf4j public class InjectionMetaObjectHandler implements MetaObjectHandler { @@ -62,7 +63,7 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler { this.strictInsertFill(metaObject, "updateTime", Date.class, date); } } catch (Exception e) { - throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_INTERNAL_ERROR); } } @@ -80,17 +81,14 @@ public class InjectionMetaObjectHandler implements MetaObjectHandler { baseEntity.setUpdateTime(current); // 获取当前登录用户的ID,并填充更新人信息 - Long userId = LoginHelper.getUserId(); - if (ObjectUtil.isNotNull(userId)) { - baseEntity.setUpdateBy(userId); - } else { - baseEntity.setUpdateBy(DEFAULT_USER_ID); - } + LoginUser loginUser = getLoginUser(); + Long userId = ObjectUtil.isNotNull(loginUser) ? loginUser.getUserId() : DEFAULT_USER_ID; + baseEntity.setUpdateBy(userId); } else { this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); } } catch (Exception e) { - throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_UNAUTHORIZED); + throw new ServiceException("自动注入异常 => " + e.getMessage(), HttpStatus.HTTP_INTERNAL_ERROR); } } diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java index cc4bc9d36..abdf49d7a 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java @@ -67,7 +67,7 @@ public class PlusDataPermissionHandler { public Expression getSqlSegment(Expression where, boolean isSelect) { try { LoginUser currentUser = currentUser(); - // 如果是超级管理员,则不过滤数据 + // 如果是超级管理员或租户管理员,则不过滤数据 if (LoginHelper.isSuperAdmin()) { return where; } @@ -134,7 +134,7 @@ public class PlusDataPermissionHandler { } for (RoleDTO role : scopeRoles) { - user.setRoleId(role.getRoleId()); + context.setVariable("roleId", role.getRoleId()); // 获取角色权限泛型 DataScopeType type = DataScopeType.findCode(role.getDataScope()); if (ObjectUtil.isNull(type)) { @@ -175,7 +175,13 @@ public class PlusDataPermissionHandler { return StringUtils.EMPTY; } + /** + * 获取当前登录用户信息 + * + * @return 当前登录用户的LoginUser对象,可能为null(如未登录场景) + */ private LoginUser currentUser() { + // 从数据权限助手缓存中获取当前登录用户 LoginUser currentUser = DataPermissionHelper.getVariable("user"); if (ObjectUtil.isNull(currentUser)) { currentUser = LoginHelper.getLoginUser(); @@ -194,32 +200,6 @@ public class PlusDataPermissionHandler { return resolvedAccess; } - private DataPermissionAccess resolveAccess() { - HttpServletRequest request = ServletUtils.getRequest(); - if (request == null) { - return DataPermissionAccess.EMPTY; - } - Object handler = request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE); - if (!(handler instanceof HandlerMethod handlerMethod)) { - return DataPermissionAccess.EMPTY; - } - Set perms = new LinkedHashSet<>(); - Set roleKeys = new LinkedHashSet<>(); - SaCheckPermission saCheckPermission = findAnnotation(handlerMethod, SaCheckPermission.class); - if (saCheckPermission != null) { - perms.addAll(toSet(saCheckPermission.value())); - roleKeys.addAll(toSet(saCheckPermission.orRole())); - } - SaCheckRole saCheckRole = findAnnotation(handlerMethod, SaCheckRole.class); - if (saCheckRole != null) { - roleKeys.addAll(toSet(saCheckRole.value())); - } - if (perms.isEmpty() && roleKeys.isEmpty()) { - return DataPermissionAccess.EMPTY; - } - return new DataPermissionAccess(Set.copyOf(perms), Set.copyOf(roleKeys)); - } - private List scopeRoles(LoginUser user, DataPermissionAccess access) { List roles = user.getRoles(); if (!access.constrained()) { @@ -253,6 +233,32 @@ public class PlusDataPermissionHandler { return new ArrayList<>(roleMap.values()); } + private DataPermissionAccess resolveAccess() { + HttpServletRequest request = ServletUtils.getRequest(); + if (request == null) { + return DataPermissionAccess.EMPTY; + } + Object handler = request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE); + if (!(handler instanceof HandlerMethod handlerMethod)) { + return DataPermissionAccess.EMPTY; + } + Set perms = new LinkedHashSet<>(); + Set roleKeys = new LinkedHashSet<>(); + SaCheckPermission saCheckPermission = findAnnotation(handlerMethod, SaCheckPermission.class); + if (saCheckPermission != null) { + perms.addAll(toSet(saCheckPermission.value())); + roleKeys.addAll(toSet(saCheckPermission.orRole())); + } + SaCheckRole saCheckRole = findAnnotation(handlerMethod, SaCheckRole.class); + if (saCheckRole != null) { + roleKeys.addAll(toSet(saCheckRole.value())); + } + if (perms.isEmpty() && roleKeys.isEmpty()) { + return DataPermissionAccess.EMPTY; + } + return new DataPermissionAccess(Set.copyOf(perms), Set.copyOf(roleKeys)); + } + private A findAnnotation(HandlerMethod handlerMethod, Class annotationType) { A annotation = AnnotationUtil.getAnnotation(handlerMethod.getMethod(), annotationType); if (annotation != null) { diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java index 84a8a5c2a..03c521edb 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java @@ -2,6 +2,7 @@ package org.dromara.common.mybatis.helper; import cn.hutool.core.convert.Convert; import com.baomidou.dynamic.datasource.DynamicRoutingDataSource; +import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.dromara.common.core.exception.ServiceException; @@ -14,6 +15,8 @@ import java.sql.DatabaseMetaData; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * 数据库助手 @@ -24,6 +27,7 @@ import java.util.List; public class DataBaseHelper { private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class); + private static final Map DB_TYPE_CACHE = new ConcurrentHashMap<>(); /** * 获取当前数据源对应的数据库类型 @@ -37,13 +41,17 @@ public class DataBaseHelper { */ public static DataBaseType getDataBaseType() { DataSource dataSource = DS.determineDataSource(); - try (Connection conn = dataSource.getConnection()) { - DatabaseMetaData metaData = conn.getMetaData(); - String databaseProductName = metaData.getDatabaseProductName(); - return DataBaseType.find(databaseProductName); - } catch (SQLException e) { - throw new RuntimeException("获取数据库类型失败", e); - } + String dsKey = DynamicDataSourceContextHolder.peek(); + final String key = dsKey != null ? dsKey : "primary"; + return DB_TYPE_CACHE.computeIfAbsent(key, k -> { + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData metaData = conn.getMetaData(); + String databaseProductName = metaData.getDatabaseProductName(); + return DataBaseType.find(databaseProductName); + } catch (SQLException e) { + throw new RuntimeException("获取数据库类型失败", e); + } + }); } /** @@ -74,7 +82,9 @@ public class DataBaseHelper { } /** - * 获取当前加载的数据库名 + * 获取当前注册的数据源名称列表。 + * + * @return 数据源名称列表 */ public static List getDataSourceNameList() { return new ArrayList<>(DS.getDataSources().keySet()); diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java index f326560b9..d31b45b1a 100644 --- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java +++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java @@ -8,13 +8,14 @@ import com.baomidou.mybatisplus.core.plugins.IgnoreStrategy; import com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.dromara.common.mybatis.core.domain.DataPermissionAccess; import org.dromara.common.core.utils.reflect.ReflectUtils; import org.dromara.common.mybatis.annotation.DataPermission; -import org.dromara.common.mybatis.core.domain.DataPermissionAccess; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.HashMap; import java.util.Map; -import java.util.Stack; import java.util.function.Supplier; /** @@ -27,10 +28,10 @@ import java.util.function.Supplier; @SuppressWarnings("unchecked") public class DataPermissionHelper { - public static final String DATA_PERMISSION_KEY = "data:permission"; + private static final String DATA_PERMISSION_KEY = "data:permission"; private static final String ACCESS_KEY = "data:permission:access"; - private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(Stack::new); + private static final ThreadLocal> REENTRANT_IGNORE = ThreadLocal.withInitial(ArrayDeque::new); private static final ThreadLocal PERMISSION_CACHE = new ThreadLocal<>(); @@ -46,7 +47,7 @@ public class DataPermissionHelper { /** * 设置当前执行mapper权限注解 * - * @param dataPermission 数据权限注解 + * @param dataPermission 数据权限注解 */ public static void setPermission(DataPermission dataPermission) { PERMISSION_CACHE.set(dataPermission); @@ -82,10 +83,20 @@ public class DataPermissionHelper { context.put(key, value); } + /** + * 获取当前数据权限访问控制对象。 + * + * @return 访问控制对象 + */ public static DataPermissionAccess getAccess() { return getVariable(ACCESS_KEY); } + /** + * 设置当前数据权限访问控制对象。 + * + * @param access 访问控制对象 + */ public static void setAccess(DataPermissionAccess access) { setVariable(ACCESS_KEY, access); } @@ -97,21 +108,23 @@ public class DataPermissionHelper { * @throws NullPointerException 如果数据权限上下文类型异常,则抛出NullPointerException */ public static Map getContext() { - Object attribute = new HashMap<>(); - if (SaHolder.getContext().isValid()) { - SaStorage saStorage = SaHolder.getStorage(); + SaStorage saStorage = SaHolder.getStorage(); + Object attribute = saStorage.get(DATA_PERMISSION_KEY); + if (ObjectUtil.isNull(attribute)) { + saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); attribute = saStorage.get(DATA_PERMISSION_KEY); - if (ObjectUtil.isNull(attribute)) { - saStorage.set(DATA_PERMISSION_KEY, new HashMap<>()); - attribute = saStorage.get(DATA_PERMISSION_KEY); - } } if (attribute instanceof Map map) { return map; } - throw new NullPointerException("data permission context type exception"); + throw new IllegalStateException("data permission context type exception"); } + /** + * 获取当前忽略策略。 + * + * @return 忽略策略 + */ private static IgnoreStrategy getIgnoreStrategy() { Object ignoreStrategyLocal = ReflectUtils.getStaticFieldValue(ReflectUtils.getField(InterceptorIgnoreHelper.class, "IGNORE_STRATEGY_LOCAL")); if (ignoreStrategyLocal instanceof ThreadLocal IGNORE_STRATEGY_LOCAL) { @@ -132,7 +145,7 @@ public class DataPermissionHelper { } else { ignoreStrategy.setDataPermission(true); } - Stack reentrantStack = REENTRANT_IGNORE.get(); + Deque reentrantStack = REENTRANT_IGNORE.get(); reentrantStack.push(reentrantStack.size() + 1); } @@ -147,7 +160,7 @@ public class DataPermissionHelper { && !Boolean.TRUE.equals(ignoreStrategy.getIllegalSql()) && !Boolean.TRUE.equals(ignoreStrategy.getTenantLine()) && CollectionUtil.isEmpty(ignoreStrategy.getOthers()); - Stack reentrantStack = REENTRANT_IGNORE.get(); + Deque reentrantStack = REENTRANT_IGNORE.get(); boolean empty = reentrantStack.isEmpty() || reentrantStack.pop() == 1; if (noOtherIgnoreStrategy && empty) { InterceptorIgnoreHelper.clearIgnoreStrategy(); @@ -176,6 +189,7 @@ public class DataPermissionHelper { * 在忽略数据权限中执行 * * @param handle 处理执行方法 + * @return 执行结果 */ public static T ignore(Supplier handle) { enableIgnore(); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java index 582f8a42a..be5857cfd 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java @@ -2,6 +2,7 @@ package org.dromara.system.dubbo; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.RequiredArgsConstructor; import org.apache.dubbo.config.annotation.DubboService; @@ -53,7 +54,7 @@ public class RemoteDeptServiceImpl implements RemoteDeptService { @Override public Long selectDeptLeaderById(Long deptId) { SysDeptVo vo = deptService.selectDeptById(deptId); - return vo.getLeader(); + return ObjectUtil.isNull(vo) ? null : vo.getLeader(); } /** diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java index 680064efe..d3f91a2af 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java @@ -142,7 +142,7 @@ public class SysConfigServiceImpl implements ISysConfigService { SysConfig config = MapstructUtils.convert(bo, SysConfig.class); if (config.getConfigId() != null) { SysConfig temp = baseMapper.selectById(config.getConfigId()); - if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) { + if (ObjectUtil.isNotNull(temp) && !StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) { CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey()); } row = baseMapper.updateById(config); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java index 820f39c70..556323603 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java @@ -281,7 +281,10 @@ public class SysDeptServiceImpl implements ISysDeptService { @Override public int insertDept(SysDeptBo bo) { SysDept info = baseMapper.selectById(bo.getParentId()); - // 如果父节点不为正常状态,则不允许新增子节点 + // 如果父节点不存在或不为正常状态,则不允许新增子节点 + if (ObjectUtil.isNull(info)) { + throw new ServiceException("父部门不存在"); + } if (!SystemConstants.NORMAL.equals(info.getStatus())) { throw new ServiceException("部门停用,不允许新增"); } @@ -356,7 +359,7 @@ public class SysDeptServiceImpl implements ISysDeptService { for (SysDept child : children) { SysDept dept = new SysDept(); dept.setDeptId(child.getDeptId()); - dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors)); + dept.setAncestors(StringUtils.replaceOnce(child.getAncestors(), oldAncestors, newAncestors)); list.add(dept); } if (CollUtil.isNotEmpty(list)) { @@ -374,7 +377,7 @@ public class SysDeptServiceImpl implements ISysDeptService { */ @Caching(evict = { @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId"), - @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId") + @CacheEvict(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, allEntries = true) }) @Override public int deleteDeptById(Long deptId) { diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java index 5aeb87136..eb41afea7 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java @@ -28,6 +28,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -100,7 +101,7 @@ public class SysDictTypeServiceImpl implements ISysDictTypeService { @Override public List selectDictDataByType(String dictType) { List dictDatas = dictDataMapper.selectDictDataByType(dictType); - return CollUtil.isNotEmpty(dictDatas) ? dictDatas : null; + return CollUtil.isNotEmpty(dictDatas) ? dictDatas : Collections.emptyList(); } /**