x-http-wrapper: 如何解决每次发版时,修改http相关代码造成的错误!(Android、iOS、h5)

其实是我做了个开源工具(^__^),拿出来给大家鉴赏下,欢迎大家提意见

项目:https://github.com/xuyt11/x-http-wrapper 欢迎关注和star 。

功能:这是一个http相关代码的创建工具。

现在我们每一次发版,基本上都会涉及到http相关的修改,以此来满足发版的业务需求。

而在其中需要添加或修改的有http request、http request param、http response entity等其他相关的http代码。

而在多次的修改中,若前后端没有协调好,就有可能会造成之后的返工、重复修改与线上bug量的增加等问题。

现在的痛点

如何解决每次发版时,都需要新增、修改http相关代码!

如何解决每次发版时,修改http相关代码造成的错误!

解决思路:规范

其实很简单,就是一个词“规范”,任何事情,只要我们有了一定的规范,就会有一定的流程、可追踪并且降低难度。

我相信99.99%的公司,都会有相关的http接口文档提供给前端同学,而且也会自己的一套规范(不论是我现在依赖的apidocjs,还是上家公司的doc文件)。

当然,肯定也有口头约定的情况,但这需要在之后,立即将约定转化为文档,提供给前端的同学。git、http都可以作为提供的形式。

我们依赖这个http的规范,就可以将http接口文档去解析转义为x-http-wrapper内部的API数据。

再来就是依赖一定的规范(x-http-wrapper的模板文件规范),将内部API数据转化为http相关文件。这样,每次只要接口文档更新过后,我们就可以根据文档生成各个程序内部可以运行的代码。

这个功能与现在IDE中的getter、setter方法生成器功能其实是相同的原理!

x-http-wrapper介绍

这是一个http相关代码的创建工具。

现在能创建的http相关的文件类型有:http请求分类,http请求,请求方法参数,响应实体,响应实体中状态码列表和基础响应实体类。

HttpApi(http请求分类): 所有API请求的统一调用入口,统合所有的请求类别的接口,防止API接口分散。

public class HttpApi {

private static Account account;

private static Data data;

public static Account account() {

if (null == account) {

account = Account.getInstance();

}

return account;

}

public static Data data() {

if (null == data) {

data = Data.getInstance();

}

return data;

}

}

Request(http请求): 单个请求分组中,所有的请求方法。

public class Account extends BaseApi {

public static Account getInstance() {

return Helper.instance;

}

private static class Helper {

public static final Account instance = new Account();

}

private Account() {

super();

}

/**

* @version 2.0.0

* @requestUrl

* @title 初始化账号信息

*

*/

public RequestHandle init(Context cxt001,

ResponseHandlerInterface response) {

// hide implementation

}

/**

* @version 2.0.0

* @title 扫二维码到 web 端进行操作

*

* @param context String desc

* @param project_id isOptional Integer desc

* @param scene isOptional String desc

* @param uuid_rand String desc

*/

public RequestHandle qrcodeConfirm(Context cxt001,

String context, Integer project_id, String scene, String uuid_rand,

ResponseHandlerInterface response) {

// hide implementation

}

/**

* 缩略请求方法

*/

public RequestHandle qrcodeConfirm(Context cxt001,

QrcodeConfirmRP.Parameter parameter,

ResponseHandlerInterface response) {

return qrcodeConfirm(cxt001,

parameter.context, parameter.project_id, parameter.scene, parameter.uuid_rand,

response);

}

}

RequestParam(请求方法参数): 请求参数分组归类,对应单个请求,用于请求参数较多的情况,生成请求参数的分类实体类(请求参数也肯能有多个分类),减少请求方法的输入参数。

/**

* 请求方法参数

*/

public class QrcodeConfirmRP implements Serializable {

public static final class Parameter implements Serializable {

/**

* type: String

* isOptional : false

* desc:

扫码场景,枚举值

*/

public String context;

/**

* type: Integer

* isOptional : true

* desc:

业务参数: 根据 context 的不同而不同

*/

public Integer project_id;

/**

* type: String

* isOptional : true

* desc:

身份信息: 服务端会优先使用客户端传入的身份信息,当为”投资人“的时候必传

*/

public String scene;

/**

* type: String

* isOptional : false

* desc:

从二维码扫描得到的唯一码

*/

public String uuid_rand;

}

}

Response(响应实体): 请求的相应数据model

public class Init {

private long member_id;

private long member_role;

private long member_status;

private String ry_token;

private long step;

public long getMemberId() {return member_id;}

public long getMemberRole() {return member_role;}

public long getMemberStatus() {return member_status;}

public String getRyToken() {return ry_token;}

public long getStep() {return step;}

public void setMemberId(long member_id) {this.member_id = member_id;}

public void setMemberRole(long member_role) {this.member_role = member_role;}

public void setMemberStatus(long member_status) {this.member_status = member_status;}

public void setRyToken(String ry_token) {this.ry_token = ry_token;}

public void setStep(long step) {this.step = step;}

}

StatusCode(响应实体中状态码列表): 响应中所有状态码的枚举类

public class StatusCode {

/** '') */

public static final int OK = 0;

/** '登录状态已过期,请重新登入') */

public static final int UNAUTHORIZED = 101;

/** '您没有权限查看') */

public static final int FORBIDDEN = 102;

/** '资源未找到') */

public static final int NOT_FOUND = 103;

/** '客户端请求错误') # 4XX客户端错误 */

public static final int CLIENT_ERROR = 228;

/** '服务器错误') # 5XX 服务器错误 */

public static final int SERVER_ERROR = 229;

/** '参数错误') */

public static final int PARAM_ERROR = 230;

/** '登录失败,请检查您的邮箱地址是否正确') */

public static final int LOGIN_FAIL_EMAIL_NOT_EXIST = 332;

/** '登录失败,请确认您的手机号是否正确') */

public static final int LOGIN_FAIL_MOBILE_NOT_EXIST = 333;

/** '登录失败,请检查密码是否正确') */

public static final int LOGIN_FAIL_PASSWORD_ERROR = 334;

}

BaseResponse(基础响应实体类): 基础的响应实体类

public class ResponseEntity {

private int status_code;

private String message;

private Error error;

private T data;

public int getStatusCode() {return status_code;}

public void setStatusCode(int status_code) {this.status_code = status_code;}

public String getMessage() {return message;}

public void setMessage(String message) {this.message = message;}

public Error getError() {return error;}

public void setError(Error error) {this.error = error;}

public T getData() {return data;}

public void setData(T data) {this.data = data;}

public static class Error {

private String detail;

private List device_token;

private List content;

private List followed_id;

public String getDetail() {return detail;}

public void setDetail(String detail) {this.detail = detail;}

public List getDeviceToken() {return device_token;}

public void setDeviceToken(List device_token) {this.device_token = device_token;}

public List getContent() {return content;}

public void setContent(List content) {this.content = content;}

public List getFollowedId() {return followed_id;}

public void setFollowedId(List followed_id) {this.followed_id = followed_id;}

}

}

http的数据来源,现阶段只有apidocjs这一个

若有其他数据来源,可以配置api_data.source属性,然后添加对应的解析器,解析为xhw的model。

工具环境与依赖

命令行运行jar文件: 需要java8及以上的版本

开发环境:

Java的版本: java8及以上的版本

开发平台: intellij idea

依赖的jar: gson:2.8.0, rxjava:1.2.2, junit:4.12

快速使用入门

下载项目的Zip包,解压缩,从xhwt文件夹下,选取其中的一个包装器模板文件夹,作为目标包装器的配置,该文件夹在下面都叫做target dir

例如:xhwt/asynchttp/non_version(这是android-async-http库的一个模板与配置);

获取接口数据文件(api_data.json:存储apidocjs生成的API文档的数据)的路径;

例如:guide文件夹中的api_data.json的绝对路径

修改target dir下配置文件(x-http-wrapper.json)中api_data.file_path_infos的配置信息,将api_data.json的绝对路径添加上去;

"api_data": {

"source": "apidocjs",

"file_path_type": "file",

"file_path_infos": [

{

"os_name": "Mac OS X",

"path": "api_data.json的绝对路径"

},

{

"os_name": "Windows",

"path": "api_data.json的绝对路径"

}

],

"file_charset": "UTF-8"

}

修改target dir中,API的模板文件中标签内,生成文件的目标路径;

API的模板文件是以.xhwt为后缀的文件,是生成各个http相关文件的模板;

标签内,保存的是模板文件生成文件的文件名称与文件地址;

例如:

{

"file_name":"HttpApi.swift",

"file_dirs":[

{

"os_name":"Windows",

"path":"生成文件的目标路径(绝对路径)"

},

{

"os_name":"Mac OS X",

"path":"生成文件的目标路径(绝对路径)"

}

]

}

修改target dir下配置文件(x-http-wrapper.json)中template_file_infos中的need_generate属性,用于开启、关闭生成文件的功能;

例如:若你想生成HttpApi类型的文件,就需要将template_file_infos.HttpApi.need_generate设置为true,并要修改了xxx-httpapi.xhwt文件中header标签内的地址;

"template_file_infos": {

"HttpApi": {

"need_generate": true,

"path": "ncm_ios_n-httpapi.xhwt"

},

...

}

命令行生成相关http文件

命令行运行:java -jar (jar文件的路径) (配置文件的绝对路径)

jar文件的路径:在guide文件夹下有最新的jar(x-http-wrapper.jar)

配置文件的绝对路径:配置文件(x-http-wrapper.json)的绝对路径

java -jar x-http-wrapper.jar xxxx/x-http-wrapper.json

api的数据源:apidocjs

api_data.json就是使用apidocjs工具生成的数据文件;

工作流程

解析x-http-wrapper.json这个配置文件;

在配置文件中,有API数据文件(在api_data中),再根据配置数据,将API数据解析为x-http-wrapper中的model数据;

在配置文件中,有所有的x-http-wrapper的template文件(在template_file_infos中),根据template文件中的内容与model datas和配置一起,生成目标文件;

最新的jar

使用方式:

java -jar x-http-wrapper.jar xxx/x-http-wrapper.json

x-http-wrapper.json文件,必须是绝对路径,该文件是整个wrapper的配置文件;

若有多个json文件,也可以(如:有多个程序(ios,android)需要生成代码);

wrapper的配置文件:

x-http-wrapper.json (详细的配置文件介绍)

该文件保存有所有的配置信息, 共有8个分类: api_data, template_file_infos, base_config, filter, request, response, status_code, param_types

wrapper内部api数据模型

BaseModel:

所有的model都需要继承BaseModel

BaseModel中有一个泛型用于存储更高一级的BaseModel

在template engine中,反射只认BaseModel,不是BaseModel的model不能反射

template engine在反射调用时,若没有在反射的对象中找到方法,会从higherLevel中去找,直到没有higherLevel为止;

model的结构:

VersionModel-->StatusCodeGroup, RequestGroup

StatusCodeGroup-->StatusCode

RequestGroup-->Request-->Url,Header,Input,Response

Response-->Response File,Response Message

wrapper模板文件的类型

所有的类别都在XHWTFileType枚举中,现阶段共有6个类别;

HttpApi, Request, RequestParam, Response, StatusCode, BaseResponse

且在该枚举中也有该模板类别所需数据的获取过滤功能(getReflectiveDatas方法);

wrapper模板标签

生成的文件内容由该文件类型获取到的API数据与标签两者来驱动

头部标签: 用于标示该模板文件,生成的目标文件路径和名称;

file_dirs:目标文件路径

file_name:目标文件名称

现阶段只有7个标签类型:使用反射来进行数据的加工

text, foreach, retain, list_single_line, if_else, list_replace, list_attach

标签内部的匹配都为反射的方法名称;

例如:在foreach标签中

匹配的request_groups即为反射后去request_groups方法的数据,然后利用该数据去遍历;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容