SpringbootV2.6整合Knife4j 3.0.3 问题记录

news2025/2/23 3:22:27

参考

https://juejin.cn/post/7249173717749940284

近期由于升级到springboot2.6X,所以服务端很多组件都需要重新导入以及解决依赖问题。
下面就是一个很经典的问题了,
springboot2.6与knife4j的整合。

版本对应

springboot2.6与knife4j 3.0.3

  • 两者路径匹配模式不同

由于Springfox使用的路径匹配是基于AntPathMatcher,而Spring Boot 2.6.X使用的是PathPatternMatcher,所以将MVC的路径匹配规则改成 AntPathMatcher。具体配置如下:

--- application.yml:
spring:
  mvc:
    pathmatch:
      #Springfox使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher 解决knife4j匹配boot2.6.7 boot版本过高的问题
      matching-strategy: ant_path_matcher
      
-- 或者:application.properties:
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
  • springboot加载springfox过程中失败:
    第一个点很多文章都提到了,但是我主要遇到的是第二个点,表现在:
"org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()" because "this.condition" is null

这时候你可以

新增一个配置类,注意配置类不能放到swagger的配置类下,测试无效。配置Bean可以放在启动类下或者重新新增一个配置Bean,代码如下:

package net.w2p.AppBase.fixBugs;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;

import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Springboot整合Knife4j问题修正
 */
@Configuration
public class BeanPostProcessorConfig {

    @Bean
    public BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
                    customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
                }
                return bean;
            }

            private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
                List<T> copy = mappings.stream()
                        .filter(mapping -> mapping.getPatternParser() == null)
                        .collect(Collectors.toList());
                mappings.clear();
                mappings.addAll(copy);
            }

            @SuppressWarnings("unchecked")
            private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
                try {
                    Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                    field.setAccessible(true);
                    return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalStateException(e);
                }
            }
        };
    }

}


  • 配置demo
package net.w2p.AppBase;


import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import io.swagger.annotations.ApiOperation;
import net.w2p.WebExt.config.AppENV;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.http.HttpSession;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static springfox.documentation.builders.PathSelectors.regex;


/*
 * @Api: 修饰整个类,描述Controller的作用
 * @ApiOperation: 描述一个类的一个方法,或者说一个接口
 * @ApiParam: 单个参数描述
 * @ApiModel: 用对象来接收参数
 * @ApiProperty: 用对象接收参数时,描述对象的一个字段
 * @ApiResponse: HTTP响应其中1个描述
 * @ApiResponses: HTTP响应整体描述
 * @ApiIgnore: 使用该注解忽略这个API
 * @ApiError :发生错误返回的信息
 * @ApiImplicitParam: 一个请求参数
 * @ApiImplicitParams: 多个请求参数
 *  doc.html
 */

@EnableSwagger2
@Configuration
@EnableKnife4j

public class Swagger2Configuration implements WebMvcConfigurer {

    private String accessToken="token";

    private String title;

    private String description;

    private String version;

    private String termsOfServiceUrl;

    private String name;

    private String url;

    private String email;


    @Bean
    public Docket createRestApi() {
        boolean isEnableSwagger=true;
        if(!"test".equalsIgnoreCase(AppENV.getEnv())&&!"dev".equalsIgnoreCase(AppENV.getEnv())){
            isEnableSwagger=false;
        }
        if("dev".equalsIgnoreCase(AppENV.getEnv())){
            isEnableSwagger=true;
        }else{
            isEnableSwagger=false;
        }
        String scanPaths = "net.w2p.AppBase.controller.api;" +
                "net.w2p.AppBase.controller.common;" ;

        return new Docket(DocumentationType.SWAGGER_2).enable(isEnableSwagger)
                .apiInfo(apiInfo())
                //                .enable(enableSwagger)
                .directModelSubstitute(Timestamp.class, Long.class)//将Timestamp类型全部转为Long类型
                .directModelSubstitute(Date.class, Long.class)//将Date类型全部转为Long类型
                .forCodeGeneration(true)
                .select()

                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
//                .apis(RequestHandlerSelectors.any())
                .apis(basePackage(scanPaths))
//                .paths(PathSelectors.ant("/api/**"))
//                .paths(regex("^.*(?<!error)$"))
                .paths(PathSelectors.any())
                .build()
                // 添加忽略类型
                .ignoredParameterTypes(HttpSession.class)
                .securitySchemes(securitySchemes())
                .securityContexts(securityContexts());
    }

    private List<SecurityScheme> securitySchemes() {
        List<SecurityScheme> apiKeyList= new ArrayList();
        apiKeyList.add(new ApiKey("token", "token", "header"));
        return apiKeyList;
    }

    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContexts=new ArrayList<>();
        securityContexts.add(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .forPaths(regex("^(?!auth).*$"))
                        .build());
        return securityContexts;
    }


    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference(accessToken, authorizationScopes));
        return securityReferences;
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("api文档")
                .description("综合前台网站")
                .termsOfServiceUrl("http://www.baidu.com")
                .contact(new Contact("freeLife","baidu.com","1000@qq.com"))
                .version("2.9.2")
                .build();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        System.out.println("================> add doc.html -url");
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
//        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    // 定义分隔符
    private static final String splitor = ";";
    /**
     * 声明基础包
     *
     * @param basePackage 基础包路径
     * @return
     */
    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
    }

    /**
     * 校验基础包
     *
     * @param basePackage 基础包路径
     * @return
     */
    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
        return input -> {
            for (String strPackage : basePackage.split(splitor)) {
                boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                if (isMatch) {
                    return true;
                }
            }
            return false;
        };
    }

    /**
     * 检验基础包实例
     *
     * @param requestHandler 请求处理类
     * @return
     */
    @SuppressWarnings("deprecation")
    private static Optional<? extends Class<?>> declaringClass(RequestHandler requestHandler) {
        return Optional.fromNullable(requestHandler.declaringClass());
    }
}

运行结果

在这里插入图片描述
正常运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1433800.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSRF:跨站请求伪造攻击

目录 什么是CSRF&#xff1f; DVWA中的CSRF low medium hight impossible 防御CSRF 1、验证码 2、referer校验 3、cookie的Samesite属性 4、Anti-CSRF-Token 什么是CSRF&#xff1f; CSRF全称为跨站请求伪造&#xff08;Cross-site request forgery&#xff09;&…

【学网攻】 第(20)节 -- 网络端口地址转换NAPT配置

系列文章目录 目录 系列文章目录 文章目录 前言 一、NAPT是什么&#xff1f; 二、实验 1.引入 实验目的 技术原理 实验步骤 实验设备 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第…

AIGC实战——归一化流模型(Normalizing Flow Model)

AIGC实战——归一化流模型 0. 前言1. 归一化流模型1.1 归一化流模型基本原理1.2 变量变换1.3 雅可比行列式1.4 变量变换方程 2. RealNVP2.1 Two Moons 数据集2.2 耦合层2.3 通过耦合层传递数据2.4 堆叠耦合层2.5 训练 RealNVP 模型 3. RealNVP 模型分析4. 其他归一化流模型4.1 …

计算机网络——新型网络架构:SDN/NFV

1. 传统节点与SDN节点 1.1 传统节点(Traditional Node) 这幅图展示了传统网络节点的结构。在这种设置中&#xff0c;控制层和数据层是集成在同一个设备内。 以太网交换机&#xff1a;在传统网络中&#xff0c;交换机包括控制层和数据层&#xff0c;它不仅负责数据包的传输&…

FANUC机器人如何清除示教器右上角的白色感叹号?

FANUC机器人如何清除示教器右上角的白色感叹号&#xff1f; 如下图所示&#xff0c;示教器上显示白色的感叹号&#xff0c;如何清除呢&#xff1f; 具体可参考以下步骤&#xff1a; 按下示教器上白色的“i”键&#xff0c;如下图所示&#xff0c; 如下图所示&#xff0c;按…

飞天使-linux操作的一些技巧与知识点6-node,npm与jenkins执行用户

文章目录 安装node,npmjenkins执行时候出现找不到npm 命令 安装node,npm 以下是在 CentOS 7.9 上使用 nvm 安装 Node.js 的步骤&#xff1a;安装 nvm&#xff1a;bashCopy Codecurl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash在终端中重新加…

Java 运用 StringJoiner 高效的拼接字符串

运用 StringJoiner 高效的拼接字符串 package com.zhong.stringdemo;import java.util.ArrayList; import java.util.StringJoiner;public class Test {public static void main(String[] args) {ArrayList<String> s new ArrayList<>();s.add("11");s.…

备战蓝桥杯---搜索(剪枝)

何为剪枝&#xff0c;就是减少搜索树的大小。 它有什么作用呢&#xff1f; 1.改变搜索顺序。 2.最优化剪枝。 3.可行性剪枝。 首先&#xff0c;单纯的广搜是无法实现的&#xff0c;因为它存在来回跳的情况来拖时间。 于是我们可以用DFS&#xff0c;那我们如何剪枝呢&#…

Vulnhub靶机:hacksudoAliens

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;hacksudoAliens&#xff08;10.0.2.46&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://download.vulnhub.com…

PyTorch使用

前言 系统环境&#xff1a;win10 使用Anaconda&#xff0c;Anaconda的安装自行百度。 conda 23.7.4 目录 前言 创建虚拟环境 1、查看当前有哪些虚拟环境 2、创建虚拟环境pytorch 3、激活及关闭pytorch虚拟环境 4、删除pytorch虚拟环境 使用yolov5测试 1、切换至yolo…

UWA Pipeline 2.6.0 版本更新

UWA Pipeline是一款面向游戏开发团队的本地协作平台&#xff0c;旨在为游戏开发团队搭建专属的DevOps研发交付流水线&#xff0c;提供可视化的CICD操作界面、高可用的自动化测试以及UWA性能保障服务的无缝贴合等实用功能。 本周&#xff0c;我们迎来了全新的UWA Pipeline 2.6.…

MES系统是什么?MES软件有什么用?

在制造业领域&#xff0c;伴随着科技的不断进步和产业升级&#xff0c;企业越来越重视数字化和信息化在生产管理中的应用。引入先进的管理系统成为企业提高生产效率、降低成本、增强产品质量的关键途径。在工业4.0的大背景下&#xff0c;MES制造执行系统作为一种位于ERP企业资源…

docker手动迁移镜像

1&#xff0c;将镜像保存在本地 docker save 镜像名称:版本号 > 镜像名称.tar 2&#xff0c;下载镜像 通过 ftp 工具或者命令&#xff0c;下载到本地 3&#xff0c;上传镜像到目标 docker 所在服务器 4&#xff0c;导入镜像 docker load < 镜像名称.tar

【ACL 2023】Enhancing Document-level EAE with Contextual Clues and Role Relevance

【ACL 2023】Enhancing Document-level Event Argument Extraction with Contextual Clues and Role Relevance 论文&#xff1a;https://aclanthology.org/2023.findings-acl.817/ 代码&#xff1a;https://github.com/LWL-cpu/SCPRG-master Abstract 与句子级推理相比&…

程序员转行餐饮店之路:从开始到失败

之前一直有做副业的想法&#xff0c;比如最开始的水果摊&#xff0c;地铁口的烟花摆摊&#xff0c;都是从开始到失败。执着于摆摊的原因有两个&#xff1a;一是工资款如同上证指数一样&#xff0c;越来越低&#xff1b;二是为了先熟悉一下“创业”的过程。 契机终于来了&#x…

互联网加竞赛 基于深度学习的水果识别 设计 开题 技术

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/pos…

第三篇:SQL数据模型、通用语法和语法分类

一&#xff0c;SQL数据模型 &#xff08;一&#xff09;关系型数据库&#xff08;RDBMS&#xff09; 1.概念 &#xff08;百度百科&#xff09;指采用了关系模型来组织数据的数据库&#xff0c;其以行和列的形式存储数据&#xff0c;以便于用户理解&#xff0c;关系型数据库这…

19113133262(微信同号)2024年光电信息与机器视觉国际学术会议(ICOIMV 2024)

【征稿进行时|见刊、检索快速稳定】2024年光电信息与机器视觉国际学术会议(ICOIMV 2024) 2024 International Conference Optoelectronic Information and Machine Vision(ICOIMV 2024) 一、【会议简介】 本次会议的主题为“光电信息与机器视觉的未来发展”。围绕这一主题&…

信钰证券:部分金融股表现坚挺,四大行集体上扬,农业银行再创新高

部分金融股5日盘中表现坚挺&#xff0c;截至发稿&#xff0c;中信银行、光大证券涨超3%&#xff0c;工商银行涨逾2%&#xff0c;中国银行、农业银行、交通银行、建设银行涨超1%。值得注意的是&#xff0c;农业银行盘再度刷新历史新高。 音讯面上&#xff0c;2月5日&#xff0c…

Fink CDC数据同步(六)数据入湖Hudi

数据入湖Hudi Apache Hudi(简称&#xff1a;Hudi)使得您能在hadoop兼容的存储之上存储大量数据&#xff0c;同时它还提供两种原语&#xff0c;使得除了经典的批处理之外&#xff0c;还可以在数据湖上进行流处理。这两种原语分别是&#xff1a; Update/Delete记录&#xff1a;H…