介绍
Springfox 是一个结合 Spring Web 及 Swagger UI 的一个可视化 API 框架,自从出现了 springfox-boot-starter �后即可实现零配置的 swagger ui 可视化 API 页面。那么他是如何做到零配置的呢?了解它的实现方式对于我们来说也是极具参考价值。
API 访问地址
Springfox.SwaggerUI2 的 API 可视化访问页面地址是
http://localhost:8080/swagger-ui.html
而 Springfox.SwaggerUI3(OpenAPI) 的 API 可视化访问页面地址是 http://localhost:8080/swagger-ui/index.html 或者简化为 http://localhost:8080/swagger-ui/(请不要忽略最后一个斜杆 /)
Demo 程序
`edward`
|-`springfox`
|-`controller`
| |- DemoController.java
|- BootApplication.java
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
</parent>
<groupId>org.example</groupId>
<artifactId>my-first-springfox-swagger-ui</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
</project>
package edward.springfox.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("/hello")
public String hello(@RequestParam(defaultValue = "World") String name) {
return String.format("Hello %s!", name);
}
}
package edward.springfox;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BootApplication {
public static void main(String[] args) {
SpringApplication.run(BootApplication.class, args);
}
}
运行 edward.springfox.BootApplication
后访问 http://localhost:8080/swagger-ui/index.html 或者简化为 http://localhost:8080/swagger-ui/(请不要忽略最后一个斜杆 /)
源码探究集成原理
首先找到 starter 的配置文件 springfox-boot-starter-3.0.0.jar!/META-INF/spring.factories,了解过 starter 的都知道,这里配置的 AutoConfiguration 是 starter 的启动入口,是所有 Bean 加载的起源。
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
springfox.boot.starter.autoconfigure.OpenApiAutoConfiguration
1. 映射 /swagger-ui/*
模块来源: springfox-boot-starter-
通过SwaggerUiWebFluxConfigurer
实现静态资源映射到 classpath:/META-INF/resources/webjars/springfox-swagger-ui/ 资源地址(Jar 包内的 /META-INF/resources 文件)
package springfox.boot.starter.autoconfigure;
public class SwaggerUiWebFluxConfigurer implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String baseUrl = StringUtils.trimTrailingCharacter(this.baseUrl, '/');
registry.
addResourceHandler(baseUrl + "/swagger-ui/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
.resourceChain(false);
}
}
2. 映射 /v3/api-docs
模块来源: springfox-oas-
package springfox.documentation.oas.web;
@ApiIgnore
@RestController
// @RequestMapping(OPEN_API_SPECIFICATION_PATH) // 请看下一行
@RequestMapping("${springfox.documentation.open-api.v3.path:/v3/api-docs}")
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@Conditional(OnReactiveWebApplication.class)
public class OpenApiControllerWebFlux {
@GetMapping(
produces = {
APPLICATION_JSON_VALUE,
HAL_MEDIA_TYPE})
public ResponseEntity<Json> getDocumentation(
@RequestParam(value = "group", required = false) String swaggerGroup,
ServerHttpRequest serverRequest) {
... ...
}
}
3. 映射 /swagger-resource/*
模块来源: springfox-swagger-common-
package springfox.documentation.swagger.web;
@RestController
@ApiIgnore
@RequestMapping({"${springfox.documentation.swagger-ui.base-url:}/swagger-resources"})
public class ApiResourceController {
@GetMapping(
value = {"/configuration/security"},
produces = {"application/json"}
)
public ResponseEntity<SecurityConfiguration> securityConfiguration() {}
@GetMapping(
value = {"/configuration/ui"},
produces = {"application/json"}
)
public ResponseEntity<UiConfiguration> uiConfiguration() {}
@GetMapping(
produces = {"application/json"}
)
public ResponseEntity<List<SwaggerResource>> swaggerResources() {}
}
4. 简化访问首页
模块来源: springfox-boot-starter-
http://localhost:8080/swagger-ui/index.html 简化为 http://localhost:8080/swagger-ui/ (请不要忽略最后一个斜杆 /)
package springfox.boot.starter.autoconfigure;
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@ConditionalOnProperty(
value = "springfox.documentation.swagger-ui.enabled",
havingValue = "true",
matchIfMissing = true)
public class SwaggerUiWebFluxConfiguration {
@Bean
public WebFilter uiForwarder() {
return new CustomWebFilter();
}
private static class CustomWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
String path = exchange.getRequest().getURI().getPath();
if (path.matches(".*/swagger-ui/")) {
return chain.filter(exchange.mutate().request(exchange.getRequest()
.mutate()
.path(StringUtils.trimTrailingCharacter(path, '/') + "/index.html")
.build())
.build());
}
return chain.filter(exchange);
}
}
}
5. 扫包加载 Controller
注意到 Configuration 配置类的 ComponentScan 配置 “springfox.documentation.swagger.web” 及 “springfox.documentation.oas.web”。
5.1 springfox-swagger-common-.jar
package springfox.documentation.swagger.configuration;
@Configuration
@ComponentScan(
basePackages = {"springfox.documentation.swagger.schema",
"springfox.documentation.swagger.readers",
"springfox.documentation.swagger.web"}
)
public class SwaggerCommonConfiguration {
public SwaggerCommonConfiguration() {
}
}
5.2 springfox-oas-.jar
package springfox.documentation.oas.configuration;
@Configuration
@Import({
SpringfoxWebConfiguration.class,
SpringfoxWebMvcConfiguration.class,
SpringfoxWebFluxConfiguration.class,
SwaggerCommonConfiguration.class,
OpenApiMappingConfiguration.class,
OpenApiWebMvcConfiguration.class,
OpenApiWebFluxConfiguration.class
})
@ComponentScan(basePackages = {
"springfox.documentation.oas.web",
"springfox.documentation.oas.mappers"
})
public class OpenApiDocumentationConfiguration {
}