“org.springframework.context.ApplicationContextException: Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerException ”
Bug输出
问题原因:是由于用了高版本Springboot原因(2.7.5),降到2.6一下就是正常的。
因为Springfox 使用的路径匹配是基于AntPathMatcher的,而Spring Boot 2.6.X使用的是PathPatternMatcher。
如何解决呢,以下方案:
1.application.yml 或applicaiton.properties 中添加如下配置
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
2.加入依赖(加入knife4j UI)
<!--swagger 高版本Springboot2.6+使用3.0以上-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<!--swagger ui 高版本Springboot2.6+使用3.0以上-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
3.编写配置文件:SwaggerConfig
package com.cn.config.swagger;
import io.swagger.annotations.ApiOperation;
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.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
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.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* @program: toolbox-common
* @description
* @date 2023/3/9
*/
@Configuration
public class SwaggerConfig {
/**
* swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
*
* @return Docket
*/
@Bean(value = "defaultApi2")
public Docket defaultApi2() {
return new Docket(DocumentationType.SWAGGER_2)
//是否启用Swagger
.enable(true)
.apiInfo(apiInfo())
.select()
//此包路径下的类,才生成接口文档
//.apis(RequestHandlerSelectors.basePackage("com.cn"))
//扫描所有
//.apis(RequestHandlerSelectors.any())
//加了ApiOperation注解的类,才生成接口文档
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build()
//设置自定义swagger请求头
.securitySchemes(Collections.singletonList(securityScheme()))
.securityContexts(securityContexts());
//.globalOperationParameters(setHeaderToken());
}
/**
* 设置自定义swagger请求头
* @return ApiKey
*/
@Bean
SecurityScheme securityScheme() {
return new ApiKey("Access-Token", "Access-Token", "header");
}
/**
* 新增 securityContexts 保持登录状态
*/
private List<SecurityContext> securityContexts() {
return new ArrayList(
Collections.singleton(SecurityContext.builder()
.securityReferences(defaultAuth())
.forPaths(PathSelectors.regex("^(?!auth).*$"))
.build())
);
}
/**
* 配置
*/
private List<SecurityReference> defaultAuth() {
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
authorizationScopes[0] = authorizationScope;
return new ArrayList(
Collections.singleton(new SecurityReference("Access-Token", authorizationScopes)));
}
/**
* swagger主页名
* @return ApiInfo
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("接口文档")
.description("swagger接口文档")
.version("1.0")
.build();
}
/**
* JWT token
* @return setHeaderToken
*/
private List<Parameter> setHeaderToken() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
tokenPar.name("Access-Token").description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return pars;
}
/**
* 务必加入配置类中的springfoxHandlerProviderBeanPostProcessor方法
* @return BeanPostProcessor
*/
@Bean
public static 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);
}
}
};
}
}
4.1.swagger ui 页面
4.2.knife4j UI 页面
5.总结
- 务必加入配置类中的springfoxHandlerProviderBeanPostProcessor方法。
- yaml文件中必须将匹配策略改为ant_path_matcher。
- 配置类中必须有springfoxHandlerProviderBeanPostProcessor方法。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/192764.html