系列目录
编者按
本节转载自:Spring Boot教程第10篇:restdoc - 方志朋的博客 Spring Boot教程第11篇:swagger2 - 方志朋的博客 给Swagger升级了新版本,没想到居然有这么多坑! - Document
一个 API 最好要有面向使用者的文档,因为 API 就是给其他开发者调用的,这是 API 开发和其他应用开发不同的地方。
API 文档生成器的作用就在于,代码和文档是绑定的,更新代码而忘记更新文档的情形会减少很多。
Spring Boot REST API 项目常用的 API 文档有两种:
Spring REST Docs :基于测试的文档生成器。需要编写测试样例,测试运行的同时会生成 adoc
格式的测试输入与输出,然后编写文档模板,文档就可以嵌入测试的输入和输出。
Swagger 2 :在 Controller 中添加说明程序功能的注解,Swagger 就可以自动生成 API 文档页面。
Spring REST Docs
swagger
Spring REST Docs 创建工程 引入依赖,其pom文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <dependencies > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-web</artifactId > </dependency > <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-test</artifactId > <scope > test</scope > </dependency > <dependency > <groupId > org.springframework.restdocs</groupId > <artifactId > spring-restdocs-mockmvc</artifactId > <scope > test</scope > </dependency > </dependencies >
通过@SpringBootApplication
,开启springboot:
1 2 3 4 5 6 7 @SpringBootApplication public class Application { public static void main (String[] args) { SpringApplication.run(Application.class , args ) ; } }
在springboot通常创建一个controller:
1 2 3 4 5 6 7 8 9 @RestController public class HomeController { @GetMapping ("/" ) public Map<String, Object> greeting () { return Collections.singletonMap("message" , "Hello World" ); } }
启动工程,访问localhost:8080
,浏览器显示:
1 {“message”:”Hello World”}
证明接口已经写好了,但是如何通过restdoc生存api文档呢
通过单元测试生成api文档 restdocs是通过单元测试生存snippets文件,然后snippets根据插件生成htm文档的。
建一个单元测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @RunWith (SpringRunner.class ) @WebMvcTest (HomeController .class ) @AutoConfigureRestDocs (outputDir = "target/snippets" )public class WebLayerTest { @Autowired private MockMvc mockMvc; @Test public void shouldReturnDefaultMessage () throws Exception { this .mockMvc.perform(get("/" )).andDo(print()).andExpect(status().isOk()) .andExpect(content().string(containsString("Hello World" ))) .andDo(document("home" )); } }
其中,@AutoConfigureRestDocs
注解开启了生成snippets文件,并指定了存放位置。
启动单元测试,测试通过,你会发现在target
文件下生成了一个snippets
文件夹,其目录结构如下:
1 2 3 4 5 6 7 └── target └── snippets └── home └── httpie-request .adoc └── curl-request .adoc └── http-request .adoc └── http-response .adoc
默认情况下,snippets是Asciidoctor格式的文件,包括request和reponse,另外其他两种httpie和curl两种流行的命令行的http请求模式。
到目前为止,只生成了Snippets文件,需要用Snippets文件生成文档。
怎么用Snippets 创建一个新文件src/main/asciidoc/index.adoc
:
1 2 3 4 5 6 7 8 9 = 用 Spring REST Docs 构建文档 This is an example output for a service running at http://localhost:8080: .request include::{snippets}/home/http-request.adoc[] .response include::{snippets}/home/http-response.adoc[]
这个例子非常简单,通过单元测试和一些简单的配置就能够得到api文档了。
adoc的书写格式,参考:http://docs.spring.io/spring-restdocs/docs/current/reference/html5/,这里不多讲解。
需要使用asciidoctor-maven-plugin插件,在其pom文件加上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <plugin > <groupId > org.asciidoctor</groupId > <artifactId > asciidoctor-maven-plugin</artifactId > <executions > <execution > <id > generate-docs</id > <phase > prepare-package</phase > <goals > <goal > process-asciidoc</goal > </goals > <configuration > <sourceDocumentName > index.adoc</sourceDocumentName > <backend > html</backend > <attributes > <snippets > $ {project.build.directory} /snippets</snippets > </attributes > </configuration > </execution > </executions > </plugin >
这时只需要通过mvnw package
命令就可以生成文档了。 在/target/generated-docs下有个index.html,打开这个html,显示如下,界面还算简洁:
adoc 文档
结语 通过单元测试,生存adoc文件,再用adoc文件生存html,只需要简单的几步就可以生成一个api文档的html文件,这个html文件你可以通网站发布出去。整个过程很简单,对代码无任何影响。
源码下载:https://github.com/forezp/SpringBootLearning
参考资料
Swagger 2 swagger,中文“拽”的意思。它是一个功能强大的api框架,它的集成非常简单,不仅提供了在线文档的查阅,而且还提供了在线文档的测试。另外swagger很容易构建restful风格的api,简单优雅帅气,正如它的名字。
引入依赖 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <properties > <swagger2.version > 2.9.2</swagger2.version > </properties > <dependencies > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger2</artifactId > <version > ${swagger2.version}</version > </dependency > <dependency > <groupId > io.springfox</groupId > <artifactId > springfox-swagger-ui</artifactId > <version > ${swagger2.version}</version > </dependency > </dependencies >
写配置类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Configuration @EnableSwagger 2public class Swagger2 { @Bean public Docket createRestApi () { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.forezp.controller" )) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo () { return new ApiInfoBuilder() .title("springboot利用swagger构建api文档" ) .description("简单优雅的restfun风格,http://blog.csdn.net/forezp" ) .termsOfServiceUrl("http://blog.csdn.net/forezp" ) .version("1.0" ) .build(); } }
通过@Configuration
注解,表明它是一个配置类,@EnableSwagger2
开启swagger2。apiINfo()
配置一些基本的信息。apis()
指定扫描的包会生成文档。
写生产文档的注解 swagger通过注解表明该接口会生成文档,包括接口名、请求方法、参数、返回信息的等等。
@Api
:修饰整个类,描述Controller的作用
@ApiOperation
:描述一个类的一个方法,或者说一个接口
@ApiParam
:单个参数描述
@ApiModel
:用对象来接收参数
@ApiProperty
:用对象接收参数时,描述对象的一个字段
@ApiResponse
:HTTP响应其中1个描述
@ApiResponses
:HTTP响应整体描述
@ApiIgnore
:使用该注解忽略这个API
@ApiError
:发生错误返回的信息
@ApiParamImplicitL
:一个请求参数
@ApiParamsImplicit
多个请求参数
现在通过一个栗子来说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 package com.forezp.controller;import com.forezp.entity.Book;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.*;import springfox.documentation.annotations.ApiIgnore;import java.util.*;@RestController @RequestMapping (value = "/books" )public class BookContrller { Map<Long, Book> books = Collections.synchronizedMap(new HashMap<Long, Book>()); @ApiOperation (value="获取图书列表" , notes="获取图书列表" ) @RequestMapping (value={"" }, method= RequestMethod.GET) public List<Book> getBook () { List<Book> book = new ArrayList<>(books.values()); return book; } @ApiOperation (value="创建图书" , notes="创建图书" ) @ApiImplicitParam (name = "book" , value = "图书详细实体" , required = true , dataType = "Book" ) @RequestMapping (value="" , method=RequestMethod.POST) public String postBook (@RequestBody Book book) { books.put(book.getId(), book); return "success" ; } @ApiOperation (value="获图书细信息" , notes="根据url的id来获取详细信息" ) @ApiImplicitParam (name = "id" , value = "ID" , required = true , dataType = "Long" ,paramType = "path" ) @RequestMapping (value="/{id}" , method=RequestMethod.GET) public Book getBook (@PathVariable Long id) { return books.get(id); } @ApiOperation (value="更新信息" , notes="根据url的id来指定更新图书信息" ) @ApiImplicitParams ({ @ApiImplicitParam (name = "id" , value = "图书ID" , required = true , dataType = "Long" ,paramType = "path" ), @ApiImplicitParam (name = "book" , value = "图书实体book" , required = true , dataType = "Book" ) }) @RequestMapping (value="/{id}" , method= RequestMethod.PUT) public String putUser (@PathVariable Long id, @RequestBody Book book) { Book book1 = books.get(id); book1.setName(book.getName()); book1.setPrice(book.getPrice()); books.put(id, book1); return "success" ; } @ApiOperation (value="删除图书" , notes="根据url的id来指定删除图书" ) @ApiImplicitParam (name = "id" , value = "图书ID" , required = true , dataType = "Long" ,paramType = "path" ) @RequestMapping (value="/{id}" , method=RequestMethod.DELETE) public String deleteUser (@PathVariable Long id) { books.remove(id); return "success" ; } @ApiIgnore @RequestMapping (value = "/hi" , method = RequestMethod.GET) public String jsonTest () { return " hi you!" ; } }
通过相关注解,就可以让swagger2生成相应的文档。如果你不需要某接口生成文档,只需要在加@ApiIgnore
注解即可。需要说明的是,如果请求参数在url上,@ApiImplicitParam
上加paramType = “path”
。
启动工程,访问:http://localhost:8080/swagger-ui.html
,就看到swagger-ui:
swagger-ui
整个集成过程非常简单,但是我看了相关的资料,swagger 没有做安全方面的防护,可能需要我们自己做相关的工作。
参考资料
最后更新时间:2021-08-30 16:46:32