knife4j


1.介绍

knife4j 集成 微服务模板工程 pom 可直接使用 高内聚低耦合

2.项目结构

framework-knife4J
└─src
   └─main
       ├─java
       │  └─com
       │      └─yan
       │          ├─abstractinterface
       │          │  └─swagger
       │          ├─config
       │          ├─constants
       │          └─scan
       └─resources

3.pom文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.yan</groupId>
    <artifactId>framework-knife4j</artifactId>
    <version>${project-module.version}</version>

    <properties>
        <java.version>8</java.version>
        <project-module.version>0.0.1-SNAPSHOT</project-module.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <!--swagger 版本-->
        <knife4j.version>4.1.0</knife4j.version>
        <springdoc-openapi-ui.version>1.6.15</springdoc-openapi-ui.version>
        <javax.servlet-api.version>4.0.1</javax.servlet-api.version>
        <javax.annotation-api.version>1.3.2</javax.annotation-api.version>

        <spring-core.version>5.3.27</spring-core.version>

    </properties>
    <!--      网关引用需要排除
    <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-webmvc</artifactId>
                </exclusion>
            </exclusions>

            -->
     <dependencyManagement>
         <dependencies>
             <!--swagger-->
             <dependency>
                 <groupId>com.github.xiaoymin</groupId>
                 <artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
                 <version>${knife4j.version}</version>
             </dependency>

             <dependency>
                 <groupId>org.springdoc</groupId>
                 <artifactId>springdoc-openapi-ui</artifactId>
                 <version>${springdoc-openapi-ui.version}</version>
             </dependency>

             <dependency>
                 <groupId>javax.servlet</groupId>
                 <artifactId>javax.servlet-api</artifactId>
                 <version>${javax.servlet-api.version}</version>
             </dependency>

             <dependency>
                 <groupId>javax.annotation</groupId>
                 <artifactId>javax.annotation-api</artifactId>
                 <version>${javax.annotation-api.version}</version>
             </dependency>

             <dependency>
                 <groupId>org.springframework</groupId>
                 <artifactId>spring-core</artifactId>
                 <version>${spring-core.version}</version>
                 <optional>true</optional>
             </dependency>
         </dependencies>
     </dependencyManagement>

    <dependencies>
        <!--适用于springboot3版本替换依赖-->
<!--
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
            <version>4.4.0</version>
        </dependency>

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-common</artifactId>
            <version>1.6.9</version>
            <scope>compile</scope>
        </dependency>
        -->

        <!--swagger-->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-ui</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.25</version>
            <optional>true</optional>
        </dependency>
    </dependencies>
</project>

4.com.yan.constants

4.1 SwaggerConstants

package com.yan.constants;

/**
 * @author yan
 * @date 2023/9/30 5:30
 */
public class SwaggerConstants {
    public static final String swaggerScanPackage = "com.yan.config";
    public static final String authorization = "${api.authorization:Authorization}";
    public static final String version = "${api.common.version:1.0.0}";
    public static final String title = "${api.common.title:标题}";
    public static final String description = "${api.common.description:说明}";
    public static final String termsOfService = "${api.common.termsOfService:}";
    public static final String license = "${api.common.license:}";
    public static final String licenseUrl = "${api.common.licenseUrl:}";
    public static final String externalDocDesc = "${api.common.externalDocDesc:}";
    public static final String externalDocUrl = "${api.common.externalDocUrl:}";
    public static final String contactName = "${api.common.contact.name:}";
    public static final String contactUrl = "${api.common.contact.url:}";
    public static final String contactEmail = "${api.common.contact.email:}";
    public static final String serverServletContextPath = "${server.servlet.context-path:}";
}

4.2 GroupExpressionConstants

package com.yan.constants;

/**
 * @Author yan
 * @Date 2024/11/12 上午12:40:02
 * @Description
 */
public class GroupExpressionConstants {
    public static final String defaultGroupEnableExpression = "${springdoc.open.default-group-configs.enable:false}";
    public static final String defaultApiGroupExpression = "${springdoc.open.default-group-configs.api:true}";
    public static final String defaultJwtGroupExpression = "${springdoc.open.default-group-configs.jwt:true}";
    public static final String defaultOtherGroupExpression = "${springdoc.open.default-group-configs.other:true}";
}

5.com.yan.abstractinterface.swagger

5.1 AbstractSwagger

package com.yan.abstractinterface.swagger;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author yan
 * @Date 2024/7/26 0026 11:47:39
 * @Description
 */
public interface AbstractSwagger {
    String authorization = HttpHeaders.AUTHORIZATION;
    String apiGroupName = "api";
    String jwtGroupName = "jwt";
    String otherGroupName = "other";
    String GroupSuffix = "_Group";

    default <T> T defaultIfEmpty(T object, T defaultValue) {
        return ObjectUtil.isEmpty(object) ? defaultValue : object;
    }

    default <T> T defaultIfEmpty(T object) {
        return defaultIfEmpty(object, null);
    }

    default List<String> getPrefixByAuthorization() {
        Environment env = SpringUtil.getBean(Environment.class);
        String property = env.getProperty("authorization.prefix");
        List<String> list = CollUtil.newArrayList("/jwt/", "/test/");
        if (StrUtil.isNotBlank(property)) {
            list = Arrays.stream(property.split(",")).map(o -> {
                String str = "/";
                String strEnd = "**";
                if (!o.startsWith(str)) {
                    o = new StringBuffer(str).append(o).toString();
                }
                if (o.contains(strEnd)) {
                    o = o.replace(strEnd, "");
                }
                if (!o.endsWith(str)) {
                    o = new StringBuffer(o).append(str).toString();
                }
                return o;
            }).collect(Collectors.toList());
        }
        return list;
    }

    default String getAuthorization() {
        return authorization;
    }

    /**
     * 安全模式,这里配置通过请求头 Authorization 传递 token 参数
     */
    default Map<String, SecurityScheme> buildSecuritySchemes() {
        String authorization = getAuthorization();
        Map<String, SecurityScheme> securitySchemes = new HashMap<>();
        SecurityScheme securityScheme = new SecurityScheme()
                .type(SecurityScheme.Type.APIKEY) // 类型
                .name(authorization) // 请求头的 name
                .in(SecurityScheme.In.HEADER); // token 所在位置
        securitySchemes.put(authorization, securityScheme);
        return securitySchemes;
    }
    /*####################################################################################################################################################################################################################################################*/

    /**
     * 配置api组
     * 注意请和yaml中配置的组名不要重复(俩者配置同时生效)
     *
     * @return
     */

    //@Lazy//懒加载
    default GroupedOpenApi buildApiGroupedOpenApi() {
        String path = new StringBuilder().append("/api/**").toString();
        List<String> paths = CollUtil.newArrayList(path);

        SwaggerParameter sign = new SwaggerParameter()
                .setName("sign").setDescription("签名")
                .setStringSchemaDefault("签名sign")
                .setRequired(true);

        SwaggerParameter timestamp = new SwaggerParameter()
                .setName("timestamp").setDescription("时间戳")
                .setStringSchemaDefault(String.valueOf(System.currentTimeMillis()+ 3000))
                .setRequired(true);

        List<SwaggerParameter> swaggerParameters = CollUtil.newArrayList(sign, timestamp);
        //加入全局
        List<Parameter> parameterList = swaggerParameters.stream().filter(ObjectUtil::isNotEmpty)
                .map(this::buildHeaderParameter).collect(Collectors.toList());

        //Parameter signParameter = buildHeaderParameter("sign", "验签",
        //        null, "验签1"
        //        , null, null).required(true);
        //
        //Parameter timestampParameter = buildHeaderParameter("timestamp", "时间戳",
        //        null, System.currentTimeMillis() + 3000 + ""
        //        , null, "时间戳1").required(true);
        //
        ////加入全局
        //List<Parameter> parameterList = CollUtil.newArrayList(signParameter, timestampParameter);

        GroupSwagger groupSwagger = new GroupSwagger()
                .setGroupName(apiGroupName)
                .setPaths(paths)
                .setParameterList(parameterList);

        GroupedOpenApi groupedOpenApi = buildGroupedOpenApi(groupSwagger);
        return groupedOpenApi;
    }

    /**
     * 配置jwt组
     * 注意请和yaml中配置的组名不要重复(俩者配置同时生效)
     *
     * @return
     */

    //@Lazy//懒加载
    default GroupedOpenApi buildJwtGroupedOpenApi() {
        String path = new StringBuilder().append("/jwt/**").toString();

        List<String> paths = CollUtil.newArrayList(path);
        List<Parameter> parameterList = CollUtil.newArrayList(buildSecurityHeaderParameter(getAuthorization()));

        GroupSwagger groupSwagger = new GroupSwagger()
                .setGroupName(jwtGroupName)
                .setPaths(paths)
                .setParameterList(parameterList);

        GroupedOpenApi groupedOpenApi = buildGroupedOpenApi(groupSwagger);
        return groupedOpenApi;
    }

    /**
     * 配置other组
     * 注意请和yaml中配置的组名不要重复(俩者配置同时生效)
     *
     * @return
     */

    //@Lazy//懒加载
    default GroupedOpenApi buildOtherGroupedOpenApi() {
        //无需验证,无组必传参数
        String apiPath = new StringBuilder().append("/api/**").toString();
        String jwtPath = new StringBuilder().append("/jwt/**").toString();

        List<String> excludePaths = CollUtil.newArrayList(apiPath, jwtPath);
        GroupSwagger groupSwagger = new GroupSwagger()
                .setGroupName(otherGroupName)
                .setExcludePaths(excludePaths);
        GroupedOpenApi groupedOpenApi = buildGroupedOpenApi(groupSwagger);
        return groupedOpenApi;
    }

    @Data @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    class GroupSwagger {
        /**
         * 组名
         */
        String groupName;
        /**
         * 路径
         */
        List<String> paths;
        /**
         * 排除路径
         */
        List<String> excludePaths;
        /**
         * 参数
         */
        List<Parameter> parameterList;
    }
    default GroupedOpenApi buildGroupedOpenApi(@Valid @NotNull GroupSwagger groupSwagger){
        String groupName = groupSwagger.getGroupName();
        List<String> paths = groupSwagger.getPaths();
        List<String> excludePaths = groupSwagger.getExcludePaths();
        List<Parameter> parameterList = groupSwagger.getParameterList();
        return buildGroupedOpenApi(groupName, paths, excludePaths, parameterList);
    }
    /**
     * 配置 ,组|指定路径|全局 --必传参数
     *
     * @param groupName     该组名
     * @param paths         该组路径
     * @param excludePaths  该组排除路径
     * @param parameterList 该组参数
     * @return
     */
    default GroupedOpenApi buildGroupedOpenApi(String groupName, List<String> paths, List<String> excludePaths, List<Parameter> parameterList) {
        GroupedOpenApi.Builder builder = GroupedOpenApi.builder();
        if (StrUtil.isNotBlank(groupName)) {
            //加组配置
            builder.group(groupName);
        }
        if (CollUtil.isNotEmpty(paths)) {
            //组路径
            String[] pathsToMatch = paths.toArray(new String[paths.size()]);
            builder.pathsToMatch(pathsToMatch);
        }
        if (CollUtil.isNotEmpty(excludePaths)) {
            //组排除路径
            String[] pathsToExclude = excludePaths.toArray(new String[excludePaths.size()]);
            builder.pathsToExclude(pathsToExclude);
        }
        if (CollUtil.isNotEmpty(parameterList)) {
            builder.addOperationCustomizer(
                    //加全局变量
                    (operation, handlerMethod) -> {
                        Operation reOperation = new Operation();
                        for (Parameter parameter : parameterList) {
//                            parameter.setRequired(true);
                            //再原有方法参数基础上添加全局参数
                            reOperation = operation.addParametersItem(parameter);
                        }
                        //该方法会覆盖原有参数
                        //Operation parameters = operation.parameters(parameterList);
                        return reOperation;
                    }
            );
        }
        return builder.build();
    }
    /*####################################################################################################################################################################################################################################################*/


    /**
     * 构建 Authorization 认证请求头参数
     * <p>
     * 解决 Knife4j <a href="https://gitee.com/xiaoym/knife4j/issues/I69QBU">Authorize 未生效,请求header里未包含参数</a>
     *
     * @return 认证参数
     */
    default Parameter buildSecurityHeaderParameter(String authorization) {
        //String authorization = getAuthorization();
        Parameter parameter = new Parameter()
                .name(authorization) // header 名
                .description("认证 Token")// 描述
                .in(String.valueOf(SecurityScheme.In.HEADER))// 请求 header
                .schema(new StringSchema()
                        // ._default("Bearer ") // 最好关闭
                        .name(authorization).description("认证 Token"))//
                .required(true);
        return parameter;
    }

    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    @AllArgsConstructor
    class SwaggerParameter {
        /**
         * 名称
         */
        String name = "SwaggerParameter名称";
        /**
         * 描述
         */
        String description = "SwaggerParameter描述";
        /**
         * 请求参数位置
         */
        SecurityScheme.In securitySchemeIn = SecurityScheme.In.HEADER;
        /**
         * schema默认值
         */
        String stringSchemaDefault = null;
        String schemaName = "schemaName";
        /**
         * schema描述
         */
        String schemaDescription = "schema描述";
        /**
         * 是否必须
         */
        Boolean required = false;
    }

    default Parameter buildHeaderParameter(@Valid @NotNull SwaggerParameter swaggerParameter) {
        String name = swaggerParameter.getName();
        String description = swaggerParameter.getDescription();
        SecurityScheme.In securitySchemeIn = swaggerParameter.getSecuritySchemeIn();
        String stringSchemaDefault = swaggerParameter.getStringSchemaDefault();
        String schemaName = swaggerParameter.getSchemaName();
        String schemaDescription = swaggerParameter.getSchemaDescription();
        Boolean required = swaggerParameter.getRequired();
        return buildHeaderParameter(name, description, String.valueOf(securitySchemeIn), stringSchemaDefault, schemaName, schemaDescription)
                .required(required);
    }

    /**
     * 自定义参数
     *
     * @param parameterName        名称
     * @param parameterDescription 描述
     * @param parameterIn          请求参数位置
     * @param schemaDefault        默认值
     * @param schemaName
     * @param schemaDescription    schema描述
     * @return
     */
    default Parameter buildHeaderParameter(@NotNull String parameterName,
                                           @NotNull String parameterDescription,
                                           String parameterIn,
                                           String schemaDefault,
                                           String schemaName,
                                           String schemaDescription) {
        // header 名
        parameterName = defaultIfEmpty(parameterName, "header&" + System.currentTimeMillis());
        // 描述
        parameterDescription = defaultIfEmpty(parameterDescription, "认证 Token");
        // 请求 header
        parameterIn = defaultIfEmpty(parameterIn, String.valueOf(SecurityScheme.In.HEADER));
        schemaDefault = defaultIfEmpty(schemaDefault, "StringSchema");
        schemaDescription = defaultIfEmpty(schemaDescription, "schemaDescription");

        StringSchema stringSchema = new StringSchema()
                ._default(schemaDefault);

        Schema schema = stringSchema.name(schemaName)
                .description(schemaDescription);

        Parameter parameter = new Parameter()
                .name(parameterName)
                .description(parameterDescription)
                .in(parameterIn)
                .schema(schema);// 默认:使用用户编号为 1
        return parameter;
    }

    default OpenAPI buildOpenAPI() {
        String authorization = getAuthorization();
        OpenAPI api = new OpenAPI()
                .addSecurityItem(new SecurityRequirement().addList(authorization))
                .components(new Components()
                        .addSecuritySchemes(authorization, new SecurityScheme().name(authorization)
                                .type(SecurityScheme.Type.HTTP)
                                .scheme("Bearer ")
                                .in(SecurityScheme.In.HEADER)
                                .description("鉴权token")));
        return api;
    }

    default GlobalOpenApiCustomizer buildGlobalOpenApiCustomizer() {
        //Logger log = LoggerFactory.getLogger(getClass());
        //log.info("start");
        return openApi -> {
            if (ObjectUtil.isNotEmpty(openApi)) {
                openApi.getPaths().forEach((path, pathItem) -> {
                    boolean pathBool = false;
                    //log.info("path:{};pathItem:{};", path, pathItem);
                    List<String> list = getPrefixByAuthorization();
                    if (CollUtil.isEmpty(list)) {
                        pathBool = true;
                    } else {
                        for (String prefix : list) {
                            if (path.startsWith(prefix)) {
                                pathBool = true;
                                break;
                            }
                        }
                    }
                    if (pathBool) {
                        pathItem.readOperations().forEach(operation ->
                                operation.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION))
                        );
                    }
                });
            }
        };
    }

    default GlobalOpenApiCustomizer buildOpenApiCustomizer() {
        GlobalOpenApiCustomizer customizer = buildGlobalOpenApiCustomizer();
        return customizer;
    }
}

6.com.yan.config

6.1 SwaggerConfiguration

package com.yan.config;

import com.yan.constants.SwaggerConstants;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;

/**
 * @Author yan
 * @Date 2024/5/27 0027 13:19
 * @Description
 */
@Configuration
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Slf4j
public class SwaggerConfiguration {
    @Value(SwaggerConstants.authorization)
    private String authorization;
    @Value(SwaggerConstants.version)
    private String version;
    @Value(SwaggerConstants.title)
    private String title;
    @Value(SwaggerConstants.description)
    private String description;
    @Value(SwaggerConstants.termsOfService)
    private String termsOfService;
    @Value(SwaggerConstants.license)
    private String license;
    @Value(SwaggerConstants.licenseUrl)
    private String licenseUrl;
    @Value(SwaggerConstants.externalDocDesc)
    private String externalDocDesc;
    @Value(SwaggerConstants.externalDocUrl)
    private String externalDocUrl;
    @Value(SwaggerConstants.contactName)
    private String contactName;
    @Value(SwaggerConstants.contactUrl)
    private String contactUrl;
    @Value(SwaggerConstants.contactEmail)
    private String contactEmail;
    @Value(SwaggerConstants.serverServletContextPath)
    private String serverServletContextPath;
}

6.2 SwaggerConfig

package com.yan.config;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.github.xiaoymin.knife4j.core.util.StrUtil;
import com.yan.abstractinterface.swagger.AbstractSwagger;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import javax.annotation.Resource;
import java.util.*;

/**
 * @author yan
 * @date 2023/9/30 4:24
 */
@Data
@NoArgsConstructor
@Configuration
@Slf4j
public class SwaggerConfig implements AbstractSwagger {
    @Lazy
    @Resource
    private SwaggerConfiguration config;

    @Override
    public String getAuthorization() {
        String result = config.getAuthorization();
        return result;
    }
    //    @Bean
    public OpenAPI getOpenApiDocumentation() {

        ExternalDocumentation externalDocs = new ExternalDocumentation()
                .description(defaultIfEmpty(config.getExternalDocDesc()))
                .description(defaultIfEmpty(config.getExternalDocUrl()));

        Contact contact = new Contact()
                .name(defaultIfEmpty(config.getContactName()))
                .url(defaultIfEmpty(config.getContactUrl()))
                .email(defaultIfEmpty(config.getContactEmail()));

        License license = new License()
                .name(defaultIfEmpty(config.getLicense()))
                .url(defaultIfEmpty(config.getLicenseUrl()));

        Info info = new Info()
                .title(defaultIfEmpty(config.getTitle()))
                .description(defaultIfEmpty(config.getDescription()))
                .version(defaultIfEmpty(config.getVersion()))
                .contact(contact)
                .termsOfService(defaultIfEmpty(config.getTermsOfService()))
                .license(license);


        /**
         * 全局参数
         */
        // 设置 spring security jwt accessToken 认证的请求头 Authorization: Bearer xxx.xxx.xxx
        String authorization = getAuthorization();
        /*System.err.println(authorization);*/
        Map<String, SecurityScheme> securitySchemas = buildSecuritySchemes();

        Components components = new Components()
                .securitySchemes(securitySchemas);

        SecurityRequirement securityRequirement = new SecurityRequirement();
        securityRequirement.addList(authorization);

        OpenAPI openApi = new OpenAPI()
                .info(info)
                .components(components)
                .addSecurityItem(securityRequirement)
                .externalDocs(externalDocs);

        securitySchemas.keySet().forEach(key -> openApi.addSecurityItem(new SecurityRequirement().addList(key)));
        return openApi;
    }


    /**
     * 配置api组
     * 注意请和yaml中配置的组名不要重复(俩者配置同时生效)
     *
     * @return
     */

    //@Lazy//懒加载
    public static GroupedOpenApi beanBuildApiGroupedOpenApi() {
        return SpringUtil.getBean(SwaggerConfig.class).buildApiGroupedOpenApi();
    }

    /**
     * 配置jwt组
     * 注意请和yaml中配置的组名不要重复(俩者配置同时生效)
     *
     * @return
     */

    //@Lazy//懒加载
    public static GroupedOpenApi beanBuildJwtGroupedOpenApi() {
        return SpringUtil.getBean(SwaggerConfig.class).buildJwtGroupedOpenApi();
    }

    /**
     * 配置other组
     * 注意请和yaml中配置的组名不要重复(俩者配置同时生效)
     *
     * @return
     */

    //@Lazy//懒加载
    public static GroupedOpenApi beanBuildOtherGroupedOpenApi() {
        return SpringUtil.getBean(SwaggerConfig.class).buildOtherGroupedOpenApi();
    }


    @Bean
    public OpenAPI openAPI() {
        return buildOpenAPI();
    }


    @Bean
    public GlobalOpenApiCustomizer globalOpenApiCustomizer() {
        return buildOpenApiCustomizer();
    }
}

6.3 GroupedOpenApiBeanList

package com.yan.config;

import com.yan.constants.GroupExpressionConstants;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Author yan
 * @Date 2024/10/20 下午11:34:00
 * @Description
 */
@Slf4j
@Configuration
//@ConditionalOnExpression("${springdoc.open.default-group-configs.enable:false}")
@ConditionalOnExpression(GroupExpressionConstants.defaultGroupEnableExpression)
public class GroupedOpenApiBeanList {
    @Bean
    @ConditionalOnExpression(GroupExpressionConstants.defaultApiGroupExpression)
    public GroupedOpenApi api(){
        log.info("GroupedOpenApi {} init...","api");
       return SwaggerConfig.beanBuildApiGroupedOpenApi();
    }
    @Bean
    @ConditionalOnExpression(GroupExpressionConstants.defaultJwtGroupExpression)
    public GroupedOpenApi jwt(){
        log.info("GroupedOpenApi {} init...","jwt");
        return SwaggerConfig.beanBuildJwtGroupedOpenApi();
    }
    @Bean
    @ConditionalOnExpression(GroupExpressionConstants.defaultOtherGroupExpression)
    public GroupedOpenApi other(){
        log.info("GroupedOpenApi {} init...","other");
        return SwaggerConfig.beanBuildOtherGroupedOpenApi();
    }
}

7. com.yan.scan

7.1 SwaggerScan

package com.yan.scan;

import com.yan.constants.SwaggerConstants;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author yan
 * @date 2023/9/30 5:30
 */
@ComponentScan(basePackages = {SwaggerConstants.swaggerScanPackage}
        , basePackageClasses = {RestController.class}
)
@Configuration
public class SwaggerScan {
}

8.yml

## 自定义open API公共描述信息
#api:
#  authorization: token
#  common:
#    version: 3.0.0
#    title: SecuityAPI
#    description: SecuityAPI
#    termsOfService:
#    license: 未经许可不得转载
#    licenseUrl: xxx.license.com
#    externalDocDesc:
#    externalDocUrl:
#    contact:
#      name: kirito-asuna
#      url:
#      email:
#
#springdoc:
#  api-docs:
#    path: /v3/api-docs
## 请注意使用group名时如果配置了GroupedOpenApi引用自动配置时组名不能重复
#  open:
#    default-group-configs: true
#  group-configs:
#    - group: "api"
#      paths-to-match: "/api/**"
#    - group: "jwt"
#      paths-to-match: "/jwt/**"
#    - group: "other"
#      paths-to-exclude:
#        - "/swagger-resources/**"
#        - "/v2/api-docs"
#        - "/v3/api-docs"
#        - "/api/**"
#        - "/jwt/**"
#  swagger-ui:
#    operations-sorter: alpha
#    path: /swagger-ui.html
#    tags-sorter: alpha
# Authorization 在knife4j中失效==>替代方案 使用knife4j中全局参数设置Authorization
#knife4j:
#  cors: true
#  enable: true
#  setting:
#    enable-dynamic-parameter: true
#  #swagger
#  basic:
#    #    enable: true
#    username: root
#    password: root

#cors: true - 开启跨域资源共享(CORS),允许不同域名的请求访问。
#enable: true - 启用knife4j。
#setting: enable-dynamic-parameter: true - 开启动态参数功能,允许在运行时动态修改API接口参数。
#basic: enable: true - 开启基本认证,使用用户名和密码进行认证。
#username: root - 用户名为root。
#password: root - 密码为root。

9.依赖

       <!--swagger-->
        <dependency>
            <groupId>com.yan</groupId>
            <artifactId>framework-knife4j</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>