背景
- 软件开发过程中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; }