在分享培训了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. 2017.10.7 QBXT 模拟赛

    题目链接 T1 容斥原理,根据奇偶性进行加减 #include<iostream> #include<cstdio> using namespace std; typedef ...

  2. SpringMVC-请求参数的绑定

    绑定的机制 表单提交的数据都是k=v格式的 username=haha&password=123 SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的 要求 ...

  3. centos7-vsftpd文件服务器

    FTP简介: 文件传输协议(File Transfer Protocol,FTP),基于该协议FTP客户端与服务端可以实现共享文件.上传文件.下载文件. FTP 基于TCP协议生成一个虚拟的连接,主要 ...

  4. oracle 数据导到 sql server

    方法一: navicate:用法比较简单,选择工具-数据传输就可以了.目前测试了下暂时没遇到什么问题. 方法二: Microsoft SQL Server Migration Assistant 8. ...

  5. java中异常处理机制 throw抛出自定义业务逻辑异常 throws继续抛出 catch捕获后会自动继续抛向调用方法

    package com.swift; public class Exception_TestC { public static void main(String[] args) { /* * 第5题: ...

  6. VC下的C语言程序随机数的产生

    本文章适用于VC编译器,VC编译器里有个rand()函数,我们用它来实现取随机数. #include <stdio.h> #include<stdlib.h> //随机数的头文 ...

  7. 【网络基础】【TCP/IP】私有IP地址段

    私有IP地址段 Class A:10.0.0.0    - 10.255.255.255 Class B:172.16.0.0  - 172.31.255.255 Class C:192.168.0. ...

  8. 双击内容变input框可编辑,失去焦点后修改的数据异步提交

    <html> <head> <meta charset="utf8"> <script src="https://cdn.boo ...

  9. Python 成长之路

    Python roadmap python 基础 ... 内置常用函数.三元运算.递归 迭代器和生成器 模块和常用的模块 面向对象 对向对象进阶 网络编程 并发编程 ... 数据库 MySQL pym ...

  10. Can Japan stand up to US request to contain China?

    From Global Times Two days before US President Donald Trump's visit to Japan, A fake news story caug ...