在分享培训了swagger对于API的设计之后,有一些人问我说:你看,现在咱们前端使用web_API做为mock data在进行测试,后端也有mock 测试。然后我们再进行联调,这之中肯定会出现一些偏差。有没有一种方案是:前端不用写mock数据测试,从一开始,就由后端提供一个在线运行的服务,以此减少后期联调的工作量!   答案是:可以!

当然,在最开始,由于我近期在做API网关的一些工作,我直接简单粗暴的,将swagger的API文档,导入了网关,由网关做了一个mock服务提供。额,现在想来很不负责哈(因为我在做那一块的内容,图省事儿,并没有过多去想当时那个项目的现状),后来想了想,那个项目并不需要专门搭建网关去做这么个服务,并且由于它的架构设计,如果再增加网关服务,会额外增添一些工作量和难度。然后,我看了看笔记,再溜了一圈swagger的网站,得出的解决方案为:

1,利用codegen立即生成可运行的工程

2,直接将服务注册到Dubbo,以供前端使用

备注:公司对于Dubbo这块内容很熟悉了,我主要介绍一下从swagger的API文档,生成可部署工程的过程(其实,这中间还有很多需要进行个人总结,比如嵌入式服务器Jetty,还有我解决一些问题的过程思考和思路总结)!

一、使用swagger Codegen生成可部署工程

这个特别简单,真的特别简单,简单得不能再简单。(当然,我用百度,或者说查到的中文资料,关于从API生成到工程,几乎为零。不过,好在后期集成swagger的还不少,虽然比较复杂)

首先,是看swagger官方对于codegen是怎么说的:https://swagger.io/docs/swagger-tools/#installation-11

然后,再看看具体的命令怎么写:https://github.com/swagger-api/swagger-codegen/wiki/Server-stub-generator-HOWTO

最后,看看对于swagger editor示例中的API,在各种语言下生成的工程示例:https://github.com/swagger-api/swagger-codegen  备注:具体的语言示例路径为:https://github.com/swagger-api/swagger-codegen/tree/master/samples/server/petstore

实例:比如说我用swagger编辑了一个basic API,那么生成JAX-RS(Jersey)的工程命令如下:

java -jar J:\swagger-codegen-cli-2.2.1.jar generate -i "C:\Users\10283_000\Desktop\API lifecycle\Basic.json" -l jaxrs -o jaxrs/jersey2

简单粗暴,然后,运行方式为,在工程的Pom.xml同路径下,执行:mvn jetty:run

然后,没你啥事儿了,开始用吧!  这是一个运行状态的服务,你有两种方式,可以把这个服务变成一个mock service,第一:也就是比较省事儿的,直接在编辑API文档的时候,给设置一个example值; 第二:在这个工程中,设置其指定返回值

这个过程,对于我个人来说,要反思的内容,有点多,额!!!我感觉,很有必要给贴一下代码,再次强调,我只执行了一行命令,别的,我什么都没有做:看看主要的几个点吧(以JAX-RS:Jersey为例):

这是整个项目工程的结构图,所有的代码均是自动生成。开发人员,只需要专注于我用红圈画起来的类的实现就OK了!  其他的一些公共问题,比如说跨域,JSON,异常等,已经被简单处理过。如果要求不是特别高,特别严密,那么直接使用是完全可以的! 再,展示一下关键的类(额,用的swagger API 是我第一次学的时候导出的JSON文件,并不是很完善,吐槽不要太过分)

API接口类:

package io.swagger.api;

import io.swagger.model.*;
import io.swagger.api.ResourcesApiService;
import io.swagger.api.factories.ResourcesApiServiceFactory; import io.swagger.annotations.ApiParam;
import io.swagger.jaxrs.*; import io.swagger.model.Build; import java.util.List;
import io.swagger.api.NotFoundException; import java.io.InputStream; import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam; import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.*; @Path("/resources")
@Consumes({ "application/json" })
@Produces({ "application/json" })
@io.swagger.annotations.Api(description = "the resources API")
@javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaJerseyServerCodegen", date = "2017-08-21T09:59:53.975+08:00")
public class ResourcesApi {
private final ResourcesApiService delegate = ResourcesApiServiceFactory.getResourcesApi(); @POST
@Path("/api/tb-build")
@io.swagger.annotations.ApiOperation(value = "", notes = "新增一个建筑", response = void.class, tags={ "建筑", })
@io.swagger.annotations.ApiResponses(value = {
@io.swagger.annotations.ApiResponse(code = 200, message = "新增建筑成功!", response = void.class), @io.swagger.annotations.ApiResponse(code = 404, message = "找不到API服务", response = void.class), @io.swagger.annotations.ApiResponse(code = 200, message = "未知错误", response = void.class) })
public Response addBuild(@ApiParam(value = "Pet object that needs to be added to the store" ,required=true) Build body
,@Context SecurityContext securityContext)
throws NotFoundException {
return delegate.addBuild(body,securityContext);
}
@GET
@Path("/api/tb-build")
@io.swagger.annotations.ApiOperation(value = "", notes = "获取所有的建筑信息", response = void.class, tags={ "建筑", })
@io.swagger.annotations.ApiResponses(value = {
@io.swagger.annotations.ApiResponse(code = 200, message = "操作成功", response = void.class), @io.swagger.annotations.ApiResponse(code = 404, message = "找不到API服务", response = void.class), @io.swagger.annotations.ApiResponse(code = 200, message = "未知错误", response = void.class) })
public Response getBuild(@ApiParam(value = "Status values that need to be considered for filter",required=true) @QueryParam("buildId") String buildId
,@Context SecurityContext securityContext)
throws NotFoundException {
return delegate.getBuild(buildId,securityContext);
}
}

APIService类:

package io.swagger.api;

import io.swagger.api.*;
import io.swagger.model.*; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import io.swagger.model.Build; import java.util.List;
import io.swagger.api.NotFoundException; import java.io.InputStream; import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext; @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaJerseyServerCodegen", date = "2017-08-21T09:59:53.975+08:00")
public abstract class ResourcesApiService {
public abstract Response addBuild(Build body,SecurityContext securityContext) throws NotFoundException;
public abstract Response getBuild(String buildId,SecurityContext securityContext) throws NotFoundException;
}

APIServiceImpl类:

package io.swagger.api.impl;

import io.swagger.api.*;
import io.swagger.model.*; import io.swagger.model.Build; import java.util.List;
import io.swagger.api.NotFoundException; import java.io.InputStream; import org.glassfish.jersey.media.multipart.FormDataContentDisposition; import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext; @javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaJerseyServerCodegen", date = "2017-08-21T09:59:53.975+08:00")
public class ResourcesApiServiceImpl extends ResourcesApiService {
@Override
public Response addBuild(Build body, SecurityContext securityContext) throws NotFoundException {
// do some magic!
return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
}
@Override
public Response getBuild(String buildId, SecurityContext securityContext) throws NotFoundException {
// do some magic!
return Response.ok().entity(new ApiResponseMessage(ApiResponseMessage.OK, "magic!")).build();
}
}

额,其他具体的,还得自己去看看,也不用自己写,就拿提供的示例看看就行! 有些还是有点区别,比如说JAX-RS(Jersey)这里面用到的是抽象类,而springmvc用的是接口

二、从项目工程集成Swagger生成在线API文档

其实,我很不想说这一点的,因为写这个集成的有很多,我也看了很多,我之所以写它,是因为我感觉我找到的这种方式,是相对比较简单的。代码写完后,集成swagger做基本的文档处理,其实特别简单,简单到只有两步:

第一:在pom文件中,添加依赖(版本的话,你随意)

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

第二:在springmvc的配置文件中,添加对于swagger文档静态资源的访问授权

    <bean class="springfox.documentation.swagger2.configuration.Swagger2DocumentationConfiguration" id="swagger2Config"/>
<mvc:resources location="classpath:/META-INF/resources/" mapping="swagger-ui.html"/>
<mvc:resources location="classpath:/META-INF/resources/webjars/" mapping="/webjars/**"/>

有了这两步之后,就可以得到一个这样的文档

第三步:通过使用swagger的API注解,增添一些额外的注释说明

三、总结

其实,这些东西,都挺容易的。但中间也遇到了一些问题,也包括因为自己主要所在项目是java EE体系的,自己就主要关心、解决java EE这边可能会面临的问题,但对于公司其他项目,相对来说,并不那么上心。这个态度,真是很low啊!

接下来,会总结一些在这个过程之中的一些思维方式,以及遇到的一些问题和解决过程、解决方案!

API生命周期第三阶段:API实施:使用swagger codegen生成可部署工程,择取一个作为mock service的更多相关文章

  1. API生命周期第三阶段:API实施模式,以及结合swagger和项目现状的最佳模式

    这篇博客,主要是宏观介绍一下开发模式,尤其是针对于目前公司前后分离的项目! 一.API实施模式概述 API实施模式,主要是三个,其中API-First又是作为一种指导思想的一种,所以,简单来说事实实施 ...

  2. java EE技术体系——CLF平台API开发注意事项(4)——API生命周期治理简单说明

    文档说明 截止日期:20170905,作者:何红霞,联系方式:QQ1028335395.邮箱:hehongxia626@163.com 综述 有幸加入到javaEE技术体系的研究与开发,也得益于大家的 ...

  3. API生命周期第二阶段——设计:采用swagger进行API描述、设计

    本篇博客主要是以swagger为依托,介绍API生命周期的第二个阶段--设计!在详细介绍之前,我必须声明一点:如果是想了解swagger和项目框架的集成的,这里没有.我要介绍的swagger进行的AP ...

  4. API生命周期

    这一系列的文章,主要是结合了参加Oracle code之后对于API治理的记录收获,以及回到公司后,根据公司目前的一些现状,对此加以实践的过程总结 API生命周期通常包括八个内容,而安全策略贯穿始终. ...

  5. Uber的API生命周期管理平台边缘网关(Edge Gateway)的设计实践

    设计边缘网关(Edge Gateway),一个高可用和高可扩展的自助服务网关,用于配置.管理和监控 Uber 每个业务领域的 API. Uber 的 API 网关的演进 2014 年 10 月,优步开 ...

  6. Uber三代API 生命周期管理平台实现 Uber

    Uber三代API 生命周期管理平台实现 - InfoQ https://www.infoq.cn/article/H8Ml6L7vJGQz0efpWvyJ Uber 三代 API 生命周期管理平台实 ...

  7. Asp.net Mvc 与 Web Api生命周期对比

    完整的生命周期比较复杂,对细节感兴趣的同学可购买老A的图书学习:传送门 本文只简单讲述路由注册.controller创建.action选择的3个主逻辑线,其他的内容大家可自己阅读相应的代码 先上二者单 ...

  8. [译] ASP.NET 生命周期 – ASP.NET 请求生命周期(三)

    使用特殊方法处理请求生命周期事件 为了在全局应用类中处理这些事件,我们会创建一个名称以 Application_ 开头,以事件名称结尾的方法,比如 Application_BeginRequest.举 ...

  9. JAVA面试题 线程的生命周期包括哪几个阶段?

    面试官:您知道线程的生命周期包括哪几个阶段? 应聘者: 线程的生命周期包含5个阶段,包括:新建.就绪.运行.阻塞.销毁. 新建:就是刚使用new方法,new出来的线程: 就绪:就是调用的线程的star ...

随机推荐

  1. javaSe-hashMap

    package com.java.chap08.sec05; public class Student { private String name; private Integer age; publ ...

  2. 洛谷 P2691 逃离

    题目描述 一个n×n栅格是由n行和n列顶点组成的一个无向图,如图所示.用(i,j)表示处于第i行第j列的顶点.除了边界顶点(即满足i=1,i=n,j=1或j=n的顶点(i,j)),栅格中的所有其他顶点 ...

  3. BZOJ 4423: [AMPPZ2013]Bytehattan 并查集+平面图转对偶图

    4423: [AMPPZ2013]Bytehattan Time Limit: 3 Sec  Memory Limit: 128 MB Submit: 277  Solved: 183 [Submit ...

  4. hdparm - 获取/设置硬盘参数

    总览 hdparm [ -a [扇区数] ] [ -A [0|1] ] [ -c [芯片组模式] ] [ -C ] [ -d [0|1] ] [ -f ] [ -g ] [ -i ] [ -k [0| ...

  5. jQuery如何获取选中单选按钮radio的值

    使用jquery获取radio的值,最重要的是掌握jquery选择器的使用,在一个表单中我们通常是要获取被选中的那个radio项的值,所以要加checked来筛选,比如有以下的一些radio项: 1. ...

  6. Win10开机启动项

    键盘输入:win+r 输入命令:shell:startup

  7. javaweb基础(20)_JavaBean总结

    一.什么是JavaBean JavaBean是一个遵循特定写法的Java类,它通常具有如下特点: 这个Java类必须具有一个无参的构造函数 属性必须私有化. 私有化的属性必须通过public类型的方法 ...

  8. gradle更换国内镜像、配置本地仓库地址

    gradle更换国内镜像,安装包解压后init.d文件夹下面创建init.gradle文件,内容如下 allprojects{ repositories { def REPOSITORY_URL = ...

  9. 解决mysql出现的问题#1055 - Expression of SELECT list is not in GROUP BY clause and contains nonaggregated column this i

    最近在学flask, 在访问主页时,一直出现1055错误,在网上找的解决方法是删除ONLY_FULL_GROUP_BY,当时是删除了,但是退出在进行select @@sql_mode时,仍出现ONLY ...

  10. 【python】python安装和运行报错汇总

    本文主要用于汇总在python开发过程中遇到的各种环境.工具相关问题,便于后续遇到相关问题,及时搞定,持续更新. 一.安装pip失败,具体如下: 错误信息: python setup.py insta ...