一、问题
本地项目做了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接口了。
上边的修改方法是直接写死的,所以,我们可以在配置文件中配置swaggerProperties.getBasePackage()这个controller包路径(即SwaggerProperties类中的basePackage属性),例如在 application.yml
配置文件中添加controller包路径
# Swagger2属性配置
swagger2:
base-package: com.quantsmart.controller # 需要指定扫描的包的路径
然后访问 http://localhost:8989/swagger-ui.html
页面,可以看到可以成功看到接口文档页面了:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。