首页> 博客> SpringBoot 中如何使用SwaggerAPI接口文档?
17 05 2019
一、背景介绍

随着互联网技术的不断发展,网站项目架构基本都是前后端分离了,原来需要后端渲染数据展示,现在只需要提供Restful风格的Api接口给前端或移动端。这样API文档便成为了前后端开发人员联系的纽带。这就引入了一个新的问题:如何提供一个灵活高质量的API文档给多个开发人员或者团队?

  • 对于一个项目,接口众多,并且细节复杂(接口参数的说明、要求等),如果要想高质量的创建API文档,想想就是一件很不容易的事情。对于很多开发人员来说,撰写文档是一件很痛苦的事情,至少对于我来说是这样的^^

  • 随着项目的不断迭代更新,接口可能随时变动,每次接口的变动也避免不了API文档的同步更新,若更新不及时,可能会给不同的开发团队带来困扰,灵活性不够!

为了解决这些问题,本文将给您介绍Restful API的伙伴Swagger2,一款可以让你更好的书写API文档框架。并且它可以轻轻松松的整合到SpringBoot 中去!

二、初识 Swagger
2.1、认识 Swagger

官方网站 ,打开官网你就大概了解到 Swagger 能做什么?

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标就是让维护API文档和修改代码整合为一体,在修改代码的同时也方便修改API文档说明,这样就可以使API信息始终保持同步!

作用:

  1. 接口文档的在线自动生成。
  2. API接口测试

先看一下使用 Swagger 给我们展现的一个效果:

看着是不是觉得很清晰呀!接下来我就具体介绍一下如何在SpringBoot 中使用Swagger2。

三、SpringBoot中使用Swagger2
3.1、导入依赖

Maven依赖如下,目前使用最新版本(2.9.2版本,该版本有个小坑后面会提到!)

<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>
3.2、创建一个Swagger配置类
package com.xmlvhy.boot.swagger.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @ClassName SwaggerConfig1
 * @Description TODO
 * @Author 小莫
 * @Date 2019/05/17 14:05
 * @Version 1.0
 **/
@Configuration
//开启Swagger2的自动化配置
@EnableSwagger2
public class SwaggerConfig {

    /**
     *功能描述: 配置Docket
     * @Author 小莫
     * @Date 14:07 2019/05/17
     * @Param []
     * @return springfox.documentation.spring.web.plugins.Docket
     */
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2);
    }
}

说明:

1.@EnableSwagger2 是Swagger2的核心注解,即打开Swagger2的自动化配置;
2.@Configuration注解表明该类是一个配置类;
3.Swagger的实例Bean是Docket,所有通过配置Docket实例化来配置Swagger

以上便完成Swagger的一个基本配置,此时我们已经可以使用Swagger了,访问如下链接:

http://localhost:8080/swagger-ui.html

3.3、Swagger API文档详细配置

通过apiInfo()属性配置文档信息,相关内容属性通过配置文件注入方式设置。主要涉及到Swagger中 ApiInfo 以及 Contact 两个实体类,具体配置如下:

swagger:
  title: SpringBoot整合Swagger2学习
  description: Swagger2学习
  version: 1.0
  termsOfServiceUrl:  https://www.xmlvhy.com
  license:  测试许可
  licenseUrl: https://www.xmlvhy.com
  name: 芝君的个人技术博客
  url:  https://www.xmlvhy.com
  email:  1059224309@qq.com

此时,配置类修改如下:

package com.xmlvhy.boot.swagger.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @ClassName SwaggerConfig1
 * @Description TODO
 * @Author 小莫
 * @Date 2019/05/17 14:05
 * @Version 1.0
 **/
@Configuration
@EnableConfigurationProperties(SwaggerConfig1.class)
@ConfigurationProperties(prefix = "swagger")
//开启Swagger2的自动化配置
@EnableSwagger2
//lombok插件注解,自动生成setter and getter
@Data
public class SwaggerConfig1 {

    /*ApiInfo对象的属性*/
    /*文档标题*/
    private String title;
    /*文档描述*/
    private String description;
    /*文档版本信息*/
    private String version;
    /*文档编辑组织团队链接*/
    private String termsOfServiceUrl;
    /*文档许可说明*/
    private String license;
    /*文档许可链接*/
    private String licenseUrl;

    /*Contact 对象属性*/
    //联系人姓名
    private String name;
    //联系人访问链接
    private String url;
    //联系人email
    private String email;

    /**
     *功能描述: 配置Docket
     * @Author 小莫
     * @Date 14:07 2019/05/17
     * @Param []
     * @return springfox.documentation.spring.web.plugins.Docket
     */
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
    }

    /**
     *功能描述: 通过ApiInfo 来配置Api文档信息
     * @Author 小莫
     * @Date 15:12 2019/05/17
     * @Param []
     * @return springfox.documentation.service.ApiInfo
     */
    private ApiInfo apiInfo(){
        Contact contact = new Contact(name, url, email);
        return new ApiInfoBuilder()
                .title(title)
                .description(description)
                .version(version)
                .termsOfServiceUrl(termsOfServiceUrl)
                .license(license)
                .licenseUrl(licenseUrl)
                .contact(contact)
                .build();
    }
}

配置完成后,重启项目并访问,可以看到我们配置的信息:

3.4、配置我们要扫描的包

1.首先我们创建一个 OrderController.java

package com.xmlvhy.boot.swagger.controller;

import io.swagger.annotations.Api;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName OrderController
 * @Description TODO
 * @Author 小莫
 * @Date 2019/05/16 12:54
 * @Version 1.0
 **/
@RequestMapping("/order")
@ResponseBody
@Controller
@Api(tags = "订单模块")
public class OrderController {

    @PutMapping("modify")
    public String modifyOrder(Long orderId,String name){
        StringBuffer sb = new StringBuffer();
        return sb.append(orderId).append(name).toString();
    }

    @DeleteMapping("delete")
    public String removeOrder(Integer id, Long idL, HttpSession session, HttpServletRequest request){
        return "delete";
    }

    @GetMapping
    public String test(){
        return "这是一个测试";
    }

    @GetMapping("/get_map_data")
    public Map getMapData(){
        Map<String,Object> ret = new HashMap<>();
        ret.put("code",200);
        ret.put("token","wqeqwdqwdqwdqwdfefe7656");
        ret.put("msg","ok");
        return ret;
    }
}

@Api(tags = "订单模块") 是Swagger中的注解,该注解作用是:对该类的一个简要说明

2.构建 Docket 时通过其select()方法来设置扫描接口策略,配置文件信息修改如下:

package com.xmlvhy.boot.swagger.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * @ClassName SwaggerConfig1
 * @Description TODO
 * @Author 小莫
 * @Date 2019/05/17 14:05
 * @Version 1.0
 **/
@Configuration
//开启Swagger2的自动化配置
@EnableConfigurationProperties(SwaggerConfig1.class)
@ConfigurationProperties(prefix = "swagger")
@EnableSwagger2
@Data
public class SwaggerConfig1 {

    /*ApiInfo对象的属性*/
    /*文档标题*/
    private String title;
    /*文档描述*/
    private String description;
    /*文档版本信息*/
    private String version;
    /*文档编辑组织团队链接*/
    private String termsOfServiceUrl;
    /*文档许可说明*/
    private String license;
    /*文档许可链接*/
    private String licenseUrl;

    /*Contact 对象属性*/
    //联系人姓名
    private String name;
    //联系人访问链接
    private String url;
    //联系人email
    private String email;

    /**
     *功能描述: 配置Docket
     * @Author 小莫
     * @Date 14:07 2019/05/17
     * @Param []
     * @return springfox.documentation.spring.web.plugins.Docket
     */
    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .build();
    }

    /**
     *功能描述: 通过ApiInfo 来配置Api文档信息
     * @Author 小莫
     * @Date 15:12 2019/05/17
     * @Param []
     * @return springfox.documentation.service.ApiInfo
     */
    private ApiInfo apiInfo(){
        Contact contact = new Contact(name, url, email);
        return new ApiInfoBuilder()
                .title(title)
                .description(description)
                .version(version)
                .termsOfServiceUrl(termsOfServiceUrl)
                .license(license)
                .licenseUrl(licenseUrl)
                .contact(contact)
                .build();
    }
}

配置完成,重启项目并访问:

此时我们指定扫描的包下:OrderController.java 提供的接口全部被加载出来了

当然除了包路径扫描这种策略外,还有其它的方式可以指定扫描的接口,可以自己尝试,详情如下:

1.any()  默认的类型,表示扫描所有接口,所有接口都可以被扫描到
2.通过类上的注解扫描,只扫描 @RestController
	如:.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
3.通过方法上的注解扫描,只扫描get请求
    如:.apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class))
4.basePackage()根据包路径扫描接口
   如:.apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
3.5、配置接口扫描过滤

通过以上的方式可以设置通过具体的类、方法来扫描接口,在这基础上还可以通过配置请求路径来指定扫描的接口。使用.paths(PathSelectors.ant("..."))

    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .select()               .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .paths(PathSelectors.ant("/order/**"))
                .build();
    }

此时就指定了只扫描/order/**下的所有接口;除了ant()外还有如下方式可以配置:

1.any()  表示任何请求都扫描
2.none() 表示任何请求都不扫描
3.regex(final String pathRegex) 表示通过正则表达式控制,返回true扫描,false不扫描
4.ant(final String antPattern) 表示通过ant()表达式控制,返回true扫描,false不扫描
3.5、配置要忽略的请求参数

可以通过.ignoredParameterTypes()来配置要忽略的参数,我们先来看看,在OrderController的delete接口中,有 HttpServletRequestHttpSession 两个参数,API文档中查看接口:

类似这种情况,我们就可以配置要忽略的参数了:

@Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
				//.ignoredParameterTypes要在select()以及paths之前设置
                .ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
                .select()               .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .paths(PathSelectors.ant("/order/**"))
                .build();
    }
3.6、配置API接口分组

此功能是很有必要的,当我们项目中有很多模块接口的时候这时候就需要做个区分,我们在查看api的时候就更方便了。当我们没有配置API分组的时候,默认是default,具体可看之前的截图。可以通过groupName()方法来设置分组,如下:

@Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .groupName("订单")
                //.ignoredParameterTypes要在select()以及paths之前设置
                .ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .paths(PathSelectors.ant("/order/**"))
                .build();
    }

重启项目,查看效果:

当我们需要配置多个分组的时候,只需要配置多个Docket即可,如上我们在配置两个docket,分组分别设置为:会员和地址如下:

@Bean
    public Docket docket1(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("会员");
    }

    @Bean
    public Docket docket2(){
        return new Docket(DocumentationType.SWAGGER_2).groupName("地址");
    }

重启项目,查看效果:

备注:第一次进入Swagger文档页面展示的API信息,是以配置的第一个Docket中设置的规则为准!

3.7、配置是否启动Swagger

为什么需要这个配置呢?实际中,在生产环境,我们如果给外界暴露我们的接口是很不安全的,这就需要我们做一个限制,只允许在开发或者测试环境才可以查看或者其它限制。总之接口不要随便暴露给外界!!!本文我通过enable()方法来配置是否启用Swagger,如果设置false,那么API文档就不能在浏览中访问了:

    @Bean
    public Docket docket(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .groupName("订单")
                .enable(false)
                //.ignoredParameterTypes要在select()以及paths之前设置
                .ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
                .select()
          .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .paths(PathSelectors.ant("/order/**"))
                .build();
    }

项目重启,此时访问:

无法查看API文档信息了。

通过以上的配置,我们可以稍微修改一下,即通过SpringBoot 的多环境配置,当非处于生产环境中的时候,都可以查看API文档,反之不能查看。这样我们就实现了动态启动Swagger

  @Bean
    public Docket docket(Environment environment){
        Profiles profiles = Profiles.of("pro");
        boolean isEnable = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .groupName("订单")
                .enable(!isEnable)
                //.ignoredParameterTypes要在select()以及paths之前设置
                .ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .paths(PathSelectors.ant("/order/**"))
                .build();
    }

重启项目,此时查看效果,开发环境下可以正常访问:

3.8、配置一个全局参数

全局参数,只要扫描出来的接口都要有!应用场景:比如一个全局token参数信息。通过globalOperationParameters()来构造一个全局参数。如下:

@Bean
    public Docket docket2(Environment environment){
        Profiles profiles = Profiles.of("pro");
        boolean isEnable = environment.acceptsProfiles(profiles);

        //构造一个全局参数
        Parameter parameter = new ParameterBuilder()
                //参数名称
                .name("token")
                //参数类型,放在请求头中
                .parameterType("header")
                //参数描述
                .description("用户令牌")
                //是否必须
                .required(true)
                //参数类型
                .modelRef(new ModelRef("String"))
                .build();
        List<Parameter> parameters = new ArrayList<>();
        parameters.add(parameter);

        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .groupName("默认")
                .globalOperationParameters(parameters)
                .enable(!isEnable)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .build();
    }

重启项目查看效果:

3.9、Swagger中实体类和Controller中的配置

创建一个User实体类,如下:

package com.xmlvhy.boot.swagger.entity;

import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @ClassName User
 * @Description TODO
 * @Author 小莫
 * @Date 2019/05/16 12:00
 * @Version 1.0
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
//@ApiModel 为类添加注释
@ApiModel("用户实体")
public class User{
    @ApiModelProperty(value = "用户Id")
    private Integer userId;
    @ApiModelProperty("用户名")
    private String name;
    @ApiModelProperty(value = "用户年龄")
    private Integer age;
    @ApiModelProperty(value = "手机号")
    private String mobile;
    @ApiModelProperty("电子邮箱")
    private String email;
    @ApiModelProperty("性别")
    private String sex;
}

说明:

1.@ApiModel	为类添加注释
2.@ApiModelProperty	为类属性添加注释

创建一个UserController类,如下:

package com.xmlvhy.boot.swagger.controller;

import com.xmlvhy.boot.swagger.entity.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName UserController
 * @Description TODO
 * @Author 小莫
 * @Date 2019/05/16 11:59
 * @Version 1.0
 **/
@Api(tags = "用户模块")
@RestController
@RequestMapping("/user")
public class UserController {

    //模拟数据库
    private static List<User> users = new ArrayList<>();
    static {
        users.add(new User(101,"xiaomo",26,"13641711060","1059224309@qq.com","男"));
        users.add(new User(102,"xiaohong",16,"13641711xxx","105xxx9@qq.com","女"));
        users.add(new User(103,"xiaowang",6,"13641711060","aa@qq.com","男"));
    }

    @ApiOperation(value = "获取用户信息",notes = "获取所有的用户信息列表")
    @GetMapping("getUsers")
    public List<User> getUsers(){
        return users;
    }

    @ApiOperation(value = "保存一个用户信息")
    @ApiImplicitParam(name = "user",value = "用户实体类")
    @PostMapping("save")
    public Object saveUser(@RequestBody User user){
        return users.add(user);
    }

    @ApiOperation(value = "修改用户信息",notes = "根据用户id修改用户名")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "query"),
            @ApiImplicitParam(name = "name",value = "用户姓名",required = true,dataType = "string",paramType = "query")
    })
    @PutMapping("putUser")
    public Object putUser(@RequestParam(value = "id") int id, @RequestParam(value = "name") String name){
        users.get(id).setName(name);
        return "ok";
    }

    @ApiOperation(value = "获取单个用户信息",notes = "根据用户id查询某个用户信息")
    @ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "path")
    @GetMapping("/getOne/{id}")
    public Object getOneUser(@PathVariable(value = "id") int id){
        return users.get(id);
    }

    @ApiOperation(value = "移除某个用户",notes = "根据id删除某个用户信息")
    @ApiImplicitParam(name = "id",value = "用户ID")
    @DeleteMapping("deleteUser")
    public Object deleteUser(@RequestParam(value = "id") int id){
        return users.remove(id);
    }
}

重新修改一下Swagger配置类:

package com.xmlvhy.boot.swagger.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.env.Profiles;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * @ClassName SwaggerConfig1
 * @Description TODO
 * @Author 小莫
 * @Date 2019/05/17 14:05
 * @Version 1.0
 **/
@Configuration
//开启Swagger2的自动化配置
@EnableConfigurationProperties(SwaggerConfig1.class)
@ConfigurationProperties(prefix = "swagger")
@EnableSwagger2
@Data
public class SwaggerConfig1 {

    /*ApiInfo对象的属性*/
    /*文档标题*/
    private String title;
    /*文档描述*/
    private String description;
    /*文档版本信息*/
    private String version;
    /*文档编辑组织团队链接*/
    private String termsOfServiceUrl;
    /*文档许可说明*/
    private String license;
    /*文档许可链接*/
    private String licenseUrl;

    /*Contact 对象属性*/
    //联系人姓名
    private String name;
    //联系人访问链接
    private String url;
    //联系人email
    private String email;

    /**
     *功能描述: 默认组,显示所有模块接口,以定义dokect定义的扫描接口规则为准
     * @Author 小莫
     * @Date 16:58 2019/05/17
     * @Param [environment]
     * @return springfox.documentation.spring.web.plugins.Docket
     */
    @Bean
    public Docket docket2(Environment environment){
        Profiles profiles = Profiles.of("dev", "test");
        boolean isEnable = environment.acceptsProfiles(profiles);
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .groupName("默认")
                .enable(isEnable)
                .select()            .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .build();
    }

    /**
     *功能描述: 配置Docket
     * @Author 小莫
     * @Date 14:07 2019/05/17
     * @Param []
     * @return springfox.documentation.spring.web.plugins.Docket
     */
    @Bean
    public Docket docket(Environment environment){
        Profiles profiles = Profiles.of("dev", "test");
        boolean isEnable = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .groupName("订单")
                .enable(isEnable)
                //.ignoredParameterTypes要在select()以及paths之前设置
                .ignoredParameterTypes(HttpServletRequest.class, HttpSession.class)
                .select()
     .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .paths(PathSelectors.ant("/order/**"))
                .build();
    }

    /**
     *功能描述: 通过ApiInfo 来配置Api文档信息
     * @Author 小莫
     * @Date 15:12 2019/05/17
     * @Param []
     * @return springfox.documentation.service.ApiInfo
     */
    private ApiInfo apiInfo(){
        Contact contact = new Contact(name, url, email);
        return new ApiInfoBuilder()
                .title(title)
                .description(description)
                .version(version)
                .termsOfServiceUrl(termsOfServiceUrl)
                .license(license)
                .licenseUrl(licenseUrl)
                .contact(contact)
                .build();
    }

    @Bean
    public Docket docket1(Environment environment){
        Profiles profiles = Profiles.of("dev", "test");
        boolean isEnable = environment.acceptsProfiles(profiles);

        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .groupName("用户")
                .enable(isEnable)
                .select()            .apis(RequestHandlerSelectors.basePackage("com.xmlvhy.boot.swagger.controller"))
                .paths(PathSelectors.ant("/user/**"))
                .build();
    }
}

完成以上配置,重启项目,查看效果:

此时我们选择用户组,查看用户模块的API信息:

看用户模块中定义的接口,看着是不是更清晰了。我们主要来说明下,UserController中用到的Swagger中的相关注解:

//1. @Api	修饰整个类,描述Controller的作用
   如:@Api(tags = "用户模块")

//2. @ApiOperation 描述一个类的一个方法,或者说一个接口
   如:@ApiOperation(value = "获取用户信息",notes = "获取所有的用户信息列表") 
   value:描述大概信息		notes: 详细描述

//3. @ApiImplicitParam  一个请求参数;如:
	@ApiOperation(value = "获取单个用户信息",notes = "根据用户id查询某个用户信息")
    @ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "path")
    @GetMapping("/getOne/{id}")
    public Object getOneUser(@PathVariable(value = "id") int id){
        return users.get(id);
    }

//4. @ApiImplicitParams 多个请求参数,如:
	@ApiOperation(value = "修改用户信息",notes = "根据用户id修改用户名")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id",value = "用户id",required = true,dataType = "int",paramType = "query"),
            @ApiImplicitParam(name = "name",value = "用户姓名",required = true,dataType = "string",paramType = "query")
    })
    @PutMapping("putUser")
    public Object putUser(@RequestParam(value = "id") int id, @RequestParam(value = "name") String name){
        users.get(id).setName(name);
        return "ok";
    }

/*其中内部参数功能:value: 备注输入参数名称(中文)name:备注输入参数名称(英文)required:该入参是否必填dataType:该入参的数据类型 paramType:前台接口调用时url 参数形式如:query 的形式:getUser?user=admin ;path的形式:getUser/user/admin*/
3.10、测试接口相关信息

四、修复 swaggerfox 升级 2.9.2版本问题
4.1、解决新版本问题

文章开篇,我有提到,整合Swagger新版本中,有一个小坑。这里具体说明下,当我们使用版本2.9.2时候,如果项目实体中有Integer类型的属性,当我们打开Api文档的时候会出现一个警告信息:

2019-05-17 17:31:47.743  WARN 4452 --- [nio-8080-exec-1] i.s.m.p.AbstractSerializableParameter    : Illegal DefaultValue  for parameter type integer

java.lang.NumberFormatException: For input string: ""
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[na:1.8.0_181]
	at java.lang.Long.parseLong(Long.java:601) ~[na:1.8.0_181]
	at java.lang.Long.valueOf(Long.java:803) ~[na:1.8.0_181]
	at io.swagger.models.parameters.AbstractSerializableParameter.getExample(AbstractSerializableParameter.java:412) ~[swagger-models-1.5.20.jar:1.5.20]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serializeContents(IndexedListSerializer.java:119) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:79) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.impl.IndexedListSerializer.serialize(IndexedListSerializer.java:18) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serializeFields(MapSerializer.java:722) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:643) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.std.MapSerializer.serialize(MapSerializer.java:33) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:727) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905) [jackson-databind-2.9.8.jar:2.9.8]
	at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3219) [jackson-databind-2.9.8.jar:2.9.8]
	at springfox.documentation.spring.web.json.JsonSerializer.toJson(JsonSerializer.java:38) [springfox-spring-web-2.9.2.jar:null]
	at springfox.documentation.swagger2.web.Swagger2Controller.getDocumentation(Swagger2Controller.java:105) [springfox-swagger2-2.9.2.jar:null]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) [spring-webmvc-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) [tomcat-embed-websocket-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-5.1.7.RELEASE.jar:5.1.7.RELEASE]
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) [tomcat-embed-core-9.0.19.jar:9.0.19]
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

解决方案:

1.方案一:排除springfox-swagger2 引入的 swagger-annotations、swagger-models 1.5.20版本,手动引入1.5.21版本的jar。具体原因可以查看如下链接,这篇文章说的很详细!

https://blog.csdn.net/qq122516902/article/details/89673363

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.xmlvhy</groupId>
    <artifactId>springboot-swagger</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.1.5.RELEASE</version>
        </dependency>
        <!--swagger2 相关依赖-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
            <!--解决进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
            <exclusions>
                <exclusion>
                    <artifactId>swagger-models</artifactId>
                    <groupId>io.swagger</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>swagger-annotations</artifactId>
                    <groupId>io.swagger</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--手动引入 swagger-models 以及 swagger-annotations 的 1.5.21 版本解决
            java.lang.NumberFormatException: For input string: "" 错误
        -->
        <dependency>
            <artifactId>swagger-annotations</artifactId>
            <groupId>io.swagger</groupId>
            <version>1.5.21</version>
        </dependency>
        <dependency>
            <artifactId>swagger-models</artifactId>
            <groupId>io.swagger</groupId>
            <version>1.5.21</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
        </dependency>
    </dependencies>
</project>

2.方案二:通过方案一,我们可以了解得该警告并没有实质性影响,知识报错信息看着不好,所以我们通过设置报错包下的log级别来避开此警告信息,这种方式比较粗暴!

# 将 io.swagger.models.parameters.AbstractSerializableParameter 包下的日志级别设置为error,避免提示出现
# "" 转换为 integer 的类转换异常,不影响
logging:
  level:
    io.swagger.models.parameters.AbstractSerializableParameter:  error

以上便是我学习Swagger做的相关总结,如有不对之处,还请指出!

参考链接:

https://blog.csdn.net/qq122516902/article/details/89417964

本篇文章涉及的源码,点击下载

类似文章

  1. SpringCloud入门系列之服务链路追踪Sleuth&Zipkin
  2. SpringCloud入门系列之微服务之间的通信
  3. SpringCloud入门系列之API网关
  4. SpringCloud入门系列之配置中心
  5. SpringCloud入门系列之Eureka注册中心

评论区

| 0 评论

还没有评论,快来抢沙发吧!