1. 依赖版本
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.18</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
2. Spring Boot 2.5.x ~ 2.7.18
2.1 swagger配置属性
@ConfigurationProperties("swagger")
public class SwaggerProperties {
/**
* 是否开启swagger
*/
private Boolean enabled = true;
/**
* 标题
**/
private String title = "API文档";
/**
* 描述
**/
private String desc = "";
/**
* 版本
**/
private String version = "v3.0";
/**
* 许可证
**/
private String license = "Powered By Swagger";
/**
* 许可证URL
**/
private String licenseUrl = "https://swagger.io/";
/**
* 服务条款URL
**/
private String termsOfServiceUrl = "";
/**
* host信息
**/
private String host = "";
/**
* 接口前缀
*/
private String pathMapping = "";
/**
* 排除路径
*/
private List<String> excludePaths = new ArrayList<>();
/**
* 联系人信息
*/
private Contact contact = new Contact();
public static class Contact {
/**
* 联系人
**/
private String name = "";
/**
* 联系人url
**/
private String url = "";
/**
* 联系人email
**/
private String email = "";
}
}
2.2 swagger配置
@Component
public class SwaggerWebConfiguration implements WebMvcConfigurer {
private static final Logger log = LoggerFactory.getLogger(SwaggerWebConfiguration.class);
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
/** swagger-ui 地址 */
registry.addResourceHandler("/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
registry.addResourceHandler("/doc.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").
addResourceLocations("classpath:/META-INF/resources/webjars/");
log.info("映射swagger资源路径");
}
}
解决 springboot 2.5.x 默认使用 path-pattern-matcher,swagger扫描不到接口
@Configuration
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerConfiguration implements ApplicationListener<WebServerInitializedEvent> {
private static final Logger log = LoggerFactory.getLogger(SwaggerConfiguration.class);
private final WebMvcProperties webMvcProperties;
public SwaggerConfiguration(WebMvcProperties webMvcProperties) {
this.webMvcProperties = webMvcProperties;
}
@Bean
public Docket api(SwaggerProperties swaggerProperties) {
webMvcProperties.getPathmatch().setMatchingStrategy(WebMvcProperties.MatchingStrategy.ANT_PATH_MATCHER);
ApiSelectorBuilder apiSelectorBuilder = new Docket(DocumentationType.OAS_30)
.enable(swaggerProperties.getEnabled())
.host(swaggerProperties.getHost())
.pathMapping(swaggerProperties.getPathMapping())
.apiInfo(apiInfo(swaggerProperties)).select()
.apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class))
.apis(RequestHandlerSelectors.withMethodAnnotation(PutMapping.class))
.apis(RequestHandlerSelectors.withMethodAnnotation(PostMapping.class))
.apis(RequestHandlerSelectors.withMethodAnnotation(DeleteMapping.class))
.paths(PathSelectors.any())
.paths(PathSelectors.regex("/.*/error").negate());
swaggerProperties.getExcludePaths().forEach(path -> apiSelectorBuilder.paths(PathSelectors.ant(path).negate()));
return apiSelectorBuilder.build()
.protocols(new HashSet<String>() {{
add("https");
add("http");
}})
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
}
private List<SecurityScheme> securitySchemes() {
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
apiKeyList.add(new ApiKey(HeaderConstant.TOKEN, HeaderConstant.TOKEN, io.swagger.v3.oas.models.security.SecurityScheme.In.HEADER.toString()));
return apiKeyList;
}
private List<SecurityContext> securityContexts() {
List<SecurityContext> securityContexts = new ArrayList<>();
securityContexts.add(SecurityContext.builder().securityReferences(Collections.singletonList(new SecurityReference(HeaderConstant.TOKEN, new AuthorizationScope[]{new AuthorizationScope("global", "token授权信息")}))).operationSelector(o -> o.requestMappingPattern().matches("/.*")).build());
return securityContexts;
}
private ApiInfo apiInfo(SwaggerProperties swaggerProperties) {
return new ApiInfoBuilder()
.title(swaggerProperties.getTitle())
.description(swaggerProperties.getDesc())
.license(swaggerProperties.getLicense())
.licenseUrl(swaggerProperties.getLicenseUrl())
.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
.version(swaggerProperties.getVersion())
.build();
}
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
try {
SwaggerProperties swaggerProperties = event.getApplicationContext().getBean(SwaggerProperties.class);
if (swaggerProperties.getEnabled()) {
String hostAddress = Inet4Address.getLocalHost().getHostAddress();
int port = event.getWebServer().getPort();
String contextPath = event.getApplicationContext().getApplicationName();
System.out.println(
" __ __ __ __ __ \n" +
"(_ | | /\\ / _ / _ |_ |__) \n" +
"__) |/\\| /--\\ \\__) \\__) |__ | |"
);
System.out.println(String.format("http://%s:%s%s/doc.html", hostAddress, port, contextPath));
System.out.println(String.format("http://%s:%s%s/swagger-ui/index.html", hostAddress, port, contextPath));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
swagger 在 springboot 2.5.x 不兼容问题
@Component
public class SwaggerBeanPostProcessor implements BeanPostProcessor {
private static final Logger log = LoggerFactory.getLogger(SwaggerBeanPostProcessor.class);
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
log.info("处理swagger在springboot2.6.x不兼容的问题");
}
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);
List<RequestMappingInfoHandlerMapping> requestMappingInfoHandlerMappings = (List<RequestMappingInfoHandlerMapping>) field.get(bean);
return requestMappingInfoHandlerMappings;
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
3. 备注
这段代码
webMvcProperties.getPathmatch().setMatchingStrategy(WebMvcProperties.MatchingStrategy.ANT_PATH_MATCHER);
也可以写在yaml中
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
# swagger:
# title: 数据处理
# pathMapping: /data