SpringBoot integrates Swagger2 to generate API interface documentation

Keywords: SpringBoot Spring Java

SpringBoot 2.3.0 Integrated Swagger2

Background: Recent work has found that interface protocols and actual business code provided by back-end developers are inconsistent on many occasions.These phenomena are often caused by developers not updating the protocol documents in time after adjusting the interface protocol.

Introduce Swagger2's corresponding dependencies

Importing Swagger2 dependency packages in SpringBoot is simple, as is the case inPom.xmlYou can simply include the appropriate dependencies in the file.

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<version>2.8.0</version>
</dependency>
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>2.8.0</version>
</dependency>

Example of getting started

Let's create a starter Springboot project.The overall catalog structure of the project is as follows:

Then write a DemoController class and add several methods to it, as follows:

package com.majing.learning.springboot.swagger2.controller;

import com.majing.learning.springboot.swagger2.entity.User;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@RestController
@Api(tags = "User management related interfaces")
@RequestMapping(value="/users")
public class DemoController {

    static Map<Long, User> users = Collections.synchronizedMap(new HashMap<>());

    static{
        users.put(1L, new User(1L,"majing1", "31"));
        users.put(2L, new User(2L,"majing2", "32"));
        users.put(3L, new User(3L,"majing3", "33"));
        users.put(4L, new User(4L,"majing4", "34"));
    }

    @ApiOperation(value="Get User List", notes="")
    @RequestMapping(value={""}, method= RequestMethod.GET)
    @ApiResponses(value={@ApiResponse(code=9001, message="OK"),@ApiResponse(code=9002, message="ERROR")})
    public List<User> getUserList() {
        List<User> r = new ArrayList<User>(users.values());
        return r;
    }

    @ApiOperation(value="Create User", notes="according to User Object Creation User")
    @ApiImplicitParam(name = "user", value = "User Detailed Entities user", required = true, dataType = "User")
    @RequestMapping(value="/", method=RequestMethod.POST)
    public String postUser(@RequestBody User user) {
        users.put(user.getId(), user);
        return "success";
    }

    @ApiOperation(value="Get user details", notes="according to url Of id To get user details")
    @ApiImplicitParam(name = "id", value = "user ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.GET)
    public User getUser(@PathVariable Long id) {
        return users.get(id);
    }

    @ApiOperation(value="Update user details", notes="according to url Of id To specify the update object and user Information to update user details")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "user ID", required = true, dataType = "Long"),
            @ApiImplicitParam(name = "user", value = "User Detailed Entities user", required = true, dataType = "User")
    })
    @RequestMapping(value="/{id}", method=RequestMethod.PUT)
    public String putUser(@PathVariable Long id, @RequestBody User user) {
        User u = users.get(id);
        u.setName(user.getName());
        u.setAge(user.getAge());
        users.put(id, u);
        return "success";
    }

    @ApiOperation(value="delete user", notes="according to url Of id To specify the deletion object")
    @ApiImplicitParam(name = "id", value = "user ID", required = true, dataType = "Long")
    @RequestMapping(value="/{id}", method=RequestMethod.DELETE)
    public String deleteUser(@PathVariable Long id) {
        users.remove(id);
        return "success";
    }

}

For the above entity class User is defined as follows:

package com.majing.learning.springboot.swagger2.entity;

import io.swagger.annotations.ApiModel;

@ApiModel
public class User {

    private Long id;
    private String name;
    private String age;

    public User(long id, String name, String age){
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

To use Swagger2, you need to add Swagger2 configuration and annotations to your application startup class sibling directory as follows:

package com.majing.learning.springboot.swagger2;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class Swagger2Config {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.majing.learning.springboot.swagger2.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Spring Boot Use Swagger2 structure RESTful APIs")
                .description("Test Use Swagger2 generate API File")
                .termsOfServiceUrl("https://***.com/")
                .contact("Ma Jing")
                .version("1.0")
                .build();
    }
}

Next let's start the app and access itHttp://localhost: 5002/swagger-Ui.htmlYou will see the automatically generated API document.The ports here are as neededApplication.propertiesThe file adjusts itself.

So far, the integration of Swagger2 in SpringBoot2 has been completed, and looking at the generated API documentation, it feels good.

Startup error after SpringBoot2 integration with Swagger2

The above example is okay, but when you first tried to integrate Swagger2, you encountered a startup error with one of the following error messages:

AnnotationConfigServletWebServerApplicationContext: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'linkDiscoverers' defined in class path resource [org/springframework/hateoas/config/HateoasConfiguration.class]: Unsatisfied dependency expressed through method 'linkDiscoverers' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.plugin.core.PluginRegistry<org.springframework.hateoas.client.LinkDiscoverer, org.springframework.http.MediaType>' available: expected single matching bean but found 15: modelBuilderPluginRegistry,modelPropertyBuilderPluginRegistry,typeNameProviderPluginRegistry,documentationPluginRegistry,apiListingBuilderPluginRegistry,operationBuilderPluginRegistry,parameterBuilderPluginRegistry,expandedParameterBuilderPluginRegistry,resourceGroupingStrategyRegistry,operationModelsProviderPluginRegistry,defaultsProviderPluginRegistry,pathDecoratorRegistry,relProviderPluginRegistry,linkDiscovererRegistry,entityLinksPluginRegistry

At first, I was a little confused when I saw this error. Then Baidu said it was caused by incompatibility between Swagger2 and Springboot, so I modified the version of Swagger2, using 2.8.0, and my own version of SpringBoot is 2.3.0. After restarting, I found that the problem was really gone.Make a note here.

epilogue

Above we have implemented the background code generation and update API documents dynamically through Swagger2, which is very convenient.But one drawback is lack of access control, data Mock, and so on.There is also some code intrusion.Later, for domestic and foreign API interface management platforms to investigate, mainly look at ShowDoc, AliYun's RAP and CRAP-API, feel that they are still very useful, you can research on their own if you need, these three can support private deployment.

Posted by Bad HAL 9000 on Fri, 12 Jun 2020 18:54:35 -0700