????相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟注释一样,经常会抱怨别人写的代码没有写注释,然而自己写起代码起来,最讨厌的,也是写注释。所以仅仅只通过强制来规范大家是不够的,随着时间推移,版本迭代,接口文档往往很容易就跟不上代码了。
????之前一直用 yapi+postman 的形式去完成和测试一整套接口文档,需要花费大量的经历和时间,自从项目引入Swagge 后,才知道Swagge在文档方面的强大之处。
<!-- swagger-springmvc -->
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-models</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>com.wordnik</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.3.11</version>
</dependency>
<!-- swagger-springmvc dependencies -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
<version>1.1.0</version>
</dependency>
@Configuration
@EnableSwagger
@EnableWebMvc
public class SwaggerConfig {
private SpringSwaggerConfig springSwaggerConfig;
/**
* Required to autowire SpringSwaggerConfig
*/
@Autowired
public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig){
this.springSwaggerConfig = springSwaggerConfig;
}
/**
* Every SwaggerSpringMvcPlugin bean is picked up by the swagger-mvc
* framework - allowing for multiple swagger groups i.e. same code base
* multiple swagger resource listings.
*/
@Bean
public SwaggerSpringMvcPlugin customImplementation(){
return new SwaggerSpringMvcPlugin(this.springSwaggerConfig)
.apiInfo(apiInfo())
.includePatterns(".*api*.*");
}
.includePatterns(".*api*.*");在此处,代表扫描的controller或者接口的名。有些教程在类开始处注解@compentScan,这个是无效的。
private ApiInfo apiInfo(){
ApiInfo apiInfo = new ApiInfo(
"吃瓜app",
"接口文档",
"",
"ywd979@foxmail.com",
"",
"");
return apiInfo;
}
}
sping-mvc.xml配置一下
<!-- 接口自动化文档,注入 Sawgge 的配置类到 spring中 -->
<bean class="com.pricl.frame.swagger.SwaggerConfig" />
<bean class="com.mangofactory.swagger.configuration.SpringSwaggerConfig" />
<!-- 引入swagger包 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.6.1</version>
</dependency>
<!-- 引入swagger-ui包 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.6.1</version>
</dependency>
<!-- 引入swagger-bootstrap-ui包 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.3</version>
</dependency>
import static com.google.common.base.Predicates.or;
import static springfox.documentation.builders.PathSelectors.regex;
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
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;
/**
* swaggerconfig 整体配置
*
* @author cuids
* @email
* @date 2017-07-14 18:08:25
*/
@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI
public class SwaggerConfig implements WebMvcConfigurer {
/**
* SpringBoot默认已经将classpath:/META-INF/resources/和classpath:/META-INF/resources/webjars/映射
* 所以该方法不需要重写,如果在SpringMVC中,可能需要重写定义(我没有尝试) 重写该方法需要 extends WebMvcConfigurerAdapter
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//引入 swagge-ui 的页面
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
//引入 swagger-bootstrap-ui 的页面
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* 可以定义多个组,比如本类中定义把test和demo区分开了 (访问页面就可以看到效果了)
*/
@Bean
public Docket itemApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("1_item")
//.genericModelSubstitutes(DeferredResult.class)
//.useDefaultResponseMessages(false)
.forCodeGeneration(false)
.pathMapping("/")
.select()
//过滤的接口
.paths(or(regex("/datasource-service/.*")))
.build()
.apiInfo(itemApiInfo());
}
private ApiInfo itemApiInfo() {
return new ApiInfoBuilder()
//大标题
.title("数据源管理接口API")
//详细描述
.description(
"Service Platform's REST API, all the applications could access the Object model data via JSON.")
//版本
.version("1.0")
.termsOfServiceUrl("NO terms of service")
//作者
.contact(new Contact("zhangke", "http://127.0.0.1:8056/doc.html", "freedom.zhang@baifendian.com"))
.license("The Apache License, Version 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.build();
}
@Bean
public Docket apiApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("2_item")
//.genericModelSubstitutes(DeferredResult.class)
//.useDefaultResponseMessages(false)
.forCodeGeneration(false)
// base,最终调用接口后会和paths拼接在一起
.pathMapping("/")
.select()
//过滤的接口
.paths(or(regex("/api/.*")))
.build()
.apiInfo(apiApiInfo());
}
private ApiInfo apiApiInfo() {
return new ApiInfoBuilder()
//大标题
.title("数据源管理接口远程A调用PI")
//详细描述
.description(
"Service Platform's REST API, all the applications could access the Object model data via JSON.")
//版本
.version("1.0")
.termsOfServiceUrl("NO terms of service")
//作者
.contact(new Contact("desheng.cui", "", "desheng.cui@baifendian.com"))
.license("The Apache License, Version 2.0")
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.build();
}
}
@ Api用于声明Swagger资源API。 它有双重用途 - 它会影响资源列表和_API声明。 只有使用@ Api注释的类才会被Swagger扫描。在资源清单中,注释将转换为[资源对象]。在API声明中,它基本上将作为[API声明]本身的基础。
详解:
@Api()用于类;表示标识这个类是swagger的资源
属性:
tags–表示说明 。
value–也是说明,可以使用tags替代 。
tags="说明该类的作用,可以在UI界面上看到的注解"
实例:
@Api(tags = "区域:/area", description = "地区的增删查改")
@RestController
@RequestMapping(value = "area", produces = {"application/json;charset=UTF-8"})
@ApiResponses(value = {
@ApiResponse(code = 400, message = "系统异常", response = RedisService.class),
@ApiResponse(code = 401, message = "测试异常", response = AreaMapper.class)
})
public class AreaController {
...
}
@ ApiOperation用于在API资源中声明单个操作。 操作被认为是路径和HTTP方法的唯一组合。
只扫描使用@ ApiOperation注释的方法并添加API声明。注释将影响Swagger输出的两个部分,
[API对象],每个路径将创建一个,以及[操作对象],将根据@ApiOperation创建一个。
请记住,在使用Servlet时,@ Api会在设置路径时影响API对象。
详解:
@ApiOperation()用于方法; 表示一个http请求的操作
属性:
value:用于方法描述,说明方法的用途、作用
notes用于提示内容,方法的备注说明
tags可以重新分组(视情况而用)
实例:
@ApiOperation(value = "根据areaId获取地区", notes = "根据url的id来获取地区")
@RequestMapping(value = " {areaId}", method = RequestMethod.GET)
public Map<String, Object> getArea(@PathVariable("areaId") Integer areaId) {
...
}
@ ApiParam仅用于JAX-RS参数注释(@PathParam,@ QueryParam,@HeaderParam,@ FormParam和JAX-RS 2,@ BeanParam)。
虽然swagger-core默认扫描这些注释,但@ ApiParam可用于添加有关参数的更多详细信息,或在从代码中读取时更改值。
在Swagger规范中,这转换为[参数对象]。
Swagger将获取这些注释的value()并将它们用作参数名称,并根据注释设置参数类型。 对于body参数(JAX-RS方法的单个输入参数),名称将自动设置为body(根据Swagger规范的要求)。
如果存在,Swagger还将使用@ DefaultValue的值作为默认值属性。
详解:
@ApiParam()用于方法,参数,字段说明; 表示对参数的添加元数据(说明或是否必填等)
属性:
name–参数名
value–参数说明
required–是否必填
dataType–数据类型 ,默认String,其它值dataType="Integer"
paramType–参数类型
header:请求参数放置于Request Header,使用@RequestHeader获取
query:请求参数放置于请求地址,使用@RequestParam获取
path:(用于restful接口)-->请求参数的获取:@PathVariable
body:(不常用)
form(不常用)
实例:
@ApiImplicitParams({
@ApiImplicitParam(name = "areaName", value = "地区名称", required = true, dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "priority", value = "地区编号", required = false, dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "id", value = "地区id", required = true, dataType = "long", paramType = "query")
})
@RequestMapping(value = "editArea", method = RequestMethod.POST)
public Map<String, Object> editArea(Area area) {
...
}
两个注意点:
@ApiModel:用于响应类上,表示一个返回响应数据的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候)。
详解:
@ApiModel()用于类 ,表示对类进行说明,用于参数用实体类接收
value–表示对象名
description–描述 ,都可省略
实例:
@ApiModel(value = "区域domain",description = "区域的数据库模型")
public class Area {
...
}
详解:
@ApiModelProperty()用于方法,字段 ,表示对model属性的说明或者数据操作更改
value–字段说明
name–重写属性名字
dataType–重写属性类型
required–是否必填
example–举例说明
hidden–隐藏
实例:
@ApiModel(value = "区域domain",description = "区域的数据库模型")
public class Area {
@ApiModelProperty(value = "区域id", required = true, position = 1, example = "1")
private Integer areaId;
@ApiModelProperty(value = "区域名称", required = true, position = 2, example = "北京")
private String areaName;
@ApiModelProperty(value = "区域编号", required = true, position = 3, example = "10001")
private Integer priority;
@ApiModelProperty(value = "添加时间", required = false, position = 4, example = "2017-02-02")
private Date createTime;
@ApiModelProperty(value = "最后修改时间", required = false, position = 5, example = "2017-02-02")
private Date lastEditTime;
}
@ApiIgnore()用于类,方法,方法参数 ,表示这个方法或者类被忽略 (使用比较少)
package com.bfd.common.result;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
/**
* @author zhangke
* @description 通用返回对象
* @date 2019/9/11
* @return
**/
@ApiModel(value = "api接口通用返回对象 ",description = "定义统一的接口返回类型")
public class Result<T> implements Serializable {
/**
* 返回状态码
* 状态码格式为6位数字:101001(201001)
* 第1位:1、系统错误,2、服务错误;2到3位:服务模块(00为公共模块);4到6位:具体错误代码
* 00 公共模块
* 01 Authority
* 02 Workflow
* 03 配置中心
* 04 服务中心
* 05 Ranger
* 06 IDE
* 07 数据接入港
* 08 数据模型
*/
@ApiModelProperty(value="状态码",dataType = "String",required = true)
private String code ;
/**
* 消息
*/
@ApiModelProperty(value="消息",dataType = "String",required = true)
private String msg;
/**
* 数据
*/
@ApiModelProperty(value="实体对象")
private T data;
public Result() {
}
public Result(String msg) {
this.msg= msg;
}
/**
* 获取结果
* @param success
* @param msg
* @param <T>
* @return
*/
public static <T>Result<T> getResult(boolean success, String msg) {
return getResult(success, msg, null);
}
/**
* 获取结果(带返回给前端的数据)
* @param success
* @param msg
* @param data
* @param <T>
* @return
*/
public static <T>Result<T> getResult(boolean success, String msg, T data) {
if(success) {
return new Result(ResultConstant.SUCESS, msg + "成功", data);
} else {
return new Result(ResultConstant.ERROR, msg + "失败",data);
}
}
public Result(String code, String msg) {
this.code = code;
this.msg= msg;
}
public Result(String code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public Result ok(String msg) {
return new Result(msg);
}
public Result ok( String msg,T data) {
return new Result(ResultConstant.SUCESS, msg,data);
}
public Result ok(String code,String msg,T data) {
return new Result(code,msg,data);
}
public Result error(String msg) {
return new Result(msg);
}
public Result error(String code, String msg) {
return new Result(code, msg);
}
public Result error( String msg,T data) {
return new Result(ResultConstant.ERROR, msg,data);
}
public Result error(String code, String msg,T data) {
return new Result(code, msg,data);
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
最重要的一步,以上步骤完全正确,代码也没有问题,可是ui还是不显示属性,必须在接口层强指定泛型类型
(可能是Swagger要求我们写代码要规范吧),
@ApiOperation(value = "1、查询当前微服务的可用数据源类型", notes = "微服务的名字不能为空",position = 1)
@ApiImplicitParams({
@ApiImplicitParam(paramType = "query", dataType = "String", name = "name", value = " 微服务的名字", defaultValue = "data_integration", required = true)})
@GetMapping(value = "/getUsableDatasourceType")
public Result<List<DsDataSourceConfig>> getUsableDatasourceType(String name) {
AssertUtil.isBlank(name, "当前微服务的名字的名字不能为空");
// 查询数据源分页对象
List<DsDataSourceConfig> result = iDsDataSourceConfigService.getUsableDatasourceType(name);
if (CollectionUtils.isNotEmpty(result)) {
// 设置返回值
return new Result<>(ResultConstant.SUCESS, "查询所有数据源的类型成功", result);
} else {
// 设置返回值
logger.error("当前可用数据源为空");
return new Result<>().error(ResultConstant.ERROR, "当前可用数据源类型为空");
}
}
1、官方文档的地址 ;使用参考文档
2、源代码github的地址
3、swagger-bootstrap-ui的项目地址:http://127.0.0.1:8056/doc.html(必须要以 doc.html,如果有权限限制,记得放开扫描)
Springfox-Swagger升级到2.9.2导致的NoSuchMethodError异常
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
原因是Springfox-Swagger中的guava 的版本为 20
<dependency>
<g roupId> com. goog le. guava</groupId>
<a rtifactId>guava</artifactId>
<version>20.0</vers ion>
<S cope>compi le</ scope> .
</dependency>
解决此错误的办法排除低版本的 guava 即可
本文由博客一文多发平台 OpenWrite 发布!
原文:https://www.cnblogs.com/zhangke306shdx/p/12119769.html