前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[Swagger] Springfox Swagger 项目接口自动化管理平台

[Swagger] Springfox Swagger 项目接口自动化管理平台

作者头像
架构探险之道
发布2019-07-25 15:57:17
2.8K0
发布2019-07-25 15:57:17
举报
文章被收录于专栏:架构探险之道架构探险之道

Springfox Swagger 项目接口自动化管理平台搭建准备工作 之 swagger.json在编译期生成

手机用户请横屏获取最佳阅读体验,REFRENCES中是本文参考的链接,如需要链接和更多资源,可百度”Yiyuery”获取

  • CSDN
  • 简书
  • 个人博客地址 同步更新,文章中有对应的参考资源链接。

基于公司项目实战的技术总结和可行性方案分析

接口文档自动化管理方案

编译期生成swagger.json模式

代码语言:javascript
复制
接口打包忽略springfox依赖

获取swagger.json的方式有两种,一种是直接运行组件,在线访问获取文件。另一种是编译期通过mock服务从接口中获取到swagger.json文档。 通过编译生成此文件能够最大化的降低获取文件与组件的运行态依赖,以及能够减少组件不必要的jar包引入

  • swagger-pom

swagger相关maven文件放在公共父层,在parent-pom中,springfox的scope设置为provided,Springfox以及其依赖的jar都不会打进war包中

代码语言:javascript
复制
<!-- swagger begin -->
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
   <version>2.8.0</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
   <version>2.8.0</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>io.swagger</groupId>
   <artifactId>swagger-models</artifactId>
   <version>1.5.14</version>
</dependency>
<!-- swagger end -->
  • base-pom[项目内最外层pom]
代码语言:javascript
复制
<dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger2</artifactId>
</dependency><dependency>
   <groupId>io.springfox</groupId>
   <artifactId>springfox-swagger-ui</artifactId>
</dependency><dependency>
   <groupId>io.swagger</groupId>
   <artifactId>swagger-models</artifactId>
</dependency>
  • SwaggerTest测试类

为了能在编译期生成文件需要增加一个单元测试类来访问Mock出来的组件服务以获取swagger.json文件

代码语言:javascript
复制
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath:*-test.xml"})
  • maven-surefire-plugin

为了能在编译时运行测试类需要增加此插件。该插件配置有文件存放的目录<io.springfox.staticdocs.outputdir>,以及swagger.json访问的地址,以及每个文件的命名,而${project.build.directory}是pom内置属性,默认是/target。配置的swagger.json地址按接口分组来填写,分组几个地址就填写几个,文件名称也是如此</io.springfox.staticdocs.outputdir>

代码语言:javascript
复制
# web-pom<properties>
   ...
   <rest.ui.version>v1</rest.ui.version>
   <rest.api.version>v1</rest.api.version>
</properties>...<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <configuration>
       <systemPropertyVariables>
           <io.springfox.staticdocs.outputDir>${project.build.directory}/swagger</io.springfox.staticdocs.outputDir>
           <io.swagger.json.uris>/v2/api-docs?group=UI,/v2/api-docs?group=API</io.swagger.json.uris>
           <io.swagger.json.output.name>xxx-ui-${rest.ui.version}.json,xxx-api-${rest.api.version}.json</io.swagger.json.output.name>
       </systemPropertyVariables>
   </configuration>
</plugin>

如果组件本身的parent-pom设置了此插件并设置了true则测试类不会运行,得将此设置去除

利用MAVEN生成swagger.json

思路

  • Test中利用Mock生成swagger.json
  • 利用maven-surefire-plugin插件执行
  • 指定执行SwaggerTest.java
  • svn提交代码,jenknis框架通过脚本判断svn代码是否有更新,有更新则拉取副本,执行机通过bat[windows服务器]执行mvn clean install 命令生成文件到项目target/swagger下
  • 创建服务定时拉取swagger.json文件
  • 搭建EasyMock平台,自动提交并生成接口文档
  • 每次变更向接口关注人发送邮件推送接口变更消息

Springfox Swagger配置

  • 打包时跨过springfox相关依赖
  • 执行测试类生成swagger.json

[配置方案]

Mock数据源注入
代码语言:javascript
复制
package com.xxx.controller.common.config;import com.alibaba.druid.pool.DruidDataSource;
import com.xxx.dolphin.resources.synchronize.log.LocalFileLogger;
import org.easymock.EasyMock;
import org.easymock.IMocksControl;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;import javax.sql.DataSource;/**
* <p>
* mock注入SwaggerTest执行所需实例
* </p>
*
* @author xiachaoyang 2018年06月26日 14:03
* @version V1.0
* @modificationHistory=========================逻辑或功能性重大变更记录
* @modify by user: {修改人} 2018年06月26日
* @modify by reason:{方法名}:{原因}
*/
public class BeanMockFactory {   //-- 数据源相关   public DataSource mockDataSource() {
       IMocksControl control = EasyMock.createControl();
       DruidDataSource bean = control.createMock(DruidDataSource.class);
       return bean;
   }   public JdbcTemplate mockJdbcTemplate() {
       IMocksControl control = EasyMock.createControl();
       JdbcTemplate bean = control.createMock(JdbcTemplate.class);
       return bean;
   }   public NamedParameterJdbcTemplate mockNamedParameterJdbcTemplate() {
       IMocksControl control = EasyMock.createControl();
       NamedParameterJdbcTemplate bean = control.createMock(NamedParameterJdbcTemplate.class);
       return bean;
   }   //-- 日志相关   public LocalFileLogger mockLocalFileLogger() {
       IMocksControl control = EasyMock.createControl();
       LocalFileLogger bean = control.createMock(LocalFileLogger.class);
       return bean;
   }   public xxxBusinessLogDao mockxxxBusinessLogDao(){
       IMocksControl control = EasyMock.createControl();
       xxxBusinessLogDao bean = control.createMock(xxxBusinessLogDao.class);
       return bean;
   }
}
SwaggerTest类中配置扫描
代码语言:javascript
复制
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath:*-test.xml"})
public class SwaggerTest {
   ...
}
  • xml中通过mock实现虚拟实例注入
代码语言:javascript
复制
<bean id = "beanMockFactory" class ="com.xxx.web.config.BeanMockFactory"/><bean id="dataSource" factory-method="mockDataSource" factory-bean="beanMockFactory"/><bean id="jdbcTemplate" factory-method="mockJdbcTemplate" factory-bean="beanMockFactory"/><bean id="namedJdbcTemplate" factory-method="mockNamedParameterJdbcTemplate" factory-bean="beanMockFactory"/><bean id="xxxBusinessLogDao" factory-method="mockxxxBusinessLogDao" factory-bean="beanMockFactory"/>
  • 调整xml文件名,确保以-test.xml后缀,并将*-test.xml相关的配置xml直接放在test的resource下
  • 处理mybatis相关的注入[主要是数据源Mock和Mapper的扫描路径检查]
  • 检查xml配置文件间通过import引入的xml是否都是以-test后缀结尾的文件,避免误引
  • 读取本地配置文件后完成的实例注入需要利用BeanMockFactory中完成注入
  • 通过JdbcTemplet自定义完成Dao数据层查询的示例需要通过Mock注入,因为myabtis的扫描不会处理自定义Dao类
  • 静态方法调用(读取配置文件中的变量),需要添加try…catch…异常处理,捕获异常但是不抛出
  • service层未调用,而是通过xml中扫描完成的实例注入可以直接注释或删除
  • AMQ相关的代码中启动未连接则不需要Mock

任务示例

代码语言:javascript
复制
# 任务相关的示例类扫描不要注释,只注释任务的执行计划(如下),避免任务执行<task:scheduler id="xxx_task" pool-size="4"/><task:scheduled-tasks scheduler="xxx_task">
  ...
</task:scheduled-tasks>

线程、监听器等示例

代码语言:javascript
复制
<context:component-scan base-package="com.xxx.notify"/>
<context:component-scan base-package="com.xxx.*.client"/>
<context:component-scan base-package="com.xxx.*.service"/>
<context:component-scan base-package="com.xxx.*.listenter"/>
<context:component-scan base-package="com.xxx.*.thread"/>
代码语言:javascript
复制
只要不是扫描后启动则不需要去注释和Mock,正常扫描即可

LDAP、resource示例

代码语言:javascript
复制
正常扫描,除示例化需要读取配置文件外,其他都不需要处理,读取本地配置文件的需要手动在BeanMockFactory中添加实例mock方法

maven-surefire-plugin

代码语言:javascript
复制
api、core、web层中使用该插件不要配置    <skipTest>true</skipTest> (跳过执行测试用例)
代码语言:javascript
复制
<plugin>  
   <groupId>org.apache.maven.plugins</groupId>  
   <artifactId>maven-surefire-plugin</artifactId>  
   <version>2.5</version>  
   <configuration>  
       <skipTests>true</skipTests>  
   </configuration>  </plugin>
  • web-pom-config
代码语言:javascript
复制
<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <configuration>
       <systemPropertyVariables>
           <io.springfox.staticdocs.outputDir>${project.build.directory}/swagger</io.springfox.staticdocs.outputDir>
           <io.swagger.json.uris>/v2/api-docs?group=UI,/v2/api-docs?group=API</io.swagger.json.uris>
           <io.swagger.json.output.name>xxx-ui-${rest.ui.version}.json,xxx-api-${rest.api.version}.json</io.swagger.json.output.name>
       </systemPropertyVariables>
   </configuration></plugin>
  • parent-pom-config
代码语言:javascript
复制
<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-surefire-plugin</artifactId>
   <configuration>
       <includes>
           <include>**/SwaggerTest.java</include>
       </includes>
   </configuration></plugin>
  • 测试日志
代码语言:javascript
复制
# IDAE MAVEN
mvn clean install# cmd
# 不执行测试用例,但编译测试用例类生成相应的class文件至target/test-classes下。
mvn clean install -Dmaven.test.skip=false
相当于
<plugin>  
   <groupId>org.apache.maven.plugins</groupId>  
   <artifactId>maven-surefire-plugin</artifactId>  
   <version>2.5</version>  
   <configuration>  
       <skip>true</skip>  
   </configuration>  
</plugin># log
target/surefire-reports目录下
com.xxx.web.test.SwaggerTest.txt
阅读日志并解决相关报错,其他无需关注# 正常生成打印日志如下
-------------------------------------------------------------------------------
Test set: com.xxx.web.test.SwaggerTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 11.735 sec

[核心]

代码语言:javascript
复制
- controller和相关数据Dto扫描
- controller中依赖的servcie、task等实例注入类引用(Autowired、Resource等)
- 观察测试日志,解决影响swagger.json生成的报错
配置遇到的问题
  • maven-surefire-plugin插件中skip和skipTests区别 ../../env/maven/2018-06-27-maven-surefire-plugin.md
  • 生成的文档里只有一个license的报错返回日志
代码语言:javascript
复制
{"code":"0x02f10003","msg":"xxx.xxx.license.expire","data":null}
代码语言:javascript
复制
将License相关的拦截器配置注释
代码语言:javascript
复制
<!-- 拦截器 配置多个将会顺序执行 -->
<mvc:interceptors>
   <bean class="com.xxx.common.web.interceptor.HttpServletResponseInterceptor" />
   <bean class="com.xxx.common.web.interceptor.NoCacheInterceptor"/>
<!--<bean class="com.xxx.interceptor.LicenseVaildateInterceptor" />-->
</mvc:interceptors>
  • 无法找到resource下文件夹包裹的xml配偶文件 若非直接放入resource下,而是含有resource/xml/*-test-xml中的xml之类的文件夹,实际执行中会报中间目录找不到的问题
  • 生成swagger的测试类依赖的servlet jar包2.5和3.0版本冲突
代码语言:javascript
复制
# 报错信息java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRequest.getAsyncContext()Ljavax/servlet/AsyncContext;   at org.springframework.test.web.servlet.TestDispatcherServlet.initAsyncDispatchLatch(TestDispatcherServlet.java:88)
   at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:68)
   at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
   at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:160)
   at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:127)
   at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:151)
   at com.xxx.controller.common.test.SwaggerTest.getSwaggerJson(SwaggerTest.java:75)
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
   at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
   at java.lang.reflect.Method.invoke(Method.java:498)
   at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
   at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
   at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
   at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
   at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
   at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
   at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
   at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
   at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
   at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
   at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
   at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
   at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
   at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
   at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
   at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
   at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
   at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
   at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
   at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
   at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
   at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
   at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
代码语言:javascript
复制
原因:   swagger.json生成需要通过mock模拟请求,请求的处理依赖servlet.api的3.0版本的jar包,但是由于maven引用的jar包冲突,虽然项目中存在其他jar包依赖而导入的3.0版本的servlet.api,但项目中配置的基础依赖是基于2.5版本的。实际运行时调用的是2.5版本的。
   可通过在IDEA中的项目lib管理中删除2.5版本的jar包后来执行测试类,实际运行结果是可以生成的,所以核心问题是解决jar包版本冲突。
代码语言:javascript
复制
# 核心错误代码...
import javax.servlet.http.HttpServletRequest;
...final class TestDispatcherServlet extends DispatcherServlet {   ...   private void initAsyncDispatchLatch(HttpServletRequest request) {
           if (request.getAsyncContext() != null) {
               final CountDownLatch dispatchLatch = new CountDownLatch(1);
               ((MockAsyncContext) request.getAsyncContext()).addDispatchHandler(new Runnable() {
                   @Override
                   public void run() {
                       dispatchLatch.countDown();
                   }
               });
               getMvcResult(request).setAsyncDispatchLatch(dispatchLatch);
           }
   }   ...}
代码语言:javascript
复制
分析:   2.5版本的servlet.api中request.getAsyncContext()方法未定义,3.0.1版本中含有该方法,所以需要调整pom依赖引用顺序解决方式:   在测试类所在层web-pom中添加3.0的servlet依赖配置,并将顺序调整至2.5前方。
代码语言:javascript
复制
# web-pom<!-- servlet-api版本依赖声明 -->
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <scope>provided</scope>
</dependency><dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <scope>provided</scope>
</dependency># parent-pom<properties>
   ...
   <servlet-version>2.5</servlet-version>
   <javax.servlet-version>3.1.0</javax.servlet-version>
   ...
</properties><!-- servlet-api版本依赖声明 -->
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>${servlet-version}</version>
   <scope>provided</scope>
</dependency><!-- servlet-api版本依赖声明 -->
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>${javax.servlet-version}</version>
</dependency>

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构探险之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Springfox Swagger 项目接口自动化管理平台搭建准备工作 之 swagger.json在编译期生成
    • 接口文档自动化管理方案
      • 编译期生成swagger.json模式
      • 利用MAVEN生成swagger.json
相关产品与服务
邮件推送
邮件推送(Simple Email Service,SES)是一款基于腾讯云端的平台化服务, 为企业提供安全稳定、简单快速、精准高效的营销、通知和事务邮件的推送服务。产品提供灵活的 IP 部署、电子邮件身份验证以及企业专属定制的启动计划,以保护发件人声誉,同时提供精准智能的数据分析。产品的服务范围覆盖200+国家/地区,可即时触达全球各地的邮箱地址。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档