Flutter 使用json_model解析json生成dart文件
一、json_serializable使用步骤
1.集成json_serializable
pubspec.yaml 添加以下依赖
dependencies:
json_annotation: ^2.0.0
dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^2.0.0
添加完记得执行 flutter packages get
2.生成文件
在项目根目录下执行 flutter packages pub run json_model 即可生成xxx.g.dart
3.解析及序列化
注意导包import 'dart:convert';
///json转model
String jsonString = '{"name": "Tony","email": "tony@example.com"}'
Map userMap = json.decode(jsonString);
var user = User.fromJson(userMap);
///model转json
String jsonEncode = json.encode(user);
print(jsonEncode);
二、自动化生成模板
上述过程需要每次把json去生成网站去转化成Model,接下来我们直接在本地生成,只需要写个user.json文件再执行下命令即可。这样每次json结构有修改后可以直接修改json文件再执行下命令即可,并且json结构能存在本地方便查看。
1.使用json_model
集成json_model
dev_dependencies:
json_model: ^0.0. #最新版本
使用
- 在工程根目录下创建一个名为 "jsons" 的目录;
- 创建或拷贝Json文件到"jsons" 目录中 ;
- 运行 pub run json_model (Dart VM工程)or flutter packages pub run json_model(Flutter中) 命令生成Dart model类,生成的文件默认在"lib/models"目录下
具体文档地址:https://github.com/flutterchina/json_model
2.一点点小优化
上述方式直接导入插件包已经很方便了,但使用过程中遇到了一点问题:
- 生成的model文件名和json文件名一样,如果文件名有下划线
_时生成的类名也是有下划线的,但我习惯使用驼峰命名 - 同上,当字段名中有下划线
_,生成的字段也是有下划线的,要想使用驼峰命名需要手动在字段上方加上@JsonKey(name: 'user_name') - 自动解析数据类型只支持
bool num Map List等几种常见类型,如果是DateTime类型或其他类型的字段只能解析成String。 - 生成的model没有完美的格式化,有强迫症的还得再手动格式化一下
如果你感觉这样不友好或有自己的书写习惯那么就自己动手吧。我这里按照自己的习惯改了一下:
- 类名,字段名驼峰命名
- 支持
DateTime类型(后期有其他支持可以添加) - 完美的格式化
做法:不使用json_model,自己动手
- 在工程根目录下创建一个名为 "jsons" 的目录;
- 创建或拷贝Json文件到"jsons" 目录中 ;
- 在项目根目录下创建
mo.dart文件,内容如下:
import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as path; const TAG = "\$";
const SRC = "./json"; //JSON 目录
const DIST = "lib/models/"; //输出model目录 void walk() {
//遍历JSON目录生成模板
var src = new Directory(SRC);
var list = src.listSync();
var template = "import 'package:json_annotation/json_annotation.dart';\r\n%t\npart '%s.g.dart';\r\n\r\n@JsonSerializable()\r\nclass %s {\r\n %s();\r\n\r\n %sfactory %s.fromJson(Map<String, dynamic> json) => _\$%sFromJson(json);\r\n\r\n Map<String, dynamic> toJson() => _\$%sToJson(this);\r\n}\r\n";
File file;
list.forEach((f) {
if (FileSystemEntity.isFileSync(f.path)) {
file = new File(f.path);
var paths = path.basename(f.path).split(".");
String name = paths.first;
if (paths.last.toLowerCase() != "json" || name.startsWith("_")) return;
if (name.startsWith("_")) return;
//下面生成模板
var map = json.decode(file.readAsStringSync());
//为了避免重复导入相同的包,我们用Set来保存生成的import语句。
var set = new Set<String>();
StringBuffer attrs = new StringBuffer();
(map as Map<String, dynamic>).forEach((key, v) {
if (key.startsWith("_")) return;
/// #############################
///处理key包含"_"时,转为驼峰并加上@JsonKey(name="key")
if (key.contains("_")) {
attrs.write('@JsonKey(name: "$key")');
attrs.write("\r\n ");
attrs.write(getType(v, set, name));
attrs.write(" ");
attrs.write(changeToCamelCase(key, false));
attrs.writeln(";");
attrs.write("\r\n ");
} else {
attrs.write(getType(v, set, name));
attrs.write(" ");
attrs.write(key);
attrs.writeln(";");
attrs.write("\r\n ");
}
});
String className = "";
/// #############################
///处理有"_"时class不是驼峰命名
if (name.contains("_")) {
className = changeToCamelCase(name, true);
} else {
className = name[0].toUpperCase() + name.substring(1);
}
var dist = format(template, [
name,
className,
className,
attrs.toString(),
className,
className,
className
]);
var _import = set.join(";\r\n");
_import += _import.isEmpty ? "" : ";";
dist = dist.replaceFirst("%t", _import);
//将生成的模板输出
new File("$DIST$name.dart").writeAsStringSync(dist);
}
});
}
/// #############################
///转为驼峰命名
///big 是否大驼峰
String changeToCamelCase(String word, bool big) {
if (word.contains("_")) {
String result = "";
List<String> words = word.split("_");
for (var value in words) {
result += (value[0].toUpperCase() + value.substring(1).toLowerCase());
}
return big ? result : (result[0].toLowerCase() + result.substring(1));
} else {
return big
? word[0].toUpperCase() + word.substring(1)
: word[0].toLowerCase() + word.substring(1);
}
} String changeFirstChar(String str, [bool upper = true]) {
return (upper ? str[0].toUpperCase() : str[0].toLowerCase()) +
str.substring(1);
} //将JSON类型转为对应的dart类型
String getType(v, Set<String> set, String current) {
current = current.toLowerCase();
if (v is bool) {
return "bool";
} else if (v is num) {
return "num";
} else if (v is Map) {
return "Map<String,dynamic>";
} else if (v is List) {
return "List";
} else if (v is String) {
/// #############################
///添加DateTime类型
try {
DateTime dateTime = DateTime.parse(v);
if (dateTime != null) {
return "DateTime";
}
} catch (e) {} //处理特殊标志
if (v.startsWith("$TAG[]")) {
var className = changeFirstChar(v.substring(3), false);
if (className.toLowerCase() != current) {
set.add('import "$className.dart"');
}
/// #############################
/// 自定义model类型名字大驼峰命名
return "List<${changeToCamelCase(className, true)}>";
} else if (v.startsWith(TAG)) {
var fileName = changeFirstChar(v.substring(1), false);
if (fileName.toLowerCase() != current) {
set.add('import "$fileName.dart"');
}
/// #############################
/// 自定义model类型名字大驼峰命名
return changeToCamelCase(fileName, true);
}
return "String";
} else {
return "String";
}
} //替换模板占位符
String format(String fmt, List<Object> params) {
int matchIndex = 0;
String replace(Match m) {
if (matchIndex < params.length) {
switch (m[0]) {
case "%s":
return params[matchIndex++].toString();
}
} else {
throw new Exception("Missing parameter for string format");
}
throw new Exception("Invalid format string: " + m[0].toString());
} return fmt.replaceAllMapped("%s", replace);
} void main() {
walk();
}
这里是生成model的方法及模板,Json_model的前身,来自这里
其中注释包含 “#############################”的地方是修改过的地方,大家要有自己的需求可以自行修改。
- 在项目根目录下创建
mo.sh文件,内容如下:
#!/usr/bin/env bash
dart mo.dart
flutter packages pub run build_runner build --delete-conflicting-outputs
这个是脚本,把命令打包后一起执行
注:如果你没有配置dart环境变量,需要配置一下:(Mac下)
vim ~/.bash_profile- 添加
export PATH=your flutter path/flutter/bin/cache/dart-sdk/bin:$PATH source ~/.bash_profiledart --version正常显示版本号即可
- 以上都配置完后只需一步,项目根目录下执行
sh mo.sh,ok,一切完美的搞定了,给大家看看结果


重要参考:
https://www.jianshu.com/p/b20514e16e10
https://book.flutterchina.club/chapter10/json_model.html
Flutter 使用json_model解析json生成dart文件的更多相关文章
- 使用Pull解析器生成XML文件和读取xml文件
有些时候,我们需要生成一个XML文件,生成XML文件的方法有很多,如:可以只使用一个StringBuilder组拼XML内容,然后把内容写入到文件中:或者使用DOM API生成XML文件,或者也可以使 ...
- 使用Pull解析器生成XML文件
有些时候,我们需要生成一个XML文件,生成XML文件的方法有很多,如:可以只使用一个StringBuilder组拼XML内容,然后把内容写入到文件中:或者使用DOM API生成XML文件,或者也可以使 ...
- 认识Json解析json生成json
.markdown-body hr::after,.markdown-body::after { clear: both } .loopLine,.messageLine0 { } .markdown ...
- JavaWeb_使用dom4j解析、生成XML文件
dom4j 官网 xml解析DOM文档对象模型(树形结构) DOM方式解析:把xml文档加载到内存形成树形结构,可以进行增删改的操作 Learn 使用dom4j解析文件"NewFile. ...
- python xml文件解析 及生成xml文件
#解析一个database的xml文件 """ <databaselist type="database config"> <dat ...
- Newtonsoft.Json.dll解析json的dll文件使用
要解析的json //解析前 //解析前 {,,,,,,,,,,},,,,,,,,,,,},,,,,,,,,,,,,,,,},,,,,,,,,},,,,,,,,,,,,},,,,,,,,,,,},,, ...
- 无废话Android之android下junit测试框架配置、保存文件到手机内存、android下文件访问的权限、保存文件到SD卡、获取SD卡大小、使用SharedPreferences进行数据存储、使用Pull解析器操作XML文件、android下操作sqlite数据库和事务(2)
1.android下junit测试框架配置 单元测试需要在手机中进行安装测试 (1).在清单文件中manifest节点下配置如下节点 <instrumentation android:name= ...
- Java&Xml教程(四)使用DOM方式生成XML文件
在前面的教程中,我们学习了使用DOM解析方式读取和修改XML文件内容,今天我们来学习如何使用DOM解析机制生成XML文件. 下面是我们对要生成的XML文件的具体要求: 1.根节点元素为"Em ...
- Flutter网络请求与JSON解析
本文介绍如何在Flutter中创建HTTP网络请求和对请求的json string进行类型解析. 网络请求 官方使用的是用dart io中的HttpClient发起的请求,但HttpClient本身功 ...
随机推荐
- VS2019 还原Resharper菜单位置
方法: 第一步: Tools -> Customize -> Extensions Menu tab, uncheck Resharper 工具->自定义->扩展菜单-> ...
- Vue中修改组件默认样式
vue 中直接使用 class 修改组件的默认样式,在使用 scoped 之后,样式是没有效果. 此时可以使用div 包裹组件,deep 可以实现修改组件样式 .lxfix /deep/ .contr ...
- 从头学pytorch(四) softmax回归实现
FashionMNIST数据集共70000个样本,60000个train,10000个test.共计10种类别. 通过如下方式下载. mnist_train = torchvision.dataset ...
- unittest---unittest错误截图
在做自动化的过程中,大多数执行者都不在旁边,那么如果用例失败了我们通常看报告上的失败信息,但是这样有时候可能不够清楚的判断到底哪里出了错误,我们还可以通过自动截图的功能,判断用例走到哪里出了错误. 截 ...
- Linux 笔记:虚拟控制台
登录后按Alt+F2键这时又可以看到"login:"提示符,这个就是第二个虚拟控制台. 一般新安装的Linux有四个虚拟控制台,可以用Alt+F1~Alt+F4来访问. 虚拟控制台 ...
- 使用Vue时localhost:8080中localhost换成ip地址后无法显示页面的问题
解决办法是:在package.json中 然后重新启动服务器 npm run dev 就正常显示了.
- 吴裕雄 python 神经网络——TensorFlow训练神经网络:卷积层、池化层样例
import numpy as np import tensorflow as tf M = np.array([ [[1],[-1],[0]], [[-1],[2],[1]], [[0],[2],[ ...
- 一大波新款iPhone跟安卓厂商抢夺5G市场
据外媒最新报道称,苹果已经基本完成了今年iPhone的推新阵容,其发布的多款新机中,将涵盖399美元-1149美元的售价区间,特别是5G手机,起步价可能会很亲民,其目的在于进一步占据市场. 今年苹果将 ...
- 高级T-SQL进阶系列 (一)【中篇】:使用 CROSS JOIN 介绍高级T-SQL
[译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文连接:传送门. 当一个CROSS JOIN 表现得如同一个INNER JOIN 在上一章节我提到当你使用一个CROSS JOIN ...
- 洛谷 P3009 [USACO11JAN]利润Profits
嗯... 题目链接:https://www.luogu.org/problemnew/show/P3009 这是DP的另一个功能,求最大子段和(最大子段和模板:https://www.luogu.or ...