Swagger 使用总结

一、初识Swagger

由于Spring Boot能够快速开发、便捷部署等特性,相信有很大一部分Spring Boot的用户会用来构建RESTful API。而我们构建RESTful API的目的通常都是由于多终端的原因,这些终端会共用很多底层业务逻辑,因此我们会抽象出这样一层来同时服务于多个移动端或者Web前端。

这样一来,我们的RESTful API就有可能要面对多个开发人员或多个开发团队:IOS开发、Android开发或是Web开发等。为了减少与其他团队平时开发期间的频繁沟通成本,传统做法我们会创建一份RESTful API文档来记录所有接口细节,然而这样的做法有以下几个问题:

由于接口众多,并且细节复杂(需要考虑不同的HTTP请求类型、HTTP头部信息、HTTP请求内容等),高质量地创建这份文档本身就是件非常吃力的事,下游的抱怨声不绝于耳。
随着时间推移,不断修改接口实现的时候都必须同步修改接口文档,而文档与代码又处于两个不同的媒介,除非有严格的管理机制,不然很容易导致不一致现象。
为了解决上面这样的问题,本文将介绍RESTful API的重磅好伙伴Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档。它既可以减少我们创建文档的工作量,同时说明内容又整合入实现代码中,让维护文档和修改代码整合为一体,可以让我们在修改代码逻辑的同时方便的修改文档说明。另外Swagger2也提供了强大的页面测试功能来调试每个RESTful API。

作用总结:

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

二、实战演练

2.1 添加依赖

在pom.xml中加入Swagger3的依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

2.2 创建Swagger配置类

@Configuration
public class SwaggerConfig {
    
    

    @Bean
    public Docket initDocket(Environment env) {
    
    

        //设置要暴漏接口文档的配置环境
        Profiles profile = Profiles.of("dev", "test");
        boolean flag = env.acceptsProfiles(profile);
        return new Docket(DocumentationType.OAS_30)
                .apiInfo(apiInfo())
                .enable(flag)
                .select()
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
    
    
        return new ApiInfoBuilder()
                .title("Swagger3-Demo接口文档")
                .description("XXXX团队")
                .contact(new Contact("XXXX技术团队", "http://www.XXXX.com", "[email protected] "))
                .version("1.0")
                .build();
    }
}

三、 常用注解

3.1 类

@Api():表示这个类是 swagger 资源

  • tags:表示说明内容,只写 tags 就可以省略属性名
  • value:同样是说明,不过会被 tags 替代,没卵用

3.2 方法上

@ApiOperation() :对方法的说明,注解位于方法上

  • value:方法的说明
  • notes:额外注释说明
  • response:返回的对象
  • tags:这个方法会被单独摘出来,重新分组,若没有,所有的方法会在一个Controller分组下

3.3 方法入参

@ApiParam():对方法参数的具体说明,用在方法入参括号里,该注解在post请求参数时,参数名不显示

  • name:参数名
  • value:参数说明
  • required:是否必填

@ApiImplicitParam对方法参数的具体说明,用在方法上@ApiImplicitParams之内,该注解在get,post请求参数时,参数名均正常显示

  • name 参数名称
  • value 参数的简短描述
  • required 是否为必传参数
  • dataType 参数类型,可以为类名,也可以为基本类型(String,int、boolean等)指定也不起作用,没卵用
  • paramType 参数的传入(请求)类型,可选的值有path, query, body, header or form。

3.4 实体

@ApiModel描述一个Model的信息(一般用在请求参数无法使用@ApiImplicitParam注解进行描述的时候)

  • value : model的别名,默认为类名
  • description: model的详细描述

@ApiModelProperty描述一个model的属性

  • value 属性简短描述
  • example 属性的示例值
  • required 是否为必须值

3.5 header参数

@ApiImplicitParams({
    
          
@ApiImplicitParam(
paramType="header",
name="USERTOKEN",
dataType="String",
required=true,
value="用户token")
    })

3.6 file入参

需要使用@RequestPart 注解

@ApiOperation(value = "上传文件接口",notes = "上传文件接口")
    @ApiImplicitParams({
    
    
            @ApiImplicitParam(name = "name", value = "上传人")
    })
    @PostMapping(value = "/uploadFile")
    public String uploadFile(
    @RequestParam("name") String name,
    @RequestPart("file") MultipartFile file){
    
    
        
    }

四、拦截器放行

若项目中有使用拦截器,放行以下路径

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    

    @Autowired
    TokenInterceptor tokenInterceptor;

    /**
     * 拦截器
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
    
    
        // 注册token拦截器
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/**/swagger-ui/**")
                .excludePathPatterns("/**/swagger-resources/**")
                .excludePathPatterns("/**/v3/**")
        ;
    }
}

五、文档访问地址

http://ip:port/context-path/swagger-ui/

http://ip:port/context-path/swagger-ui/index.html

六、Swagger3 Demo

/**
 * @Auther: lya
 * @Description: swagger3-演示
 * @Version: 1.0
 */
@RestController
@RequestMapping("/oss")
@Api(value = "swagger3-演示",description = "用来演示Swagger的一些注解")
public class TestController {
    
    


    @ApiOperation(value="修改用户密码", notes="根据用户id修改密码")
    @ApiImplicitParams({
    
    
        @ApiImplicitParam(paramType="query", name = "userId", value = "用户ID", required = true, dataType = "Integer"),
        @ApiImplicitParam(paramType="query", name = "password", value = "旧密码", required = true, dataType = "String"),
        @ApiImplicitParam(paramType="query", name = "newPassword", value = "新密码", required = true, dataType = "String")
    })
    @RequestMapping("/updatePassword")
    public String updatePassword(@RequestParam(value="userId") Integer userId, @RequestParam(value="password") String password, 
            @RequestParam(value="newPassword") String newPassword){
    
    
         if(userId <= 0 || userId > 2){
    
    
             return "未知的用户";
         }
         if(StringUtils.isEmpty(password) || StringUtils.isEmpty(newPassword)){
    
    
             return "密码不能为空";
         }
         if(password.equals(newPassword)){
    
    
             return "新旧密码不能相同";
         }
         return "密码修改成功!";
     }
}

七、Swagger2 Demo

pom.xml

  <!-- Swagger依赖 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
            <!-- 排除下面两个依赖,解决 For input string: "" 异常 -->
            <exclusions>
                <exclusion>
                    <groupId>io.springfox</groupId>
                    <artifactId>swagger-annotations</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.swagger</groupId>
                    <artifactId>swagger-models</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- 单独引用版本偏低的两个依赖 -->
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.21</version>
        </dependency>
        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-models</artifactId>
            <version>1.5.21</version>
        </dependency>
        <!-- UI页面展示 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

config.java


import io.swagger.annotations.ApiOperation;

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;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    
    
    @Bean
    public Docket initDocket(Environment env) {
    
    
        //设置要暴漏接口文档的配置环境
        Profiles profile = Profiles.of("dev", "test");
        boolean flag = env.acceptsProfiles(profile);
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName("test1")
                .apiInfo(apiInfo())
                .host("base url")
                .enable(flag)
                .select()
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    @Bean
    public Docket docket1() {
    
    
        return new Docket(DocumentationType.SWAGGER_2)
                //分组
                .groupName("test2")
                //当前分组信息
                .apiInfo(apiInfoByLYA())
                //扫描范围select开始 build结束
                .select()
                //根据给定的包的位置进行扫描
                .apis(RequestHandlerSelectors.basePackage("com.yeyoo.support.swagger.controller2"))
                //类上有对应注解会被扫描
//                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
                //路径过滤
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
    
    
        return new ApiInfoBuilder()
                //标题
                .title("Swagger-Demo接口文档")
                //简介
                .description("平台支撑小组")
                //服务条款
//                .termsOfServiceUrl("www.fuwutiaokuan.com")
                //作者个人信息
                .contact(new Contact("平台支撑小组", "http://www.baidu.com", "[email protected] "))
                //版本
                .version("1.0")
                .build();
    }

    private ApiInfo apiInfoByLYA() {
    
    
        return new ApiInfoBuilder()
                //标题
                .title("SwaggerByYEYOO接口文档")
                //简介
                .description("lya")
                //作者个人信息
                .contact(new Contact("lya", "http://www.baidu.com", "[email protected] "))
                //版本
                .version("1.0")
                .build();
    }
}

dao

@Data
@ApiModel(value=" user ", description=" 用户实体类 ")
public class User {
    
    
    @ApiModelProperty(value = "用户名")
    private String name;

    @ApiModelProperty(value = "年龄")
    private Integer age;

    @ApiModelProperty(value = "性别")
    private Integer sex;
}

controller


import com.yeyoo.support.swagger.pojo.User;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Api(value = "用户", tags = {
    
    "用户测试"})
@RestController
public class UserController {
    
    

    @ApiOperation(value = "用户测试用例")
    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public void userTest(User user){
    
    
        user.setAge(1);
        user.setName("1");
        System.out.println(user.toString());
    }

    @ApiOperation(value="修改用户密码", notes="根据用户id修改密码")
    @ApiImplicitParams({
    
    
            @ApiImplicitParam(paramType="query", name = "userId", value = "用户ID", required = true, dataType = "Integer"),
            @ApiImplicitParam(paramType="query", name = "password", value = "旧密码", required = true, dataType = "String"),
            @ApiImplicitParam(paramType="query", name = "newPassword", value = "新密码", required = true, dataType = "String")
    })
    @RequestMapping("/updatePassword")
    public String updatePassword(@RequestParam(value="userId") Integer userId,
                                 @RequestParam(value="password") String password,
                                 @RequestParam(value="newPassword") String newPassword){
    
    
        if(userId <= 0 || userId > 2){
    
    
            return "未知的用户";
        }
        if(StringUtils.isEmpty(password) || StringUtils.isEmpty(newPassword)){
    
    
            return "密码不能为空";
        }
        if(password.equals(newPassword)){
    
    
            return "新旧密码不能相同";
        }
        return "密码修改成功!";
    }

}

TestApplication

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan(basePackages = {
    
    "com.support.swagger","com.support.redis"})
@SpringBootApplication(scanBasePackages = "com.yeyoo.support")
public class TestApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(TestApplication.class, args);
    }
}

猜你喜欢

转载自blog.csdn.net/L_994572281_LYA/article/details/120259692
今日推荐