Code前端首页关于Code前端联系我们

Flutter json 解析 json_serializable 的使用并自动创建模板

terry 2年前 (2023-09-23) 阅读数 78 #移动小程序

1。使用 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包后记得运行 get

2。创建模板将你的json数据放在这里(点我)即可创建模板文件,如下:Flutter json解析json_serializable使用及自动化生成模板
  1. 填写json数据
  2. 填写类名
  3. 复制或下载。创建文件

在项目根目录运行flutter packages pub run build_runner watch,创建xxx.g.dart

4。解析和序列化

注意引导包Confutse'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);
复制代码

2.自动生成模板

上述过程需要每次在网站上生成一个json文件来转换为模板。接下来我们直接在本地生成,只需要编写user.json文件,然后运行命令即可。这样每次改变json结构时,都可以直接编辑json文件然后运行命令,并且可以将json结构保存在本地,方便查看。? 运行 pub run json_model (Dart VM 项目)或 flutter packages pub run json_model (在 Flutter 中)来创建 Dart 模型类。生成的文件默认在“lib/models”目录下

详细文档地址:github.com/flutterchin…

2.一个小优化

如上直接导入插件包非常方便,但是使用过程中出现了一个小问题:

  • 创建的模板文件名称与json文件名称相同。如果文件名下划线为_时,创建的类名也有下划线,不过我习惯使用驼峰命名法
  • 同上。当字段名称带有下划线_时,创建的字段也会带有下划线。是的,如果要使用驼峰式命名,需要手动添加 @JsonKey(name: 'username')
  • 自动解析数据类型只支持几种常见类型,如 bool num Map列表。 ,如果是DateTime或任何其他类型的字段,则只能解析为字符串。
  • 创建的模板格式不完美,强迫症患者必须手动格式化

如果这对你来说不友好或者你有自己的写作习惯,那就自己动手吧。我按照自己的习惯改成了这样:

  • 类名、字段名驼峰式命名
  • 支持DateTime类型(以后可以添加其他支持)完整 hod : 不要使用json_model文件,自己动手
    1. 在项目根目录下创建一个名为“jsons”的目录;
    2. 创建或复制Json文件到“jsons”目录下;
    3. 在项目根目录下创建将项目复制到目录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();
    }
    复制代码

    这里是创建模板的方法和模板,Json_model的前身,这里
    包含“#的注释## ##########################" 为修改部分。如果您有自己的需求,可以自行修改。

    1. 在项目根目录下创建mo.sh文件。内容如下:
    #!/usr/bin/env bash
    dart mo.dart
    flutter packages pub run build_runner build --delete-conflicting-outputs
    复制代码

    这是一个脚本。将命令打包并一起运行

    注意:如果还没有设置 dart 环境变量,则必须:(在 Mac 上)

    • vim ~/.bash_profile
    • 添加 exporter path/flutter/bin/cache /dart -sdk/bin:$PATH
    • source ~/. bash_profile
    • dart --version正常显示版本号就可以了
    1. 设置好上面之后就只需要一步了。在项目根目录下运行sh mo.sh,ok,一切完美完成,让我给你看看结果
      Flutter json解析json_serializable使用及自动化生成模板

      重要参考:
      www.jianshu.com/p/41210 …53/41210 book .flutterchina.club/chapter10/j…

      作者:天宇
      链接:https://juejin.im/post/5d08a920e51d454f7230250b来源:et454f7230250b 版权归作者所有。商业转载请联系作者获得许可。非商业转载请注明出处。

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门