若是尚未看過官方的相關文檔,請移步至JSON和序列化查看。java
若是開發過android、iOS或者java後臺應用,那麼你應該曾使用過各類插件用於將JSON字符串解析生成模板類(例如GsonFormat和ESJsonFormat ),這些工具極大提升了開發效率。python
反序列化(json字符串->對象)
將生成的代碼粘貼到dart源文件中後,便可以在任意地方導包使用,通常方法爲(以http.get請求爲例):linux
var response = await HTTP.get(url);
var resp = BeanResp(response.body);
複製代碼
也就是說,將請求到的json內容做爲參數傳遞給BeanResp的默認構造函數,這樣生成的resp對象便是請求到內容的實體。 須要說明的是,默認構造既能夠傳入json的原始字符串,也能夠傳入已經用原生json.decode()方法解析過的json對象(這主要是爲了照顧使用dio庫進行數據請求時結果數據會被自動解析成json對象的狀況)。 只有頂級對象擁有默認構造方法,而其餘子層級對象將使用xxx.fromJson()的命名構造進行對象建立。android
序列化(對象->json字符串)
與官方樣例的處理方式不一樣,直接調用對象的toString()方法便可獲得json字符串完成序列化操做git
手動建立對象
爲了方便大部分使用場景下的便利性,bean的默認構造函數被用來實現反序列化,因此若是想要在代碼中手動傳參建立bean對象,可使用xxx.fromParams()命名構造來完成。github
在 Release 頁面中,選擇下載對應平臺最新的二進制文件後——json
在程序目錄打開終端後執行:chmod u+x Formatter_linux && ./Formatter_linuxwindows
在程序目錄打開終端後執行:chmod u+x Formatter_mac && ./Formatter_mac數組
直接雙擊運行 Formatter_win.exebash
沒有python運行環境的用戶須要先安裝python
mac中可使用以下命令安裝
brew install python3
brew install pip3
複製代碼
pip3是python3的包管理工具
brew 能夠參考下面的連接
運行庫的時候會可能會提示
Traceback (most recent call last):
File "formater.py", line 8, in <module>
from mainwindow import *
File "/Users/cjl/IdeaProjects/flutter/sxw-flutter-app/JSONFormat4Flutter/mainwindow.py", line 9, in <module>
from PyQt5 import QtCore, QtGui, QtWidgets
ModuleNotFoundError: No module named 'PyQt5'
複製代碼
這時候能夠直接用 pip3 install PyQt5
pip3 install pyperclip
等待安裝完成
(注:brew安裝最新版python3可能會出現ssl模塊丟失致使pip3沒法正常使用,此時也能夠考慮直接在python官網下載pkg包方式安裝python)
後面使用就是在命令行敲入 python3 formatter.py
緣由其一是我曾寫過簡單的AS/idea插件,發現開發資料至關匱乏,調試也很麻煩,雖然也有一些現成的插件源碼可供參考,可是開發這樣一個工具的週期預計會大幅超過我當時容許的時間(本工具第一個可用版本的實際開發時間爲3天多一點);
其二是因爲Flutter既能夠用AS/idea開發也能夠用VSCode開發的特性(並且據我觀察二者使用人數比例相仿),兩種IDE體系下開發插件的語言工具及流程都徹底不一樣,一旦我選擇了開發原生IDE插件,那麼勢必須要編寫維護兩份代碼,成本過高;
其三是由於python強大的文本處理能力使得它特別適合這種模板生成的工做,並且正巧以前的工做中就有利用python解析excel數據生成其餘語言源代碼的腳本,能夠快速借用已有的代碼邏輯來實現功能;
其四是得益於PyQt強大的跨平臺能力,能夠方便快捷地打出三個桌面平臺的應用包,從而達到接近原生插件的通用性(期待Flutter的桌面版項目早日成熟,這樣之後開發桌面工具也多一種選擇)
另外,能夠參考issue #9中的演示,將工具添加到IDE的外部工具中以方便打開,這樣使用體驗就與IDE插件更加類似了
由於我寫這個玩意的時候官網文檔尚未如今的樣例模板(也可能單純是我沒注意到),因此徹底是本身構思的方式來作的。後來看到樣例後也想過仿照那個格式改一下,但轉念一想其實也沒什麼本質區別,加上又忙就一直沒動。我作這個工具主要仍是以可以處理各類奇怪json爲目標的,好比爲了處理多層list嵌套,頂級結構爲list,list內部元素爲基本數據類型等,這些花了很多精力……並且生成的代碼裏沒用樣例裏類型轉換,因此dart2升級強類型模式之後不少人根據那個樣板寫的json解析都報錯的,而這個工具生成的卻一直能用,既然可以保證功能,具體的風格方式問題應該也不必太過糾結了
這主要是一些以前作android開發的同窗習慣於android開發中流行的’網絡請求封裝‘,就是假設後臺返回的JSON擁有相同的一級結構,好比都是
{"code":0,"msg":"success","data":{}}
這種結構,全部的請求結果都須要先進行code和msg字段的判斷處理,而後要使用的實際數據全在data字段中,因此但願有一個統一的處理函數能夠進行code和msg字段的處理,並經過指定泛型或class來返回指定類型的data內容對象。
雖然我我的認爲這只是個習慣問題,不必堅持,因爲dart語法特性確實很差實現,那麼不如換種形式同樣能處理地很好,可是由於見到不止一我的有這種疑問,因此我試着用這種思路寫了個dart版本的demo僅供參考,但願有人能提供更好更優雅的方案:
Person接口返回的json: {"code":0,"msg":"success","data":{"name":"debuggerx","age":26}}
Phone接口返回json: {"code":0,"msg":"success","data":{"model":"MI6X","price":1999}}
PersonResp.dart:
import 'dart:convert' show json;
class PersonResp {
int code;
String msg;
Person data;
PersonResp.fromParams({this.code, this.msg, this.data});
factory PersonResp(jsonStr) => jsonStr is String ? PersonResp.fromJson(json.decode(jsonStr)) : PersonResp.fromJson(jsonStr);
PersonResp.fromJson(jsonRes) {
code = jsonRes['code'];
msg = jsonRes['msg'];
data = new Person.fromJson(jsonRes['data']);
}
@override
String toString() {
return '{"code": $code,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}';
}
}
class Person {
int age;
String name;
Person.fromParams({this.age, this.name});
Person.fromJson(jsonRes) {
age = jsonRes['age'];
name = jsonRes['name'];
}
@override
String toString() {
return '{"age": $age,"name": ${name != null?'${json.encode(name)}':'null'}}';
}
}
複製代碼
PhoneResp.dart:
import 'dart:convert' show json;
class PhoneResp {
int code;
String msg;
Phone data;
PhoneResp.fromParams({this.code, this.msg, this.data});
factory PhoneResp(jsonStr) => jsonStr is String ? PhoneResp.fromJson(json.decode(jsonStr)) : PhoneResp.fromJson(jsonStr);
PhoneResp.fromJson(jsonRes) {
code = jsonRes['code'];
msg = jsonRes['msg'];
data = new Phone.fromJson(jsonRes['data']);
}
@override
String toString() {
return '{"code": $code,"msg": ${msg != null?'${json.encode(msg)}':'null'},"data": $data}';
}
}
class Phone {
int price;
String model;
Phone.fromParams({this.price, this.model});
Phone.fromJson(jsonRes) {
price = jsonRes['price'];
model = jsonRes['model'];
}
@override
String toString() {
return '{"price": $price,"model": ${model != null?'${json.encode(model)}':'null'}}';
}
}
複製代碼
只須要編寫一個BaseResp.dart以下:
import 'dart:convert' show json;
class BaseResp<T> {
int code;
String msg;
T data;
factory BaseResp(jsonStr, Function buildFun) =>
jsonStr is String ? BaseResp.fromJson(json.decode(jsonStr), buildFun) : BaseResp.fromJson(jsonStr, buildFun);
BaseResp.fromJson(jsonRes, Function buildFun) {
code = jsonRes['code'];
msg = jsonRes['msg'];
/// 這裏能夠作code和msg的處理邏輯
data = buildFun(jsonRes['data']);
}
}
複製代碼
那麼在解析的位置能夠寫以下代碼:
var response = await HTTP.get(url);
Person data = BaseResp<Person>(response.body, (res) => Person.fromJson(res)).data;
///或者
Phone data = BaseResp<Phone>(response.body, (res) => Phone.fromJson(res)).data;
複製代碼
也就是說,經過構造BaseResp對象,指定data對象的泛型,並傳入data對象特有的fromJson構造函數,便可實現對象的建立,最後經過'.data'取值,便可獲得想要的特定類型的data。
固然,那一長串挺長的,每次寫這麼一大段也有點麻煩,能夠把這一行代碼作成代碼模板,只留下泛型部分做爲模板變量便可。
有小夥伴指出,上面的BaseResp並不能很好地處理json中data的類型爲數組的狀況,也就是是相似: {"code":0,"msg":"success","data":[{"name":"debuggerx","age":26},{"name":"dx","age":27}]}
data的類型爲List<Person>這種狀況。此時能夠參考issue 11擴充一個BaseRespList便可解決這個問題。