x-http-wrapper: 如何解決每次發版時,修改http相關代碼形成的錯誤!(Android、iOS、h5)

實際上是我作了個開源工具(^__^),拿出來給你們鑑賞下,歡迎你們提意見
項目:github.com/xuyt11/x-ht… 歡迎關注和star 。
功能:這是一個http相關代碼的建立工具。 javascript

如今咱們每一次發版,基本上都會涉及到http相關的修改,以此來知足發版的業務需求。
而在其中須要添加或修改的有http request、http request param、http response entity等其餘相關的http代碼。
而在屢次的修改中,若先後端沒有協調好,就有可能會形成以後的返工、重複修改與線上bug量的增長等問題。html

如今的痛點

如何解決每次發版時,都須要新增、修改http相關代碼!
如何解決每次發版時,修改http相關代碼形成的錯誤!前端

解決思路: 規範

  1. 其實很簡單,就是一個詞「規範」,任何事情,只要咱們有了必定的規範,就會有必定的流程、可追蹤而且下降難度。
    我相信99.99%的公司,都會有相關的http接口文檔提供給前端同窗,並且也會本身的一套規範(不管是我如今依賴的apidocjs,仍是上家公司的doc文件)。
    固然,確定也有口頭約定的狀況,但這須要在以後,當即將約定轉化爲文檔,提供給前端的同窗。git、http均可以做爲提供的形式。 java

  2. 咱們依賴這個http的規範,就能夠將http接口文檔去解析轉義爲x-http-wrapper內部的API數據。android

  3. 再來就是依賴必定的規範(x-http-wrapper的模板文件規範),將內部API數據轉化爲http相關文件。這樣,每次只要接口文檔更新事後,咱們就能夠根據文檔生成各個程序內部能夠運行的代碼。
    這個功能與如今IDE中的getter、setter方法生成器功能實際上是相同的原理!

x-http-wrapper介紹

  1. 這是一個http相關代碼的建立工具。
  2. 如今能建立的http相關的文件類型有:http請求分類,http請求,請求方法參數,響應實體,響應實體中狀態碼列表和基礎響應實體類。ios

    • HttpApi(http請求分類): 全部API請求的統一調用入口,統合全部的請求類別的接口,防止API接口分散。git

      public class HttpApi {
      
       private static Account account;
       private static Data data;
       private static Message message;
      
       public static Account account() {
           if (null == account) {
               account = Account.getInstance();
           }
           return account;
       }
      
       public static Data data() {
           if (null == data) {
               data = Data.getInstance();
           }
           return data;
       }
      
       public static Message message() {
           if (null == message) {
               message = Message.getInstance();
           }
           return message;
       }
      }複製代碼
    • Request(http請求): 單個請求分組中,全部的請求方法。github

      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(請求方法參數): 請求參數分組歸類,對應單個請求,用於請求參數較多的狀況,生成請求參數的分類實體類(請求參數也肯能有多個分類),減小請求方法的輸入參數。web

      /** * 請求方法參數 */
      public class QrcodeConfirmRP implements Serializable {
      
       public static final class Parameter implements Serializable {
           /** * type: String<br> * isOptional : false<br> * desc: <p>掃碼場景,枚舉值</p> */
           public String context;
           /** * type: Integer<br> * isOptional : true<br> * desc: <p>業務參數: 根據 context 的不一樣而不一樣</p> */
           public Integer project_id;
           /** * type: String<br> * isOptional : true<br> * desc: <p>身份信息: 服務端會優先使用客戶端傳入的身份信息,當爲」投資人「的時候必傳</p> */
           public String scene;
           /** * type: String<br> * isOptional : false<br> * desc: <p>從二維碼掃描獲得的惟一碼</p> */
           public String uuid_rand;
       }
      
      }複製代碼
    • Response(響應實體): 請求的相應數據modeljson

      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<T> {
      
        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<String> device_token;
            private List<String> content;
            private List<String> followed_id;
      
            public String getDetail() {return detail;}
            public void setDetail(String detail) {this.detail = detail;}
            public List<String> getDeviceToken() {return device_token;}
            public void setDeviceToken(List<String> device_token) {this.device_token = device_token;}
            public List<String> getContent() {return content;}
            public void setContent(List<String> content) {this.content = content;}
            public List<String> getFollowedId() {return followed_id;}
            public void setFollowedId(List<String> followed_id) {this.followed_id = followed_id;}
        }
      
      }複製代碼
  3. 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

快速使用入門

  1. 下載項目的Zip包,解壓縮,從xhwt文件夾下,選取其中的一個包裝器模板文件夾,做爲目標包裝器的配置,該文件夾在下面都叫作target dir
    • 例如:xhwt/asynchttp/non_version(這是android-async-http庫的一個模板與配置);
  2. 獲取接口數據文件(api_data.json:存儲apidocjs生成的API文檔的數據)的路徑;
    • 例如:guide文件夾中的api_data.json的絕對路徑
  3. 修改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"
       }複製代碼
  4. 修改target dir中,API的模板文件中\ \ 標籤內,生成文件的目標路徑;
    • API的模板文件是以.xhwt爲後綴的文件,是生成各個http相關文件的模板;
    • \ \ 標籤內,保存的是模板文件生成文件的文件名稱與文件地址;
      • 例如:
        {
          "file_name":"HttpApi.swift",
          "file_dirs":[
              {
                  "os_name":"Windows",
                  "path":"生成文件的目標路徑(絕對路徑)"
              },
              {
                  "os_name":"Mac OS X",
                  "path":"生成文件的目標路徑(絕對路徑)"
              }
          ]
        }複製代碼
  5. 修改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"
        },
        ...
      }複製代碼
  6. 命令行生成相關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工具生成的數據文件;

工做流程

  1. 解析x-http-wrapper.json這個配置文件;
  2. 在配置文件中,有API數據文件(在api_data中),再根據配置數據,將API數據解析爲x-http-wrapper中的model數據;
  3. 在配置文件中,有全部的x-http-wrapper的template文件(在template_file_infos中),根據template文件中的內容與model datas和配置一塊兒,生成目標文件;

最新的jar

  1. 使用方式:
    java -jar x-http-wrapper.jar xxx/x-http-wrapper.json複製代碼
  2. x-http-wrapper.json文件,必須是絕對路徑,該文件是整個wrapper的配置文件;
  3. 如有多個json文件,也能夠(如:有多個程序(ios,android)須要生成代碼);

wrapper的配置文件:

wrapper內部api數據模型

  1. BaseModel:
    • 全部的model都須要繼承BaseModel
    • BaseModel中有一個泛型用於存儲更高一級的BaseModel
    • 在template engine中,反射只認BaseModel,不是BaseModel的model不能反射
    • template engine在反射調用時,若沒有在反射的對象中找到方法,會從higherLevel中去找,直到沒有higherLevel爲止;
  2. model的結構:
    • VersionModel-->StatusCodeGroup, RequestGroup
    • StatusCodeGroup-->StatusCode
    • RequestGroup-->Request-->Url,Header,Input,Response
    • Response-->Response File,Response Message

wrapper模板文件的類型

  1. 全部的類別都在XHWTFileType枚舉中,現階段共有6個類別;
    • HttpApi, Request, RequestParam, Response, StatusCode, BaseResponse
  2. 且在該枚舉中也有該模板類別所需數據的獲取過濾功能(getReflectiveDatas方法);

wrapper模板標籤

  1. 生成的文件內容由該文件類型獲取到的API數據與標籤二者來驅動
  2. 頭部標籤\ \ : 用於標示該模板文件,生成的目標文件路徑和名稱;
    • file_dirs:目標文件路徑
    • file_name:目標文件名稱
  3. 現階段只有7個標籤類型:使用反射來進行數據的加工
    • text, foreach, retain, list_single_line, if_else, list_replace, list_attach
    • 標籤內部的匹配都爲反射的方法名稱;
      • 例如:在foreach標籤中
        <t:foreach each="request_groups">
        </t:foreach>複製代碼
        匹配的request_groups即爲反射後去request_groups方法的數據,而後利用該數據去遍歷;
相關文章
相關標籤/搜索