Swagger2文檔導出為HTML或markdown等格式離線閱讀
網上有很多《使用swagger2構建API文檔》的文章,swagger2文檔是一個在線文檔,需要使用HTTP訪問。但是在我們日常使用swagger接口文檔的時候,有的時候需要接口文檔離線訪問,如將文檔導出為html、markdown格式。又或者我們不希望應用系統與swagger接口文檔使用同一個服務,而是導出HTML之后單獨部署,這樣做保證了對接口文檔的訪問不影響業務系統,也一定程度提高了接口文檔的安全性。核心的實現過程就是:
注意:adoc是一種文件格式,不是我的筆誤。不是doc文件也不是docx文件。
在已經集成了swagger2的應用內,通過maven坐標引入相關依賴類庫,pom.xml代碼如下:
<dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-core</artifactId> <version>1.5.16</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>1.5.16</version> </dependency>
swagger2markup用于將swagger2在線接口文檔導出為html,markdown,adoc等格式文檔,用于靜態部署或離線閱讀。其中第一個maven坐標是必須的。后兩個maven坐標,當你在執行后面的代碼過程中報下圖中的ERROR,或者有的類無法import的時候使用。
swagger2markup過程可能拋出的異常
產生異常的原因已經有人在github的issues上給出解釋了:當你使用swagger-core版本大于等于1.5.11,并且swagger-models版本小于1.5.11就會有異常發生。所以我們顯式的引入這兩個jar,替換掉swagger2默認引入的這兩個jar。
swagger2markup異常的解決方案
下面的代碼是通過編碼方式實現的生成adoc格式文件的方式
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.DEFINED_PORT) public class DemoApplicationTests { @Test public void generateAsciiDocs() throws Exception { // 輸出Ascii格式 Swagger2MarkupConfig config=new Swagger2MarkupConfigBuilder() .withMarkupLanguage(MarkupLanguage.ASCIIDOC) //設置生成格式 .withOutputLanguage(Language.ZH) //設置語言中文還是其他語言 .withPathsGroupedBy(GroupBy.TAGS) .withGeneratedExamples() .withoutInlineSchema() .build(); Swagger2MarkupConverter.from(new URL("http://localhost:8888/v2/api-docs")) .withConfig(config) .build() .toFile(Paths.get("src/main/resources/docs/asciidoc")); } }
@Test public void generateMarkdownDocsToFile() throws Exception { // 輸出Markdown到單文件 Swagger2MarkupConfig config=new Swagger2MarkupConfigBuilder() .withMarkupLanguage(MarkupLanguage.MARKDOWN) .withOutputLanguage(Language.ZH) .withPathsGroupedBy(GroupBy.TAGS) .withGeneratedExamples() .withoutInlineSchema() .build(); Swagger2MarkupConverter.from(new URL("http://localhost:8888/v2/api-docs")) .withConfig(config) .build() .toFile(Paths.get("src/main/resources/docs/markdown")); }
上面的這一段代碼是生成markdown格式接口文件的代碼。執行上面的2段單元測試代碼,就可以生產對應格式的接口文件。
還有一種方式是通過maven插件的方式,生成adoc和markdown格式的接口文件。筆者不常使用這種方式,沒有使用代碼生成的方式配置靈活,很多配置都放到pom.xml感覺很臃腫。但還是介紹一下,首先配置maven插件swagger2markup-maven-plugin。
<plugin> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup-maven-plugin</artifactId> <version>1.3.1</version> <configuration> <swaggerInput>http://localhost:8888/v2/api-docs</swaggerInput><!---swagger-api-json路徑--> <outputDir>src/main/resources/docs/asciidoc</outputDir><!---生成路徑--> <config> <swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage><!--生成格式--> </config> </configuration> </plugin>
然后運行插件swagger2markup就可以了,如下圖:
插件運行方式(點擊可放大)
<plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>1.5.6</version> <configuration> <!--asciidoc文件目錄--> <sourceDirectory>src/main/resources/docs</sourceDirectory> <!---生成html的路徑--> <outputDirectory>src/main/resources/html</outputDirectory> <backend>html</backend> <sourceHighlighter>coderay</sourceHighlighter> <attributes> <!--導航欄在左--> <toc>left</toc> <!--顯示層級數--> <!--<toclevels>3</toclevels>--> <!--自動打數字序號--> <sectnums>true</sectnums> </attributes> </configuration> </plugin>
adoc的sourceDirectory路徑必須和第三小節中生成的adoc文件路徑一致。然后按照下圖方式運行插件。
asciidoctor:process-asciidoc插件運行
HTMl接口文檔顯示的效果如下,有了HTML接口文檔你想轉成其他各種格式的文檔就太方便了,有很多工具可以使用。這里就不一一介紹了。
HTML顯示結果
wagger介紹
前后端分離是目前一種非常流行的開發模式,前端和后端開發人員通過接口進行數據交換,因此接口文檔顯得尤為重要,借助swagger在線接口文檔,可以方便查看接口相關信息及進行接口測試,極大地提高了開發效率。swagger是API文檔自動生成工具,用于生成、描述、調用和可視化Restful風格的web服務。
1、pom文件中添加依賴
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
2、創建配置類SwaggerConfig
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket createApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
//是否開啟 (默認開啟, false關閉,生產環境建議關閉)
//.enable(false)
.select()
//掃描的路徑包,設置basePackage會將包下的所有被@Api標記類的所有方法作為api
.apis(RequestHandlerSelectors.basePackage("com.xx.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
//設置文檔標題(API名稱)
.title("測試API")
//文檔描述
.description("測試API說明")
//版本號
.version("1.0")
.build();
}
}
3、編寫controller,添加注解
@RestController
@RequestMapping("user")
@Api(tags="用戶管理")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("users")
@ApiOperation("用戶列表")
public Result<List<User>> user() {
List<User> users=userService.findAll();
return Result.success(users);
}
@GetMapping("{id}")
@ApiOperation("根據id查詢")
public Result<User> user(@PathVariable Long id) {
User user=userService.findById(id);
return Result.success(user);
}
...
4、在線訪問測試: http://ip:port/swagger-ui.html
swagger在線訪問
5、接口測試及返回結果
接口測試
@Api:用在請求的類上,表示對類的說明
tags="說明該類的作用,可以在UI界面上看到的注解"
value="該參數沒什么意義"
@ApiOperation:用在請求的方法上
value="說明方法的作用"
notes="方法的備注說明"
@ApiImplicitParams:用在請求的方法上,表示一組參數說明
@ApiImplicitParam:用在@ApiImplicitParams注解中,
指定一個請求參數的各個方面
name:參數名
value:參數的漢字說明、解釋
required:參數是否必須傳
paramType:參數放在哪個地方
· header --> 請求參數的獲取:@RequestHeader
· query --> 請求參數的獲取:@RequestParam
· path(用于restful接口)--> 請求參數的獲取:@PathVariable
· body(不常用)
· form(不常用)
dataType:參數類型,默認String,其它值dataType="Integer"
defaultValue:參數的默認值
@ApiResponses:用在請求的方法上,表示一組響應
@ApiResponse:用在@ApiResponses中,一般用于表達一個錯誤的響應信息
code:數字,例如400
message:信息,例如"請求參數沒填好"
response:拋出異常的類
@ApiModel:用于響應類上,表示一個返回響應數據的信息
(這種一般用在post創建的時候,使用@RequestBody這樣的場景,
請求參數無法使用@ApiImplicitParam注解進行描述的時候)
@ApiModelProperty:用在屬性上,描述響應類的屬性
Swagger 接口導出成 Word 格式如何實現?需要使用一個 Swagger 的增強工具Knife4j。
1、添加依賴
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.9</version>
</dependency>
2、在線訪問地址 http://ip:port/doc.html
Knife4j 在線訪問
Knife4j 提供了 4 種格式的離線文檔下載:Markdown、Html、Word、OpenAPI 等方式,如圖:
word下載
Knife4j 還可以實現過濾某一類型的接口、接口搜索、設置公共的請求參數等。
前后端分離,前端和后端api溝通目前企業中幾乎都是使用Swagger2。本文主要講解一下幾個案例,基本上工作中都會用到:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
2. Swagger2Config
@Configuration
@EnableSwagger2
public class Swagger2Config {
@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("demo")
.apiInfo(apiInfo())
.select()
// 設置basePackage會將包下的所有類的所有方法作為api
// .apis(RequestHandlerSelectors.basePackage("com.example.demo2.controller"))
// 只有標記@ApiOperation才會暴露出給swagger
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.regex("/api/.*"))
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("API接口文檔")
.description("RESTful風格接口")
.termsOfServiceUrl("https://blog.csdn.net/vbirdbest") // 服務條款網址
.version("1.0")
.contact(new Contact("mengday", "httphttp://wwww.xxx.com", "xxx@gmail.com"))
.build();
}
}
@RestController
@RequestMapping("/api/v1/users")
@Api(value="User API接口", tags="user", description="User API接口")
public class UserController {
@ApiOperation(value="用戶登錄", notes="用戶登錄接口")
@ApiResponses({
@ApiResponse(code=0, message="success"),
@ApiResponse(code=10001, message="用戶名錯誤", response=IllegalArgumentException.class),
@ApiResponse(code=10002, message="密碼錯誤")
})
@PostMapping(value="/login")
public String login(@ApiParam(name="username", value="用戶名", required=true) @RequestParam String username,
@ApiParam(name="password", value="密碼", required=true) @RequestParam String password){
return "{'username':'" + username + "', 'password':'" + password + "'}";
}
@ApiOperation(value="修改用戶信息", notes="修改用戶信息")
@ApiImplicitParams({
@ApiImplicitParam(dataTypeClass=String.class, paramType="header", name="phone", required=true, value="手機號"),
@ApiImplicitParam(dataTypeClass=String.class, paramType="query", name="nickname", required=true, value="nickname", defaultValue="雙擊666"),
@ApiImplicitParam(dataTypeClass=String.class, paramType="path", name="platform", required=true, value="平臺", defaultValue="PC"),
@ApiImplicitParam(dataTypeClass=String.class, paramType="body", name="password", required=true, value="密碼")
})
@PutMapping(value="/{platform}/regist")
public String regist(@RequestHeader String phone, @RequestParam String nickname, @PathVariable String platform, @RequestBody String password){
return "{'username':'" + phone + "', 'nickname':'" + nickname + "', 'platform': '" + platform + "', 'password':'"+password+"'}";
}
@ApiOperation(value="用戶列表", notes="查詢用戶列表")
@GetMapping(value="/list")
public String getUserList(PagerIDto pager){
return "[{'id': "+pager.getPage()+", 'username': 'zhangsan"+pager.getSize()+"'}]";
}
@ApiOperation(value="刪除用戶", notes="刪除用戶")
@DeleteMapping("/{id}")
public String removeUser(@PathVariable Long id){
return "success";
}
@ApiIgnore
@RequestMapping("/ignoreApi")
public String ignoreApi(){
return "docs";
}
}
4. 啟動應用程序并訪問swagger-ui.html
5. 為swagger-ui增加密碼
5.1 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
5.2 application.yml
spring:
security:
basic:
path: /swagger-ui.html
enabled: true
user:
name: admin
password: 123456
5.3 WebSecurityConfigurerAdapter
/**
* Spring Security 會攔截swagger-ui.html 同樣也會攔截api,這里將或略掉/api/下的所有子路徑
*/
@EnableWebSecurity
@Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring().antMatchers("/api/v1/**");
}
}
5.4 重啟項目再次訪問swagger-ui
訪問 http://localhost:8080/swagger-ui.html 會跳轉到 http://localhost:8080/login 輸入application.yml配置的用戶名密碼即可跳轉到到swagger-ui.html
apis(RequestHandlerSelectors.basePackage(“com.example.demo2.controller”)) 會將包下的所有Controller類帶有@RequestMapping或者XxxMapping都會給暴露給swagger,如果想部分類暴露出去部分不暴露出去,只能將不暴露的controller放到其他package中,放在同一個package是做不到的。
apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)): 只有在類上使用@Api注解標注并且在方法上使用@ApiOperation注解才會暴露給swagger,這種方式沒有包名的限制,可以將需要暴露的接口分散到各個包里,只要類上有@Api注解方法上有@ApiOperation注解就能暴露出來,如果不想暴露出來就不用使用這兩個注解。
現在的項目一般都是微服務,swagger可以做到將多個項目合并到一個swagger上,這樣便于接口的使用。
本示例只使用了Spring Boot, 后面可以結合spring-cloud-zuul來使用。
首先準備兩個api項目(platform-user-server、platform-order-server),并且每個項目都配置好swagger,然后再使用一個聚合的api項目(platform-api-gateway)來聚合這兩個api,這樣只需查看聚合api上對應的swagger ui即可。
1. maven
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
2. application.properties
server.port=8081
3. Configuration
@Configuration
public class CORSConfiguration {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration=new CorsConfiguration();
// 1 設置訪問源地址
corsConfiguration.addAllowedOrigin("*");
// 2 設置訪問源請求頭
corsConfiguration.addAllowedHeader("*");
// 3 設置訪問源請求方法
corsConfiguration.addAllowedMethod("*");
// 4 對接口配置跨域設置
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
@Configuration
public class Swagger2Configuration {
@Bean
public Docket shopRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.platform.user"))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
Contact contact=new Contact("mengday", "https://blog.csdn.net/vbirdbest", "mengday.zhang@gmail.com");
return new ApiInfoBuilder()
.title("用戶API")
.description("用戶API")
.termsOfServiceUrl("http://localhost:8081/swagger-ui.html")
.contact(contact)
.version("1.0")
.build();
}
4. Application
@EnableSwagger2
@SpringBootApplication
public class PlatformUserServerApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformUserServerApplication.class, args);
}
}
5. controller
@RestController
@RequestMapping("/user")
@Api(description="用戶API")
public class UserController {
@ApiOperation(value="用戶登錄", notes="用戶登錄", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiImplicitParams({
@ApiImplicitParam(name="username", value="用戶名", required=true, paramType="body", dataType="String"),
@ApiImplicitParam(name="password", value="密碼", required=true, paramType="body", dataType="String")
})
@PostMapping("/login")
public String login(String username, String password) {
return "success";
}
}
6. 訪問swagger
http://localhost:8081/swagger-ui.html
注意:swagger不要使用太高的版本,不建議使用2.8.0以上的版本,不然很可能會報如下錯誤,即使低版本也可能會報該錯誤。Chrome報錯,遇到這個錯誤可以嘗試清除緩存或者使用其他瀏覽器,這個問題很多人都遇到了,也沒找到有效的解決方案,自己在測試的時候就一會好使,一會又不好使,祝你好運。
1. maven
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
2. application.properties
server.port=8082
3. Configuration
@Configuration
public class CORSConfiguration {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration=new CorsConfiguration();
// 1 設置訪問源地址
corsConfiguration.addAllowedOrigin("*");
// 2 設置訪問源請求頭
corsConfiguration.addAllowedHeader("*");
// 3 設置訪問源請求方法
corsConfiguration.addAllowedMethod("*");
// 4 對接口配置跨域設置
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
@Configuration
public class Swagger2Configuration {
@Bean
public Docket shopRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.platform.order"))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
Contact contact=new Contact("mengday", "https://blog.csdn.net/vbirdbest", "mengday.zhang@gmail.com");
return new ApiInfoBuilder()
.title("訂單API")
.description("訂單API")
.termsOfServiceUrl("http://localhost:8082/swagger-ui.html")
.contact(contact)
.version("1.0")
.build();
}
}
4. Application
@EnableSwagger2
@SpringBootApplication
public class PlatformOrderServerApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformOrderServerApplication.class, args);
}
}
5. controller
@RestController
@RequestMapping("/shoppingcart")
@Api(description="購物車API")
public class ShoppingCartController {
@ApiOperation(value="加入購物車", notes="加入購物車", produces=MediaType.APPLICATION_JSON_UTF8_VALUE)
@ApiImplicitParams({
@ApiImplicitParam(name="barcode", value="條形碼", required=true, paramType="body", dataType="String"),
@ApiImplicitParam(name="quantity", value="數量", required=true, paramType="body", dataType="Integer")
})
@PostMapping("/add")
public String addShoppingCart(String barcode, Integer quantity) {
return "success";
}
}
6. 訪問swagger
1. maven
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
2. application.properties
server.port=8080
3. Application
@EnableSwagger2
@SpringBootApplication
public class PlatformApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(PlatformApiGatewayApplication.class, args);
}
}
4. configuration
@Configuration
public class CORSConfiguration {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration=new CorsConfiguration();
// 1 設置訪問源地址
corsConfiguration.addAllowedOrigin("*");
// 2 設置訪問源請求頭
corsConfiguration.addAllowedHeader("*");
// 3 設置訪問源請求方法
corsConfiguration.addAllowedMethod("*");
// 4 對接口配置跨域設置
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
@Configuration
public class SwaggerConfiguration {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo());
}
private ApiInfo apiInfo() {
Contact contact=new Contact("mengday", "https://blog.csdn.net/vbirdbest", "mengday.zhang@gmail.com");
return new ApiInfoBuilder()
.title("項目名稱")
.description("Swagger多項目聚合")
.termsOfServiceUrl("http://localhost:8080")
.contact(contact)
.version("1.0")
.build();
}
}
@Component
@Primary
public class DocumentationConfiguration implements SwaggerResourcesProvider {
@Override
public List<SwaggerResource> get() {
List resources=new ArrayList<>();
resources.add(swaggerResource("用戶API", "http://localhost:8081/v2/api-docs", "2.0"));
resources.add(swaggerResource("購物車API", "http://localhost:8082/v2/api-docs", "2.0"));
return resources;
}
private SwaggerResource swaggerResource(String name, String location, String version) {
SwaggerResource swaggerResource=new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion(version);
return swaggerResource;
}
}
5. 訪問swagger
*請認真填寫需求信息,我們會在24小時內與您取得聯系。