Spring Boot 2.X: integrated Swagger2 development API documentation (Online + offline)

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.

Complete code

github

Code cloud

Keywords: Programming ascii JSON Spring github

Added by hmvrulz on Wed, 06 Nov 2019 04:54:00 +0200