参考:https://www.jianshu.com/p/af7a6f29bf4f
(0)pom.xml 引入依赖:
<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>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<version>1.1.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-staticdocs</artifactId>
<version>2.6.1</version>
</dependency>
pom.xml 引入插件:asciidoctor-maven-plugin插件是用来把Asciidoc格式转成HTML5格式。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Documentation.java</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.3</version>
<!-- Configure generic document generation settings -->
<configuration>
<sourceDirectory>${project.basedir}/docs/asciidoc</sourceDirectory>
<sourceDocumentName>index.adoc</sourceDocumentName>
<attributes>
<doctype>book</doctype>
<toc>left</toc>
<toclevels>3</toclevels>
<numbered></numbered>
<hardbreaks></hardbreaks>
<sectlinks></sectlinks>
<sectanchors></sectanchors>
<generated>${project.build.directory}/asciidoc</generated>
</attributes>
</configuration>
<!-- Since each execution can only handle one backend, run
separate executions for each desired output type -->
<executions>
<execution>
<id>output-html</id>
<phase>test</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html5</backend>
<!--<outputDirectory>${project.basedir}/docs/asciidoc/html</outputDirectory>-->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
(1)StudentController.java
@Api(value = "学生信息查询", description = "学生基本信息操作API", tags = "StudentApi", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@RestController
@RequestMapping("/student")
public class StudentController {
//@ApiOperation(value = "查询学生信息", notes = "依据学生姓名查询学生信息", code = 200, response = Student.class, consumes = MediaType.APPLICATION_JSON_VALUE)
//@ApiResponse()
@ApiOperation(value = "getStudent", notes = "依据学生姓名查询学生信息")
@RequestMapping(value = "/get", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public Student getStudent(@RequestParam("name") String name){
Student reponse = new Student();
reponse.setId(1);
reponse.setName("zhangsan");
reponse.setAge(12);
reponse.setCls("二年级");
reponse.setAddress("重庆市大竹林");
reponse.setSex("男");
return reponse;
}
@ApiOperation(value = "addStudent", notes = "添加一个学生", code = 201)
@RequestMapping(value = "/add", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public void addStudent(@RequestBody Student student){
return ;
}
}
(2)Student.java
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "Student", description = "学生信息描述")
public class Student {
@ApiModelProperty("学号")
private int id;
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty(value="年龄", required = true)
private int age;
@ApiModelProperty(value="性别")
private String sex;
@ApiModelProperty("班级")
private String cls;
@ApiModelProperty("家庭住址")
private String address;
//省略get/set方法
}
(3)测试类
import com.alibaba.fastjson.JSON;
import com.chinamobile.iot.model.Student;
import io.github.robwin.markup.builder.MarkupLanguage;
import io.github.robwin.swagger2markup.GroupBy;
import io.github.robwin.swagger2markup.Swagger2MarkupConverter;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import springfox.documentation.staticdocs.SwaggerResultHandler;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse;
import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@AutoConfigureMockMvc
@AutoConfigureRestDocs(outputDir = "target/generated-snippets")
@RunWith(SpringRunner.class)
@SpringBootTest
public class Documentation {
private String snippetDir = "target/generated-snippets";
private String outputDir = "target/asciidoc";
@Autowired
private MockMvc mockMvc;
@After
public void Test() throws Exception{
// 得到swagger.json,写入outputDir目录中
// v2/api-docs 接口是 swagger 自带的
mockMvc.perform(get("/v2/api-docs").accept(MediaType.APPLICATION_JSON))
.andDo(SwaggerResultHandler.outputDirectory(outputDir).build())
.andExpect(status().isOk())
.andReturn();
// 读取上一步生成的swagger.json转成asciiDoc,写入到outputDir
// 这个outputDir必须和插件里面<generated></generated>标签配置一致
Swagger2MarkupConverter.from(outputDir + "/swagger.json")
.withPathsGroupedBy(GroupBy.TAGS)// 按tag排序
.withMarkupLanguage(MarkupLanguage.ASCIIDOC)// 格式
.withExamples(snippetDir)
.build()
.intoFolder(outputDir);// 输出
}
@Test
public void TestApi() throws Exception{
mockMvc.perform(get("/student/get").param("name", "szl")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(MockMvcRestDocumentation.document("getStudent", preprocessResponse(prettyPrint())));
Student student = new Student();
student.setName("szl");
student.setAge(23);
student.setAddress("湖北麻城");
student.setCls("二年级");
student.setSex("男");
mockMvc.perform(post("/student/add").contentType(MediaType.APPLICATION_JSON)
.content(JSON.toJSONString(student))
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().is2xxSuccessful())
.andDo(MockMvcRestDocumentation.document("addStudent", preprocessResponse(prettyPrint())));
}
}
(4)index.adoc
include::{generated}/overview.adoc[]
include::{generated}/definitions.adoc[]
include::{generated}/paths.adoc[]
(5)另附 @ApiModelProperty的用法:
属性 | 解释 |
---|---|
value | 属性的简要描述 |
name | 重写属性名字 |
dataType | 重写属性类型 |
required | 是否必填 |
example | 举例说明 |
hidden | 隐藏 |
ApiModelProperty 源码如下:
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiModelProperty {
/**
* A brief description of this property.
*/
String value() default "";
/**
* Allows overriding the name of the property.
*
* @return the overridden property name
*/
String name() default "";
/**
* Limits the acceptable values for this parameter.
* <p>
* There are three ways to describe the allowable values:
* <ol>
* <li>To set a list of values, provide a comma-separated list.
* For example: {@code first, second, third}.</li>
* <li>To set a range of values, start the value with "range", and surrounding by square
* brackets include the minimum and maximum values, or round brackets for exclusive minimum and maximum values.
* For example: {@code range[1, 5]}, {@code range(1, 5)}, {@code range[1, 5)}.</li>
* <li>To set a minimum/maximum value, use the same format for range but use "infinity"
* or "-infinity" as the second value. For example, {@code range[1, infinity]} means the
* minimum allowable value of this parameter is 1.</li>
* </ol>
*/
String allowableValues() default "";
/**
* Allows for filtering a property from the API documentation. See io.swagger.core.filter.SwaggerSpecFilter.
*/
String access() default "";
/**
* Currently not in use.
*/
String notes() default "";
/**
* The data type of the parameter.
* <p>
* This can be the class name or a primitive. The value will override the data type as read from the class
* property.
*/
String dataType() default "";
/**
* Specifies if the parameter is required or not.
*/
boolean required() default false;
/**
* Allows explicitly ordering the property in the model.
*/
int position() default 0;
/**
* Allows a model property to be hidden in the Swagger model definition.
*/
boolean hidden() default false;
/**
* A sample value for the property.
*/
String example() default "";
/**
* Allows a model property to be designated as read only.
*/
boolean readOnly() default false;
/**
* Specifies a reference to the corresponding type definition, overrides any other metadata specified
*/
String reference() default "";
}