refactor(core): 合并 SpringWebUtils 到 SpringUtils

This commit is contained in:
2025-12-30 22:52:41 +08:00
parent 8ce00d8892
commit 25fb9e0a27
8 changed files with 182 additions and 210 deletions

View File

@@ -188,4 +188,6 @@ public class ServletUtils extends JakartaServletUtil {
public static void writeJSON(HttpServletResponse response, String data) {
write(response, data, MediaType.APPLICATION_JSON_VALUE);
}
}

View File

@@ -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<String> 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<String> patterns) {
return patterns.stream().anyMatch(pattern -> isMatchAnt(path, pattern));
}
/**
* 取消注册静态资源映射
*
* @param handlerMap 静态资源映射
*/
public static void deRegisterResourceHandler(Map<String, String> handlerMap) {
ApplicationContext applicationContext = SpringUtil.getApplicationContext();
// 获取已经注册的映射
final HandlerMapping resourceHandlerMapping = applicationContext
.getBean("resourceHandlerMapping", HandlerMapping.class);
final Map<String, Object> oldHandlerMap = (Map<String, Object>)ReflectUtil
.getFieldValue(resourceHandlerMapping, "handlerMap");
// 移除之前注册的映射
for (Map.Entry<String, String> entry : handlerMap.entrySet()) {
String pathPattern = CharSequenceUtil.appendIfMissing(entry.getKey(), StringConstants.PATH_PATTERN);
oldHandlerMap.remove(pathPattern);
}
}
/**
* 注册静态资源映射
*
* @param handlerMap 静态资源映射
*/
public static void registerResourceHandler(Map<String, String> handlerMap) {
ApplicationContext applicationContext = SpringUtil.getApplicationContext();
// 获取已经注册的映射
final HandlerMapping resourceHandlerMapping = applicationContext
.getBean("resourceHandlerMapping", HandlerMapping.class);
final Map<String, Object> oldHandlerMap = (Map<String, Object>)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<String, String> 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<String, ?> additionalUrlMap = ReflectUtil
.<SimpleUrlHandlerMapping>invoke(resourceHandlerRegistry, "getHandlerMapping")
.getUrlMap();
ReflectUtil.<Void>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;
}
}
}

View File

@@ -1,198 +0,0 @@
/*
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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<String> 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<String> patterns) {
return patterns.stream().anyMatch(pattern -> isMatchAnt(path, pattern));
}
/**
* 取消注册静态资源映射
*
* @param handlerMap 静态资源映射
*/
public static void deRegisterResourceHandler(Map<String, String> handlerMap) {
ApplicationContext applicationContext = SpringUtil.getApplicationContext();
// 获取已经注册的映射
final HandlerMapping resourceHandlerMapping = applicationContext
.getBean("resourceHandlerMapping", HandlerMapping.class);
final Map<String, Object> oldHandlerMap = (Map<String, Object>)ReflectUtil
.getFieldValue(resourceHandlerMapping, "handlerMap");
// 移除之前注册的映射
for (Map.Entry<String, String> entry : handlerMap.entrySet()) {
String pathPattern = CharSequenceUtil.appendIfMissing(entry.getKey(), StringConstants.PATH_PATTERN);
oldHandlerMap.remove(pathPattern);
}
}
/**
* 注册静态资源映射
*
* @param handlerMap 静态资源映射
*/
public static void registerResourceHandler(Map<String, String> handlerMap) {
ApplicationContext applicationContext = SpringUtil.getApplicationContext();
// 获取已经注册的映射
final HandlerMapping resourceHandlerMapping = applicationContext
.getBean("resourceHandlerMapping", HandlerMapping.class);
final Map<String, Object> oldHandlerMap = (Map<String, Object>)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<String, String> 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<String, ?> additionalUrlMap = ReflectUtil
.<SimpleUrlHandlerMapping>invoke(resourceHandlerRegistry, "getHandlerMapping")
.getUrlMap();
ReflectUtil.<Void>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;
}
}
}

View File

@@ -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();

View File

@@ -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));
}
}

View File

@@ -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));
}
/**

View File

@@ -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<String> 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<String> 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);

View File

@@ -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()));
}
}