From 8df354037254dd1811185822014bc98b26a273b2 Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Wed, 24 Jun 2026 08:12:01 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E5=88=A0=E9=99=A4=E9=99=90?= =?UTF-8?q?=E6=B5=81Filter=20=E5=AE=9E=E4=BD=93=E7=BB=9F=E4=B8=80=20?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=BD=92=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/youlai_admin.sql | 3 +- .../boot/common/constant/RedisConstants.java | 2 +- .../boot/common/constant/SystemConstants.java | 4 - .../boot/common/enums/CaptchaTypeEnum.java | 27 ---- .../boot/common/result/ResponseWriter.java | 122 ------------------ .../captcha/enums/CaptchaTypeEnum.java | 15 +++ .../captcha/service/CaptchaService.java | 2 +- .../mybatis/config/MybatisConfig.java | 4 +- ...er.java => AutoFillMetaObjectHandler.java} | 2 +- .../security/config/SecurityConfig.java | 3 - .../filter/CaptchaValidationFilter.java | 2 +- .../filter/TokenAuthenticationFilter.java | 2 +- .../handler/MyAccessDeniedHandler.java | 2 +- .../handler/MyAuthenticationEntryPoint.java | 2 +- .../web/filter/RateLimiterFilter.java | 98 -------------- .../framework/web/util/ResponseWriter.java | 61 +++++++++ ...CountJob.java => OnlineUserCountTask.java} | 2 +- .../boot/system/enums/MenuTypeEnum.java | 14 +- .../youlai/boot/system/model/entity/Menu.java | 33 ++--- .../boot/system/model/form/MenuForm.java | 3 + .../youlai/boot/system/model/vo/MenuVO.java | 3 + .../boot/system/service/ConfigService.java | 7 - .../service/impl/ConfigServiceImpl.java | 14 -- .../resources/mapper/system/MenuMapper.xml | 1 + 24 files changed, 110 insertions(+), 318 deletions(-) delete mode 100644 src/main/java/com/youlai/boot/common/enums/CaptchaTypeEnum.java delete mode 100644 src/main/java/com/youlai/boot/common/result/ResponseWriter.java create mode 100644 src/main/java/com/youlai/boot/framework/captcha/enums/CaptchaTypeEnum.java rename src/main/java/com/youlai/boot/framework/mybatis/handler/{MyMetaObjectHandler.java => AutoFillMetaObjectHandler.java} (94%) delete mode 100644 src/main/java/com/youlai/boot/framework/web/filter/RateLimiterFilter.java create mode 100644 src/main/java/com/youlai/boot/framework/web/util/ResponseWriter.java rename src/main/java/com/youlai/boot/message/job/{OnlineUserCountJob.java => OnlineUserCountTask.java} (96%) 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 redisTemplate; - private final ConfigService configService; - - private static final long DEFAULT_IP_LIMIT = 10L; // 默认 IP 限流阈值 - - public RateLimiterFilter(RedisTemplate redisTemplate, ConfigService configService) { - this.redisTemplate = redisTemplate; - this.configService = configService; - } - - /** - * 判断 IP 是否触发限流 - * 默认限制同一 IP 每秒最多请求 10 次,可通过系统配置调整。 - * 如果系统未配置限流阈值,默认跳过限流。 - * - * @param ip IP 地址 - * @return 是否限流:true 表示限流;false 表示未限流 - */ - public boolean rateLimit(String ip) { - // 限流 Redis 键 - String key = StrUtil.format(RedisConstants.RateLimiter.IP, ip); - - // 自增请求计数 - Long count = redisTemplate.opsForValue().increment(key); - if (count == null || count == 1) { - // 第一次访问时设置过期时间为 1 秒 - redisTemplate.expire(key, 1, TimeUnit.SECONDS); - } - - // 获取系统配置的限流阈值 - Object systemConfig = configService.getSystemConfig(SystemConstants.SYSTEM_CONFIG_IP_QPS_LIMIT_KEY); - if (systemConfig == null) { - // 系统未配置限流,跳过限流逻辑 - log.warn("系统未配置限流阈值,跳过限流"); - return false; - } - - // 转换系统配置为限流值,默认为 10 - long limit = Convert.toLong(systemConfig, DEFAULT_IP_LIMIT); - return count != null && count > limit; - } - - /** - * 执行 IP 限流逻辑 - * 如果 IP 请求超出限制,直接返回限流响应;否则继续执行过滤器链。 - * - * @param request 请求体 - * @param response 响应体 - * @param filterChain 过滤器链 - */ - @Override - protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, - @NotNull FilterChain filterChain) throws ServletException, IOException { - // 获取请求的 IP 地址 - String ip = IPUtils.getIpAddr(request); - - // 判断是否限流 - if (rateLimit(ip)) { - // 返回限流错误信息 - ResponseWriter.writeError(response, ResultCode.REQUEST_CONCURRENCY_LIMIT_EXCEEDED); - return; - } - - // 未触发限流,继续执行过滤器链 - filterChain.doFilter(request, response); - } -} diff --git a/src/main/java/com/youlai/boot/framework/web/util/ResponseWriter.java b/src/main/java/com/youlai/boot/framework/web/util/ResponseWriter.java new file mode 100644 index 00000000..a2573451 --- /dev/null +++ b/src/main/java/com/youlai/boot/framework/web/util/ResponseWriter.java @@ -0,0 +1,61 @@ +package com.youlai.boot.framework.web.util; + +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处理器等场景统一写入HTTP响应

+ */ +@Slf4j +public final class ResponseWriter { + + private ResponseWriter() { + throw new UnsupportedOperationException("工具类不允许实例化"); + } + + public static void writeSuccess(HttpServletResponse response, Object data) { + writeResult(response, Result.success(data), HttpStatus.OK.value()); + } + + public static void writeSuccess(HttpServletResponse response) { + writeSuccess(response, null); + } + + public static void writeError(HttpServletResponse response, ResultCode resultCode) { + writeError(response, resultCode, null); + } + + 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); + } + + private static void writeResult(HttpServletResponse response, Result result, int httpStatus) { + try { + 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={}", httpStatus, e); + } + } + + 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/message/job/OnlineUserCountJob.java b/src/main/java/com/youlai/boot/message/job/OnlineUserCountTask.java similarity index 96% rename from src/main/java/com/youlai/boot/message/job/OnlineUserCountJob.java rename to src/main/java/com/youlai/boot/message/job/OnlineUserCountTask.java index 14ecb42e..96bad07a 100644 --- a/src/main/java/com/youlai/boot/message/job/OnlineUserCountJob.java +++ b/src/main/java/com/youlai/boot/message/job/OnlineUserCountTask.java @@ -15,7 +15,7 @@ import org.springframework.stereotype.Component; @Component @Slf4j @RequiredArgsConstructor -public class OnlineUserCountJob { +public class OnlineUserCountTask { private final SseSessionRegistry sessionRegistry; private final SseService sseService; diff --git a/src/main/java/com/youlai/boot/system/enums/MenuTypeEnum.java b/src/main/java/com/youlai/boot/system/enums/MenuTypeEnum.java index 8745ff7f..dde3a1bc 100644 --- a/src/main/java/com/youlai/boot/system/enums/MenuTypeEnum.java +++ b/src/main/java/com/youlai/boot/system/enums/MenuTypeEnum.java @@ -5,28 +5,22 @@ import com.youlai.boot.common.base.IBaseEnum; import lombok.Getter; /** - * 菜单类型枚举(char) + * 菜单类型枚举 * - * C:目录 - * M:菜单 - * B:按钮 + * @author Ray.Hao + * @since 0.0.1 */ @Getter public enum MenuTypeEnum implements IBaseEnum { CATALOG("C", "目录"), MENU("M", "菜单"), + EXTERNAL("E", "外链"), BUTTON("B", "按钮"); - /** - * 数据库存储值 - */ @EnumValue private final String value; - /** - * 友好名称 - */ private final String label; MenuTypeEnum(String value, String label) { diff --git a/src/main/java/com/youlai/boot/system/model/entity/Menu.java b/src/main/java/com/youlai/boot/system/model/entity/Menu.java index 475e966a..4839f40b 100644 --- a/src/main/java/com/youlai/boot/system/model/entity/Menu.java +++ b/src/main/java/com/youlai/boot/system/model/entity/Menu.java @@ -2,10 +2,10 @@ package com.youlai.boot.system.model.entity; import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; -import lombok.Getter; -import lombok.Setter; +import com.youlai.boot.common.base.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; -import java.time.LocalDateTime; import java.util.Map; /** @@ -15,15 +15,9 @@ import java.util.Map; * @since 2023/3/6 */ @TableName(value = "sys_menu", autoResultMap = true) -@Getter -@Setter -public class Menu { - /** - * 菜单ID - */ - @TableId(type = IdType.AUTO) - private Long id; - +@Data +@EqualsAndHashCode(callSuper = true) +public class Menu extends BaseEntity { /** * 父菜单ID */ @@ -54,6 +48,11 @@ public class Menu { */ private String component; + /** + * 外链地址 + */ + private String externalUrl; + /** * 权限标识 */ @@ -100,14 +99,4 @@ public class Menu { @TableField(updateStrategy = FieldStrategy.ALWAYS, typeHandler = JacksonTypeHandler.class) private Map params; - - @TableField(fill = FieldFill.INSERT) - private LocalDateTime createTime; - - /** - * 更新时间 - */ - @TableField(fill = FieldFill.INSERT_UPDATE) - private LocalDateTime updateTime; - } diff --git a/src/main/java/com/youlai/boot/system/model/form/MenuForm.java b/src/main/java/com/youlai/boot/system/model/form/MenuForm.java index dabc73ce..41cda185 100644 --- a/src/main/java/com/youlai/boot/system/model/form/MenuForm.java +++ b/src/main/java/com/youlai/boot/system/model/form/MenuForm.java @@ -38,6 +38,9 @@ public class MenuForm { @Schema(description = "组件路径(vue页面完整路径,省略.vue后缀)") private String component; + @Schema(description = "外链地址") + private String externalUrl; + @Schema(description = "权限标识") private String perm; diff --git a/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java b/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java index 81010597..2353a18e 100644 --- a/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java +++ b/src/main/java/com/youlai/boot/system/model/vo/MenuVO.java @@ -31,6 +31,9 @@ public class MenuVO { @Schema(description = "组件路径") private String component; + @Schema(description = "外链地址") + private String externalUrl; + @Schema(description = "菜单排序(数字越小排名越靠前)") private Integer sort; diff --git a/src/main/java/com/youlai/boot/system/service/ConfigService.java b/src/main/java/com/youlai/boot/system/service/ConfigService.java index d663826f..76bd563a 100644 --- a/src/main/java/com/youlai/boot/system/service/ConfigService.java +++ b/src/main/java/com/youlai/boot/system/service/ConfigService.java @@ -58,11 +58,4 @@ public interface ConfigService extends IService { */ boolean refreshCache(); - /** - * 获取系统配置 - * @param key 配置键 - * @return 配置值 - */ - Object getSystemConfig(String key); - } diff --git a/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java b/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java index 711b90c2..6c38a372 100644 --- a/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java +++ b/src/main/java/com/youlai/boot/system/service/impl/ConfigServiceImpl.java @@ -142,18 +142,4 @@ public class ConfigServiceImpl extends ServiceImpl impleme return false; } - /** - * 获取系统配置 - * - * @param key 配置键 - * @return 配置值 - */ - @Override - public Object getSystemConfig(String key) { - if (StringUtils.isNotBlank(key)) { - return redisTemplate.opsForHash().get(RedisConstants.System.CONFIG, key); - } - return null; - } - } diff --git a/src/main/resources/mapper/system/MenuMapper.xml b/src/main/resources/mapper/system/MenuMapper.xml index d1e97b97..bb19c07d 100644 --- a/src/main/resources/mapper/system/MenuMapper.xml +++ b/src/main/resources/mapper/system/MenuMapper.xml @@ -13,6 +13,7 @@ t1.route_name, t1.route_path, t1.component, + t1.external_url, t1.icon, t1.sort, t1.visible,