关于IDEA配置Swagger自动生成API

这年头很流行前后端分离的方式来开发项目,然后我也找了一些有关的资料学习了一下。

前两天学习了一下Swagger自动生成API的方法。然后就有一些自己的总结,感兴趣的可以看看。

我们要了解swagger,我们就要先从前后端分离去入手。按照现在的发展趋势,可以说前后端分离已经是业内对开发和部署方式所达成的一种共识。但是还有很多公司还是采用传统的开发风格,也就是以后端的MVC为主,前端人员只要提供一些静态的HTML页面、JS、CSS、Image等,然后大部分的后端团队担当了大量的开发工作,如后端团队会将前端人员提供的静态素材再配以模板技术如jsp、framemark等,实现项目的开发。在这种一种开发模式下,可以说前端的开发和调试都是需要依赖于后端的web容器的支持,实际上这种开发模式根本无法做到前后端真正的分离

那到底什么是真正的前后端分离呢

如图:关于IDEA配置Swagger自动生成API

真正的前后端分离的方式如上图所示,首先后端开发团队,他们只要专注后端的控制层(Controller层)、服务层(service层)、数据访问层(dao层),整个后台会通过Restful风格的API向前端去提供数据或者讲前端会通过Restful风格的API到后端获取数据

然后后端开发团队,他们只要专注于前端的控制层、视图层。即除了负责前端的静态页面,还需要负责页面上所有的交互代码以及与后端API的交互工作它要对API进行相应的调用,并获取到数据拿到数据后对数据进行相应地处理,将数据在视图层进行相应的展示。最终在前后端分离的模式下,前端可以实现在没有后端API的情况下,还能完美地运行和完美地奔跑。

所以以这样的一种方式形成的前后端分离,无论是在开发上还是在项目部署上都可以说是各自独立且松耦合,这才是真正意义上的前后端分离

         API(Application Programming Interface,应用程序编程接口)是一些预先定义的方法,开发人员只要调用API中所提供的方法就能实现相应的功能,而且开发人员是不用知道方法内部的实现细节

但是前后端分离也是会给我们带来一些问题的

作为一个web项目来说,在前后端分离模式下可以实现项目的独立开发、部署。但是最终还是需要进行前后端集成的,在集成过程中肯定要进行集成测试以及接口的联调。但是这个集成往往都是令人头痛的问题。

         问题比如在最后集成的时候才发现,最开始设计商量好的数据结构发生了变化,而且这种变化是在所难免的,这样的话,前后端人员在集成的时候肯定要花费大量的时间去集成

         产生这样的问题的原因是前后端人员无法做到及时协商、尽早解决。那么怎么才能保证我们前后端人员在开发的过程中不至于分道扬镳、越走越远呢?

         解决方案首先定义schema(方案/计划),并实时跟踪最新的API,降低集成风险

         即后端主要是开发API,再根据已经定义好的schema来进行数据测试。那么前端团队在开发前端工程当中,也会按照schema来做这个mock数据(模拟的假数据)用进行相应的测试。这样才能达到这个工作的正常进行。

         但是这个schema并不是在开始设计好后就不能被修改,是有可能会修改的,比如当需求有变化或者是一开始的设计并不是十分合理,可能考虑得并不是十分周到。我们肯定在后期会对schema做一定的修改,那么在修改的过程中我们要做的是什么?是前后端双方都必须实时跟踪最新的API,如果是实时跟踪那么可能出现这样的问题,比如后端团队修改schema生成最新的API,然后因为前端人员没能及时跟踪最新的API,导致前端人员还是拿着旧的API来进行相应的mock数据的测试以及相应的API接口的调用,那么最后集成的时候肯定会出现问题

  1. Swagger简介

         swagger是一个自动生成API说明文档的工具,帮助我们更好地实现前后端分离。swagger号称是全球最流行的API框架,官方的说法是swagger是一个规范的完整的框架,主要是用于生成、描述和调用以及可视化的Restful风格的WEB服务,它是一个既简单又强大的Restful API文档在线自动生成器。另外还有如下特点

  1. 它支持API文档与API定义同步更新的特点,即当API有了变化那么API的说明文档也会随之发生变化
  2. 它可以直接运行,并且能够在线测试API接口。这是因为它提供了Swagger UI这样的界面,供我们进行API接口的测试。4
  3. 它是支持多种语言(比如:JavaPHP)

         Swagger的官网:https://swagger.io/ 有兴趣的同学可以去浏览一下,爱旅行项目中就是使用swagger去自动生成API描述文档。

2.在项目中集成swagger自动生成API文档

  1. Swagger版本

       我们爱旅行是一个SSM项目,那么项目是如何集成Swagger呢?Spring提供了与Swagger集成的工具包叫springfox,springfox它可以让SSM项目与swagger更好地集成。官方提供了两个版本让项目去集成swagger:

  1. 第一个版本:springfox-swagger2 (新版本)
  2. 第二个版本:swagger-springmvc (老版本)

 

3.Spring集成Swagger之项目环境

  1. 项目环境
  2. 项目环境
    1. JDK1.8   一定要jdk1.8,不然跑不起swagger (可不用卸载之前1.7jdk)

                            上传jdk-8u11-linux-x64.tar.gz的安装包,命令tar -zxvf -C /usr/local/java解压,                       之后配置环境变量

  1. 命令:vim -r /etc/profile ,即对profile文件进行编辑,
  2. 在profile文件中输入下面的命令

#set java environment

JAVA_HOME=/usr/local/java/jdk1.8.0_11   #jdk1.8.0_11 jdk的版本

CLASSPATH=.:$JAVA_HOME/lib.tools.jar

PATH=$JAVA_HOME/bin:$PATH

export JAVA_HOME CLASSPATH PATH

  1. 命令:source /etc/profile ,对profile文件进行重新加载(让配置起效果)。
    1. Spring4.1.7
    2. Mybatis3.2.2
        1. SpringMVC集成springfox-swagger2构建Restful API
  1. Maven依赖
    • springfox-swagger2
    • springfox-swagger-ui
    • guava
    • mapstruct-jdk8
    • Jackson   因为数据都是json格式,所以要加入json的依赖。

                            - Jackson-core

                            - Jackson-databind

                            - Jackson-annotations

4.Spring集成Swagger之配置步骤

  1. 在pom.xml文件中添加Swagger2相关的依赖

         相关依赖如下所示。

<!--START ======= Swagger所需要的依赖包======= START-->
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.4.0</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.4.0</version>
</dependency>
<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>19.0</version>
</dependency>
<dependency>
  <groupId>org.mapstruct</groupId>
  <artifactId>mapstruct-jdk8</artifactId>
  <version>1.1.0.Final</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.8.7</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.8.7</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
  <version>2.8.7</version>
</dependency>

<!--END ======= Swagger所需要的依赖包======= END-->

Spring4.1.7所需要的依赖库如下:

<!--START =====  Spring4.1.7所需要的依赖 ===== START-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>4.1.7.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context-support</artifactId>
  <version>4.1.7.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-oxm</artifactId>
  <version>4.1.7.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-tx</artifactId>
  <version>4.1.7.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-orm</artifactId>
  <version>4.1.7.RELEASE</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jms</artifactId>
  <version>4.1.7.RELEASE</version>
  <scope>compile</scope>
</dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>4.1.7.RELEASE</version>
      <scope>compile</scope>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>4.1.7.RELEASE</version>
      <scope>test</scope>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.1.7.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>4.1.7.RELEASE</version>
  </dependency>
  <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>4.1.7.RELEASE</version>
  </dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>4.1.7.RELEASE</version>
  <scope>compile</scope>
</dependency>
<!--END =====  Spring4.1.7所需要的所有依赖 ===== END-->

 需要的jar包比较多,建议大家在网络好的时候再导入Maven进行自动下载 

5.配置类:SwaggerConfig.java(官网下载)

@ComponentScan:设置Swagger扫描包

@EnableSwagger2:使用Swagger2生效

@Configuration:自动在本类上下文加载一些环境变量信息 记得加包的扫描    

        

         SwaggerConfig.java类的关键代码如下所示。

@EnableSwagger2
@Configuration
public class SwaggerConfig extends WebMvcConfigurationSupport {
   
/**
     * 创建API应用
     * apiInfo() 增加API相关信息
     * 通过select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现,
     * 本例采用指定扫描的包路径来定义指定要建立API的目录。
     */
    @Bean
   
public Docket createRestApi() {
       
return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage(
"cn.appsys.controller"))
                .paths(PathSelectors.any())
                .build();
    }

   
/**
     * 创建该API的基本信息(这些基本信息会展现在文档页面中)
     * 访问地址:http://ip:port/swagger-ui.html
     */
    private ApiInfo apiInfo() {
       
return new ApiInfoBuilder()
                .title(
"") //标题。
                .termsOfServiceUrl("http://127.0.0.1:8080/swagger-ui.html")
                .contact(
""//开发团队名称
                .version("")   //版本
                .build();
    }
}

 

SpringMVC配置文件

<mvc:default-servlet-handler/>

添加指定扫描:<context:component-scan/>

 

         1)      在SSM项目中的springmvc-servlet.xml配置文件中加入<mvc:default-servlet-handler/>,它主要的作用是防止js、css、image等静态资源读取不到进而报404错误,因为是SpringMVC是通过DispatcherServlet去拦截所有的请求,同时js、css、image这样的静态资源也会被拦截。SwaggerUI的项目都是静态资源,所以Restful形式的拦截方式会将静态资源进行相应的拦截处理。所以在springmvc或spring的配置文件中需要配置对静态文件的处理方式。就需要加入<mvc:default-servlet-handler/>的配置。

         2) <context-component-san backpage=”cn.appsys.controller”>它会对cn.appsys.controller下的所有包进行扫描所有的类,让这些类上标注的关于swagger注解生效。而且API扫描文档也会进行及时更新。

<!--START ==== 添加Spring集成Swagger所需要的配置 ==== START-->
<mvc:default-servlet-handler/>
<context:component-scan base-package="cn.appsys.controller">
   <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
   <context:include-filter type="annotation" expression="org.springframework.context.annotation.Configuration"/>
   <context:include-filter type="annotation" expression="org.springframework.scheduling.annotation.Scheduled"/>
</context:component-scan>
<!--END ==== 添加Spring集成Swagger所需要的配置 ==== END-->

 

  1. 在API中加入Swagger

         在各类的配置完成之后,怎么在页面上显示API接口的描述性注释呢?那么就要在API中加入Swagger。如何在API中加入Swagger呢?可以通过在API上添加注解实现API文档的同步效果具体的注解如下。

  1. @Api

                   表明可供Swagger展示的接口类(多用在Controller类上面)

                   tags=”说明该类的作用,非空时将覆盖value的值”。

                   value=”描述类的作用”

                   basePath=”基本路径”,基本路径可不配置,在Swagger1.5   版本后不再支持。

  1. @ApiOperation

       描述API方法(用在方法上面)

  1. value=”说明方法的用途、作用”
  2. httpMethod 指定HTTP请求的方式,GET/POST等。
  3. produces  设置MIME类型列表,如application/json,application/xml等。
  4. notes  接口发布说明
  5. protocols  设置特定协议,如http、https等。
  6. response  响应类型(即返回对象)
  1. @ApiParam

                   单个参数描述(方法中的参数只有加了@ApiParam注解才能生成中文的描述)

                   :上面三个注解在下面示例一中得到体现。

  1. @ApiModel

                   在请求的方法中如果是以对象作为入参时,可使用注释@RequestBody 对象类型    参数名。如@RequestBody Users users,然后如果想在SwaggerUI中看出这个对象属性的      详细描述就可以使用两个注解,分别是@ApiModel、@ApiModelProperty。

                   其中@ApiModel注解是写到实体类上面

  1. @ApiModelProperty

         该注解写到实体类中的属性上面,用来定义属性的详细信息(注释)。

                   :第4、5个注解在下面示例二、三中得到体现。

   

         示例一如下所示。

// 在修改appinfo过程中,当点击[删除]链接跳转到当前方法中。  在修改appinfo时,删除LOGO图片
@ApiOperation(
      value="根据appinfo主键的id查询appinfo详情对象信息,将此对象中的LOGO图片删除",
      httpMethod = "GET", protocols = "HTTP",produces = "application/json",
      response = Object.class,
      notes="<p>返回的值是一个Map集合,key都为result,值的取值如下/p>" +
            "<p>value='failed' 表示删除失败!</p>" +
            "<p>value='success' 表示删除成功!</p>" +
            "<p>value='noexist' 表示要删除的LOGO图片不存在!</p>" )
@RequestMapping(value = "/delfile", method = RequestMethod.GET)
@ResponseBody
public Object delfile(
      @ApiParam(required = true, name="id" ,value="appinfo主键的id")
      @RequestParam("id") Integer id) {// idappinfo的主键id
  
Map<String, String> map = new HashMap<String, String>();
   if (id == null) {
      map.put("result", "failed"); // 删除失败
  
} else {
   }
   return map;
}

        

         示例二的代码:

// 负责完成最终的新增app基础信息操作
@ApiOperation(
      value="负责完成最终的新增app基础信息操作",protocols = "HTTP",
      response = String.class, httpMethod = "GET",
      notes = "调用业务层的insertAppInfo方法返回int类型值,取值分别是:" +
            "<p>result > 0时,新增成功跳转到app列表信息页面</p>" +
            "<p>否则,新增失败又跳转回新增页面</p>" )
@RequestMapping("/appinfoaddsave")
public String appAddSave(HttpSession session, HttpServletRequest request,
      @RequestBody AppInfo appInfo, Model model,
      @RequestParam("a_logoPicPath") MultipartFile attach) {
 
   int result = deveAppInfoService.insertAppInfo(appInfo);
   if (result > 0) {
      return "redirect:/dev/appinfo/list"; // 新增成功跳转到app列表信息页面
  
} else {
      return "developer/appinfoadd"; // 新增失败又跳转回新增页面
  
}
}

        在示例二代码中如果ajax请求方法中是以对象作为入参时,可使用注释@RequestBody,然后再到这个注解所对应的对象类型的实体类中加入相关注解,如示例三所示。如此就可以在SwaggerUI界面右下角的Model选项卡中就可以看出对象中属性的详细信息

         示例三的代码:

@ApiModel(value="AppInfo", description = "App信息实体类")
public class AppInfo {

   @ApiModelProperty("【必填】Appid")
   private Integer id;//主键id

  
@ApiModelProperty("【必填】软件名称")
   private String softwareName;//软件名称

  
@ApiModelProperty("【必填】APK名称")
   private String APKName;//APK名称

  
@ApiModelProperty("【必填】支持ROM")
   private String supportROM;//支持ROM

  
@ApiModelProperty("【必填】界面语言")
   private String interfaceLanguage;//界面语言

  
@ApiModelProperty("【必填】更新日期")
   private Date updateDate;//更新日期

  
@ApiModelProperty("【必填】软件大小(单位:M")
   private BigDecimal softwareSize;//软件大小(单位:M

  
@ApiModelProperty("【必填】开发者id")
   private Integer devId;//开发者id

  
@ApiModelProperty("【必填】应用简介")
   private String appInfo;//应用简介

  
@ApiModelProperty("【必填】app状态id")
   private Integer status;//app状态id

  
@ApiModelProperty("【必填】上架时间")
   private Date onSaleDate;//上架时间

 

      1. 访问Swagger界面

         访问Swagger界面URL:http://IP:port/项目名/swagger-ui.html。

        

         准备工作:将App信息管理平台项目的相关代码编写完后,打成war包,然后发布到linux系统上的tomcat中,启动tomcat后,http://IP:port/项目名/swagger-ui.html进行访问。

         如果出现上面这种情况,swagger2与fastjson兼容的问题具体因为springmvc-servlet.xml文件中使用fastJsonHttpMessageConverter导致swagger2 解析json失败

         方式一:升级fastjson的jar包版本。

<dependency>

  <groupId>com.alibaba</groupId>

  <artifactId>fastjson</artifactId>

  <version>1.2.31</version>

</dependency>

         方式二:自定义fastjson转换器。步骤如下:

  1. 自定义的fastJosn转换器——FastJsonHttpMessageContextEx,具体代码如下。

public class FastJsonHttpMessageConverterEx extends FastJsonHttpMessageConverter {

    public FastJsonHttpMessageConverterEx() {
        super();
        this.getFastJsonConfig().getSerializeConfig().put(Json.class, SwaggerJsonSerializer.instance);
    }
}

 

  1. SwaggerJsonSerializer中具体代码如下。

public class SwaggerJsonSerializer  implements ObjectSerializer, ObjectDeserializer {
    public final static SwaggerJsonSerializer instance = new SwaggerJsonSerializer();

    @Override
   
public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
        SerializeWriter out = serializer.getWriter();
        Json json = (Json) object;
        out.write(json.value());
    }

    @Override
   
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
        return null;
    }

    @Override
   
public int getFastMatchToken() {
        return 0;
    }
}

 

  1. 修改springmvc-servlet.xml中的代码,把原来的FastJsonXXX替换成新下定义的。

 

<!-- 配置FastJson的消息转换器来解决 JSON数据传递过程中的日期格式问题 -->
<bean
  
class="cn.appsys.tools.FastJsonHttpMessageConverterEx"
>
   <property name="supportedMediaTypes">
      <list>
         <value>text/plain;charset=UTF-8</value>
         <value>text/html;charset=UTF-8</value>
         <!-- 设置当前 消息转换器的编码格式为UTF-8,原来是ISO-8859-1 text/html;charset=UTF-8 -->
        
<value>application/json;charset=UTF-8</value>
      </list>
   </property>
   <property name="features">
      <list>
         <!-- 让当前json数据中的日期格式采用FastJson默认的日期格式(yyyy-MM-dd HH:mm:ss) -->
        
<value>WriteDateUseDateFormat</value>
      </list>
   </property>
</bean>

         修改后,将springmvc-servlet.xml单独上传,之后再重启下tomcat进行访问。

         如果出现下面这种界面,那么一定是SwaggerConfig类中createRestApi()方法backPacke写错或没有写

关于IDEA配置Swagger自动生成API

         修改完后,最终的效果如下图所示。

关于IDEA配置Swagger自动生成API

 

         问题:在生产环境下为了服务器的安全,在服务器端口这块一般只开放80端口,关于tomcat的端口都不能开放,即通过Tomcat无法访问Swagger。那么在生产环境下,怎么访问Swagger呢?       

         解决方案

         通过Nginx进行Swagger的访问,修改nginx.conf,之后再通过URL进行访问:http://IP/{contenxt-path}/swagger-ui.html

         步骤:编辑nginx.conf,nginx.conf文件中的root以及location所涉及到的静态工程给注释掉。之后使用http://域名或IP/swagger-ui.html进行访问。

                   在nginx.conf文件中注解掉location与root所关联的静态资源之后,重启nginx、      tomcat, 再去访问。

关于IDEA配置Swagger自动生成API

 

注:最后附带一个我已经搞好的项目,感兴趣的博友可以去我的主页找一找,名字叫作AppInfoSystem。