若是尚未看过官方的相关文档,请移步至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便可解决这个问题。