From 25fb9e0a27a32e568cda14d12e9362ed95fc1c7e Mon Sep 17 00:00:00 2001 From: Charles7c Date: Tue, 30 Dec 2025 22:52:41 +0800 Subject: [PATCH] =?UTF-8?q?refactor(core):=20=E5=90=88=E5=B9=B6=20SpringWe?= =?UTF-8?q?bUtils=20=E5=88=B0=20SpringUtils?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../starter/core/util/ServletUtils.java | 2 + .../starter/core/util/SpringUtils.java | 168 +++++++++++++++ .../starter/core/util/SpringWebUtils.java | 198 ------------------ .../encrypt/api/filter/ApiEncryptFilter.java | 4 +- .../starter/log/model/LogProperties.java | 4 +- .../starter/log/util/AccessLogUtils.java | 4 +- .../security/xss/filter/XssFilter.java | 6 +- .../strategy/impl/LocalStorageStrategy.java | 6 +- 8 files changed, 182 insertions(+), 210 deletions(-) delete mode 100644 continew-starter-core/src/main/java/top/continew/starter/core/util/SpringWebUtils.java diff --git a/continew-starter-core/src/main/java/top/continew/starter/core/util/ServletUtils.java b/continew-starter-core/src/main/java/top/continew/starter/core/util/ServletUtils.java index 32089585..48ff14bb 100644 --- a/continew-starter-core/src/main/java/top/continew/starter/core/util/ServletUtils.java +++ b/continew-starter-core/src/main/java/top/continew/starter/core/util/ServletUtils.java @@ -188,4 +188,6 @@ public class ServletUtils extends JakartaServletUtil { public static void writeJSON(HttpServletResponse response, String data) { write(response, data, MediaType.APPLICATION_JSON_VALUE); } + + } diff --git a/continew-starter-core/src/main/java/top/continew/starter/core/util/SpringUtils.java b/continew-starter-core/src/main/java/top/continew/starter/core/util/SpringUtils.java index c0331fb5..8ef6ceb9 100644 --- a/continew-starter-core/src/main/java/top/continew/starter/core/util/SpringUtils.java +++ b/continew-starter-core/src/main/java/top/continew/starter/core/util/SpringUtils.java @@ -16,8 +16,30 @@ package top.continew.starter.core.util; +import cn.hutool.core.text.CharSequenceUtil; +import cn.hutool.core.util.ReflectUtil; import cn.hutool.extra.spring.SpringUtil; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.context.ApplicationContext; +import org.springframework.http.server.PathContainer; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.accept.ContentNegotiationManager; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerExecutionChain; +import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.util.UrlPathHelper; +import org.springframework.web.util.pattern.PathPattern; +import org.springframework.web.util.pattern.PathPatternParser; +import top.continew.starter.core.constant.StringConstants; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; /** * Spring 工具类 @@ -27,6 +49,9 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; */ public class SpringUtils { + private static final AntPathMatcher ANT_PATH_MATCHER = new AntPathMatcher(); + private static final PathPatternParser PATH_PATTERN_PARSER = PathPatternParser.defaultInstance; + private SpringUtils() { } @@ -62,4 +87,147 @@ public class SpringUtils { throw e; } } + + /** + * 路径是否匹配 + * + * @param path 路径 + * @param patterns 匹配模式列表 + * @return 是否匹配 + * @since 2.6.0 + */ + public static boolean isMatch(String path, List patterns) { + return patterns.stream().anyMatch(pattern -> isMatch(path, pattern)); + } + + /** + * 路径是否匹配 + * + * @param path 路径 + * @param patterns 匹配模式列表 + * @return 是否匹配 + * @since 2.6.0 + */ + public static boolean isMatch(String path, String... patterns) { + return Arrays.stream(patterns).anyMatch(pattern -> isMatch(path, pattern)); + } + + /** + * 路径是否匹配 + * + * @param path 路径 + * @param pattern 匹配模式 + * @return 是否匹配 + * @since 2.4.0 + */ + public static boolean isMatch(String path, String pattern) { + PathPattern pathPattern = PATH_PATTERN_PARSER.parse(pattern); + PathContainer pathContainer = PathContainer.parsePath(path); + return pathPattern.matches(pathContainer); + } + + /** + * 路径是否匹配 - Ant 风格 + * + * @param path 路径 + * @param pattern 匹配模式 + * @return 是否匹配 + * @author echo + * @since 2.15.0 + */ + public static boolean isMatchAnt(String path, String pattern) { + return ANT_PATH_MATCHER.match(pattern, path); + } + + /** + * 路径是否匹配 - Ant 风格 + * + * @param path 路径 + * @param patterns 匹配模式列表 + * @return 是否匹配 + * @author echo + * @since 2.15.0 + */ + public static boolean isMatchAnt(String path, List patterns) { + return patterns.stream().anyMatch(pattern -> isMatchAnt(path, pattern)); + } + + /** + * 取消注册静态资源映射 + * + * @param handlerMap 静态资源映射 + */ + public static void deRegisterResourceHandler(Map handlerMap) { + ApplicationContext applicationContext = SpringUtil.getApplicationContext(); + // 获取已经注册的映射 + final HandlerMapping resourceHandlerMapping = applicationContext + .getBean("resourceHandlerMapping", HandlerMapping.class); + final Map oldHandlerMap = (Map)ReflectUtil + .getFieldValue(resourceHandlerMapping, "handlerMap"); + // 移除之前注册的映射 + for (Map.Entry entry : handlerMap.entrySet()) { + String pathPattern = CharSequenceUtil.appendIfMissing(entry.getKey(), StringConstants.PATH_PATTERN); + oldHandlerMap.remove(pathPattern); + } + } + + /** + * 注册静态资源映射 + * + * @param handlerMap 静态资源映射 + */ + public static void registerResourceHandler(Map handlerMap) { + ApplicationContext applicationContext = SpringUtil.getApplicationContext(); + // 获取已经注册的映射 + final HandlerMapping resourceHandlerMapping = applicationContext + .getBean("resourceHandlerMapping", HandlerMapping.class); + final Map oldHandlerMap = (Map)ReflectUtil + .getFieldValue(resourceHandlerMapping, "handlerMap"); + // 重新注册映射 + final ServletContext servletContext = applicationContext.getBean(ServletContext.class); + final ContentNegotiationManager contentNegotiationManager = applicationContext + .getBean("mvcContentNegotiationManager", ContentNegotiationManager.class); + final UrlPathHelper urlPathHelper = applicationContext.getBean("mvcUrlPathHelper", UrlPathHelper.class); + final ResourceHandlerRegistry resourceHandlerRegistry = new ResourceHandlerRegistry(applicationContext, servletContext, contentNegotiationManager, urlPathHelper); + for (Map.Entry entry : handlerMap.entrySet()) { + // 移除之前注册的映射 + String pathPattern = CharSequenceUtil.appendIfMissing(CharSequenceUtil.removeSuffix(entry + .getKey(), StringConstants.SLASH), StringConstants.PATH_PATTERN); + oldHandlerMap.remove(pathPattern); + // 重新注册映射 + String resourceLocations = CharSequenceUtil.appendIfMissing(entry.getValue(), StringConstants.SLASH); + resourceHandlerRegistry.addResourceHandler(pathPattern).addResourceLocations("file:" + resourceLocations); + } + final Map additionalUrlMap = ReflectUtil + .invoke(resourceHandlerRegistry, "getHandlerMapping") + .getUrlMap(); + ReflectUtil.invoke(resourceHandlerMapping, "registerHandlers", additionalUrlMap); + } + + /** + * 获取处理器方法 + * + * @param request 请求 + * @return 处理器方法 + * @since 2.14.0 + */ + public static HandlerMethod getHandlerMethod(HttpServletRequest request) { + try { + RequestMappingHandlerMapping handlerMapping = SpringUtil + .getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); + HandlerExecutionChain handlerExecutionChain = handlerMapping.getHandler(request); + // 检查是否存在处理链 + if (handlerExecutionChain == null) { + return null; + } + // 获取处理器 + Object handler = handlerExecutionChain.getHandler(); + if (handler instanceof HandlerMethod handlerMethod) { + return handlerMethod; + } + return null; + } catch (Exception e) { + return null; + } + } } diff --git a/continew-starter-core/src/main/java/top/continew/starter/core/util/SpringWebUtils.java b/continew-starter-core/src/main/java/top/continew/starter/core/util/SpringWebUtils.java deleted file mode 100644 index bec4c6a1..00000000 --- a/continew-starter-core/src/main/java/top/continew/starter/core/util/SpringWebUtils.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - *

- * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - *

- * http://www.gnu.org/licenses/lgpl.html - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package top.continew.starter.core.util; - -import cn.hutool.core.text.CharSequenceUtil; -import cn.hutool.core.util.ReflectUtil; -import cn.hutool.extra.spring.SpringUtil; -import jakarta.servlet.ServletContext; -import jakarta.servlet.http.HttpServletRequest; -import org.springframework.context.ApplicationContext; -import org.springframework.http.server.PathContainer; -import org.springframework.util.AntPathMatcher; -import org.springframework.web.accept.ContentNegotiationManager; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerExecutionChain; -import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; -import org.springframework.web.util.UrlPathHelper; -import org.springframework.web.util.pattern.PathPattern; -import org.springframework.web.util.pattern.PathPatternParser; -import top.continew.starter.core.constant.StringConstants; - -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -/** - * Spring Web 工具类 - * - * @author Charles7c - * @since 1.1.1 - */ -public class SpringWebUtils { - - private static final AntPathMatcher MATCHER = new AntPathMatcher(); - - private SpringWebUtils() { - } - - /** - * 路径是否匹配 - * - * @param path 路径 - * @param patterns 匹配模式列表 - * @return 是否匹配 - * @since 2.6.0 - */ - public static boolean isMatch(String path, List patterns) { - return patterns.stream().anyMatch(pattern -> isMatch(path, pattern)); - } - - /** - * 路径是否匹配 - * - * @param path 路径 - * @param patterns 匹配模式列表 - * @return 是否匹配 - * @since 2.6.0 - */ - public static boolean isMatch(String path, String... patterns) { - return Arrays.stream(patterns).anyMatch(pattern -> isMatch(path, pattern)); - } - - /** - * 路径是否匹配 - * - * @param path 路径 - * @param pattern 匹配模式 - * @return 是否匹配 - * @since 2.4.0 - */ - public static boolean isMatch(String path, String pattern) { - PathPattern pathPattern = PathPatternParser.defaultInstance.parse(pattern); - PathContainer pathContainer = PathContainer.parsePath(path); - return pathPattern.matches(pathContainer); - } - - /** - * 路径是否匹配 - Ant 风格 - * - * @param path 路径 - * @param pattern 匹配模式 - * @return 是否匹配 - * @author echo - * @since 2.15.0 - */ - public static boolean isMatchAnt(String path, String pattern) { - return MATCHER.match(pattern, path); - } - - /** - * 路径是否匹配 - Ant 风格 - * - * @param path 路径 - * @param patterns 匹配模式列表 - * @return 是否匹配 - * @author echo - * @since 2.15.0 - */ - public static boolean isMatchAnt(String path, List patterns) { - return patterns.stream().anyMatch(pattern -> isMatchAnt(path, pattern)); - } - - /** - * 取消注册静态资源映射 - * - * @param handlerMap 静态资源映射 - */ - public static void deRegisterResourceHandler(Map handlerMap) { - ApplicationContext applicationContext = SpringUtil.getApplicationContext(); - // 获取已经注册的映射 - final HandlerMapping resourceHandlerMapping = applicationContext - .getBean("resourceHandlerMapping", HandlerMapping.class); - final Map oldHandlerMap = (Map)ReflectUtil - .getFieldValue(resourceHandlerMapping, "handlerMap"); - // 移除之前注册的映射 - for (Map.Entry entry : handlerMap.entrySet()) { - String pathPattern = CharSequenceUtil.appendIfMissing(entry.getKey(), StringConstants.PATH_PATTERN); - oldHandlerMap.remove(pathPattern); - } - } - - /** - * 注册静态资源映射 - * - * @param handlerMap 静态资源映射 - */ - public static void registerResourceHandler(Map handlerMap) { - ApplicationContext applicationContext = SpringUtil.getApplicationContext(); - // 获取已经注册的映射 - final HandlerMapping resourceHandlerMapping = applicationContext - .getBean("resourceHandlerMapping", HandlerMapping.class); - final Map oldHandlerMap = (Map)ReflectUtil - .getFieldValue(resourceHandlerMapping, "handlerMap"); - // 重新注册映射 - final ServletContext servletContext = applicationContext.getBean(ServletContext.class); - final ContentNegotiationManager contentNegotiationManager = applicationContext - .getBean("mvcContentNegotiationManager", ContentNegotiationManager.class); - final UrlPathHelper urlPathHelper = applicationContext.getBean("mvcUrlPathHelper", UrlPathHelper.class); - final ResourceHandlerRegistry resourceHandlerRegistry = new ResourceHandlerRegistry(applicationContext, servletContext, contentNegotiationManager, urlPathHelper); - for (Map.Entry entry : handlerMap.entrySet()) { - // 移除之前注册的映射 - String pathPattern = CharSequenceUtil.appendIfMissing(CharSequenceUtil.removeSuffix(entry - .getKey(), StringConstants.SLASH), StringConstants.PATH_PATTERN); - oldHandlerMap.remove(pathPattern); - // 重新注册映射 - String resourceLocations = CharSequenceUtil.appendIfMissing(entry.getValue(), StringConstants.SLASH); - resourceHandlerRegistry.addResourceHandler(pathPattern).addResourceLocations("file:" + resourceLocations); - } - final Map additionalUrlMap = ReflectUtil - .invoke(resourceHandlerRegistry, "getHandlerMapping") - .getUrlMap(); - ReflectUtil.invoke(resourceHandlerMapping, "registerHandlers", additionalUrlMap); - } - - /** - * 获取处理器方法 - * - * @param request 请求 - * @return 处理器方法 - * @since 2.14.0 - */ - public static HandlerMethod getHandlerMethod(HttpServletRequest request) { - try { - RequestMappingHandlerMapping handlerMapping = SpringUtil - .getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class); - HandlerExecutionChain handlerExecutionChain = handlerMapping.getHandler(request); - // 检查是否存在处理链 - if (handlerExecutionChain == null) { - return null; - } - // 获取处理器 - Object handler = handlerExecutionChain.getHandler(); - if (handler instanceof HandlerMethod handlerMethod) { - return handlerMethod; - } - return null; - } catch (Exception e) { - return null; - } - } -} diff --git a/continew-starter-encrypt/continew-starter-encrypt-api/src/main/java/top/continew/starter/encrypt/api/filter/ApiEncryptFilter.java b/continew-starter-encrypt/continew-starter-encrypt-api/src/main/java/top/continew/starter/encrypt/api/filter/ApiEncryptFilter.java index ba9930e0..8910cce2 100644 --- a/continew-starter-encrypt/continew-starter-encrypt-api/src/main/java/top/continew/starter/encrypt/api/filter/ApiEncryptFilter.java +++ b/continew-starter-encrypt/continew-starter-encrypt-api/src/main/java/top/continew/starter/encrypt/api/filter/ApiEncryptFilter.java @@ -22,7 +22,7 @@ import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpMethod; -import top.continew.starter.core.util.SpringWebUtils; +import top.continew.starter.core.util.SpringUtils; import top.continew.starter.encrypt.api.annotation.ApiEncrypt; import top.continew.starter.encrypt.api.autoconfigure.ApiEncryptProperties; @@ -93,7 +93,7 @@ public class ApiEncryptFilter implements Filter { */ private boolean isResponseEncrypt(HttpServletRequest request) { // 获取 API 加密注解 - ApiEncrypt apiEncrypt = Optional.ofNullable(SpringWebUtils.getHandlerMethod(request)) + ApiEncrypt apiEncrypt = Optional.ofNullable(SpringUtils.getHandlerMethod(request)) .map(h -> h.getMethodAnnotation(ApiEncrypt.class)) .orElse(null); return apiEncrypt != null && apiEncrypt.response(); diff --git a/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/model/LogProperties.java b/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/model/LogProperties.java index 1f6c26c6..dca68a42 100644 --- a/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/model/LogProperties.java +++ b/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/model/LogProperties.java @@ -19,8 +19,8 @@ package top.continew.starter.log.model; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; import top.continew.starter.core.constant.PropertiesConstants; +import top.continew.starter.core.util.SpringUtils; import top.continew.starter.log.enums.Include; -import top.continew.starter.core.util.SpringWebUtils; import java.util.ArrayList; import java.util.List; @@ -95,6 +95,6 @@ public class LogProperties { * @return true: 匹配; false: 不匹配 */ public boolean isMatchExcludeUri(String uri) { - return this.getExcludePatterns().stream().anyMatch(pattern -> SpringWebUtils.isMatch(uri, pattern)); + return this.getExcludePatterns().stream().anyMatch(pattern -> SpringUtils.isMatch(uri, pattern)); } } diff --git a/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/util/AccessLogUtils.java b/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/util/AccessLogUtils.java index 4bea73e6..78e4fe64 100644 --- a/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/util/AccessLogUtils.java +++ b/continew-starter-log/continew-starter-log-core/src/main/java/top/continew/starter/log/util/AccessLogUtils.java @@ -18,7 +18,7 @@ package top.continew.starter.log.util; import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.json.JSONUtil; -import top.continew.starter.core.util.SpringWebUtils; +import top.continew.starter.core.util.SpringUtils; import top.continew.starter.log.http.RecordableHttpRequest; import top.continew.starter.log.model.AccessLogProperties; import top.continew.starter.log.model.LogProperties; @@ -97,7 +97,7 @@ public class AccessLogUtils { public static boolean exclusionPath(LogProperties properties, String path) { // 放行路由配置的排除检查 return properties.isMatchExcludeUri(path) || RESOURCE_PATH.stream() - .anyMatch(resourcePath -> SpringWebUtils.isMatchAnt(path, resourcePath)); + .anyMatch(resourcePath -> SpringUtils.isMatchAnt(path, resourcePath)); } /** diff --git a/continew-starter-security/continew-starter-security-xss/src/main/java/top/continew/starter/security/xss/filter/XssFilter.java b/continew-starter-security/continew-starter-security-xss/src/main/java/top/continew/starter/security/xss/filter/XssFilter.java index 48cb4678..6ddd0409 100644 --- a/continew-starter-security/continew-starter-security-xss/src/main/java/top/continew/starter/security/xss/filter/XssFilter.java +++ b/continew-starter-security/continew-starter-security-xss/src/main/java/top/continew/starter/security/xss/filter/XssFilter.java @@ -21,8 +21,8 @@ import jakarta.servlet.*; import jakarta.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import top.continew.starter.core.util.SpringUtils; import top.continew.starter.security.xss.autoconfigure.XssProperties; -import top.continew.starter.core.util.SpringWebUtils; import java.io.IOException; import java.util.List; @@ -56,7 +56,7 @@ public class XssFilter implements Filter { if (servletRequest instanceof HttpServletRequest request && xssProperties.isEnabled()) { // 放行路由:忽略 XSS 过滤 List excludePatterns = xssProperties.getExcludePatterns(); - if (CollUtil.isNotEmpty(excludePatterns) && SpringWebUtils.isMatch(request + if (CollUtil.isNotEmpty(excludePatterns) && SpringUtils.isMatch(request .getServletPath(), excludePatterns)) { filterChain.doFilter(request, servletResponse); return; @@ -64,7 +64,7 @@ public class XssFilter implements Filter { // 拦截路由:执行 XSS 过滤 List includePatterns = xssProperties.getIncludePatterns(); if (CollUtil.isNotEmpty(includePatterns)) { - if (SpringWebUtils.isMatch(request.getServletPath(), includePatterns)) { + if (SpringUtils.isMatch(request.getServletPath(), includePatterns)) { filterChain.doFilter(new XssServletRequestWrapper(request, xssProperties), servletResponse); } else { filterChain.doFilter(request, servletResponse); diff --git a/continew-starter-storage/src/main/java/top/continew/starter/storage/strategy/impl/LocalStorageStrategy.java b/continew-starter-storage/src/main/java/top/continew/starter/storage/strategy/impl/LocalStorageStrategy.java index ced72357..9a763a65 100644 --- a/continew-starter-storage/src/main/java/top/continew/starter/storage/strategy/impl/LocalStorageStrategy.java +++ b/continew-starter-storage/src/main/java/top/continew/starter/storage/strategy/impl/LocalStorageStrategy.java @@ -22,7 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.multipart.MultipartFile; import top.continew.starter.core.constant.StringConstants; -import top.continew.starter.core.util.SpringWebUtils; +import top.continew.starter.core.util.SpringUtils; import top.continew.starter.storage.autoconfigure.properties.LocalStorageConfig; import top.continew.starter.storage.common.exception.StorageException; import top.continew.starter.storage.domain.model.resp.FileInfo; @@ -70,7 +70,7 @@ public class LocalStorageStrategy implements StorageStrategy { */ public void registerResources(LocalStorageConfig config) { // 注册资源映射 - SpringWebUtils.registerResourceHandler(MapUtil.of(URLUtil.url(config.getEndpoint()).getPath(), config + SpringUtils.registerResourceHandler(MapUtil.of(URLUtil.url(config.getEndpoint()).getPath(), config .getBucketName())); } @@ -426,7 +426,7 @@ public class LocalStorageStrategy implements StorageStrategy { public void cleanup() { // 清理静态资源映射 if (config != null) { - SpringWebUtils.deRegisterResourceHandler(MapUtil.of(URLUtil.url(config.getEndpoint()).getPath(), config + SpringUtils.deRegisterResourceHandler(MapUtil.of(URLUtil.url(config.getEndpoint()).getPath(), config .getBucketName())); } }