一、需求来源
凡是用强类型语言进行开发工作的都免不了和模型打交道;就有一个不可或缺的需求:Json 字符串转成模型文件;
在做 iOS 原生开发时就基于 MacAPP 原生技术开发过自己的 swift 转模型工具 CoderHelper;可以生成 YYModel 和 HandyJSON 对应的定制模型文件,爽的一塌糊涂。
在开始接触 Flutter 开发之后,转模型都是用的网页版 json_to_dart,确实方便,但是作者不维护很久了,每次生成的模型文件一堆警告,都要一一处理,麻烦且不爽。且受制于人,我可是既要(方便)又要(高度自定义)也要(。。。)还要(。。。)的男人!
最终实现效果图:
二、实现需求
1、寻找开源支持
从零实现?怎么可能,我在 Flutter 开发可是不那么老的新手!
君子善假于物也
我可是站在巨人(开源社区)的肩上的男人。
既然 json_to_dart 作者不维护了,我维护行不行?追到 github 一看,网页版作者未开源。就此结束,怎么可能?f12 查看网页代码文件,发现有一个后缀为 dart 的文件和作者开源库 json_to_dart 非常类似,打开源码一看,确定找到目标库就是 json_to_dart。(早听说谷歌浏览器引擎可以解析 dart 文件,第一次见也是新鲜,多看了两眼。)
2、基于 json_to_dart 开发自己的工具
fork json_to_dart 克隆到本地,运行,果然生成的文件一堆黄色警告(我们开发用flutter 3.10.6)。接下来一顿修改,消灭所有警告,添加自己的定制代码(类前缀,后缀等等)。
一切搞定之后,核心功能已经实现了。但是岂能无衣?
3、开发一个操作界面,可以随意添加类名前后缀,根类名
顺手做成了响应式,可宽屏可竖屏(见效果图)。
原始 json
dart
{
"username": "javiercbk",
"favouriteInteger": 18,
"favouriteDouble": 1.618,
"url": "https://api.github.com/users/javiercbk",
"html_url": "https://github.com/javiercbk",
"tags": ["dart", "json", "cool"],
"randomIntegers": [1, 2, 3],
"randomDoubles": [1.1, 2.2, 3.3],
"personalInfo": {
"firstName": "Javier",
"lastName": "Lecuona",
"location": "Buenos Aires, Argentina",
"phones": [
{
"type": "work",
"number": "123-this-is-a-fake-phone",
"shouldCall": false
},
{
"type": "home",
"number": "123-this-is-a-phony-phone",
"shouldCall": false
}
]
}
}
生成模型:
dart
class YYRootModel {
YYRootModel({
this.username,
this.favouriteInteger,
this.favouriteDouble,
this.url,
this.htmlUrl,
this.tags,
this.randomIntegers,
this.randomDoubles,
this.personalInfo,
});
String? username;
int? favouriteInteger;
double? favouriteDouble;
String? url;
String? htmlUrl;
List<String>? tags;
List<int>? randomIntegers;
List<double>? randomDoubles;
PersonalInfo? personalInfo;
YYRootModel.fromJson(Map<String, dynamic>? json) {
if (json == null) {
return;
}
username = json['username'];
favouriteInteger = json['favouriteInteger'];
favouriteDouble = json['favouriteDouble'];
url = json['url'];
htmlUrl = json['html_url'];
tags = List<String>.from(json['tags'] ?? []);
randomIntegers = List<int>.from(json['randomIntegers'] ?? []);
randomDoubles = List<double>.from(json['randomDoubles'] ?? []);
personalInfo = json['personalInfo'] != null
? PersonalInfo.fromJson(json['personalInfo'])
: null;
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['username'] = username;
map['favouriteInteger'] = favouriteInteger;
map['favouriteDouble'] = favouriteDouble;
map['url'] = url;
map['html_url'] = htmlUrl;
map['tags'] = tags;
map['randomIntegers'] = randomIntegers;
map['randomDoubles'] = randomDoubles;
if (personalInfo != null) {
map['personalInfo'] = personalInfo!.toJson();
}
return map;
}
}
class YYPersonalInfoModel {
YYPersonalInfoModel({
this.firstName,
this.lastName,
this.location,
this.phones,
});
String? firstName;
String? lastName;
String? location;
List<Phones>? phones;
YYPersonalInfoModel.fromJson(Map<String, dynamic>? json) {
if (json == null) {
return;
}
firstName = json['firstName'];
lastName = json['lastName'];
location = json['location'];
if (json['phones'] != null) {
final array = (json['phones'] as List).map((e) => Phones.fromJson(e));
phones = List<Phones>.from(array);
}
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['firstName'] = firstName;
map['lastName'] = lastName;
map['location'] = location;
if (phones != null) {
map['phones'] = phones!.map((v) => v.toJson()).toList();
}
return map;
}
}
class YYPhonesModel {
YYPhonesModel({
this.type,
this.number,
this.shouldCall,
});
String? type;
String? number;
bool? shouldCall;
YYPhonesModel.fromJson(Map<String, dynamic>? json) {
if (json == null) {
return;
}
type = json['type'];
number = json['number'];
shouldCall = json['shouldCall'];
}
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['type'] = type;
map['number'] = number;
map['shouldCall'] = shouldCall;
return map;
}
}