diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java index 5d03cfbe5..79fd7e51a 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -153,7 +153,7 @@ public class SysLoginService { loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); } - ThreadUtils.virtualSubmit(() -> { + ThreadUtils.virtualInvokeAll(() -> { loginUser.setMenuPermission(permissionService.getMenuPermission(userId)); }, () -> { loginUser.setRolePermission(permissionService.getRolePermission(userId)); diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java index a56cb5bd4..79f1df232 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java @@ -26,19 +26,16 @@ public class ValidatorConfig { */ @Bean public Validator validator(MessageSource messageSource) { - try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) { - // 国际化 - factoryBean.setValidationMessageSource(messageSource); - // 设置使用 HibernateValidator 校验器 - factoryBean.setProviderClass(HibernateValidator.class); - Properties properties = new Properties(); - // 设置快速失败模式(fail-fast),即校验过程中一旦遇到失败,立即停止并返回错误 - properties.setProperty("hibernate.validator.fail_fast", "true"); - factoryBean.setValidationProperties(properties); - // 加载配置 - factoryBean.afterPropertiesSet(); - return factoryBean.getValidator(); - } + LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean(); + // 国际化 + factoryBean.setValidationMessageSource(messageSource); + // 设置使用 HibernateValidator 校验器 + factoryBean.setProviderClass(HibernateValidator.class); + Properties properties = new Properties(); + // 设置快速失败模式(fail-fast),即校验过程中一旦遇到失败,立即停止并返回错误 + properties.setProperty("hibernate.validator.fail_fast", "true"); + factoryBean.setValidationProperties(properties); + return factoryBean; } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java index a89a755ea..c85f7355f 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/PageResult.java @@ -6,6 +6,7 @@ import lombok.NoArgsConstructor; import java.io.Serial; import java.io.Serializable; import java.util.Collection; +import java.util.Collections; /** * 表格分页数据对象 @@ -36,7 +37,7 @@ public class PageResult implements Serializable { * @param total 总记录数 */ public PageResult(Collection list, long total) { - this.rows = list; + this.rows = emptyIfNull(list); this.total = total; } @@ -45,7 +46,7 @@ public class PageResult implements Serializable { */ public static PageResult build(Collection list, long total) { PageResult rspData = new PageResult<>(); - rspData.setRows(list); + rspData.setRows(emptyIfNull(list)); rspData.setTotal(total); return rspData; } @@ -55,8 +56,9 @@ public class PageResult implements Serializable { */ public static PageResult build(Collection list) { PageResult rspData = new PageResult<>(); - rspData.setRows(list); - rspData.setTotal(list.size()); + Collection rows = emptyIfNull(list); + rspData.setRows(rows); + rspData.setTotal(rows.size()); return rspData; } @@ -67,4 +69,8 @@ public class PageResult implements Serializable { return new PageResult<>(); } + private static Collection emptyIfNull(Collection list) { + return list == null ? Collections.emptyList() : list; + } + } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java index 972263199..53c5f7737 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java @@ -197,7 +197,7 @@ public class R implements Serializable { * @return true=成功,false=失败 */ public static Boolean isSuccess(R ret) { - return SUCCESS == ret.getCode(); + return ret != null && SUCCESS == ret.getCode(); } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java index 75e33cc54..a8e46aa80 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java @@ -57,6 +57,17 @@ public final class ServiceException extends RuntimeException { this.code = code; } + /** + * 使用错误消息和根因构造业务异常。 + * + * @param message 错误消息 + * @param cause 根因 + */ + public ServiceException(String message, Throwable cause) { + super(cause); + this.message = message; + } + /** * 使用占位符参数格式化错误消息。 * diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java index 5eb55238b..2dafe34c2 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java @@ -156,7 +156,7 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { try { return new SimpleDateFormat(format.getTimeFormat()).parse(ts); } catch (ParseException e) { - throw new RuntimeException(e); + throw new ServiceException("日期时间解析失败:" + ts, e); } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java index 329892969..5654e8bed 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java @@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.web.context.request.RequestAttributes; @@ -31,6 +32,7 @@ import java.util.Map; * @author ruoyi */ @NoArgsConstructor(access = AccessLevel.PRIVATE) +@Slf4j public class ServletUtils extends JakartaServletUtil { /** @@ -223,7 +225,7 @@ public class ServletUtils extends JakartaServletUtil { response.setCharacterEncoding(StandardCharsets.UTF_8.toString()); response.getWriter().print(string); } catch (IOException e) { - e.printStackTrace(); + log.error("渲染响应内容异常", e); } } @@ -249,7 +251,7 @@ public class ServletUtils extends JakartaServletUtil { // 判断 URI 后缀是否为 .json 或 .xml String uri = request.getRequestURI(); - if (StringUtils.equalsAnyIgnoreCase(uri, ".json", ".xml")) { + if (StringUtils.endsWithAny(StringUtils.lowerCase(uri), ".json", ".xml")) { return true; } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ThreadUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ThreadUtils.java index fd382918b..a03e96819 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ThreadUtils.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ThreadUtils.java @@ -2,6 +2,7 @@ package org.dromara.common.core.utils; import lombok.AccessLevel; import lombok.NoArgsConstructor; +import org.dromara.common.core.exception.ServiceException; import java.util.ArrayList; import java.util.List; @@ -18,7 +19,7 @@ public class ThreadUtils { /** * 批量执行任务 */ - public static void virtualSubmit(Runnable ...runnableList) { + public static void virtualInvokeAll(Runnable... runnableList) { List> callableList = new ArrayList<>(); try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) { for (Runnable runnable : runnableList) { @@ -27,8 +28,12 @@ public class ThreadUtils { for (Future future : callableList) { future.get(); } - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("线程执行被中断", e); + } catch (ExecutionException e) { + Throwable cause = e.getCause() == null ? e : e.getCause(); + throw new RuntimeException("线程执行异常:" + cause.getMessage(), cause); } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPattern.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPattern.java index 5bc41a354..0176106e4 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPattern.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPattern.java @@ -26,7 +26,7 @@ public @interface DictPattern { /** * 分隔符 */ - String separator(); + String separator() default ","; /** * 默认校验失败提示信息 diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPatternValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPatternValidator.java index 558a3438a..e454ed8d4 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPatternValidator.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPatternValidator.java @@ -45,7 +45,10 @@ public class DictPatternValidator implements ConstraintValidator { - private EnumPattern annotation; + private final Set values = new HashSet<>(); @Override public void initialize(EnumPattern annotation) { ConstraintValidator.super.initialize(annotation); - this.annotation = annotation; + String fieldName = annotation.fieldName(); + if (StringUtils.isBlank(fieldName)) { + return; + } + for (Object e : annotation.type().getEnumConstants()) { + Object fieldValue = ReflectUtils.invokeGetter(e, fieldName); + if (fieldValue != null) { + values.add(String.valueOf(fieldValue)); + } + } } @Override public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { - if (StringUtils.isNotBlank(value)) { - String fieldName = annotation.fieldName(); - for (Object e : annotation.type().getEnumConstants()) { - if (value.equals(ReflectUtils.invokeGetter(e, fieldName))) { - return true; - } - } + if (StringUtils.isBlank(value)) { + return true; } - return false; + return values.contains(value); } } diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java index 9c3256300..374ea0b2d 100644 --- a/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java +++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java @@ -2,9 +2,9 @@ package org.dromara.common.core.xss; import cn.hutool.core.util.ReUtil; import cn.hutool.http.HtmlUtil; - import jakarta.validation.ConstraintValidator; import jakarta.validation.ConstraintValidatorContext; +import org.dromara.common.core.utils.StringUtils; /** * 自定义xss校验注解实现 @@ -15,6 +15,9 @@ public class XssValidator implements ConstraintValidator { @Override public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { + if (StringUtils.isBlank(value)) { + return true; + } return !ReUtil.contains(HtmlUtil.RE_HTML_MARK, value); }