1. 为什么我们需要JSON转Model的自动化工具?
在Flutter开发中,处理JSON数据是家常便饭。无论是从后端API获取数据,还是本地存储配置,JSON都是最常用的数据交换格式。我刚开始做Flutter项目的时候,每次拿到新的API接口文档,第一件事就是手动写Model类——一个个字段去定义,一个个fromJson和toJson方法去敲。说实话,这活儿干一两次还行,但项目稍微大一点,接口多起来,简直就是体力活。
更头疼的是,手动写Model类特别容易出错。字段名拼写错误、类型写错、嵌套对象处理不当……这些错误在编译时还发现不了,非得等到运行时才暴露出来。我就踩过这样的坑:一个字段明明是int类型,我手快写成了String,结果数据解析的时候直接崩溃,查了半天才发现是类型不匹配。还有一次,后端改了字段名没及时通知,我这边还在用旧的字段名,上线后直接报错,用户体验大打折扣。
所以,我们需要自动化工具。好的工具不仅能帮我们节省时间,更重要的是能减少人为错误,保证代码质量。想象一下,你只需要维护一份JSON文件,改个字段名或者类型,运行一条命令,所有的Model类就自动更新了——这效率提升可不是一点半点。
目前Flutter生态里,主要有两种自动化方案:一种是全自动的,比如json_model,直接从JSON文件生成完整的Model类;另一种是半自动的,比如json_serializable配合build_runner,需要你先写个Model类的架子,然后工具帮你生成序列化代码。两种方案各有适用场景,后面我会详细对比。
2. 方案一:全自动生成利器——json_model
json_model这个包是我个人非常喜欢的一个工具,它的理念特别简单直接:你只管维护JSON文件,剩下的交给它。这个思路在团队协作中尤其有用,因为JSON文件本身就是前后端约定的契约,用这个契约直接生成代码,能最大程度保证一致性。
2.1 安装与基础配置
首先,你需要在项目的pubspec.yaml文件里添加依赖。注意,json_model是开发依赖,不会打包进最终的应用里:
dependencies:
json_annotation: ^4.8.1
dev_dependencies:
json_model: ^1.0.0
json_serializable: ^6.7.1
build_runner: ^2.4.9
添加完依赖后,记得运行flutter pub get或者直接在IDE里点“Pub get”按钮。我建议用命令行操作,因为有时候IDE的缓存机制会导致依赖更新不及时。
接下来,在项目根目录创建一个名为jsons的文件夹。这个文件夹就是专门存放JSON文件的地方,你可以按模块或者功能来组织这些文件。比如,用户相关的JSON放在jsons/user目录下,商品相关的放在jsons/product目录下。实测下来,良好的目录结构能让后续维护轻松很多。
2.2 编写你的第一个JSON文件
在jsons文件夹里新建一个user.json文件,内容可以这样写:
{
"name": "张三",
"email": "zhangsan@example.com",
"age": 25,
"is_vip": true,
"tags": ["flutter", "dart", "mobile"]
}
这个JSON结构很简单,包含了字符串、数字、布尔值和数组几种基本类型。保存文件后,在终端运行:
flutter packages pub run json_model
几秒钟后,你会发现在lib/models目录下(如果没有这个目录,工具会自动创建)生成了两个文件:user.dart和user.g.dart。打开user.dart看看:
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class User {
User();
late String name;
late String email;
late int age;
late bool isVip;
late List<String> tags;
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
看到没?字段名自动从下划线命名转换成了小驼峰命名(is_vip -> isVip),类型也完全正确。user.g.dart文件里则是具体的序列化实现代码,这些代码你完全不用关心,工具已经帮你写好了。
2.3 处理复杂嵌套和类型引用
真实项目中的JSON往往比这个复杂得多。比如用户有个地址信息,地址本身又是一个对象:
{
"name": "李四",
"email": "lisi@example.com",
"address": {
"city": "北京",
"street": "朝阳区某路",
"postal_code": "100000"
}
}
如果按照上面的方式生成,address字段会是Map<String, dynamic>类型。但我们更希望它是一个独立的Address类。这时候就需要用到json_model的特殊语法了。
首先,我们得为地址单独创建一个JSON文件。在jsons目录下新建address.json:
{
"city": "",
"street": "",
"postal_code": ""
}
然后修改user.json,用$符号来引用这个类型:
{
"name": "李四",
"email": "lisi@example.com",
"address": "$address"
}
重新运行生成命令,你会发现生成了两个Model类,而且User类里的address字段类型自动变成了Address,还自动添加了对应的import语句。这个功能在处理复杂数据结构时特别有用,能避免重复定义相同的类型。
数组类型也类似。如果用户有多个地址:
{
"name": "王五",
"email": "wangwu@example.com",
"addresses": "$[]address"
}
$[]语法表示这是一个数组,数组里的元素是address类型。生成后,addresses字段的类型就是List<Address>。
2.4 高级配置:@meta和@JsonKey
有时候我们需要更精细的控制。比如JSON里的字段名是+1(点赞数),这在Dart里不能直接作为变量名。又比如某些字段需要添加注释,或者某些字段需要忽略。json_model提供了@meta配置和@JsonKey注解来满足这些需求。
来看个复杂点的例子:
{
"@meta": {
"import": [
"common/profile.dart"
],
"comments": {
"name": "用户姓名",
"created_at": "创建时间"
},
"nullable": false
},
"@JsonKey(ignore: true) Profile?": "profile",
"@JsonKey(name: '+1') int?": "likes",
"name": "赵六",
"created_a


738

被折叠的 条评论
为什么被折叠?



