浅谈 Swagger —— 优化现有开发流程

浅谈Swagger

背景故事

随着互联网技术的发展,越来越多的公司选择了前后端分离,开始了敏捷转型。而前后端的技术都有了各自的突破,已然进入新的时代。
前后端之间如何有效的沟通?有的公司是依赖口口相传、有的是依靠word文档、有些公司则已经引入了新的解决方案在线编辑接口文档,而有部分公司选择了Swagger。
绝大多数都停留在前两种,看起来word文档也没啥毛病,可是实际开发中往往会出现"您的word版接口文档已过期"。原因很简单:

  • 文档与接口分开维护必定导致开发人员自认为自己等写完接口了再去修改文档就行了,接口是写完了,而文档却不记得修改了。
  • 选择了敏捷后迭代频繁,一个又一个的小改动,一次又一次的发版让开发人员已经麻木,慢慢变成了“嘿,兄弟登录接口新加了个登录类型字段你就给我传个1就行了”。

认识Swagger

Swagger是一个规范且完整的框架,提供描述、生产、消费和可视化RESTful Web Service。
Swagger的写法是直接在接口上添加注释、在对象和对象的参数上添加注释。有很多人认为这样非常鸡肋,耦合度太高,或是认为需要写较多的注释太过繁琐。

博主认为和代码结合在这恰恰是它的优点,让你每次修改接口时不需要浪费时间去找到你的文档,亦或是忘记了修改文档。而所谓过多的注释,我想这应该比写word要快的多,当然比不过口头传达了。

好的文档让项目减少联调时间

在引入Swagger后,我修改了项目组原有的开发流程。
原有老的开发流程如下(弊端:1、需要单独抽出大量联调时间;2、测试需要等待较长时间才能开始进入测试;3、前端页面开发完后需要等待较长时间才能拿到可以访问的接口):
之前的迭代开发流程
优化后的开发流程图如下:
优化后的流程

当然上图优化后的开发流程图有部分没有体现出来,1、后端的自测非常重要;2、如果同一个接口需要返回多种结果如何去写默认返回结果,例如查询订单状态接口,那么https://graphql.cn你可以了解下。

如何用Swagge

引入maven依赖

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

创建Swagger2配置类

package com.swagger.config;

import jersey.repackaged.com.google.common.collect.Lists;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.util.List;


@Configuration
@EnableSwagger2 // 启用Swagger2
public class Swagger2Config {

    @Bean
    public Docket createRestApi() {// 创建API基本信息
        List<Parameter> header = buildHeader();
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.swagger"))// 扫描该包下的所有需要在Swagger中展示的API,@ApiIgnore注解标注的除外
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(header)
                .apiInfo(apiInfo())
                .pathMapping("/");
    }

    /**
     * 给所有接口设置默认的请求头
     * @return
     */
    private List<Parameter> buildHeader() {
        List<Parameter> header = Lists.newArrayList();
        ParameterBuilder ticketPar = new ParameterBuilder();
        ticketPar.name("X-User-Token").description("X-User-Token").modelRef(new ModelRef("string")).parameterType("header").defaultValue("rmwlkpacqoozr0247401719288299520").required(true);
        header.add(ticketPar.build());
        return header;
    }

    private ApiInfo apiInfo() {// 创建API的基本信息,这些信息会在Swagger UI中进行显示
        return new ApiInfoBuilder()
                .title("Swagger Service RESTful APIs")// API 标题
                .description("Swagger2提供的RESTful APIs")// API描述
                .contact("Zhibo.lv")// 联系人
                .version("1.0")// 版本号
                .build();
    }
}

如上代码所示,通过createRestApi函数创建Docket的Bean之后,apiInfo()用来创建该Api的基本信息,buildHeader()用来设置请求头的公共参数。完成后即可在你的代码中开始编写接口文档。

接口文档编写

博主这里简单的写一个后台管理员新建和查询用户的案例

新建UserVo接收前端传递的对象

package com.swagger.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.NotBlank;

import javax.validation.constraints.NotNull;

@Data
@ApiModel("UserVo 用户信息")
public class UserVo {
    @NotBlank
    @ApiModelProperty(value = "用户姓名",required = true)
    private String name;

    @NotBlank
    @ApiModelProperty(value = "用户手机号",required = true)
    private String mobile;

    @NotNull
    @ApiModelProperty(value = "性别1:男,2:女,0:未知",allowableValues = "0,1,2", required = true)
    private Integer sex;

    @ApiModelProperty(value = "学历信息")
    private String education;
}

新建UserController 提供http接口

package com.swagger.controller;

import com.swagger.common.Urls;
import com.swagger.vo.UserVo;
import com.swagger.vo.response.ResponseVo;
import com.welab.sea.util.web.common.Constants;
import io.swagger.annotations.*;
import org.apache.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.validation.constraints.NotNull;


@Validated
@RestController
@ResponseBody
@Api(value = Urls.ROOT, description = Urls.ROOT_DESC)
public class UserController {

    @PostMapping(value=Urls.User.V1_USER_ADD)
    @ApiOperation(value = Urls.User.V1_USER_ADD, notes = Urls.User.V1_USER_ADD_DESC)
    @ApiImplicitParams({//设置前端需要额外传递的头部参数
            @ApiImplicitParam(name = "X-Origin",paramType = "header",required = true)
    })
    @ApiResponses({//描述响应信息
            @ApiResponse(code = HttpStatus.SC_OK,message = "成功" ,response = ResponseVo.class)
    })
    public ResponseVo addUser(@ApiIgnore @RequestHeader(value = Constants.HEADER_FOR_USER_ID) Long adminId,
                                    @RequestBody @NotNull UserVo userVo) {
        return ResponseVo.getSuccessResponse();
    }

    @GetMapping(value=Urls.User.V1_USER_INFO)
    @ApiOperation(value = Urls.User.V1_USER_INFO, notes = Urls.User.V1_USER_INFO_DESC)
    @ApiImplicitParams({//描述
            @ApiImplicitParam(name = "userId",value = "用户Id",paramType = "query",required = true)
    })
    @ApiResponses({//描述响应信息
            @ApiResponse(code = HttpStatus.SC_OK,message = "成功" )
    })
    public ResponseVo<UserVo> getUser(@RequestParam(value = "userId") Long userId) {
        return ResponseVo.getSuccessResponse();
    }
}

常用注解介绍

注解名称 使用地点 作用 常用属性描述
@Api 类描述 value
description
@ApiOperation 方法 方法说明及方法地址 value
notes
@ApiImplicitParams 方法 用在方法上包含一组参数说明
@ApiImplicitParam 方法 用注解来给方法入参增加说明 name:参数名
value:参数描述
defaultValue:默认值
allowableValues:取值范围
paramType:传递方式
required:是否必传
@ApiIgnore 方法的参数 忽略该参数
@ApiResponses 方法 描述一组响应
@ApiResponse 方法 用注解来给方法响应增加说明
@ApiModel 描述一个Model的信息
@ApiModelProperty 属性 描述一个Model里面的具体的属性 和@ApiImplicitParam差不多

@ApiIgnore介绍:关于接口内的adminId因为现在的项目前端传的都是token,通过网关校验token获取管理员或用户ID所以这个参数不应当由前端传递故忽略。
基本的使用方法到这里就介绍完了,下面会给出该demo生成的接口文档的部分效果图,感兴趣的还没用过swagger的可以看看。

  • 接口文档首页,展示接口列表和项目介绍
    接口文档首页,展示接口列表和项目介绍
  • 接口出入参描述及模拟调用接口出入参描述及模拟调用
    就这么简单,心动不如行动
发布了18 篇原创文章 · 获赞 45 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/zhibo_lv/article/details/84104035