26

Spring Boot 2.X(十五):集成 Swagger2 开发 API 文档(在线+离线) 原 荐

 4 years ago
source link: https://my.oschina.net/zwqh123/blog/3126402
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言

相信很多后端开发在项目中都会碰到要写 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

码云


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK