zoukankan      html  css  js  c++  java
  • 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 发布!

  • 相关阅读:
    C++中的向量学习
    delphi中判断popupmenu的弹出来源....
    在QT4中使用类似QVBox类似功能
    flex控件的学习网站(收藏)
    总结Flash XMLSocket 通信问题
    Fiddle扩展HttpPing批量检测web服务器是否正常
    flex的Socket通讯沙箱和安全策略问题
    .Net平台开源作业调度框架Quartz.Net
    IE6 7 select option设置disabled无效
    Flex值得一看参考资源
  • 原文地址:https://www.cnblogs.com/zhangke306shdx/p/12119769.html
Copyright © 2011-2022 走看看