SpringBoot 项目引入Swagge的使用教程详解

一、Swagge 的介绍

    相信无论是前端还是后端开发,都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新。其实无论是前端调用后端,还是后端调用后端,都期望有一个好的接口文档。但是这个接口文档对于程序员来说,就跟注释一样,经常会抱怨别人写的代码没有写注释,然而自己写起代码起来,最讨厌的,也是写注释。所以仅仅只通过强制来规范大家是不够的,随着时间推移,版本迭代,接口文档往往很容易就跟不上代码了。

    之前一直用 yapi+postman 的形式去完成和测试一整套接口文档,需要花费大量的经历和时间,自从项目引入Swagge 后,才知道Swagge在文档方面的强大之处。

二、spring项目的引入

2.1SpringMvc的整合swagge,需要下面三步

2.1.1、pom 文件引入 jar 包

<!-- 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>

2.1.2、添加配置类

@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;
    }
}

2.1.3、pom 注入配置类的 到 spring

sping-mvc.xml配置一下

<!-- 接口自动化文档,注入 Sawgge 的配置类到 spring中 -->
<bean class="com.pricl.frame.swagger.SwaggerConfig" />
<bean class="com.mangofactory.swagger.configuration.SpringSwaggerConfig" />

2.2、SpringBoot 的整合swagge,pom 文件的引入:

<!-- 引入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>

2.2.2、添加配置类,扫描对应的接口

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();
	}
}

三、Swagge 常用 api 的介绍

3.1@Api

@ 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 {
    ...
}

3.2@ApiOperation

@ 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) {
        ...
    }

3.3、@ApiImplicitParam()和@ApiImplicitParams()

@ 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) {
        ...
    }

两个注意点:

  1. paramType会直接影响程序的运行期,如果paramType与方法参数获取使用的注解不一致,会直接影响到参数的接收。
  2. Conntroller中定义的方法必须在@RequestMapper中显示的指定RequestMethod类型,否则SawggerUi会默认为全类型皆可访问, API列表中会生成多条项目(post和 get)。

3.4@ApiModel

@ApiModel:用于响应类上,表示一个返回响应数据的信息(这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述的时候)。
详解:

@ApiModel()用于类 ,表示对类进行说明,用于参数用实体类接收 
		value–表示对象名 
		description–描述 ,都可省略 

实例:

@ApiModel(value = "区域domain",description = "区域的数据库模型")
public class Area {
     ...
 
}

3.5 @ApiModelProperty()

详解:

@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;
}

3.6、@ApiIgnore()

@ApiIgnore()用于类,方法,方法参数 ,表示这个方法或者类被忽略 (使用比较少)

四、通用类型使用 swagge 的注解

4.1 通用返回类

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, "当前可用数据源类型为空");
		}
	}

五、swagger-bootstrap-ui样式的引入

1、官方文档的地址 ;使用参考文档
2、源代码github的地址
3、swagger-bootstrap-ui的项目地址:http://127.0.0.1:8056/doc.html(必须要以 doc.html,如果有权限限制,记得放开扫描)

六、常见问题的解决

pom 文件的版本问题

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 发布!

posted @ 2019-12-30 14:58  zhangke_shdx  阅读(878)  评论(0编辑  收藏  举报