diff --git a/sql/youlai_admin.sql b/sql/youlai_admin.sql index 03c77ef2..d8beab29 100644 --- a/sql/youlai_admin.sql +++ b/sql/youlai_admin.sql @@ -168,10 +168,11 @@ COMMENT ON COLUMN sys_menu.id IS 'ID'; COMMENT ON COLUMN sys_menu.parent_id IS '父菜单ID'; COMMENT ON COLUMN sys_menu.tree_path IS '父节点ID路径'; COMMENT ON COLUMN sys_menu.name IS '菜单名称'; -COMMENT ON COLUMN sys_menu.type IS '菜单类型(C-目录 M-菜单 B-按钮)'; +COMMENT ON COLUMN sys_menu.type IS '菜单类型(C-目录 M-菜单 E-外链 B-按钮)'; COMMENT ON COLUMN sys_menu.route_name IS '路由名称(Vue Router 中用于命名路由)'; COMMENT ON COLUMN sys_menu.route_path IS '路由路径(Vue Router 中定义的 URL 路径)'; COMMENT ON COLUMN sys_menu.component IS '组件路径(组件页面完整路径,相对于 src/views/,缺省后缀 .vue)'; +COMMENT ON COLUMN sys_menu.external_url IS '外链地址'; COMMENT ON COLUMN sys_menu.perm IS '【按钮】权限标识'; COMMENT ON COLUMN sys_menu.always_show IS '【目录】只有一个子路由是否始终显示(1-是 0-否)'; COMMENT ON COLUMN sys_menu.keep_alive IS '【菜单】是否开启页面缓存(1-是 0-否)'; diff --git a/src/main/java/com/youlai/boot/common/constant/RedisConstants.java b/src/main/java/com/youlai/boot/common/constant/RedisConstants.java index b54c0455..7555337d 100644 --- a/src/main/java/com/youlai/boot/common/constant/RedisConstants.java +++ b/src/main/java/com/youlai/boot/common/constant/RedisConstants.java @@ -12,7 +12,7 @@ public interface RedisConstants { * 限流相关键 */ interface RateLimiter { - String IP = "rate_limiter:ip:{}"; // IP限流(示例:rate_limiter:ip:192.168.1.1) + String API = "{}rate_limit:{}:{}"; // 接口限流 } /** diff --git a/src/main/java/com/youlai/boot/common/constant/SystemConstants.java b/src/main/java/com/youlai/boot/common/constant/SystemConstants.java index 43489745..0e5edc2f 100644 --- a/src/main/java/com/youlai/boot/common/constant/SystemConstants.java +++ b/src/main/java/com/youlai/boot/common/constant/SystemConstants.java @@ -24,9 +24,5 @@ public interface SystemConstants { String ROOT_ROLE_CODE = "ROOT"; - /** - * 系统配置 IP的QPS限流的KEY - */ - String SYSTEM_CONFIG_IP_QPS_LIMIT_KEY = "IP_QPS_THRESHOLD_LIMIT"; } diff --git a/src/main/java/com/youlai/boot/common/enums/CaptchaTypeEnum.java b/src/main/java/com/youlai/boot/common/enums/CaptchaTypeEnum.java deleted file mode 100644 index 8d3fe10e..00000000 --- a/src/main/java/com/youlai/boot/common/enums/CaptchaTypeEnum.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.youlai.boot.common.enums; - -/** - * EasyCaptcha 验证码类型枚举 - * - * @author haoxr - * @since 2.5.1 - */ -public enum CaptchaTypeEnum { - - /** - * 圆圈干扰验证码 - */ - CIRCLE, - /** - * GIF验证码 - */ - GIF, - /** - * 干扰线验证码 - */ - LINE, - /** - * 扭曲干扰验证码 - */ - SHEAR -} diff --git a/src/main/java/com/youlai/boot/common/result/ResponseWriter.java b/src/main/java/com/youlai/boot/common/result/ResponseWriter.java deleted file mode 100644 index 9b033990..00000000 --- a/src/main/java/com/youlai/boot/common/result/ResponseWriter.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.youlai.boot.common.result; - -import cn.hutool.extra.servlet.JakartaServletUtil; -import cn.hutool.json.JSONUtil; -import jakarta.servlet.http.HttpServletResponse; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -import java.nio.charset.StandardCharsets; - -/** - * 响应写入器 - *
- * 用于在过滤器、Security处理器等无法使用 @RestControllerAdvice 的场景中统一写入HTTP响应。
- * 支持写入成功响应和错误响应。
- * 此类为工具类,所有方法均为静态方法,禁止实例化。
- *
- * @author Ray.Hao
- * @since 2.0.0
- */
-@Slf4j
-public final class ResponseWriter {
-
- /**
- * 私有构造函数,防止实例化
- */
- private ResponseWriter() {
- throw new UnsupportedOperationException("工具类不允许实例化");
- }
-
- /**
- * 写入成功响应
- *
- * @param response HttpServletResponse
- * @param data 响应数据(可选)
- */
- public static void writeSuccess(HttpServletResponse response, Object data) {
- writeResult(response, Result.success(data), HttpStatus.OK.value());
- }
-
- /**
- * 写入成功响应(无数据)
- *
- * @param response HttpServletResponse
- */
- public static void writeSuccess(HttpServletResponse response) {
- writeSuccess(response, null);
- }
-
- /**
- * 写入错误响应
- *
- * @param response HttpServletResponse
- * @param resultCode 响应结果码
- */
- public static void writeError(HttpServletResponse response, ResultCode resultCode) {
- writeError(response, resultCode, null);
- }
-
- /**
- * 写入错误响应(带自定义消息)
- *
- * @param response HttpServletResponse
- * @param resultCode 响应结果码
- * @param message 自定义消息(可选,为 null 时使用 resultCode 的默认消息)
- */
- public static void writeError(HttpServletResponse response, ResultCode resultCode, String message) {
- Result> result = message == null
- ? Result.failed(resultCode)
- : Result.failed(resultCode, message);
-
- int httpStatus = mapHttpStatus(resultCode);
- writeResult(response, result, httpStatus);
- }
-
- /**
- * 写入响应结果(通用方法)
- *
- * @param response HttpServletResponse
- * @param result 响应结果对象
- * @param httpStatus HTTP状态码
- */
- private static void writeResult(HttpServletResponse response, Result> result, int httpStatus) {
- try {
- // 设置HTTP状态码
- response.setStatus(httpStatus);
-
- // 设置响应编码和内容类型
- response.setCharacterEncoding(StandardCharsets.UTF_8.toString());
- response.setContentType(MediaType.APPLICATION_JSON_VALUE);
-
- // 写入响应
- JakartaServletUtil.write(response,
- JSONUtil.toJsonStr(result),
- MediaType.APPLICATION_JSON_VALUE
- );
-
- } catch (Exception e) {
- log.error("写入响应时发生未知异常: httpStatus={}, result={}", httpStatus, result, e);
- }
- }
-
- /**
- * 根据业务结果码映射HTTP状态码
- * 401: 未认证(token无效/过期)
- * 403: 权限不足
- * 400: 其他业务错误
- *
- * @param resultCode 业务结果码
- * @return HTTP状态码
- */
- private static int mapHttpStatus(ResultCode resultCode) {
- return switch (resultCode) {
- case ACCESS_UNAUTHORIZED,
- ACCESS_TOKEN_INVALID,
- REFRESH_TOKEN_INVALID -> HttpStatus.UNAUTHORIZED.value();
- case ACCESS_PERMISSION_EXCEPTION -> HttpStatus.FORBIDDEN.value();
- default -> HttpStatus.BAD_REQUEST.value();
- };
- }
-}
diff --git a/src/main/java/com/youlai/boot/framework/captcha/enums/CaptchaTypeEnum.java b/src/main/java/com/youlai/boot/framework/captcha/enums/CaptchaTypeEnum.java
new file mode 100644
index 00000000..75061a6e
--- /dev/null
+++ b/src/main/java/com/youlai/boot/framework/captcha/enums/CaptchaTypeEnum.java
@@ -0,0 +1,15 @@
+package com.youlai.boot.framework.captcha.enums;
+
+/**
+ * EasyCaptcha 验证码类型枚举
+ *
+ * @author haoxr
+ * @since 2.5.1
+ */
+public enum CaptchaTypeEnum {
+
+ CIRCLE,
+ GIF,
+ LINE,
+ SHEAR
+}
diff --git a/src/main/java/com/youlai/boot/framework/captcha/service/CaptchaService.java b/src/main/java/com/youlai/boot/framework/captcha/service/CaptchaService.java
index 32ff0416..6e9d9859 100644
--- a/src/main/java/com/youlai/boot/framework/captcha/service/CaptchaService.java
+++ b/src/main/java/com/youlai/boot/framework/captcha/service/CaptchaService.java
@@ -6,7 +6,7 @@ import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.youlai.boot.common.constant.RedisConstants;
-import com.youlai.boot.common.enums.CaptchaTypeEnum;
+import com.youlai.boot.framework.captcha.enums.CaptchaTypeEnum;
import com.youlai.boot.common.result.ResultCode;
import com.youlai.boot.framework.captcha.config.CaptchaProperties;
import com.youlai.boot.framework.captcha.exception.CaptchaException;
diff --git a/src/main/java/com/youlai/boot/framework/mybatis/config/MybatisConfig.java b/src/main/java/com/youlai/boot/framework/mybatis/config/MybatisConfig.java
index 58ce0f7c..54272615 100644
--- a/src/main/java/com/youlai/boot/framework/mybatis/config/MybatisConfig.java
+++ b/src/main/java/com/youlai/boot/framework/mybatis/config/MybatisConfig.java
@@ -5,7 +5,7 @@ import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
-import com.youlai.boot.framework.mybatis.handler.MyMetaObjectHandler;
+import com.youlai.boot.framework.mybatis.handler.AutoFillMetaObjectHandler;
import com.youlai.boot.framework.mybatis.interceptor.MyDataPermissionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -43,7 +43,7 @@ public class MybatisConfig {
@Bean
public GlobalConfig globalConfig() {
GlobalConfig globalConfig = new GlobalConfig();
- globalConfig.setMetaObjectHandler(new MyMetaObjectHandler());
+ globalConfig.setMetaObjectHandler(new AutoFillMetaObjectHandler());
return globalConfig;
}
diff --git a/src/main/java/com/youlai/boot/framework/mybatis/handler/MyMetaObjectHandler.java b/src/main/java/com/youlai/boot/framework/mybatis/handler/AutoFillMetaObjectHandler.java
similarity index 94%
rename from src/main/java/com/youlai/boot/framework/mybatis/handler/MyMetaObjectHandler.java
rename to src/main/java/com/youlai/boot/framework/mybatis/handler/AutoFillMetaObjectHandler.java
index 75b6f41f..0a24cd86 100644
--- a/src/main/java/com/youlai/boot/framework/mybatis/handler/MyMetaObjectHandler.java
+++ b/src/main/java/com/youlai/boot/framework/mybatis/handler/AutoFillMetaObjectHandler.java
@@ -18,7 +18,7 @@ import java.time.LocalDateTime;
*/
@Component
@RequiredArgsConstructor
-public class MyMetaObjectHandler implements MetaObjectHandler {
+public class AutoFillMetaObjectHandler implements MetaObjectHandler {
/**
* 新增填充创建时间、更新时间
diff --git a/src/main/java/com/youlai/boot/framework/security/config/SecurityConfig.java b/src/main/java/com/youlai/boot/framework/security/config/SecurityConfig.java
index 190175e6..196477f7 100644
--- a/src/main/java/com/youlai/boot/framework/security/config/SecurityConfig.java
+++ b/src/main/java/com/youlai/boot/framework/security/config/SecurityConfig.java
@@ -3,7 +3,6 @@ package com.youlai.boot.framework.security.config;
import cn.binarywang.wx.miniapp.api.WxMaService;
import com.youlai.boot.framework.captcha.service.CaptchaService;
import cn.hutool.core.util.ArrayUtil;
-import com.youlai.boot.framework.web.filter.RateLimiterFilter;
import com.youlai.boot.framework.security.filter.CaptchaValidationFilter;
import com.youlai.boot.framework.security.filter.TokenAuthenticationFilter;
import com.youlai.boot.framework.security.handler.MyAccessDeniedHandler;
@@ -86,8 +85,6 @@ public class SecurityConfig {
.httpBasic(AbstractHttpConfigurer::disable) // 禁用 HTTP Basic 认证,避免弹窗式登录
// 禁用 X-Frame-Options 响应头,允许页面被嵌套到 iframe 中
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
- // 限流过滤器
- .addFilterBefore(new RateLimiterFilter(redisTemplate, configService), UsernamePasswordAuthenticationFilter.class)
// 验证码校验过滤器
.addFilterBefore(new CaptchaValidationFilter(captchaService), UsernamePasswordAuthenticationFilter.class)
// 验证和解析过滤器
diff --git a/src/main/java/com/youlai/boot/framework/security/filter/CaptchaValidationFilter.java b/src/main/java/com/youlai/boot/framework/security/filter/CaptchaValidationFilter.java
index 4f1d6fcb..30504bc2 100644
--- a/src/main/java/com/youlai/boot/framework/security/filter/CaptchaValidationFilter.java
+++ b/src/main/java/com/youlai/boot/framework/security/filter/CaptchaValidationFilter.java
@@ -5,7 +5,7 @@ import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.youlai.boot.common.constant.SecurityConstants;
import com.youlai.boot.common.result.ResultCode;
-import com.youlai.boot.common.result.ResponseWriter;
+import com.youlai.boot.framework.web.util.ResponseWriter;
import com.youlai.boot.framework.captcha.exception.CaptchaException;
import com.youlai.boot.framework.captcha.service.CaptchaService;
import jakarta.servlet.FilterChain;
diff --git a/src/main/java/com/youlai/boot/framework/security/filter/TokenAuthenticationFilter.java b/src/main/java/com/youlai/boot/framework/security/filter/TokenAuthenticationFilter.java
index d2514c12..4aad3db0 100644
--- a/src/main/java/com/youlai/boot/framework/security/filter/TokenAuthenticationFilter.java
+++ b/src/main/java/com/youlai/boot/framework/security/filter/TokenAuthenticationFilter.java
@@ -3,7 +3,7 @@ package com.youlai.boot.framework.security.filter;
import cn.hutool.core.util.StrUtil;
import com.youlai.boot.common.constant.SecurityConstants;
import com.youlai.boot.common.result.ResultCode;
-import com.youlai.boot.common.result.ResponseWriter;
+import com.youlai.boot.framework.web.util.ResponseWriter;
import com.youlai.boot.framework.security.token.TokenManager;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
diff --git a/src/main/java/com/youlai/boot/framework/security/handler/MyAccessDeniedHandler.java b/src/main/java/com/youlai/boot/framework/security/handler/MyAccessDeniedHandler.java
index 712cc0a4..b4b28ab4 100644
--- a/src/main/java/com/youlai/boot/framework/security/handler/MyAccessDeniedHandler.java
+++ b/src/main/java/com/youlai/boot/framework/security/handler/MyAccessDeniedHandler.java
@@ -1,7 +1,7 @@
package com.youlai.boot.framework.security.handler;
import com.youlai.boot.common.result.ResultCode;
-import com.youlai.boot.common.result.ResponseWriter;
+import com.youlai.boot.framework.web.util.ResponseWriter;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
diff --git a/src/main/java/com/youlai/boot/framework/security/handler/MyAuthenticationEntryPoint.java b/src/main/java/com/youlai/boot/framework/security/handler/MyAuthenticationEntryPoint.java
index b5110142..4f4257c1 100644
--- a/src/main/java/com/youlai/boot/framework/security/handler/MyAuthenticationEntryPoint.java
+++ b/src/main/java/com/youlai/boot/framework/security/handler/MyAuthenticationEntryPoint.java
@@ -1,7 +1,7 @@
package com.youlai.boot.framework.security.handler;
import com.youlai.boot.common.result.ResultCode;
-import com.youlai.boot.common.result.ResponseWriter;
+import com.youlai.boot.framework.web.util.ResponseWriter;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.AuthenticationException;
diff --git a/src/main/java/com/youlai/boot/framework/web/filter/RateLimiterFilter.java b/src/main/java/com/youlai/boot/framework/web/filter/RateLimiterFilter.java
deleted file mode 100644
index 5b860442..00000000
--- a/src/main/java/com/youlai/boot/framework/web/filter/RateLimiterFilter.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.youlai.boot.framework.web.filter;
-
-import cn.hutool.core.convert.Convert;
-import cn.hutool.core.util.StrUtil;
-import com.youlai.boot.common.constant.RedisConstants;
-import com.youlai.boot.common.constant.SystemConstants;
-import com.youlai.boot.common.result.ResultCode;
-import com.youlai.boot.common.util.IPUtils;
-import com.youlai.boot.common.result.ResponseWriter;
-import com.youlai.boot.system.service.ConfigService;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
-import lombok.extern.slf4j.Slf4j;
-import org.jetbrains.annotations.NotNull;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.web.filter.OncePerRequestFilter;
-
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-
-/**
- * IP 限流过滤器
- *
- * @author Theo
- * @since 2024/08/10 14:38
- */
-@Slf4j
-public class RateLimiterFilter extends OncePerRequestFilter {
-
- private final RedisTemplate 用于过滤器、Security处理器等场景统一写入HTTP响应