Swagger2启动出现Unable to scan documentation context default解决方法

一、问题

本地项目做了Swagger2的配置,在启动时报如下错误:

DocumentationPluginsBootstrapper : Unable to scan documentation context default

测试的Controller文件:

package com.quantsmart.controller;

import com.quantsmart.model.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.Authorization;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author: kaiyi
 * @Date 2021/5/21 13:57
 */
@RestController
@Api(tags = "CoinCommon里面的测试接口")
public class TestController {

    @GetMapping("/common/test")
    @ApiOperation(value = "测试方法", authorizations = {@Authorization("Authorization")})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "param", value = "参数1", dataType = "String", paramType = "query", example = "paramValue"),
            @ApiImplicitParam(name = "param1", value = "参数2", dataType = "String", paramType = "query", example = "paramValue")
    })
    public R<String> testMethod(String param, String param2){
        return R.ok("ok,哈哈哈,测试哇");
    }

}

Swagger2配置

/config/swagger/SwaggerProperties.java


package com.quantsmart.config.swagger;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author: kaiyi
 * @Date 2021/5/20 16:50
 */
@Data
@ConfigurationProperties(prefix = "swagger2")
public class SwaggerProperties {

    /**
     * 是否开启swagger
     */
    private Boolean enabled;

    /**
     * 包扫描的路径
     */
    private String basePackage;

    /**
     * 联系人的名称
     */
    private String name ;

    /**
     * 联系人的主页
     */
    private String url ;

    /**
     * 联系人的邮箱
     */
    private String email ;

    /**
     * API的标题
     */
    private String  title  ;

    /**
     * API的描述
     */
    private String description ;

    /**
     * API的版本号
     */
    private String version ;

    /**
     * API的服务团队
     */
    private String termsOfServiceUrl ;

}

/config/swagger/SwaggerAutoConfiguration.java

package com.quantsmart.config.swagger;

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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 java.util.Arrays;
import java.util.List;


/**
 * @author: kaiyi
 * @Date 2021/5/20 16:50
 */

@Configuration
@EnableSwagger2  // 开启swagger2自动生成api文档的功能
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfiguration {

    private SwaggerProperties swaggerProperties;

    public SwaggerAutoConfiguration(SwaggerProperties swaggerProperties) {
        this.swaggerProperties = swaggerProperties;
    }

    @Bean
    public Docket docket() {
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))
                .paths(PathSelectors.any())
                .build();
        // 安全的配置
        docket.securitySchemes(securitySchemes()) // 安全规则
                .securityContexts(securityContexts()); // 安全配置的上下问
        return docket;
    }

    /**
     * api 信息的简介
     *
     * @return
     */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder().contact(
                new Contact(swaggerProperties.getName(), swaggerProperties.getUrl(), swaggerProperties.getEmail())
        )
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .version(swaggerProperties.getVersion())
                .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
                .build();

    }

    /**
     * 安全的规则配置
     *
     * @return
     */
    private List<SecurityScheme> securitySchemes() {
        return Arrays.asList(new ApiKey("Authorization", "Authorization", "Authorization"));
    }

    /**
     * 安全的上下文
     *
     * @return
     */
    private List<SecurityContext> securityContexts() {
        return Arrays.asList(new SecurityContext(
                Arrays.asList(new SecurityReference("Authorization", new AuthorizationScope[]{new AuthorizationScope("global", "accessResource")})),
                PathSelectors.any()
        ));
    }




}

注意这里的apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage())) 扫描的是 controller包,是产生下面错误的原因:

ERROR 4928 --- [           main] d.s.w.p.DocumentationPluginsBootstrapper : Unable to scan documentation context default
java.lang.NullPointerException: null
    at java.lang.String.startsWith(String.java:1405) ~[na:1.8.0_131]
    at java.lang.String.startsWith(String.java:1434) ~[na:1.8.0_131]
    at springfox.documentation.builders.RequestHandlerSelectors$4.apply(RequestHandlerSelectors.java:98) ~[springfox-core-2.9.2.jar:null]
    at springfox.documentation.builders.RequestHandlerSelectors$4.apply(RequestHandlerSelectors.java:95) ~[springfox-core-2.9.2.jar:null]
    at com.google.common.base.Present.transform(Present.java:75) ~[guava-20.0.jar:na]
    at springfox.documentation.builders.RequestHandlerSelectors$5.apply(RequestHandlerSelectors.java:114) ~[springfox-core-2.9.2.jar:null]
    at springfox.documentation.builders.RequestHandlerSelectors$5.apply(RequestHandlerSelectors.java:111) ~[springfox-core-2.9.2.jar:null]
    at com.google.common.base.Predicates$AndPredicate.apply(Predicates.java:384) ~[guava-20.0.jar:na]
    at com.google.common.base.Predicates$AndPredicate.apply(Predicates.java:384) ~[guava-20.0.jar:na]
    at com.google.common.collect.Iterators$6.computeNext(Iterators.java:617) ~[guava-20.0.jar:na]
    at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:145) ~[guava-20.0.jar:na]
    at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:140) ~[guava-20.0.jar:na]
    at springfox.documentation.spring.web.scanners.ApiListingReferenceScanner.scan(ApiListingReferenceScanner.java:48) ~[springfox-spring-web-2.9.2.jar:null]
    at springfox.documentation.spring.web.scanners.ApiDocumentationScanner.scan(ApiDocumentationScanner.java:67) ~[springfox-spring-web-2.9.2.jar:null]
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.scanDocumentation(DocumentationPluginsBootstrapper.java:101) [springfox-spring-web-2.9.2.jar:null]
    at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:167) [springfox-spring-web-2.9.2.jar:null]
    at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:182) [spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:53) [spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:360) [spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:158) [spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:122) [spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:894) [spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:162) [spring-boot-2.2.7.RELEASE.jar:2.2.7.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) [spring-context-5.2.6.RELEASE.jar:5.2.6.RELEASE]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) [spring-boot-2.2.7.RELEASE.jar:2.2.7.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) [spring-boot-2.2.7.RELEASE.jar:2.2.7.RELEASE]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.2.7.RELEASE.jar:2.2.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) [spring-boot-2.2.7.RELEASE.jar:2.2.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.7.RELEASE.jar:2.2.7.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.7.RELEASE.jar:2.2.7.RELEASE]
    at com.coin.TestCommonApplication.main(TestCommonApplication.java:12) [classes/:na]

二、解决方法

上边已经发现了问题了,如果我此时将apis(RequestHandlerSelectors.basePackage(swaggerProperties.getBasePackage()))改为我具体要扫描的包

apis(RequestHandlerSelectors.basePackage(“com.quantsmart.controller”))

此时重启,可以发现打印的日志中没出现上面的错误了,且DocumentationPluginsBootstrapper 中打印扫描到一个controller接口了。

image.png

上边的修改方法是直接写死的,所以,我们可以在配置文件中配置swaggerProperties.getBasePackage()这个controller包路径(即SwaggerProperties类中的basePackage属性),例如在 application.yml 配置文件中添加controller包路径


# Swagger2属性配置
swagger2:
  base-package: com.quantsmart.controller  # 需要指定扫描的包的路径

然后访问 http://localhost:8989/swagger-ui.html 页面,可以看到可以成功看到接口文档页面了:

image.png


Corwien
为者常成,行者常至!

为者常成,行者常至。

6.3k 声望
1.6k 粉丝
0 条评论
推荐阅读
CDH6 离线安装
Cloudera Manager是一个拥有集群自动化安装、中心化管理、集群监控、报警功能的一个工具,使得安装集群从几天的时间缩短在几个小时内,运维人员从数十人降低到几人以内,极大的提高集群管理的效率。

Corwien2阅读 1.9k

与RabbitMQ有关的一些知识
工作中用过一段时间的Kafka,不过主要还是RabbitMQ用的多一些。今天主要来讲讲与RabbitMQ相关的一些知识。一些基本概念,以及实际使用场景及一些注意事项。

lpe2348阅读 1.8k

封面图
万字详解,吃透 MongoDB!
MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统,由 C++ 编写的。MongoDB 提供了 面向文档 的存储方式,操作起来比较简单和容易,支持“无模式”的数据建模,可以存储比较复杂的数据类型,是一款非常...

JavaGuide4阅读 377

封面图
Git操作不规范,战友提刀来相见!
年终奖都没了,还要扣我绩效,门都没有,哈哈。这波骚Git操作我也是第一次用,担心闪了腰,所以不仅做了备份,也做了笔记,分享给大家。问题描述小A和我在同时开发一个功能模块,他在优化之前的代码逻辑,我在开...

王中阳Go5阅读 2.1k评论 2

封面图
Redis 发布订阅模式:原理拆解并实现一个消息队列
“65 哥,如果你交了个漂亮小姐姐做女朋友,你会通过什么方式将这个消息广而告之给你的微信好友?““那不得拍点女朋友的美照 + 亲密照弄一个九宫格图文消息在朋友圈发布大肆宣传,暴击单身狗。”像这种 65 哥通过朋...

码哥字节6阅读 1.3k

封面图
PHP转Go实践:xjson解析神器「开源工具集」
我和劲仔都是PHP转Go,身边越来越多做PHP的朋友也逐渐在用Go进行重构,重构过程中,会发现php的json解析操作(系列化与反序列化)是真的香,弱类型语言的各种隐式类型转换,很大程度的减低了程序的复杂度。

王中阳Go6阅读 1.4k评论 2

封面图
NB的Github项目,看到最后一个我惊呆了!
最近看到不少好玩的、实用的 Github 项目,就来给大家推荐一把。中国制霸生成器最近在朋友圈非常火的一个小网站,可以在线标记 居住、短居、游玩、出差、路过 标记后可生成图片进行社区分享,标记过的信息会记录...

艾小仙5阅读 1.6k评论 1

为者常成,行者常至。

6.3k 声望
1.6k 粉丝
宣传栏