spring boot项目的swagger文档。
依赖从spring boot的基础上增加。参考pom.xml:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- Swagger -->
<!-- 文档可视化--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>org.json</groupId> <artifactId>json</artifactId> </dependency> <dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-staticdocs</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.8</version> </dependency>
maven插件:
<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}/target/asciidoc</sourceDirectory> <sourceDocumentName>paths.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>
Swagger2.java参考代码:
import java.util.ArrayList; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.RequestMethod; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.ResponseMessageBuilder; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.ResponseMessage; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @ComponentScan @EnableSwagger2 public class Swagger2 { @Bean public Docket petApi() { //自定义异常信息 ArrayList<ResponseMessage> responseMessages = new ArrayList<ResponseMessage>() {{ add(new ResponseMessageBuilder().code(200).message("成功").build()); add(new ResponseMessageBuilder().code(400).message("请求参数错误").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(401).message("权限认证失败").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(403).message("请求资源不可用").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(404).message("请求资源不存在").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(409).message("请求资源冲突").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(415).message("请求格式错误").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(423).message("请求资源被锁定").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(500).message("服务器内部错误").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(501).message("请求方法不存在").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(503).message("服务暂时不可用").responseModel(new ModelRef("Error")).build()); add(new ResponseMessageBuilder().code(-1).message("未知异常").responseModel(new ModelRef("Error")).build()); }}; return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("my.product.controller"))//扫描的API包 .paths(PathSelectors.any()) .build() .useDefaultResponseMessages(false) .globalResponseMessage(RequestMethod.GET, responseMessages) .globalResponseMessage(RequestMethod.POST, responseMessages) .globalResponseMessage(RequestMethod.PUT, responseMessages) .globalResponseMessage(RequestMethod.DELETE, responseMessages); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("Spring cloud 中使用Swagger2构建Restful APIs") .description("swagger项目文档测试说明") .version("1.0").build(); } }
TestController.java参考代码
import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; @Api(value = "学生信息查询", description = "学生基本信息操作API", tags = "StudentApi", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @RestController public class Swagger2TestController { @ApiOperation(value = "getStudent", notes = "依据学生姓名查询学生信息") @RequestMapping(value = "student", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public Student getStudent(@RequestParam("name") String name){ System.out.println("name : "+name); Student reponse = new Student(); reponse.setId(1); reponse.setName(name); reponse.setAge(12); reponse.setCls("二年级"); reponse.setAddress("重庆市大竹林"); reponse.setSex("男"); return reponse; } @ApiOperation(value = "addStudent", notes = "添加一个学生", code = 201) @RequestMapping(value = "addStudent", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) public void addStudent(@RequestBody Student student){ System.out.println("addStudent : "+student); return ; } }
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("年龄") private int age; /** * 性别 */ @ApiModelProperty("性别") private String sex; /** * 班级 */ @ApiModelProperty("班级") private String cls; /** * 住址 */ @ApiModelProperty("家庭住址") private String address; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getCls() { return cls; } public void setCls(String cls) { this.cls = cls; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
测试类:
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 com.alibaba.fastjson.JSON; import com.swagger.model.Student; import io.github.robwin.markup.builder.MarkupLanguage; import io.github.robwin.swagger2markup.GroupBy; import io.github.robwin.swagger2markup.Swagger2MarkupConverter; import springfox.documentation.staticdocs.SwaggerResultHandler; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.restdocs.operation.preprocess.Preprocessors.preprocessResponse; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; @AutoConfigureMockMvc @AutoConfigureRestDocs(outputDir = "target/generated-snippets") @RunWith(SpringRunner.class) @SpringBootTest public class SwaggerApplicationTests { private String snippetDir = "target/generated-snippets"; private String outputDir = "target/asciidoc"; @Autowired private MockMvc mockMvc; @After public void Test() throws Exception{ // 得到swagger.json,写入outputDir目录中 mockMvc.perform(get(Swagger2Controller.DEFAULT_URL).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 contextLoads() throws Exception { mockMvc.perform(get("/student").param("name", "xxx") .accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andDo(MockMvcRestDocumentation.document("getStudent", preprocessResponse(prettyPrint()))); Student student = new Student(); student.setName("xxx"); student.setAge(23); student.setAddress("湖北麻城"); student.setCls("二年级"); student.setSex("男"); mockMvc.perform(post("/addStudent").contentType(MediaType.APPLICATION_JSON) .content(JSON.toJSONString(student)) .accept(MediaType.APPLICATION_JSON)) .andExpect(status().is2xxSuccessful()) .andDo(MockMvcRestDocumentation.document("addStudent", preprocessResponse(prettyPrint()))); } }
每个API都需要测试一下才有效。测试完后直接install,这离线文档就会在${product.path}docsasciidochtml下生成。
在线文档启动项目访问http://localhost:8080/swagger-ui.html就行了。springboot启动类加@EnableSwagger2 注解就行