Preface
I believe that many back-end development projects will encounter the need to write api documents, whether it is to provide better docking for the front-end, mobile end, etc., or in the future for the convenience of handover, it will be required to write api documents.
There are many pain points in handwritten api documents:
- When the document is updated, it needs to be sent to the counterpart again
- Interface is too right, handwritten documents are difficult to manage
- Ambiguous result returned by interface
- It is not allowed to test the interface directly online, and tools such as postman are usually needed
Swagger solves this problem very well.
About Swagger
Swagger is a standardized and complete framework for generating, describing, invoking, and visualizing RESTful style Web services. The overall goal is to have the client and file system update at the same speed as the server. File methods, parameters, and models are tightly integrated into the server-side code, allowing the API to always keep in sync.
Official website: https://swagger.io
Swagger uses
1. Relevant dependence
<!--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 class
@Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket buildDocket() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(buildApiInf()) //Set the meta information of the api to be included in the json resourcelisting response //. host("127.0.0.1:8080") / / set ip and port, or domain name .select() //Launch generator for api selection //.apis(RequestHandlerSelectors.any()) .apis(RequestHandlerSelectors.basePackage("cn.zwqh.springboot.controller"))//Specify controller path .paths(PathSelectors.any()).build(); } private ApiInfo buildApiInf() { Contact contact=new Contact("Foggy and cold","https://www.zwqh.top/","zwqh@clover1314.com"); return new ApiInfoBuilder() .title("Swagger Demo Restful API Docs")//document title .description("Swagger Example Restful Api File")//Document description .contact(contact)//Contacts .version("1.0")//Version number //. license("") / / update license information for this API //. licenseUrl("") / / update the license Url for this API //. termsOfServiceUrl("") / / update service terms URL .build(); } }
3.Spring MVC related configuration
@Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { /** * Static resource configuration (default) */ @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");// Static resource path registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); super.addResourceHandlers(registry); } }
If you do not add this static resource configuration, an error will be reported and the relevant path cannot be found
4. Using Swagger annotation in model
@ApiModel(value = "UserEntity", description = "User object") public class UserEntity implements Serializable{ /** * */ private static final long serialVersionUID = 5237730257103305078L; @ApiModelProperty(value ="user id",name="id",dataType="Long",required = false,example = "1",hidden = false ) private Long id; @ApiModelProperty(value ="User name",name="userName",dataType="String",required = false,example = "Guan Yu" ) private String userName; @ApiModelProperty(value ="User gender",name="userSex",dataType="String",required = false,example = "male" ) 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. Use Swagger annotation in controller
@RestController @RequestMapping("/api") @Api(tags = { "Interface group 1", "Interface group 2" }) public class ApiController { @Autowired private UserDao userDao; @GetMapping("/getAllUser") @ApiOperation(value = "Get all users", notes = "", httpMethod = "GET", tags = "Interface group 3") public List<UserEntity> getAll() { return userDao.getAll(); } @GetMapping("/getUserById") @ApiOperation(value = "according to id Get users", notes = "id Biography", httpMethod = "GET") @ApiImplicitParam(name = "id", value = "user id",example = "1", required = true, dataType = "long", paramType = "query") public UserEntity getOne(Long id) { return userDao.getOne(id); } @PostMapping("/getUserByNameAndSex") @ApiOperation(value = "according to name and sex Get users", notes = "", httpMethod = "POST") @ApiImplicitParams({ @ApiImplicitParam(name = "userName", value = "User name", example = "Guan Yu", required = true, dataType = "string", paramType = "query"), @ApiImplicitParam(name = "userSex", value = "User gender", example = "male", required = true, dataType = "string", paramType = "query") }) public UserEntity getUserByNameAndSex(String userName, String userSex) { return userDao.getUserByNameAndSex(userName, userSex); } @PostMapping("/insertUser") @ApiOperation(value = "New users", notes = "pass json,Data release body", httpMethod = "POST") @ApiImplicitParams({ @ApiImplicitParam(name = "body", value = "User object json", example = "{userName:'Foggy and cold',userSex:'male'}", 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 = "Modify user", notes = "pass json,Data release body", httpMethod = "POST") @ApiImplicitParams({ @ApiImplicitParam(name = "body", value = "User object json", example = "{id:23,userName:'Foggy and cold',userSex:'female'}", 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 = "delete user", notes = "id Biography", httpMethod = "POST") public String deleteUser(@ApiParam(name = "id", value = "user id", required = true) Long id) { userDao.deleteUser(id); return "{code:0,msg:'success'}"; } }
5. test
Visit http://127.0.0.1:8080/swagger-ui.html Conduct interface online test
Swagger common notes
1.@Api
Used for a class to indicate that the class is a swagger resource. The properties are as follows:
- Tags means description. If there are multiple values for tags, multiple lists will be generated
- value indicates the description, which can be replaced by tags
2.@ApiOperation
Method that represents the operation of an http request. The properties are as follows:
- value for method description
- notes for prompt content
- Tags is a list of tags used for API document control, which can be grouped independently depending on the situation
3.@ApiParam
Used for method, parameter and field description; indicates the metadata added to the parameter.
- Name parameter name
- value parameter description
- required or not
4.@ApiModel
Used for class, indicating the description of class, and used for parameter acceptance with entity class.
- value object name
- description Description
5.@ApiModelProperty
Used for methods and fields to indicate the description of model properties or data operation changes.
- value field description
- Name override property name
- dataType override property dataType
- required or not
- example
- hidden
6.@ApiIgnore
Used for class, method and method parameter, indicating that the method or class is ignored and not displayed on swagger-ui.html.
7.@ApiImplicitParam
Used for methods to represent individual request parameters.
- Name parameter name
- value parameter description
- dataType data type
- paramType parameter type
- example
8.@ApiImplicitParams
For method, contains multiple @ ApiImplicitParam.
9.@ApiResponses @ApiResponse
Used for a class or method to describe the possible response of an operation.
- HTTP status code of the code response
- Message response with a readable message
10.@ResponseHeader
For method, response header settings.
- Name response header name
- Description header description
- Response default response class void
- responseContainer refer to the configuration in ApiOperation
Swagger exporting offline api documents
1. Export documents in ASCII docs, Markdown and Confluence formats
Add dependency
<!-- swagger2markup Dependent dependence --> <dependency> <groupId>io.github.swagger2markup</groupId> <artifactId>swagger2markup</artifactId> <version>1.3.3</version> </dependency>
Conversion tool class
public class SwaggerUtils { private static final String url = "http://127.0.0.1:8080/v2/api-docs"; /** * Generate documents in ASCII docs format * @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")); } /** * Generate documents in ASCII docs format and summarize them into a file * @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")); } /** * Generate Markdown format document * @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")); } /** * Generate Markdown format documents and summarize them into a file * @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")); } /** * Generate Confluence format document * @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")); } /** * Generate the Confluence format document and summarize it into a file * @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")); } }
Using the test 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. Export html, pdf, xml format
Add dependency
<!--Offline document --> <dependency> <groupId>org.springframework.restdocs</groupId> <artifactId>spring-restdocs-mockmvc</artifactId> <scope>test</scope> </dependency> <!--springfox-staticdocs Generate static documents --> <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> <!-- The menu bar is on the left --> <toc>left</toc> <!-- Multi Title Arrangement --> <toclevels>3</toclevels> <!-- Automatic number printing --> <sectnums>true</sectnums> </attributes> </configuration> </plugin> </plugins> </pluginManagement> </build>
You can modify the html and pdf here, and export the corresponding format file through MVN ASCII processor: process ASCII
<outputDirectory>./docs/asciidoc/html</outputDirectory> <backend>html</backend>
Execute MVN ASCII doc: process ASCII doc and then MVN generate resources. You can generate xml format files in targt / generated docs directory.