• 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.2 #最新版本
    使用
    1. 在工程根目录下创建一个名为 "jsons" 的目录;
    2. 创建或拷贝Json文件到"jsons" 目录中 ;
    3. 运行 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,自己动手

    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';
    %t
    part '%s.g.dart';
    
    @JsonSerializable()
    class %s {
      %s();
    
      %sfactory %s.fromJson(Map<String, dynamic> json) => _$%sFromJson(json);
    
      Map<String, dynamic> toJson() => _$%sToJson(this);
    }
    ";
      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("
      ");
              attrs.write(getType(v, set, name));
              attrs.write(" ");
              attrs.write(changeToCamelCase(key, false));
              attrs.writeln(";");
              attrs.write("
      ");
            } else {
              attrs.write(getType(v, set, name));
              attrs.write(" ");
              attrs.write(key);
              attrs.writeln(";");
              attrs.write("
      ");
            }
          });
          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(";
    ");
          _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的前身,来自这里

    其中注释包含 “#############################”的地方是修改过的地方,大家要有自己的需求可以自行修改。

    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
    • 添加export PATH=your flutter path/flutter/bin/cache/dart-sdk/bin:$PATH
    • source ~/.bash_profile
    • dart --version正常显示版本号即可
    1. 以上都配置完后只需一步,项目根目录下执行sh mo.sh,ok,一切完美的搞定了,给大家看看结果
       
     
     
     
     

    重要参考:
    https://www.jianshu.com/p/b20514e16e10
    https://book.flutterchina.club/chapter10/json_model.html

  • 相关阅读:
    DS博客作业03--树
    DS博客作业02--栈和队列
    DS博客作业02--线性表
    c博客06-结构体&文件
    c博客作业-指针
    C语言博客作业04--数组
    C语言博客作业03--函数
    图书馆
    5-互评-OO之接口-DAO模式代码阅读及应用.xls
    DS博客作业04--图
  • 原文地址:https://www.cnblogs.com/cap-rq/p/11797175.html
Copyright © 2020-2023  润新知