swagger使用说明及规范

背景

  • 软件开发过程中api接口文档尤其重要,特别是在前后端分离情况下,为保证开发效率,文档的及时更新,swagger在开发过程中越来越常见,重要。
  • 同时swagger的广泛使用也产生了一些问题。如部署到生产环境会暴露安全隐患。部分参数不规范导致接口歧义混淆等。
  • 在此背景下并结合koca开发过程,总结整理此规范文档,用于swagger在开发使用过程中的规范约束。

pom依赖

<!-- swagger 核心包-->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.9.2</version>
</dependency>
<!-- swagger 第三方开源展示界面,推荐使用,界面友好-->
<!-- 访问uri: http://ip:port/contextPath/doc.html-->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>swagger-bootstrap-ui</artifactId>
    <version>1.9.4</version>
</dependency>
<!-- swagger 官方展示界面-->
<!-- 访问uri: http://ip:port/contextPath/swagger-ui.html#/-->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.9.2</version>
</dependency>

配置类约定与规范

配置类规范

为解决在不同环境下对swagger界面访问权限的控制,如开发环境展示,线上环境关闭。约定通过统一配置开关进行控制。规范如下

  • @EnableSwagger2注解单个服务中有且只有一处。
  • 通过swagger.enabled开关对swagger进行开启关闭控制操作,默认不开启

示例:

@Configuration
@ConditionalOnProperty(value = "swagger.enabled",havingValue = "true")
@EnableSwagger2
public class SwaggerConfig {
    //其他swagger配置
    .......
}

ps:后续koca会提供相应组件,业务后续只需关注配置即可,无需代码开发。

应用案例

在实际项目开发过程中可以直接通过修改配置的方式控制swagger的开关,也可以通过spring的profiles的功能进行不同环境配置的切换,从而达到开关控制的目的。下面以spring-profile的方式给出案例。

首先创建不同环境配置

  • 开发环境,需要开启swagger为开发使用,swagger-dev.yml内容

    swagger:
      enabled: true
    
  • 线上环境,需要关闭swagger防止风险。swagger-master.yml内容

    swagger:
      enabled: false
    

指定配置生效配置,application.yml

spring:
  profiles:
    active: master //线上环境,开发环境改为dev

swagger注解使用规范

swagger规范为结合studio开发框架对注解使用做出的约束与规定。下面按照注解场景进行具体说明。

Controller类的注解

  • @ApiIgnore

    功能:可使用在接口或类上,将配置中扫描包下的controller进行排除,swagger在扫描是就不会扫描该类及其方法

    规范:应及时将过期或未使用的接口标注@ApiIgnore。

@ApiIgnore
public class HelloController {
}
  • @Api

    • tags–表示说明
    • value–也是说明,可以使用tags替代

    功能:应用在Controller,用于对Controller的说明

    规范:必须使用tags或value对其功能进行简要中文说明

@Api(tages = "API接口参数 Controller")
public class ApiParameterController{
}

Controller类中接口方法的注解

  • @ApiOperation
    • value用于方法描述
    • notes用于提示内容
    @ApiOperation(value = "addApp", notes = "新增应用")
    @RequestMapping(value = "/app", method = RequestMethod.POST)
    @ResponseBody
    public Result<String> addApp(@RequestBody MiApplication miApp) {
        Result<String> result = appService.addApp(miApp);
        return result;
    }

方法使用Map对象接收参数的情况

  • @ApiImplicitParams @ApiImplicitParam

    • name–参数名
    • value–参数说明
    • dataType–数据类型
    • paramType–参数类型
    • example–举例说明

    功能:用于描述接口方法参数

    规范:

    • 不推荐使用map接收参数
    • 需要使用@ApiIgnore参数,可以避免将Map也作为接口入参读取
    • paramType表示参数所在位置,name是参数的英文名称,value是参数的中文名称,required表示参数是否必填,dataType表示参数的类型。为必须数据
    @ApiOperation(value = "getAppPage", notes = "分页查询应用")
    @ApiImplicitParams({
        @ApiImplicitParam(paramType = "body", name = "pageNum", value = "起始行", required = true, dataType = "String"),
        @ApiImplicitParam(paramType = "body", name = "pageSize", value = "每页行数", required = true, dataType = "String"),
        @ApiImplicitParam(paramType = "body", name = "appCode", value = "应用Code", required = false, dataType = "String"),
        @ApiImplicitParam(paramType = "body", name = "appName", value = "应用名称", required = false, dataType = "String") })
    @PostMapping("/app/page")
    @ResponseBody
    public PageListResult<Map<String, Object>> getAppPage(@ApiIgnore @RequestBody Map<String, String> params) {
        ParamCheckUtil.checkParamString(params);
        PageListResult<Map<String, Object>> result = appService.selectPage(params);
        return result;
    }

VO对象的注解

  • @ApiModel

    • value–表示对象名
    • description–描述

    功能:用于描述接口入参VO说明

    规范:

    • value使用类名
    • 描述为中文功能描述
@ApiModel(value = "DataVo", description = "描述")
public class DataVo {
    
}

VO对象属性的注解

  • @ApiModelProperty

    • value–字段说明
    • name–重写属性名字
    • required–是否必填

    功能:对VO中具体属性进行说明

    规范:value为必须中文说明。name非必要不重写。required在false时需要写明

    @ApiModelProperty(value="接口id",name="apiId",required=true)
    private long apiId;

实际入参与vo对象不匹配

规范:在一些情况下实际入参是vo对象的子集,此时应采用和入参是map一样的处理方式,使用@ApiIgnore忽略vo对象,自定义入参注解

    @ApiOperation(value = "getBoardData", notes = "根据看板ID获取看板内容")
    @ApiImplicitParams({
    @ApiImplicitParam(paramType = "body", name = "uuID", value = "看板ID", required = true, dataType = "String")})
    @PostMapping({"/getBoardData"})
    public AjaxResult getBoardData(@ApiIgnore @RequestBody ReportParam param, @ApiIgnore @ControlParams ReportSystemParam ctrlParam) {
        AjaxResult ajaxResult = new AjaxResult();
        return ajaxResult;
    }

案例

案例一: Controller层使用VO作为接收对象

示例代码如下:

  // 一个简单的接口
  @RequestMapping(value = "/app", method = RequestMethod.POST)
  @ResponseBody
  public Result<String> addApp(@RequestBody ApplicationVo App) {
      Result<String> result = appService.addApp(miApp);
      return result;
  }
  // VO对象
  public class ApplicationVo {
      private long appId;
      private String appCode;
      private String appName;
      
      //get,set方法略
      ...
  }

当使用VO对象接收入参时,swagger会自动扫描VO对象的属性。

因此只需要在接口方法上添加@ApiOperation,并在VO对象中补全对象属性的注解@ApiModelProperty即可。

添加swagger注解后如下:

  @ApiOperation(value = "addApp", notes = "新增应用")
  @RequestMapping(value = "/app", method = RequestMethod.POST)
  @ResponseBody
  public Result<String> addApp(@RequestBody ApplicationVo App) {
      Result<String> result = appService.addApp(miApp);
      return result;
  }
  public class ApplicationVo {

      @ApiModelProperty(value = "应用ID", required = true)
      private long appId;

      @ApiModelProperty("应用代码")
      private String appCode;

      @ApiModelProperty("应用名称")
      private String appName;

      // 方法略
      ...
  }

案例二: Controller层使用Map作为接收对象

示例代码如下:

    @ResponseBody
    public PageListResult<Map<String, Object>> getAppPage(@RequestBody Map<String, String> params) {
        ParamCheckUtil.checkParamString(params);
        PageListResult<Map<String, Object>> result = appService.selectPage(params);
        return result;
    }

Map中的内容无法被获取,因此需要手动添加。

在接口方法上,除了添加@ApiOperation注解,还要添加@ApiImplicitParams注解和@ApiImplicitParam注解,将入参一一列出。

注意Map前的@ApiIgnore注解,手动添加注解后,Map不应该再被swagger扫描到。

添加swagger注解后如下:

    @ApiOperation(value = "getAppPage", notes = "分页查询应用")
    @ApiImplicitParams({
        @ApiImplicitParam(paramType = "body", name = "pageNum", value = "起始行", required = true, dataType = "String"),
        @ApiImplicitParam(paramType = "body", name = "pageSize", value = "每页行数", required = true, dataType = "String"),
        @ApiImplicitParam(paramType = "body", name = "appCode", value = "应用Code", required = false, dataType = "String"),
        @ApiImplicitParam(paramType = "body", name = "appName", value = "应用名称", required = false, dataType = "String") })
    @PostMapping("/app/page")
    @ResponseBody
    public PageListResult<Map<String, Object>> getAppPage(@ApiIgnore @RequestBody Map<String, String> params) {
        ParamCheckUtil.checkParamString(params);
        PageListResult<Map<String, Object>> result = appService.selectPage(params);
        return result;
    }

附:swagger注解api全量说明

@Api

  • 作用:用于说明类的作用

  • 位置:类的上方,与@Controller等注解并列

  • 参数:加粗的为常用参数

    参数名称 说明
    tags 说明该类的作用
    value 也是对类得说明,可使用tags替换
    produces 如, “application/json, application/xml”
    consumes 如, “application/json, application/xml”
    protocols 协议类型,如: http, https, ws, wss.
    authorizations 高级特性认证时配置
    hidden 配置为true ,将在文档中隐藏
  • 示例:

    @Api(value="用户controller",tags={"用户操作接口"})
    @RestController
    public class UserController {
    }
    

@ApiOperation

  • 作用:对方法的说明

  • 位置:用在请求的方法上

  • 参数:加粗的为常用参数

    参数名称 说明
    value 说明方法的作用
    notes 方法的备注说明
    tags 如果设置这个值,value的值会被覆盖
    produces 如, “application/json, application/xml”
    consumes 如, “application/json, application/xml”
    protocols 协议类型,如: http, https, ws, wss.
    authorizations 高级特性认证时配置
    hidden 配置为true 将在文档中隐藏
    response 返回的对象
    responseContainer 包含的这些对象是有效的 “List”,“Set”,“Map”,其他无效
    httpMethod get,head,post,put,delete,options,patch
    code http的状态码,默认200
    extensions 扩展属性
  • 示例:

        @ApiOperation(value = "getJobGroupList", notes = "获取任务分组列表")
        @PostMapping("/grouplist")
        public ListResult<String> getJobGroupList() {
            return listResult;
        }
    

@ApiParam

  • 作用:表示请求属性

  • 位置:用于方法、参数、字段上

  • 参数:加粗的为常用参数

    参数名称 说明
    name 属性名称
    value 属性说明
    required 该属性是否必填
    defaultValue 默认属性值
    hidden 是否隐藏该属性
    example 示例
    type 类型
    allowEmptyValue 允许空值
    readOnly 只读
  • 示例:

        @ApiOperation(value = "getJobGroupList", notes = "获取任务分组列表")
        @PostMapping("/grouplist")
        public ListResult<String> getJobGroupList(@ApiParam(name = "jobCode", value = "任务编码", required = true) @RequestParam("jobCode") String jobCode) {
            return listResult;
        }
    

@ApiImplicitParam

  • 作用:对单个参数的说明

  • 位置:用于方法上,用在@ApiImplicitParams 注解中

  • 参数:加粗的为常用参数

    参数名称 说明
    name 参数名
    value 参数的汉字说明,解释
    paramType 参数放在哪个地方。
    · header 参数在request headers 里边提交(@RequestHeader);
    · query 直接跟参数完成自动映射赋值(@RequestParam);
    · path 用于restful接口,以地址的形式提交数据(@PathVariable);
    · body 以流的形式提交 仅支持POST(@RequestBody);
    · form 以form表单的形式提交 仅支持POST
    dataType 参数类型,默认String,其他值dataType=“Integer”
    required 是否必填
    defaultValue 参数的默认值
  • 示例:见@ApiImplicitParams

@ApiImplicitParams

  • 作用:包含一组参数说明

  • 位置:用于方法上

  • 参数:加粗的为常用参数

    参数名称 说明
    value ApiImplicitParam
  • 示例:

        @ApiOperation(value = "user", notes = "查询用户")
        @ApiImplicitParams({
        @ApiImplicitParam(name="mobile",value="手机号",required=true,paramType="form"),
        @ApiImplicitParam(name="password",value="密码",required=true,paramType="form"),
        @ApiImplicitParam(name="age",value="年龄",required=true,paramType="form",dataType="Integer")
    })
        @PostMapping("/user")
        public ListResult<String> user(String mobile,String password,String age) {
            return listResult;
        }
    

@ApiResponse

  • 作用:响应配置,不常用

  • 位置:用于方法上,用在@ApiResponses中

  • 参数:加粗的为常用参数

    参数名称 说明
    code Http状态码
    message 描述
    response 默认响应类Void
    responseHeaders ResponseHeader的配置
    responseContainer 包含的这些对象是有效的 “List”,“Set”,“Map”,其他无效
    example 示例
  • 示例:

        @ApiOperation(value = "getJobGroupList", notes = "获取任务分组列表")
        @ApiResponse(code = 200, message = "请求成功")
        @PostMapping("/grouplist")
        public ListResult<String> getJobGroupList() {
            return listResult;
        }
    

@ApiResponses

  • 作用:响应配置组

  • 位置:用于方法上

  • 参数:加粗的为常用参数

    参数名称 说明
    value ApiResponse
  • 示例:

        @ApiOperation(value = "getJobGroupList", notes = "获取任务分组列表")
        @ApiResponses({
    		@ApiResponse(code = 200, message = "请求成功"),
    		@ApiResponse(code = 404, message = "没有对应url")
    	}) 
        @PostMapping("/grouplist")
        public ListResult<String> getJobGroupList() {
            return listResult;
        }
    

@ResponseHeader

  • 作用:响应头设置

  • 位置:用于方法上

  • 参数:加粗的为常用参数

    参数名称 说明
    name 响应头名称
    description 头部描述
    response 默认响应类Void
    responseContainer 包含的这些对象是有效的 “List”,“Set”,“Map”,其他无效
  • 示例:

        @ApiOperation(value = "getJobGroupList", notes = "获取任务分组列表")
        @ResponseHeader(name="code",description="job的编码")
        @PostMapping("/grouplist")
        public ListResult<String> getJobGroupList() {
            return listResult;
        }
    

@ApiModel

  • 作用:描述一个Model的信息,一般用于json,使用@RequestBody这样的场景

  • 位置:用于类上

  • 参数:加粗的为常用参数

    参数名称 说明
    description 描述
    value 建议使用默认,全局唯一,相同的value会覆盖
    parent 父类类型
    discriminator 使用子类型
    subTypes 子类型数组
    reference 指定对应类型
  • 示例:

    @ApiModel(description = "任务请求对象")
    public class JobInfoRequestVo extends PageParam {
        @ApiModelProperty(value = "任务名称", required = true)
        private String jobName;
    }
    

@ApiModelProperty

  • 作用:描述一个model的属性

  • 位置:用于model方法、字段上

  • 参数:加粗的为常用参数

    参数名称 说明
    value 属性简要说明
    required 是否必须
    name 覆盖属性的名称。重写属性名称
    allowableValues 限制可接收的值。固定取值或固定范围
    access 过滤属性
    notes 尚未使用
    dataType 数据类型,将覆盖原始类型
    position 显示顺序
    hidden 是否隐藏
    example 署邢示例
    readOnly 是否只读
    allowEmptyValue 是否允许传空值
  • 示例:

    @ApiModel(value = "JobInfoRequestVo", description = "任务请求对象")
    public class JobInfoRequestVo extends PageParam {
    
        /**
         * 任务名
         */
        @ApiModelProperty(value = "任务名称", required = true)
        private String jobName;
    }
    

感谢分享 :+1:

:+1:

:+1: