Sfoglia il codice sorgente

bump: 发布2.4.0

details see: https://helio.uncarbon.cc/#/i18n/zh-CN/appendix/change-log
Uncarbon 1 anno fa
parent
commit
e083af8eb1
27 ha cambiato i file con 622 aggiunte e 289 eliminazioni
  1. 1 1
      helio-core/pom.xml
  2. 1 1
      helio-starter-aop/pom.xml
  3. 1 1
      helio-starter-cloud/pom.xml
  4. 1 1
      helio-starter-crud/pom.xml
  5. 0 3
      helio-starter-crud/src/main/resources/application.yml
  6. 1 1
      helio-starter-dubbo/pom.xml
  7. 1 1
      helio-starter-i18n/pom.xml
  8. 11 5
      helio-starter-knife4j/pom.xml
  9. 63 22
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/config/HelioKnife4jAutoConfiguration.java
  10. 28 46
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/customizer/HelioBaseEnumCustomizer.java
  11. 0 170
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/customizer/Knife4jOpenApiCustomizerOverride.java
  12. 105 0
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/AbstractSecurityFilter.java
  13. 105 0
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/BasicFilter.java
  14. 92 0
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/JakartaProductionSecurityFilter.java
  15. 86 0
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/JakartaServletSecurityBasicAuthFilter.java
  16. 56 0
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/model/Knife4jHttpBasic.java
  17. 50 0
      helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/model/Knife4jProperties.java
  18. 1 1
      helio-starter-rate-limit-redis/pom.xml
  19. 1 1
      helio-starter-redis/pom.xml
  20. 1 1
      helio-starter-rocketmq-aliyun/pom.xml
  21. 1 1
      helio-starter-satoken/pom.xml
  22. 2 2
      helio-starter-satoken/src/main/java/cc/uncarbon/framework/satoken/dao/SaTokenLocalCacheDao.java
  23. 1 1
      helio-starter-tenant/pom.xml
  24. 1 1
      helio-starter-test/pom.xml
  25. 1 1
      helio-starter-web/pom.xml
  26. 0 5
      helio-starter-web/src/main/resources/application.yml
  27. 11 23
      pom.xml

+ 1 - 1
helio-core/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-aop/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-cloud/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-crud/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 0 - 3
helio-starter-crud/src/main/resources/application.yml

@@ -1,3 +0,0 @@
-mybatis-plus:
-  global-config:
-    banner: false

+ 1 - 1
helio-starter-dubbo/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-i18n/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 11 - 5
helio-starter-knife4j/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 
@@ -28,9 +28,14 @@
         <!-- 这里写其他第三方依赖 -->
         <dependency>
             <groupId>com.github.xiaoymin</groupId>
-            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
+            <artifactId>knife4j-openapi3-ui</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
             <exclusions>
-                <!-- 用不到 -->
+                <!-- 无需引入 UI 库 -->
                 <exclusion>
                     <groupId>org.webjars</groupId>
                     <artifactId>swagger-ui</artifactId>
@@ -39,8 +44,9 @@
         </dependency>
 
         <dependency>
-            <groupId>org.springdoc</groupId>
-            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <scope>provided</scope>
         </dependency>
     </dependencies>
 </project>

+ 63 - 22
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/config/HelioKnife4jAutoConfiguration.java

@@ -2,18 +2,25 @@ package cc.uncarbon.framework.knife4j.config;
 
 import cc.uncarbon.framework.core.props.HelioProperties;
 import cc.uncarbon.framework.knife4j.customizer.HelioBaseEnumCustomizer;
-import cc.uncarbon.framework.knife4j.customizer.Knife4jOpenApiCustomizerOverride;
+import cc.uncarbon.framework.knife4j.filter.AbstractSecurityFilter;
+import cc.uncarbon.framework.knife4j.filter.JakartaProductionSecurityFilter;
+import cc.uncarbon.framework.knife4j.filter.JakartaServletSecurityBasicAuthFilter;
+import cc.uncarbon.framework.knife4j.model.Knife4jHttpBasic;
+import cc.uncarbon.framework.knife4j.model.Knife4jProperties;
 import cn.hutool.core.text.CharSequenceUtil;
-import com.github.xiaoymin.knife4j.spring.configuration.Knife4jAutoConfiguration;
-import io.swagger.v3.oas.models.Components;
 import io.swagger.v3.oas.models.OpenAPI;
 import io.swagger.v3.oas.models.info.Info;
-import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.OAuthFlow;
+import io.swagger.v3.oas.models.security.OAuthFlows;
 import io.swagger.v3.oas.models.security.SecurityScheme;
+import jakarta.servlet.DispatcherType;
+import lombok.NonNull;
 import org.springdoc.core.configuration.SpringDocConfiguration;
 import org.springframework.boot.autoconfigure.AutoConfiguration;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Import;
 import org.springframework.core.env.ConfigurableEnvironment;
@@ -21,13 +28,14 @@ import org.springframework.core.env.ConfigurableEnvironment;
 
 /**
  * Helio knife4j 自动配置类
+ * @since 2.4.0 只保留 knife4j-ui,并从 knife4j 源码中移植「HTTP Basic鉴权机制」和「生产环境下不再显示开发文档」2个功能
  *
  * @author Uncarbon
  * @author xiaoymin
  */
-// 需要控制自动配置类加载顺序,去除显式 @EnableKnife4j
-@Import(value = {Knife4jOpenApiCustomizerOverride.class, HelioBaseEnumCustomizer.class, Knife4jAutoConfiguration.class, SpringDocConfiguration.class})
-@ConditionalOnExpression(value = "!${knife4j.production:false}")
+@Import(value = {HelioBaseEnumCustomizer.class, SpringDocConfiguration.class})
+@EnableConfigurationProperties({Knife4jProperties.class, Knife4jHttpBasic.class})
+@ConditionalOnExpression(value = "${knife4j.enable:false}")
 @AutoConfiguration
 public class HelioKnife4jAutoConfiguration {
 
@@ -40,24 +48,43 @@ public class HelioKnife4jAutoConfiguration {
 
         // 全局安全要求
         String headerTokenName = CharSequenceUtil.blankToDefault(env.getProperty("sa-token.token-name"), "Authorization");
-        SecurityScheme securityScheme = new SecurityScheme()
-                // 取个名字,方便被引用
-                .name(headerTokenName)
-                .type(SecurityScheme.Type.APIKEY)
-                .in(SecurityScheme.In.HEADER);
+        openApi.schemaRequirement(headerTokenName, buildSecurityScheme());
+        return openApi;
+    }
 
-        SecurityRequirement securityRequirement = new SecurityRequirement()
-                // 引用上面定义的SecurityScheme
-                .addList(headerTokenName);
+    /**
+     * Security with Basic Http
+     * @param knife4jProperties Basic Properties
+     * @return BasicAuthFilter
+     */
+    @Bean
+    @ConditionalOnMissingBean(JakartaServletSecurityBasicAuthFilter.class)
+    @ConditionalOnExpression("${knife4j.basic.enable:false}")
+    public FilterRegistrationBean<JakartaServletSecurityBasicAuthFilter> securityBasicAuthFilter(@NonNull Knife4jProperties knife4jProperties) {
+        JakartaServletSecurityBasicAuthFilter authFilter = new JakartaServletSecurityBasicAuthFilter();
+        authFilter.setEnableBasicAuth(knife4jProperties.getBasic().isEnable());
+        authFilter.setUserName(knife4jProperties.getBasic().getUsername());
+        authFilter.setPassword(knife4jProperties.getBasic().getPassword());
+        authFilter.addRule(knife4jProperties.getBasic().getInclude());
 
-        openApi
-                .components(new Components()
-                        // 在components里定义SecurityScheme
-                        .addSecuritySchemes("APIKEY", securityScheme))
-                // 添加SecurityRequirement作为全局安全要求
-                .addSecurityItem(securityRequirement);
+        FilterRegistrationBean<JakartaServletSecurityBasicAuthFilter> registration = new FilterRegistrationBean<>();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(authFilter);
+        registration.setOrder(AbstractSecurityFilter.SPRING_FILTER_ORDER);
+        return registration;
+    }
 
-        return openApi;
+    @Bean
+    @ConditionalOnMissingBean(JakartaProductionSecurityFilter.class)
+    @ConditionalOnExpression("${knife4j.production:false}")
+    public FilterRegistrationBean<JakartaProductionSecurityFilter> productionSecurityFilter(@NonNull Knife4jProperties knife4jProperties) {
+        JakartaProductionSecurityFilter prodFilter = new JakartaProductionSecurityFilter(knife4jProperties.isProduction());
+
+        FilterRegistrationBean<JakartaProductionSecurityFilter> registration = new FilterRegistrationBean<>();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(prodFilter);
+        registration.setOrder(AbstractSecurityFilter.SPRING_FILTER_ORDER - 1);
+        return registration;
     }
 
     private Info buildInfo(HelioProperties helioProperties) {
@@ -69,4 +96,18 @@ public class HelioKnife4jAutoConfiguration {
         return info;
     }
 
+    /**
+     * 利用OAuth2的安全规则,骗出 knife4j-ui 的请求头部输入框
+     */
+    private SecurityScheme buildSecurityScheme() {
+        OAuthFlow clientCredential = new OAuthFlow();
+        clientCredential.setTokenUrl("本页面无作用,只要请求接口时,在请求头带上Token即可");
+        OAuthFlows oauthFlows = new OAuthFlows();
+        oauthFlows.password(clientCredential);
+        SecurityScheme securityScheme = new SecurityScheme();
+        securityScheme.setType(SecurityScheme.Type.OAUTH2);
+        securityScheme.setFlows(oauthFlows);
+        return securityScheme;
+    }
+
 }

+ 28 - 46
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/customizer/HelioBaseEnumCustomizer.java

@@ -1,11 +1,14 @@
 package cc.uncarbon.framework.knife4j.customizer;
 
 import cc.uncarbon.framework.core.enums.HelioBaseEnum;
-import cn.hutool.core.text.CharSequenceUtil;
-import cn.hutool.core.text.StrPool;
+import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.StrUtil;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.CollectionType;
 import com.fasterxml.jackson.databind.type.SimpleType;
+import com.fasterxml.jackson.databind.type.TypeBase;
+import com.fasterxml.jackson.databind.type.TypeBindings;
 import io.swagger.v3.core.converter.AnnotatedType;
 import io.swagger.v3.oas.models.media.Schema;
 import io.swagger.v3.oas.models.parameters.Parameter;
@@ -14,8 +17,10 @@ import org.springdoc.core.customizers.PropertyCustomizer;
 import org.springframework.core.MethodParameter;
 import org.springframework.stereotype.Component;
 
+import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.Objects;
+import java.util.Optional;
 
 /**
  * HelioBaseEnum子枚举增强
@@ -32,8 +37,6 @@ import java.util.Objects;
 @Component
 public class HelioBaseEnumCustomizer implements PropertyCustomizer, ParameterCustomizer {
 
-    protected static final String TYPE_NAME_KEYWORD_COLLECTION_TYPE = "collection type;";
-    protected static final String TYPE_NAME_KEYWORD_SIMPLE_TYPE = "simple type, class ";
     protected static final String SCHEMA_TYPE_INTEGER = "integer";
     protected static final String SCHEMA_FORMAT_INT32 = "int32";
     protected static final String SCHEMA_FORMAT_INT64 = "int64";
@@ -45,21 +48,28 @@ public class HelioBaseEnumCustomizer implements PropertyCustomizer, ParameterCus
     public Schema<?> customize(Schema schema, AnnotatedType propertyType) {
         if (Objects.nonNull(schema) && Objects.nonNull(propertyType)) {
             try {
-                HelioBaseEnum<?>[] enumItems = findHelioBaseEnumInGenerics(propertyType.getType().getTypeName());
-                if (ArrayUtil.isNotEmpty(enumItems)) {
-                    updateSchema(schema, enumItems, true);
-                    return schema;
-                }
-
-                SimpleType simpleType = (SimpleType) propertyType.getType();
-                if (HelioBaseEnum.class.isAssignableFrom(simpleType.getRawClass())) {
-                    enumItems = (HelioBaseEnum<?>[]) simpleType.getRawClass().getEnumConstants();
-                    updateSchema(schema, enumItems, false);
-                    return schema;
+                Type propertyTypeType = propertyType.getType();
+                if (propertyTypeType instanceof SimpleType simpleType) {
+                    // 非数组形式
+                    Class<?> rawClass = simpleType.getRawClass();
+                    if (HelioBaseEnum.class.isAssignableFrom(rawClass)) {
+                        HelioBaseEnum<?>[] enumItems = (HelioBaseEnum<?>[]) rawClass.getEnumConstants();
+                        updateSchema(schema, enumItems, false);
+                    }
+                } else if (propertyTypeType instanceof CollectionType collectionType) {
+                    // 数组形式
+                    Class<?> rawClass = Optional.of(collectionType)
+                            .map(TypeBase::getBindings)
+                            .map(TypeBindings::getTypeParameters)
+                            .map(CollUtil::getFirst)
+                            .map(JavaType::getRawClass)
+                            .orElse(null);
+                    if (rawClass != null && HelioBaseEnum.class.isAssignableFrom(rawClass)) {
+                        HelioBaseEnum<?>[] enumItems = (HelioBaseEnum<?>[]) rawClass.getEnumConstants();
+                        updateSchema(schema, enumItems, true);
+                    }
                 }
-            } catch (Exception e) {
-                // fail to customize, ignored
-            }
+            } catch (Exception ignore) {}
         }
         return schema;
     }
@@ -78,34 +88,6 @@ public class HelioBaseEnumCustomizer implements PropertyCustomizer, ParameterCus
         return parameterModel;
     }
 
-    /**
-     * 尝试在文本描述中,寻找泛型中实现了 HelioBaseEnum 的枚举
-     */
-    protected HelioBaseEnum<?>[] findHelioBaseEnumInGenerics(String typeName) {
-        // 也许是枚举类的全限定名数组
-        String[] maybeEnumClassNames = {};
-        if (CharSequenceUtil.contains(typeName, TYPE_NAME_KEYWORD_COLLECTION_TYPE)) {
-            // 硬编码,针对类似 List<YesOrNoEnum> 的集合类型字段
-            maybeEnumClassNames = CharSequenceUtil.subBetweenAll(typeName, TYPE_NAME_KEYWORD_SIMPLE_TYPE, StrPool.BRACKET_END);
-        }
-        if (ArrayUtil.isNotEmpty(maybeEnumClassNames)) {
-            ClassLoader classLoader = getClass().getClassLoader();
-            // 从后往前匹配,一般最内层的泛型在最后
-            for (int i = maybeEnumClassNames.length - 1; i >= 0; i--) {
-                String maybeEnumClassName = maybeEnumClassNames[i];
-                try {
-                    Class<?> maybeEnumClass = Class.forName(maybeEnumClassName, false, classLoader);
-                    if (HelioBaseEnum.class.isAssignableFrom(maybeEnumClass)) {
-                        return (HelioBaseEnum<?>[]) maybeEnumClass.getEnumConstants();
-                    }
-                } catch (ClassNotFoundException e) {
-                    // ignored
-                }
-            }
-        }
-        return new HelioBaseEnum[]{};
-    }
-
     /**
      * @param isArray 枚举项是否按数组形式展现
      */

+ 0 - 170
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/customizer/Knife4jOpenApiCustomizerOverride.java

@@ -1,170 +0,0 @@
-/*
- * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * 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 cc.uncarbon.framework.knife4j.customizer;
-
-import com.github.xiaoymin.knife4j.annotations.ApiSupport;
-import com.github.xiaoymin.knife4j.core.conf.ExtensionsConstants;
-import com.github.xiaoymin.knife4j.core.conf.GlobalConstants;
-import com.github.xiaoymin.knife4j.spring.configuration.Knife4jProperties;
-import com.github.xiaoymin.knife4j.spring.configuration.Knife4jSetting;
-import com.github.xiaoymin.knife4j.spring.extension.Knife4jOpenApiCustomizer;
-import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
-import io.swagger.v3.oas.annotations.tags.Tag;
-import io.swagger.v3.oas.models.OpenAPI;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springdoc.core.properties.SpringDocConfigProperties;
-import org.springframework.beans.factory.config.BeanDefinition;
-import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
-import org.springframework.core.type.filter.AnnotationTypeFilter;
-import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.lang.annotation.Annotation;
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * 增强扩展属性支持
- * @since 4.1.0
- * @author <a href="xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
- * 2022/12/11 22:40
- * @author Uncarbon
- * 自 Spring Boot 3.4 开始,ControllerAdvice 类的构造函数改变,需要升级 SpringDoc 版本来适配,导致
- * SpringDocConfigProperties.getGroupConfigs() 返回值从 List 变为 Set,老的 knife4j 不兼容
- * 只能手动覆盖原有的 Knife4jOpenApiCustomizer
- */
-@Slf4j
-@Component
-public class Knife4jOpenApiCustomizerOverride extends Knife4jOpenApiCustomizer {
-
-    final Knife4jProperties knife4jProperties;
-    final SpringDocConfigProperties properties;
-
-    public Knife4jOpenApiCustomizerOverride(Knife4jProperties knife4jProperties, SpringDocConfigProperties properties) {
-        super(knife4jProperties, properties);
-        this.knife4jProperties = knife4jProperties;
-        this.properties = properties;
-    }
-
-    @Override
-    public void customise(OpenAPI openApi) {
-        if (log.isDebugEnabled()) {
-            log.debug("Knife4j OpenApiCustomizer Override");
-        }
-        if (knife4jProperties.isEnable()) {
-            Knife4jSetting setting = knife4jProperties.getSetting();
-            OpenApiExtensionResolver openApiExtensionResolver = new OpenApiExtensionResolver(setting, knife4jProperties.getDocuments());
-            // 解析初始化
-            openApiExtensionResolver.start();
-            Map<String, Object> objectMap = new HashMap<>(2, 1);
-            objectMap.put(GlobalConstants.EXTENSION_OPEN_SETTING_NAME, setting);
-            objectMap.put(GlobalConstants.EXTENSION_OPEN_MARKDOWN_NAME, openApiExtensionResolver.getMarkdownFiles());
-            openApi.addExtension(GlobalConstants.EXTENSION_OPEN_API_NAME, objectMap);
-            addOrderExtension(openApi);
-        }
-    }
-    /**
-     * 往OpenAPI内tags字段添加x-order属性
-     *
-     * @param openApi openApi
-     */
-    private void addOrderExtension(OpenAPI openApi) {
-        if (CollectionUtils.isEmpty(properties.getGroupConfigs())) {
-            return;
-        }
-        // 获取包扫描路径
-        Set<String> packagesToScan =
-                properties.getGroupConfigs().stream()
-                        .map(SpringDocConfigProperties.GroupConfig::getPackagesToScan)
-                        .filter(toScan -> !CollectionUtils.isEmpty(toScan))
-                        .flatMap(List::stream)
-                        .collect(Collectors.toSet());
-        if (CollectionUtils.isEmpty(packagesToScan)) {
-            return;
-        }
-        // 扫描包下被ApiSupport注解的RestController Class
-        Set<Class<?>> classes =
-                packagesToScan.stream()
-                        .map(packageToScan -> scanPackageByAnnotation(packageToScan, RestController.class))
-                        .flatMap(Set::stream)
-                        .filter(clazz -> clazz.isAnnotationPresent(ApiSupport.class))
-                        .collect(Collectors.toSet());
-        if (!CollectionUtils.isEmpty(classes)) {
-            // ApiSupport oder值存入tagSortMap<Tag.name,ApiSupport.order>
-            Map<String, Integer> tagOrderMap = new HashMap<>();
-            classes.forEach(
-                    clazz -> {
-                        Tag tag = getTag(clazz);
-                        if (Objects.nonNull(tag)) {
-                            ApiSupport apiSupport = clazz.getAnnotation(ApiSupport.class);
-                            tagOrderMap.putIfAbsent(tag.name(), apiSupport.order());
-                        }
-                    });
-            // 往openApi tags字段添加x-order增强属性
-            if (openApi.getTags() != null) {
-                openApi
-                        .getTags()
-                        .forEach(
-                                tag -> {
-                                    if (tagOrderMap.containsKey(tag.getName())) {
-                                        tag.addExtension(
-                                                ExtensionsConstants.EXTENSION_ORDER, tagOrderMap.get(tag.getName()));
-                                    }
-                                });
-            }
-        }
-    }
-
-    private Tag getTag(Class<?> clazz) {
-        // 从类上获取
-        Tag tag = clazz.getAnnotation(Tag.class);
-        if (Objects.isNull(tag)) {
-            // 从接口上获取
-            Class<?>[] interfaces = clazz.getInterfaces();
-            if (ArrayUtils.isNotEmpty(interfaces)) {
-                for (Class<?> interfaceClazz : interfaces) {
-                    Tag anno = interfaceClazz.getAnnotation(Tag.class);
-                    if (Objects.nonNull(anno)) {
-                        tag = anno;
-                        break;
-                    }
-                }
-            }
-        }
-        return tag;
-    }
-
-    private Set<Class<?>> scanPackageByAnnotation(
-            String packageName, final Class<? extends Annotation> annotationClass) {
-        ClassPathScanningCandidateComponentProvider scanner =
-                new ClassPathScanningCandidateComponentProvider(false);
-        scanner.addIncludeFilter(new AnnotationTypeFilter(annotationClass));
-        Set<Class<?>> classes = new HashSet<>();
-        for (BeanDefinition beanDefinition : scanner.findCandidateComponents(packageName)) {
-            try {
-                Class<?> clazz = Class.forName(beanDefinition.getBeanClassName());
-                classes.add(clazz);
-            } catch (ClassNotFoundException ignore) {
-
-            }
-        }
-        return classes;
-    }
-}

+ 105 - 0
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/AbstractSecurityFilter.java

@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 cc.uncarbon.framework.knife4j.filter;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.Data;
+
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * @author <a href="xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
+ * 2023/2/25 18:52
+ * @since knife4j
+ */
+@Data
+public abstract class AbstractSecurityFilter extends BasicFilter {
+
+    /**
+     * Spring过滤器顺序
+     */
+    public static final int SPRING_FILTER_ORDER = Integer.MAX_VALUE;
+
+    /***
+     * 是否开启basic验证,默认不开启
+     */
+    private boolean enableBasicAuth = false;
+
+    private String userName;
+
+    private String password;
+
+    /**
+     * 外部自定义包含过滤地址,避免BasicFilter父类中不满足的情况,交给开发者自定义传入
+     */
+    private List<String> include;
+
+    /**
+     * // SpringMVC环境中,由此init方法初始化此Filter,SpringBoot环境中则不同
+     * @param enumeration
+     * @param initBasicEnable
+     * @param initUserName
+     * @param initPassword
+     */
+    protected void initServletConfig(Enumeration<String> enumeration, String initBasicEnable, String initUserName, String initPassword) {
+        if (enumeration != null && enumeration.hasMoreElements()) {
+            setEnableBasicAuth(Boolean.valueOf(initBasicEnable));
+            setUserName(initUserName);
+            setPassword(initPassword);
+        }
+    }
+
+    /**
+     * Basic验证
+     * @param url 当前系统访问URL
+     * @param sessionAuth Basic验证服务器SessionObject
+     * @param auth 请求头value
+     * @return
+     */
+    protected boolean tryCommonBasic(String url, Object sessionAuth, String auth) {
+        if (this.isEnableBasicAuth()) {
+            if (this.match(url)) {
+                if (sessionAuth == null) {
+                    // 获取请求头Authorization
+                    if (StrUtil.isBlank(auth)) {
+                        return false;
+                    }
+                    if (auth.length() < 6) {
+                        return false;
+                    }
+                    String userAndPass = decodeBase64(auth.substring(6));
+                    if (userAndPass == null) {
+                        return false;
+                    }
+                    String[] upArr = userAndPass.split(":");
+                    if (upArr.length != 2) {
+                        return false;
+                    } else {
+                        String iptUser = upArr[0];
+                        String iptPass = upArr[1];
+                        // 匹配服务端用户名及密码
+                        return Objects.equals(iptUser, getUserName()) && Objects.equals(iptPass, getPassword());
+                    }
+                }
+            }
+        }
+        return Boolean.TRUE;
+    }
+}

+ 105 - 0
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/BasicFilter.java

@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 cc.uncarbon.framework.knife4j.filter;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+/***
+ *
+ * @since  1.9.0
+ * @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
+ * 2019/02/02 19:57
+ */
+public class BasicFilter {
+
+    private Logger logger = LoggerFactory.getLogger(BasicFilter.class);
+
+    protected List<Pattern> urlFilters = null;
+
+    public BasicFilter() {
+        urlFilters = new ArrayList<>();
+        urlFilters.add(Pattern.compile(".*?/doc\\.html.*", Pattern.CASE_INSENSITIVE));
+        urlFilters.add(Pattern.compile(".*?/v2/api-docs.*", Pattern.CASE_INSENSITIVE));
+        urlFilters.add(Pattern.compile(".*?/v2/api-docs-ext.*", Pattern.CASE_INSENSITIVE));
+        urlFilters.add(Pattern.compile(".*?/swagger-resources.*", Pattern.CASE_INSENSITIVE));
+        urlFilters.add(Pattern.compile(".*?/swagger-resources/configuration/ui.*", Pattern.CASE_INSENSITIVE));
+        urlFilters.add(Pattern.compile(".*?/swagger-resources/configuration/security.*", Pattern.CASE_INSENSITIVE));
+        // https://gitee.com/xiaoym/knife4j/issues/I6H8BE
+        urlFilters.add(Pattern.compile(".*?/swagger-ui.*", Pattern.CASE_INSENSITIVE));
+        urlFilters.add(Pattern.compile(".*?/v3/api-docs.*", Pattern.CASE_INSENSITIVE));
+    }
+
+    /**
+     * 添加外部过滤规则,正则表达式
+     * @param rule 外部自定义规则
+     */
+    public void addRule(String rule) {
+        this.urlFilters.add(Pattern.compile(rule, Pattern.CASE_INSENSITIVE));
+    }
+
+    /**
+     * 添加外部过滤规则,正则表达式
+     * @param rules
+     */
+    public void addRule(Collection<String> rules) {
+        if (rules != null && !rules.isEmpty()) {
+            rules.forEach(this::addRule);
+        }
+    }
+
+    protected boolean match(String uri) {
+        boolean match = false;
+        // 考虑双斜杠的问题会绕过校验
+        // https://gitee.com/xiaoym/knife4j/issues/I4XDYE
+        String newUri = uri.replaceAll("/+", "/");
+        if (uri != null) {
+            for (Pattern pattern : getUrlFilters()) {
+                if (pattern.matcher(newUri).matches()) {
+                    match = true;
+                    break;
+                }
+            }
+        }
+        return match;
+    }
+    protected String decodeBase64(String source) {
+        String decodeStr = null;
+        if (source != null) {
+            // BASE64Decoder decoder=new BASE64Decoder();
+            try {
+                // byte[] bytes=decoder.decodeBuffer(source);
+                byte[] bytes = Base64.getDecoder().decode(source);
+                decodeStr = new String(bytes);
+            } catch (Exception e) {
+                logger.error(e.getMessage(), e);
+            }
+        }
+        return decodeStr;
+    }
+
+    public List<Pattern> getUrlFilters() {
+        return urlFilters;
+    }
+}

+ 92 - 0
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/JakartaProductionSecurityFilter.java

@@ -0,0 +1,92 @@
+/*
+ * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 cc.uncarbon.framework.knife4j.filter;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Enumeration;
+
+/***
+ * <p>
+ * {@code @since } 1.9.0
+ * @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
+ * 2019/01/18 17:15
+ */
+public class JakartaProductionSecurityFilter extends BasicFilter implements Filter {
+
+    /***
+     * 是否生产环境,如果是生成环境,过滤Swagger的相关资源请求
+     */
+    private boolean production = false;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        // 判断filterConfig
+        Enumeration<String> enumeration = filterConfig.getInitParameterNames();
+        // SpringMVC环境中,由此init方法初始化此Filter,SpringBoot环境中则不同
+        if (enumeration.hasMoreElements()) {
+            setProduction(Boolean.valueOf(filterConfig.getInitParameter("production")));
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
+        if (production) {
+            String uri = httpServletRequest.getRequestURI();
+            if (!match(uri)) {
+                chain.doFilter(request, response);
+            } else {
+                response.setContentType("text/palin;charset=UTF-8");
+                PrintWriter pw = response.getWriter();
+                pw.write("You do not have permission to access this page");
+                pw.flush();
+            }
+        } else {
+            chain.doFilter(request, response);
+        }
+    }
+
+    @Override
+    public void destroy() {
+
+    }
+
+    public JakartaProductionSecurityFilter(boolean production) {
+        this.production = production;
+    }
+
+    public JakartaProductionSecurityFilter() {
+    }
+
+    public boolean isProduction() {
+        return production;
+    }
+
+    public void setProduction(boolean production) {
+        this.production = production;
+    }
+}

+ 86 - 0
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/filter/JakartaServletSecurityBasicAuthFilter.java

@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 cc.uncarbon.framework.knife4j.filter;
+
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.Data;
+
+import java.io.IOException;
+
+/**
+ * @author <a href="xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
+ * 2023/2/25 19:17
+ * @since knife4j
+ */
+@Data
+public class JakartaServletSecurityBasicAuthFilter extends AbstractSecurityFilter implements Filter {
+
+    /***
+     * basic auth验证
+     */
+    public static final String KNIFE4J_BASIC_AUTH_SESSION = "KNIFE4J_BASIC_AUTH_SESSION";
+
+    /**
+     * 校验Basic请求头
+     */
+    public static final String AUTH_HEADER_NAME = "Authorization";
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        this.initServletConfig(filterConfig.getInitParameterNames(),
+                filterConfig.getInitParameter("enableBasicAuth"),
+                filterConfig.getInitParameter("userName"),
+                filterConfig.getInitParameter("password"));
+    }
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+        HttpServletRequest request = (HttpServletRequest) servletRequest;
+        HttpServletResponse response = (HttpServletResponse) servletResponse;
+        String url = request.getRequestURI();
+        if (this.isEnableBasicAuth() && this.match(url)) {
+            Object sessionObject = request.getSession().getAttribute(KNIFE4J_BASIC_AUTH_SESSION);
+            String auth = request.getHeader(AUTH_HEADER_NAME);
+            if (this.tryCommonBasic(url, sessionObject, auth)) {
+                if (sessionObject == null) {
+                    request.getSession().setAttribute(KNIFE4J_BASIC_AUTH_SESSION, getUserName());
+                }
+                filterChain.doFilter(servletRequest, servletResponse);
+            } else {
+                writeJakartaForbiddenCode(response);
+            }
+        } else {
+            filterChain.doFilter(servletRequest, servletResponse);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        this.urlFilters = null;
+    }
+
+    /**
+     * 响应Basic
+     */
+    private static void writeJakartaForbiddenCode(jakarta.servlet.http.HttpServletResponse httpServletResponse) throws IOException {
+        httpServletResponse.setStatus(401);
+        httpServletResponse.setHeader("WWW-Authenticate", "Basic realm=\"input Swagger Basic userName & password \"");
+        httpServletResponse.getWriter().write("You do not have permission to access this resource");
+    }
+}

+ 56 - 0
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/model/Knife4jHttpBasic.java

@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 cc.uncarbon.framework.knife4j.model;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.List;
+
+/***
+ * 配置文件
+ * {@code @since } 1.9.6
+ * @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
+ * 2019/08/27 15:40
+ */
+@Data
+@ConfigurationProperties(prefix = "knife4j.basic")
+public class Knife4jHttpBasic {
+
+    /**
+     * basic是否开启,默认为false
+     */
+    private boolean enable = false;
+
+    /**
+     * basic 用户名
+     */
+    private String username;
+
+    /**
+     * basic 密码
+     */
+    private String password;
+
+    /**
+     * All configured urls need to be verified by basic,Only support Regex
+     * since 4.1.0
+     */
+    private List<String> include;
+
+}

+ 50 - 0
helio-starter-knife4j/src/main/java/cc/uncarbon/framework/knife4j/model/Knife4jProperties.java

@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2017-2023 Knife4j(xiaoymin@foxmail.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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 cc.uncarbon.framework.knife4j.model;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/***
+ * 配置文件
+ * {@code @since } 1.9.6
+ * @author <a href="mailto:xiaoymin@foxmail.com">xiaoymin@foxmail.com</a>
+ * 2019/08/27 15:40
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "knife4j")
+public class Knife4jProperties {
+
+    /**
+     * 是否开启Knife4j增强模式
+     */
+    private boolean enable = false;
+
+    /**
+     * 是否开启BasicHttp验证
+     */
+    private Knife4jHttpBasic basic;
+
+    /**
+     * 是否生产环境
+     */
+    private boolean production = false;
+
+}

+ 1 - 1
helio-starter-rate-limit-redis/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-redis/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-rocketmq-aliyun/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-satoken/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 2 - 2
helio-starter-satoken/src/main/java/cc/uncarbon/framework/satoken/dao/SaTokenLocalCacheDao.java

@@ -1,7 +1,7 @@
 package cc.uncarbon.framework.satoken.dao;
 
 import cc.uncarbon.framework.core.cache.TimedCacheEx;
-import cn.dev33.satoken.dao.SaTokenDaoRedisJackson;
+import cn.dev33.satoken.dao.SaTokenDaoForRedisTemplate;
 
 /**
  * SA-Token 读取时,本地缓存一定时长,减少对 Redis 的 IO
@@ -11,7 +11,7 @@ import cn.dev33.satoken.dao.SaTokenDaoRedisJackson;
  * @since 2.1.0
  * @author Uncarbon
  */
-public class SaTokenLocalCacheDao extends SaTokenDaoRedisJackson {
+public class SaTokenLocalCacheDao extends SaTokenDaoForRedisTemplate {
 
     /**
      * 标记 key 为空值

+ 1 - 1
helio-starter-tenant/pom.xml

@@ -5,7 +5,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
     </parent>
     <modelVersion>4.0.0</modelVersion>
 

+ 1 - 1
helio-starter-test/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 1 - 1
helio-starter-web/pom.xml

@@ -8,7 +8,7 @@
     <parent>
         <artifactId>helio-starters</artifactId>
         <groupId>cc.uncarbon.framework</groupId>
-        <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+        <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
         <relativePath>../pom.xml</relativePath>
     </parent>
 

+ 0 - 5
helio-starter-web/src/main/resources/application.yml

@@ -1,5 +0,0 @@
-spring:
-  # 不为工程中的资源文件建立映射
-  web:
-    resources:
-      add-mappings: false

+ 11 - 23
pom.xml

@@ -24,20 +24,20 @@
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>3.4.1</version>
+        <version>3.4.6</version>
     </parent>
 
     <groupId>cc.uncarbon.framework</groupId>
     <artifactId>helio-starters</artifactId>
-    <version>2.3.1</version><!-- BATCH REPLACEMENT MARK -->
+    <version>2.4.0</version><!-- BATCH REPLACEMENT MARK -->
 
     <properties>
         <!-- core versions -->
-        <helio-starters.version>2.3.1</helio-starters.version>
+        <helio-starters.version>2.4.0</helio-starters.version>
         <!-- 可根据实际JDK版本修改;JDK17则改为'17'  JDK21则改为'21' -->
         <java.version>17</java.version>
         <!-- 若变更Spring Boot版本, 上面parent依赖版本也要变 -->
-        <spring-boot.version>3.4.1</spring-boot.version>
+        <spring-boot.version>3.4.6</spring-boot.version>
 
 
         <!-- Spring Cloud versions -->
@@ -58,12 +58,13 @@
         <!-- 3rd-party versions -->
         <lombok.version>1.18.30</lombok.version>
         <slf4j.version>2.0.12</slf4j.version>
-        <hutool.version>5.8.34</hutool.version>
-        <sa-token.version>1.39.0</sa-token.version>
+        <hutool.version>5.8.38</hutool.version>
+        <sa-token.version>1.44.0</sa-token.version>
         <transmittable-thread-local.version>2.14.5</transmittable-thread-local.version>
         <!-- 如果 mp 较新版存在问题,可以回退至 3.5.5 试试  -->
         <mybatis-plus.version>3.5.7</mybatis-plus.version>
-        <knife4j.version>4.5.0</knife4j.version>
+        <!-- 不要升级 knife4j,升级 SpringDoc 依赖版本即可 -->
+        <knife4j.version>4.4.0</knife4j.version>
         <!-- 以下两个 SpringDoc 依赖不完全配套,但能适配 Spring Boot 3.4.x -->
         <!-- https://central.sonatype.com/artifact/org.springdoc/springdoc-openapi-starter-common/版本号/dependencies -->
         <springdoc-openapi-starter.version>2.7.0</springdoc-openapi-starter.version>
@@ -77,7 +78,7 @@
 
 
         <!-- DB Driver versions -->
-        <mysql.version>8.3.0</mysql.version>
+        <mysql.version>9.2.0</mysql.version>
         <postgresql.version>42.7.4</postgresql.version>
 
 
@@ -370,23 +371,10 @@
             <!-- KNIFE4J dependencies -->
             <dependency>
                 <groupId>com.github.xiaoymin</groupId>
-                <artifactId>knife4j-core</artifactId>
+                <artifactId>knife4j-openapi3-ui</artifactId>
                 <version>${knife4j.version}</version>
             </dependency>
 
-            <dependency>
-                <groupId>com.github.xiaoymin</groupId>
-                <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
-                <version>${knife4j.version}</version>
-                <!-- 单体应用可以不要 guava,微服务应用通过 nacos-client 引入 guava -->
-                <exclusions>
-                    <exclusion>
-                        <groupId>com.google.guava</groupId>
-                        <artifactId>guava</artifactId>
-                    </exclusion>
-                </exclusions>
-            </dependency>
-
             <!-- SpringDoc 注解包-->
             <dependency>
                 <groupId>io.swagger.core.v3</groupId>
@@ -394,7 +382,7 @@
                 <version>${springdoc-annotations.version}</version>
             </dependency>
 
-            <!-- Knife4j 默认引入的 SpringDoc 版本还没有适配 Spring Boot 3.4.x,需要手动升级底层依赖 -->
+            <!-- 手动调适 SpringDoc 与 Spring Boot 的版本 -->
             <dependency>
                 <groupId>org.springdoc</groupId>
                 <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>