一、Swagger简介

 

1、为什么要用Swagger

  • 在平时开发中,一个好的API文档可以减少大量的沟通成本,还可以帮助新加入项目的同事快速上手业务。大家都知道平时开发时,接口变化总是很多,有了变化就要去维护,也是一件比较头大的事情。尤其是现在前后端分离情况,更容易造成文档和代码不一致。这时,我们可以通过Swagger2来使接口规范,方便维护。
  • springBoot作为微服务首选框架,为其他服务提供大量的接口服务。接口对接方需要实时最近的接口文档。
  • swagger可以通过代码和注释自动为web项目生成在线文档,这里使用swagger。

swagger官网地址:https://swagger.io/
 

2、Swagger简介

  • Swagger是一款Restful接口的文档在线自动生成和功能测试功能软件。
  • Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化Restful风格的Web服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。

 
 

二、Springboot整合Swagger

 

1、项目结构

微服务集成seata_API

 

2、Swagger依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>

依赖说明

  • springfox-swagger2:
    检测spring的web请求信息,生成检测结果(json格式)。
  • springfox-swagger-ui:
    根据springfox-swagger2生成的数据,生成可视化的友好页面。

 
 

3、创建swagger的配置类:

Springfox提供Docket对象,为其设置相关属性,将其注册成为spring的bean后,可以在接口文档中展示(可配置多个Docket的bean,对应不同分组的接口)

package com.liupy.uman.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * swagger配置类:
 * 1、@EnableSwagger2的作用是启用Swagger2相关功能。
 * 2、Docket对象包含三个方面信息:
 *      1. 整个API的描述信息,即ApiInfo对象包括的信息,这部分信息会在页面上展示。
 *      2. 指定生成API文档的包名。
 *      3. 指定生成API的路径。
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    /**
     * 创建一个bean并初始化
     */
    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                //是否开启 (true 开启  false隐藏。生产环境建议隐藏)
                //.enable(false)
                .select()
                //扫描的路径包,设置basePackage会将包下的所有被@Api标记类的所有方法作为api
                .apis(RequestHandlerSelectors.basePackage("com.liupy.uman.controller"))
                //指定路径处理PathSelectors.any()代表所有的路径
                .paths(PathSelectors.any())
                .build();

    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                //设置文档标题(API名称)
                .title("SpringBoot中使用Swagger2接口规范")
                //文档描述
                .description("接口说明")
                //服务条款URL
                .termsOfServiceUrl("http://localhost:8089/")
                //版本号
                .version("1.0.0")
                .build();
    }
}

 

说明:

  • @Configuration注解,配置文件,就不多解释了。
  • @EnableSwagger2的作用是启用Swagger2相关功能。
  • Docket对象包含三个方面信息:
    1、整个API的描述信息,即ApiInfo对象包括的信息,这部分信息会在页面上展示。
    2、指定生成API文档的包名。
    3、指定生成API的路径。

 

4、控制器(controller)中代码

package com.liupy.uman.controller;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import com.liupy.uman.dto.ImportSuggestInfoDto;
import com.liupy.uman.dto.SuggestExportDto;
import com.liupy.uman.dto.SuggestionDto;
import com.liupy.uman.service.SuggestService;
import com.liupy.uman.utils.*;
import com.liupy.uman.vo.SuggestVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONArray;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/suggest")
/**说明接口文件*/
@Api(value = "优化建议接口", tags = "优化建议接口相关的接口", description = "优化建议接口")
public class SuggestController {

    @Autowired
    private SuggestService suggestService;

    /**
     * 查询优化建议列表
     */
    @PostMapping("/suggest")
    //方法参数说明,name参数名;value参数说明,备注;dataType参数类型;required 是否必传;defaultValue 默认值
    @ApiImplicitParam(name = "suggestList", value = "查询优化建议列表")
    //说明是什么方法(可以理解为方法注释)
    @ApiOperation(value = "查询优化建议列表", notes = "查询优化建议列表")
    public JsonResult SaveSuggestion(@RequestBody Map<String, Object> map) {
        JsonResult jr;
        try {
            jr = suggestService.SaveSuggestion(map);
        } catch (Exception e) {
            jr = new JsonResult("-1", "操作失败");
        }
        return jr;
    }  
}

 
接口配置:
通过在控制器和接口方法上加上相关注解,可以给接口和控制器添加相关的接口说明信息。

常用注解如下:

注解

使用的地方

用途

@Api

类/接口

描述类/接口主要用途

@ApiOperation

方法

描述方法的用途

@ApiImplicitParam

方法

用于描述接口的非对象参数

@ApiImplicitParams

方法

用于描述接口的非对象参数集

@ApiIgnore

类/方法/参数

Swagger 文档不会显示拥有该注解的接口

@ApiModel

参数实体类

可设置接口相关实体的描述

ApiModelProperty

参数实体类属性

可设置实体属性的相关描述

 

5、Swagger页面访问

因为我本地项目的配置访问路径如下:

server:
  port: 8089
  servlet:
    context-path: /liupy/umanapi

所以,swagger的访问路径为

http://localhost:8089/liupy/umanapi/swagger-ui.html

微服务集成seata_微服务集成seata_02

微服务集成seata_微服务集成seata_03

 

1、点击需要测试的接口方法,如图

微服务集成seata_spring_04

 

 

2、可以看到接口需要的参数,请求地址及接口说明信息。点击右上角的Try it out即可对接口进行测试。

微服务集成seata_restful_05

 

 

3、查询结果:

微服务集成seata_spring boot_06


 

 

 

三、解决jar包冲突:

springboot整合swagger2的时候,启动报错:
 

1、报错信息如下:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-10-12 19:21:38.196 [restartedMain] ERROR o.s.b.d.LoggingFailureAnalysisReporter - 

***************************
APPLICATION FAILED TO START
***************************

Description:

An attempt was made to call a method that does not exist. The attempt was made from the following location:

    springfox.documentation.spring.web.scanners.ApiListingScanner.scan(ApiListingScanner.java:117)

The following method did not exist:

    com.google.common.collect.FluentIterable.append(Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable;

The method's class, com.google.common.collect.FluentIterable, is available from the following locations:

    jar:file:/D:/myrepository/repository2/com/google/guava/guava/16.0.1/guava-16.0.1.jar!/com/google/common/collect/FluentIterable.class

The class hierarchy was loaded from the following locations:

    com.google.common.collect.FluentIterable: file:/D:/myrepository/repository2/com/google/guava/guava/16.0.1/guava-16.0.1.jar

 
从上述报错信息可得:

在项目启动的时候报错了,接着往下,可以看到是guava-16.0.1.jar这个包出现了冲突!!!

 

2、解决方案:

既然是jar包冲突,那么我们把冲突解决掉就可以了。分析冲突如下:
1、在父工程中引入swagger2依赖,在该swagger2中有一个guava的依赖,是20.0的版本;
2、在父工程中还有easypoi的依赖,该依赖中也有一个guava的依赖,并且它是16.0.1版本的;
3、综上,是这个guava jar包出现了冲突,导致启动失败!!

 

冲突的依赖如下图:

微服务集成seata_spring_07

微服务集成seata_spring boot_08


 

 

方案一:第一声明原则:pom.xml文件中,按照从上至下的顺序,哪个jar包的坐标在上面,这个jar包就是先声明的。先声明的jar包坐标下的依赖jar包,可以优先进入项目。

比如:easypoi、swagger2依赖下都有guava jar包,easypoi中的是16.1.0版本,swagger2中的是20.0版本,由于swagger2使用低版本的会报错,那么就将swagger2的依赖放在easypoi依赖的前面,这样,swagger2中guava.20.0版本的依赖包会先进入项目。

微服务集成seata_restful_09

 
 
方案二:直接排除法

将冲突的jar包排除掉。

微服务集成seata_微服务集成seata_10

 
 

四、SpringSecurity中配置:

如果Spring Boot项目中集成了Spring Security,接口会被拦截,需要在Spring Security的配置类中重写configure方法,对接口进行过滤一下。代码如下:

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring()
            .antMatchers("/swagger-ui.html")
            .antMatchers("/v2/**")
            .antMatchers("/swagger-resources/**");
}