Swagger+Spring mvc Generate Restful Interface Document

Posted by sjaccaud on Sat, 06 Jul 2019 19:03:56 +0200

Swagger Is a canonical 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.The file's methods, parameters, and models are tightly integrated into the server-side code, allowing the API to stay in sync at all times.Swagger makes deployment management and use of powerful APIs easier than ever.
This time, I'll build a project from scratch to demonstrate how to integrate Swagger in Spring mvc to generate a Restful interface document.

 

Add Maven Dependencies

 <properties>
        <spring.version>4.1.7.RELEASE</spring.version>
        <version.jackson>2.4.4</version.jackson>
        <swagger.version>2.2.2</swagger.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>com.mangofactory</groupId>
            <artifactId>swagger-springmvc</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${version.jackson}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${version.jackson}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${version.jackson}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
        </dependency>

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.5.0</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!--petstore Is the official one demo,This dependency was added to refer to the interface description later-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-petstore</artifactId>
            <version>${swagger.version}</version>
        </dependency>

    </dependencies>

Add Configuration

Add an ApplicationInitializer class to configure DispatchServlet startup:

Create a new spring folder under the resources folder in your project and a new spring mvc configuration file for dispatcher-servlet.xml, adding the following:

Add a SwaggerConfig class for instructions on configuring the Swagger interface:

package com.bbd.liangdian.config;

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;

/**
 * Created by Administrator on 2017/3/6.
 */
@EnableSwagger2
@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.bbd.liangdian.apis"))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Measure Point Item API File")
                .version("1.0")
                .description("1:Measuring Point API,Find what you need based on grouping API.<br /> 2:Notice the method definition of the request.")
                .build();
    }
}

Create a new GroupController and write test methods:

    package yay.apidoc.controller;

    import io.swagger.annotations.*;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import yay.apidoc.model.UamGroup;

    import java.util.LinkedList;
    import java.util.List;

    /**
     * Created by yuananyun on 2015/11/23.
     */
    @Controller
    @RequestMapping(value = "/group", produces = {"application/json;charset=UTF-8"})
    @Api(value = "/group", description = "Group related operations")
    public class GroupController {
        @RequestMapping(value = "addGroup", method = RequestMethod.PUT)
        @ApiOperation(notes = "addGroup", httpMethod = "POST", value = "Add a new group")
        @ApiResponses(value = {@ApiResponse(code = 405, message = "invalid input")})
        public UamGroup addGroup(@ApiParam(required = true, value = "group data") @RequestBody UamGroup group) {
            return group;
        }

        @RequestMapping(value = "getAccessibleGroups", method = RequestMethod.GET)
        @ApiOperation(notes = "getAccessibleGroups", httpMethod = "GET", value = "Get a list of groups I can access")
        public List<UamGroup> getAccessibleGroups() {
            UamGroup group1 = new UamGroup();
            group1.setGroupId("1");
            group1.setName("testGroup1");

            UamGroup group2 = new UamGroup();
            group2.setGroupId("2");
            group2.setName("testGroup2");

            List<UamGroup> groupList = new LinkedList<UamGroup>();
            groupList.add(group1);
            groupList.add(group2);

            return groupList;
        }
    }

UamGroup is defined as follows:

    package yay.apidoc.model;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;

    /**
     * group
     */
    @ApiModel
    public class UamGroup {
        /**
         * number
         */
        @ApiModelProperty(value = "Group Id", required = true)
        private String groupId;
        /**
         * Name
         */
        @ApiModelProperty(value = "The name of the group", required = true)
        private String name;
        /**
         * Group Icon
         */
        @ApiModelProperty(value = "Group Avatar", required = false)
        private String icon;

        public String getGroupId() {
            return groupId;
        }

        public void setGroupId(String groupId) {
            this.groupId = groupId;
        }

        public String getName() {
            return name;
        }

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

        public String getIcon() {
            return icon;
        }

        public void setIcon(String icon) {
            this.icon = icon;
        }
    }

Okay, so far our code has been written and the catalog structure for the entire project is as follows:

In order for Swagger to scan the Controller defined in Spring mvc, we need to define the scanning path and associated bean s in the MVC configuration file:

Add Swagger ui

Download on GitHub SwaggerUI Project, copy everything under dist to the local project under apidoc/web, the result directory is as follows:

Open the index.html file in the directory and find the snippet url = " http://petstore.swagger.io/v2/swagger.json "; Modify to"/apidoc/v2/api-docs".
In order for the web page to display Chinese, we can uncomment the following script:

To access the index.html page, we add the following configuration in dispatcher-servlet.xml:

        <!-- Enables swgger ui-->
        <mvc:resources mapping="*.html" location="/"/>
        <mvc:resources mapping="/**" location="/"/>

Okay, now let's start tomcat to see what happens:

Solve Chinese garbles

As you can see, the instructions we have written on the method are actually scrambled. To solve this problem, we have created a new conversion class:

    package yay.apidoc.converter;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.databind.*;
    import org.springframework.http.HttpInputMessage;
    import org.springframework.http.converter.HttpMessageNotReadableException;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

    import java.io.IOException;
    import java.text.SimpleDateFormat;

    /**
     * Created by yuananyun on 2015/11/23.
     */
    public class MappingJacksonHttpMessageConverterEx extends MappingJackson2HttpMessageConverter {
        private ObjectMapper objectMapper = new ObjectMapper();

        public MappingJacksonHttpMessageConverterEx() {
            super();
            DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig()
                    .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            objectMapper.setConfig(deserializationConfig);
            // Configure serialization
            SerializationConfig serializationConfig = objectMapper.getSerializationConfig()
                    .without(SerializationFeature.FAIL_ON_EMPTY_BEANS);
            //serializationConfig.withDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            objectMapper.setConfig(serializationConfig);
            objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

            objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    //        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
            objectMapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS,true);

            setObjectMapper(objectMapper);
        }

        @Override
        protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
                throws IOException, HttpMessageNotReadableException {
            JavaType javaType = getJavaType(null, clazz);
            return this.objectMapper.readValue(inputMessage.getBody(), javaType);
        }
    }

Then modify the mvc:annotation-driven configuration section in dispatcher-servlet.xml:

        <!-- Standard xml based mvc config-->
        <mvc:annotation-driven>
            <mvc:message-converters>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                    <property name="supportedMediaTypes">
                        <list>
                            <value>text/html;charset=UTF-8</value>
                        </list>
                    </property>
                </bean>
                <bean class="yay.apidoc.converter.MappingJacksonHttpMessageConverterEx"/>
                <bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/>
            </mvc:message-converters>
        </mvc:annotation-driven>

Let's see the effect again:

Topics: Spring xml Java JSON