Swagger

Swagger is a powerful open source framework backed by a large ecosystem of tools that helps you design, build, document, and consume your RESTful APIs.

With SpringBoot

You can get the full project demo from swagger-springboot.

springboot-blog zh_CN

File Struct may like this:

.
|____main
| |____java
| | |____com
| | | |____ryo
| | | | |____Application.java
| | | | |____controller
| | | | | |____HelloWorld.java
| | | | |____Swagger2.java
| |____resources
| | |____application.properties
| | |____log4j2.xml
| | |____README.md

Create SpringBoot Project->Import Swagger: Import Swagger->Config Swagger:

maven 配置

1、 Create SpringBoot Project

  • Import springboot jars in pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ryo</groupId>
    <artifactId>springboot</artifactId>
    <version>1.0.0</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <plugin.tomcat.version>2.2</plugin.tomcat.version>
        <maven-surefire-plugin.version>2.18.1</maven-surefire-plugin.version>
        <maven-compiler-plugin.version>3.3</maven-compiler-plugin.version>

        <!--spring-boot-->
        <spring-boot.version>1.3.5.RELEASE</spring-boot.version>

        <log4j.version>2.6</log4j.version>
    </properties>

    <dependencies>
        <!--spring-boot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>

        <!--log4j-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j.version}</version>
        </dependency>

    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surefire-plugin.version}</version>
                <configuration>
                    <skipTests>true</skipTests>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.version}</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2、Import swagger jars

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

配置信息

我们可以定义一个 swagger 的全局配置。

package com.github.houbb.register.http.admin.config;

import org.springframework.context.annotation.Bean;
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.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * swagger 配置
 *
 * @author binbin.hou
 * @since 1.0.0
 */
@EnableSwagger2
@Configuration
public class SwaggerConfig {

    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .pathMapping("/")
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.github.houbb.register.http.admin.controller"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(new ApiInfoBuilder()
                        .title("SpringBoot整合Swagger测试")
                        .description("SpringBoot整合Swagger,详细信息......")
                        .version("9.0")
                        .contact(new Contact("老马", "blog.csdn.net", "aaa@gmail.com"))
                        .license("The Apache License")
                        .licenseUrl("http://www.baidu.com")
                        .build());
    }

}

最核心的主要是 RequestHandlerSelectors.basePackage("com.github.houbb.register.http.admin.controller")

我们指定了需要扫描的包路径。

文档定义

3、Config and use

  • Application.java
package com.ryo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * Created by houbinbin on 16/6/5.
 */
@SpringBootApplication
public class Application {
    public static void main(String args[]) {
        SpringApplication.run(Application.class, args);
    }
}
  • HelloWorld.java
package com.ryo.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by houbinbin on 16/6/19.
 */
@RestController
@RequestMapping("hello")
@Api(value = "hello", description = "spring boot 初步测试")
public class HelloWorld {

    @ApiOperation(value="hello", notes="初步使用啦啦啦")
    @RequestMapping(method = RequestMethod.GET)
    public String hello() {
        return "SUCCESS";
    }
}
  • application.properties
server.port=180080

应用启动 & 访问

4、 Start the application

Maven Projects->${project}->Plugins->spring-boot->spring-boot:run

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.3.5.RELEASE)

2016-12-25 15:29:50.066  INFO 4095 --- [           main] com.ryo.Application                      : Starting Application on houbinbindeMacBook-Pro.local with PID 4095 (/Users/houbinbin/IT/code/springboot/target/classes started by houbinbin in /Users/houbinbin/IT/code/springboot)
2016-12-25 15:29:50.069  INFO 4095 --- [           main] com.ryo.Application                      : No active profile set, falling back to default profiles: default
...
2016-12-25 15:29:52.688  INFO 4095 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 18080 (http)
2016-12-25 15:29:52.692  INFO 4095 --- [           main] com.ryo.Application                      : Started Application in 3.094 seconds (JVM running for 5.262)
  • Visit in the browser

浏览器访问:http://localhost:8080/swagger-ui.html

swagger2 index

基本配置例子

Controller 控制器

package com.github.houbb.register.http.admin.controller;


import com.github.houbb.register.http.admin.model.ClientLogDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * <p>
 * 客户端数据日志 前端控制器
 * </p>
 *
 * @author binbin.hou
 * @since 2021-03-08
 */
@Controller
@RequestMapping("/clientLog")
@Api(tags = "客户端日志 CRUD")
public class ClientLogController {

    @PostMapping("/add")
    @ApiOperation("添加日志")
    @ResponseBody
    public String add(ClientLogDto clientLogDto) {
        System.out.println(clientLogDto);
        return "ok";
    }

}

实体属性

针对入参 ClientLogDto,我们可以添加对应的属性描述如下:

public class ClientLogDto implements Serializable {

    @ApiModelProperty(value = "类型")
    private String type;

    @ApiModelProperty(value = "地址")
    private String ip;

    @ApiModelProperty(value = "名称")
    private String name;

    //getter & setter & toString()
}

效果

重新启动应用,效果如下:

输入图片说明

测试

我们可以使用 【Try it out】,可以进行相关的测试。

输入图片说明

点击 execute 按钮,可以获取非常详细的文档返回。

常用注解说明

  1. @Api注解可以用来标记当前Controller的功能。

  2. @ApiOperation注解用来标记一个方法的作用。

  3. @ApiImplicitParam注解用来描述一个参数,可以配置参数的中文含义,也可以给参数设置默认值,这样在接口测试的时候可以避免手动输入。

  4. 如果有多个参数,则需要使用多个@ApiImplicitParam注解来描述,多个@ApiImplicitParam注解需要放在一个@ApiImplicitParams注解中。

  5. 需要注意的是,@ApiImplicitParam注解中虽然可以指定参数是必填的,但是却不能代替@RequestParam(required = true),前者的必填只是在Swagger2框架内必填,抛弃了Swagger2,这个限制就没用了,所以假如开发者需要指定一个参数必填,@RequestParam(required = true)注解还是不能省略。

  6. 如果参数是一个对象(例如上文的更新接口),对于参数的描述也可以放在实体类中。

With SpringMvc

You can get the full project demo from swagger-springmvc.

blog zh_CN

blog zh_CN

The file struct may like this:

.
|____main
| |____java
| | |____com
| | | |____ryo
| | | | |____swagger
| | | | | |____demo
| | | | | | |____controller
| | | | | | | |____UserController.java
| | | | | | |____model
| | | | | | | |____User.java
| | | | | | |____MySwaggerConfig.java
| | | | | | |____vo
| | | | | | | |____Result.java
| |____resources
| | |____app-beans.xml
| | |____app-mvc.xml
| | |____app.xml
| | |____log4j2.xml
| |____webapp
| | |____WEB-INF
| | | |____web.xml
|____test
| |____java

1、 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.ryo</groupId>
    <artifactId>swagger-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk.version>1.8</jdk.version>

        <plugin.tomcat.version>2.2</plugin.tomcat.version>
        <plugin-maven-surefire.version>2.18.1</plugin-maven-surefire.version>
        <plugin-maven-compiler.version>3.3</plugin-maven-compiler.version>

        <spring.version>4.2.6.RELEASE</spring.version>
        <servlet.version>3.1.0</servlet.version>
        <jackson.version>2.4.4</jackson.version>
        <swagger2.version>2.5.0</swagger2.version>

        <log4j2.version>2.6</log4j2.version>
    </properties>

    <dependencies>
        <!--spring-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!--web-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet.version}</version>
            <scope>provided</scope>
        </dependency>

        <!--============= springfox-swagger smallest dependency start ==========-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger2.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <!--============= springfox-swagger smallest dependency end ==========-->

        <!--log4j2-->
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>${log4j2.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j2.version}</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>${project.name}</finalName>

        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>${plugin.tomcat.version}</version>
                <configuration>
                    <port>18080</port>
                    <path>/</path>
                    <uriEncoding>${project.build.sourceEncoding}</uriEncoding>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${plugin-maven-surefire.version}</version>
                <configuration>
                    <skipTests>true</skipTests>
                    <testFailureIgnore>true</testFailureIgnore>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${plugin-maven-compiler.version}</version>
                <configuration>
                    <source>${jdk.version}</source>
                    <target>${jdk.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

2、Java files

  • Result.java
public class Result implements Serializable {
    // 0成功
    private int code;
    // 返回消息,成功为“success”,失败为具体失败信息
    private String message;
    // 返回数据
    private Object data;

    //...
}
  • User.java
public class User {
    private int userId;
    private String name;
    private int age;
    //...
}
  • UserController.java
@Api(value = "User控制器")
@Controller
@RequestMapping("/user")
public class UserController {

    @ApiOperation(value = "根据用户id查询用户信息", httpMethod = "GET", produces = "application/json")
    @ApiResponse(code = 200, message = "success", response = Result.class)
    @ResponseBody
    @RequestMapping(value = "queryUserById", method = RequestMethod.GET, produces = "application/json")
    public Result queryUserById(@ApiParam(name = "userId", required = true, value = "用户Id") @RequestParam("userId") int userId, HttpServletRequest request) {
        User user = new User(userId, "haoyifen", 24);
        Result result = new Result();
        result.setCode(0);
        result.setData(user);
        result.setMessage("success");
        return result;
    }
}
  • MySwaggerConfig.java

Simplest:

@Configuration
@EnableSwagger2
public class MySwaggerConfig {
}

3、Resources

  • app-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
       default-lazy-init="false">

    <bean class="com.ryo.swagger.demo.MySwaggerConfig"/>

</beans>
  • app-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	         http://www.springframework.org/schema/beans/spring-beans.xsd
	         http://www.springframework.org/schema/mvc
	         http://www.springframework.org/schema/mvc/spring-mvc.xsd
	         http://www.springframework.org/schema/context
	         http://www.springframework.org/schema/context/spring-context.xsd">


    <mvc:annotation-driven/>
    <context:component-scan base-package="com.ryo.swagger.demo"/>
    <mvc:default-servlet-handler/>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"/>
        <property name="suffix" value=".ftl"/>
    </bean>

</beans>
  • app.xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="app-beans.xml"/>
    <import resource="app-mvc.xml"/>

</beans>
  • log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="off" monitorInterval="1800">
    <Appenders>
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS}  %-5level [%t] %logger{36}:%L - %msg%n"/>
        </Console>
    </Appenders>

    <Loggers>
        <Root level="INFO">
            <AppenderRef ref="Console"/>
        </Root>
    </Loggers>
</Configuration>
  • ```web.xml``
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <!--装入spring配置文件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:app.xml</param-value>
    </context-param>

    <!-- 防止发生java.beans.Introspector内存泄露,应将它配置在ContextLoaderListener的前面 -->
    <listener>
        <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>

    <!-- 以Listener方式启动spring -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!--编码过滤器-->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 前端控制器的配置 -->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

4、Start and visit

swagger2-springmvc

一点思考

swagger2 的 ui 还是非常舒服的,功能也比较强大,不过有一点比较可惜,那就是注解显得有一点点冗余。

可以考虑配合 yAPI 使用。

参考资料

SpringBoot的整合(四、整合Swagger2)

SpringBoot swagger 配置账号密码