前言

相信很多後端開發在項目中都會碰到要寫 api 文檔,不管是給前端、移動端等提供更好的對接,還是以後爲了以後交接方便,都會要求寫 api 文檔。

而手寫 api 文檔的話有諸多痛點:

  • 文檔更新的時候,需要再次發送給對接人
  • 接口太對,手寫文檔很難管理
  • 接口返回的結果不明確
  • 不能直接在線測試接口,通常需要使用工具,如 postman 等

Swagger 就很好的解決了這個問題。

Swagger 簡介

Swagger 是一個規範和完整的框架,用於生成、描述、調用和可視化 RESTful 風格的 Web 服務。總體目標是使客戶端和文件系統作爲服務器以同樣的速度來更新。文件的方法,參數和模型緊密集成到服務器端的代碼,允許API來始終保持同步。

官網: https://swagger.io

Swagger 使用

1.相關依賴

<!--swagger2 -->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger2</artifactId>
			<version>2.9.2</version>
		</dependency>
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-swagger-ui</artifactId>
			<version>2.9.2</version>
		</dependency>

2.Swagger 配置類

@Configuration
@EnableSwagger2
public class SwaggerConfig {
	@Bean
    public Docket buildDocket() {
        return new Docket(DocumentationType.SWAGGER_2)
        .apiInfo(buildApiInf()) //將api的元信息設置爲包含在json resourcelisting響應中
        //.host("127.0.0.1:8080") //設置ip和端口,或者域名
        .select()  //啓動用於api選擇的生成器
        //.apis(RequestHandlerSelectors.any())
        .apis(RequestHandlerSelectors.basePackage("cn.zwqh.springboot.controller"))//指定controller路徑
        .paths(PathSelectors.any()).build();
    }

    private ApiInfo buildApiInf() {
    	
        Contact contact=new Contact("朝霧輕寒","https://www.zwqh.top/","[email protected]");
        return new ApiInfoBuilder()
        .title("Swagger Demo Restful API Docs")//文檔標題
        .description("Swagger 示例 Restful Api 文檔")//文檔描述
        .contact(contact)//聯繫人
        .version("1.0")//版本號
        //.license("")//更新此API的許可證信息
        //.licenseUrl("")//更新此API的許可證Url
        //.termsOfServiceUrl("")//更新服務條款URL
        .build();

    }
}

3.Spring MVC 相關配置

@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
	/**
	 * 靜態資源配置(默認)
	 */
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");// 靜態資源路徑
		registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
		registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
		super.addResourceHandlers(registry);
	}


}

如果不添加此靜態資源配置會報錯,找不到相關路徑

4.Model 中使用 Swagger 註解

@ApiModel(value = "UserEntity", description = "用戶對象")
public class UserEntity implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 5237730257103305078L;
	@ApiModelProperty(value ="用戶id",name="id",dataType="Long",required = false,example = "1",hidden = false )
	private Long id;
	@ApiModelProperty(value ="用戶名",name="userName",dataType="String",required = false,example = "關羽" )
	private String userName;
	@ApiModelProperty(value ="用戶性別",name="userSex",dataType="String",required = false,example = "男" )
	private String userSex;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getUserSex() {
		return userSex;
	}

	public void setUserSex(String userSex) {
		this.userSex = userSex;
	}

}

5. Controller 中使用 Swagger 註解

@RestController
@RequestMapping("/api")
@Api(tags = { "接口分組1", "接口分組2" })
public class ApiController {

	@Autowired
	private UserDao userDao;

	@GetMapping("/getAllUser")
	@ApiOperation(value = "獲取所有用戶", notes = "", httpMethod = "GET", tags = "接口分組3")
	public List<UserEntity> getAll() {
		return userDao.getAll();
	}

	@GetMapping("/getUserById")
	@ApiOperation(value = "根據id獲取用戶", notes = "id必傳", httpMethod = "GET")
	@ApiImplicitParam(name = "id", value = "用戶id",example = "1", required = true, dataType = "long", paramType = "query")
	public UserEntity getOne(Long id) {
		return userDao.getOne(id);
	}

	@PostMapping("/getUserByNameAndSex")
	@ApiOperation(value = "根據name和sex獲取用戶", notes = "", httpMethod = "POST")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "userName", value = "用戶名", example = "關羽", required = true, dataType = "string", paramType = "query"),
			@ApiImplicitParam(name = "userSex", value = "用戶性別", example = "男", required = true, dataType = "string", paramType = "query") })
	public UserEntity getUserByNameAndSex(String userName, String userSex) {
		return userDao.getUserByNameAndSex(userName, userSex);
	}

	@PostMapping("/insertUser")
	@ApiOperation(value = "新增用戶", notes = "傳json,數據放body", httpMethod = "POST")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "body", value = "用戶對象json", example = "{userName:'朝霧輕寒',userSex:'男'}", required = true) })
	public String insertUser(@RequestBody String body) {
		System.out.println(body);
		UserEntity user = JSON.parseObject(body, UserEntity.class);
		userDao.insertUser(user);
		return "{code:0,msg:'success'}";
	}

	@PostMapping("/updateUser")
	@ApiOperation(value = "修改用戶", notes = "傳json,數據放body", httpMethod = "POST")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "body", value = "用戶對象json", example = "{id:23,userName:'朝霧輕寒',userSex:'女'}", required = true) })
	public String updateUser(@RequestBody String body) {
		System.out.println(body);
		UserEntity user = JSON.parseObject(body, UserEntity.class);
		userDao.updateUser(user);
		return "{code:0,msg:'success'}";
	}

	@PostMapping("/deleteUser")
	@ApiOperation(value = "刪除用戶", notes = "id必傳", httpMethod = "POST")
	public String deleteUser(@ApiParam(name = "id", value = "用戶id", required = true) Long id) {
		userDao.deleteUser(id);
		return "{code:0,msg:'success'}";
	}
}

5.測試

訪問 http://127.0.0.1:8080/swagger-ui.html 進行接口在線測試

Swagger 常用註解

1. @Api

用於類,表示標識這個類是swagger的資源。屬性如下:

  • tags 表示說明,tags如果有多個值,會生成多個列表
  • value 表示說明,可以使用tags替代

2.@ApiOperation

用於方法,表示一個http請求的操作。屬性如下:

  • value 用於方法描述
  • notes 用於提示內容
  • tags 用於API文檔控制的標記列表,視情況而用,可以進行獨立分組

3.@ApiParam

用於方法、參數、字段說明;表示對參數的添加元數據。

  • name 參數名
  • value 參數說明
  • required 是否必填

4.@ApiModel

用於類,表示對類進行說明,用於參數用實體類接受。

  • value 對象名
  • description 描述

5.@ApiModelProperty

用於方法、字段,表示對model屬性的說明或者數據操作更改。

  • value 字段說明
  • name 重寫屬性名
  • dataType 重寫屬性數據類型
  • required 是否必填
  • example 舉例說明
  • hidden 隱藏

6.@ApiIgnore

用於類、方法、方法參數,表示這個方法或者類被忽略,不在swagger-ui.html上顯示。

7.@ApiImplicitParam

用於方法,表示單獨的請求參數。

  • name 參數名
  • value 參數說明
  • dataType 數據類型
  • paramType 參數類型
  • example 舉例說明

8.@ApiImplicitParams

用於方法,包含多個 @ApiImplicitParam。

9.@ApiResponses @ApiResponse

用於類或者方法,描述操作的可能響應。

  • code 響應的HTTP狀態代碼
  • message 響應附帶的可讀消息

10.@ResponseHeader

用於方法,響應頭設置。

  • name 響應頭名稱
  • description 頭描述
  • response 默認響應類 void
  • responseContainer 參考ApiOperation中配置

Swagger 導出離線 api 文檔

1.導出 AsciiDocs、Markdown、Confluence 格式文檔

添加依賴

<!-- swagger2markup 相關依賴 -->
		<dependency>
			<groupId>io.github.swagger2markup</groupId>
			<artifactId>swagger2markup</artifactId>
			<version>1.3.3</version>
		</dependency>

轉換工具類

public class SwaggerUtils {

	private static final String url = "http://127.0.0.1:8080/v2/api-docs";
	/**
	 * 生成AsciiDocs格式文檔
	 * @throws MalformedURLException
	 */
	public static void generateAsciiDocs() throws MalformedURLException {
		Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
				.withMarkupLanguage(MarkupLanguage.ASCIIDOC)
				.withOutputLanguage(Language.ZH)
				.withPathsGroupedBy(GroupBy.TAGS)
				.withGeneratedExamples()
				.withoutInlineSchema().build();

		Swagger2MarkupConverter.from(new URL(url))
				.withConfig(config)
				.build()
				.toFolder(Paths.get("./docs/asciidoc/generated"));
	}
	/**
	 * 生成AsciiDocs格式文檔,並彙總成一個文件
	 * @throws MalformedURLException
	 */
	public static void generateAsciiDocsToFile() throws MalformedURLException {
		Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.ASCIIDOC)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();

        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFile(Paths.get("./docs/asciidoc/generated/all"));
	}
	
	/**
	 * 生成Markdown格式文檔
	 * @throws MalformedURLException
	 */
	public static void generateMarkdownDocs() throws MalformedURLException {
		Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.MARKDOWN)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();

        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFolder(Paths.get("./docs/markdown/generated"));
	}
	/**
	 * 生成Markdown格式文檔,並彙總成一個文件
	 * @throws MalformedURLException
	 */
	public static void generateMarkdownDocsToFile() throws MalformedURLException {
		Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.MARKDOWN)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();

        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFile(Paths.get("./docs/markdown/generated/all"));
	}
	
	/**
	 * 生成Confluence格式文檔
	 * @throws MalformedURLException
	 */
	public static void generateConfluenceDocs() throws MalformedURLException {
		Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.CONFLUENCE_MARKUP)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();

        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFolder(Paths.get("./docs/confluence/generated"));
	}
	
	/**
	 * 生成Confluence格式文檔,並彙總成一個文件
	 * @throws MalformedURLException
	 */
	public static void generateConfluenceDocsToFile() throws MalformedURLException {
		Swagger2MarkupConfig config = new Swagger2MarkupConfigBuilder()
                .withMarkupLanguage(MarkupLanguage.CONFLUENCE_MARKUP)
                .withOutputLanguage(Language.ZH)
                .withPathsGroupedBy(GroupBy.TAGS)
                .withGeneratedExamples()
                .withoutInlineSchema()
                .build();

        Swagger2MarkupConverter.from(new URL(url))
                .withConfig(config)
                .build()
                .toFile(Paths.get("./docs/confluence/generated/all"));
	}
	
	
}

使用測試 Controller

@RestController
@RequestMapping("/export")
@ApiIgnore
public class ExportController {

	
	@RequestMapping("/ascii")
	public String exportAscii() throws MalformedURLException{
		SwaggerUtils.generateAsciiDocs();
		return "success";
	}
	
	@RequestMapping("/asciiToFile")
	public String asciiToFile() throws MalformedURLException{
		SwaggerUtils.generateAsciiDocsToFile();
		return "success";
	}
	
	@RequestMapping("/markdown")
	public String exportMarkdown() throws MalformedURLException{
		SwaggerUtils.generateMarkdownDocs();
		return "success";
	}
	
	@RequestMapping("/markdownToFile")
	public String exportMarkdownToFile() throws MalformedURLException{
		SwaggerUtils.generateMarkdownDocsToFile();
		return "success";
	}
	
	@RequestMapping("/confluence")
	public String confluence() throws MalformedURLException{
		SwaggerUtils.generateConfluenceDocs();
		return "success";
	}
	
	@RequestMapping("/confluenceToFile")
	public String confluenceToFile() throws MalformedURLException{
		SwaggerUtils.generateConfluenceDocsToFile();
		return "success";
	}
}

2.導出 html、pdf、xml 格式

添加依賴

<!--離線文檔 -->
		<dependency>
			<groupId>org.springframework.restdocs</groupId>
			<artifactId>spring-restdocs-mockmvc</artifactId>
			<scope>test</scope>
		</dependency>
		<!--springfox-staticdocs 生成靜態文檔 -->
		<dependency>
			<groupId>io.springfox</groupId>
			<artifactId>springfox-staticdocs</artifactId>
			<version>2.6.1</version>
		</dependency>
<build>
		<pluginManagement>
			<plugins>
				<plugin>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-maven-plugin</artifactId>
				</plugin>
				<plugin>
					<groupId>io.github.swagger2markup</groupId>
					<artifactId>swagger2markup-maven-plugin</artifactId>
					<version>1.3.1</version>
					<configuration>
						<swaggerInput>http://127.0.0.1:8080/v2/api-docs</swaggerInput>
						<outputDir>./docs/asciidoc/generated</outputDir>
						<config>
							<swagger2markup.markupLanguage>ASCIIDOC</swagger2markup.markupLanguage>
						</config>
					</configuration>
				</plugin>
				<plugin>
					<groupId>org.asciidoctor</groupId>
					<artifactId>asciidoctor-maven-plugin</artifactId>
					<version>1.5.3</version>
					<!-- <version>2.0.0-RC.1</version> -->
					<!-- Include Asciidoctor PDF for pdf generation -->
					<dependencies>
						<dependency>
							<groupId>org.asciidoctor</groupId>
							<artifactId>asciidoctorj-pdf</artifactId>
							<version>1.5.0-alpha.10.1</version>
						</dependency>
						<dependency>
							<groupId>org.jruby</groupId>
							<artifactId>jruby-complete</artifactId>
							<version>1.7.21</version>
						</dependency>
					</dependencies>
					<configuration>
						<sourceDirectory>./docs/asciidoc/generated</sourceDirectory>
						<outputDirectory>./docs/asciidoc/html</outputDirectory> 
						<backend>html</backend>
						<!-- <outputDirectory>./docs/asciidoc/pdf</outputDirectory> 
						<backend>pdf</backend> -->
						<headerFooter>true</headerFooter> 
						<doctype>book</doctype> 
						<sourceHighlighter>coderay</sourceHighlighter>
						<attributes>
							<!-- 菜單欄在左邊 -->
							<toc>left</toc>
							<!-- 多標題排列 -->
							<toclevels>3</toclevels>
							<!-- 自動打數字序號 -->
							<sectnums>true</sectnums>
						</attributes>
					</configuration>					
				</plugin>
			</plugins>
		</pluginManagement>

	</build>

可以修改此處 html 和 pdf,通過 mvn asciidoctor:process-asciidoc 可以導出相應格式文件

<outputDirectory>./docs/asciidoc/html</outputDirectory> 
						<backend>html</backend>

執行 mvn asciidoctor:process-asciidoc 後再執行 mvn generate-resources,可在 targt/generated-docs 目錄下生成 xml 格式文件。

完整代碼

github

碼雲

相關文章