Flutter 进阶:json 转 model 工具开发

一、需求来源

凡是用强类型语言进行开发工作的都免不了和模型打交道;就有一个不可或缺的需求: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;
  }
}

三、总结

1、工具已开发好了,工具类见 JsonToModelPage.dart
2、需要额外在类中添加自定义方法的可以二次 fork 我的 json_to_dart 进行二次开发。
3、作为开发者能把自己的部分工作自动化是一件非常酷的事情!最昂贵的是时间,省下来的都是大赚的。
相关推荐
徐同保几秒前
通过AzureOpenAI请求gpt-4.1-mini
前端
红尘散仙11 分钟前
四、WebGPU 基础入门——Uniform 缓冲区与内存对齐
前端·rust·gpu
进取星辰22 分钟前
13、性能优化:魔法的流畅之道——React 19 memo/lazy
前端·react.js·前端框架
zwjapple28 分钟前
React中createPortal 的详细用法
前端·javascript·react.js
小矮马29 分钟前
React-组件通信
前端·javascript·react.js
codingandsleeping38 分钟前
pnpm + monorepo:高效的项目管理方式
前端
程序员三千_1 小时前
最近爆火的MCP到底是什么?
前端
古时的风筝1 小时前
暴论:2025年,程序员必学技能就是MCP
前端·后端·mcp
古时的风筝1 小时前
这编程圈子变化太快了,谁能告诉我 MCP 是什么
前端·后端·mcp
王月lydia1 小时前
环境变量篇-vue3的H5项目从0到1工程化落地经验篇2
前端