zoukankan      html  css  js  c++  java
  • flutter的json转dart model问题

    原文链接

    原文链接

    Preface

    最近在做一个app,以后续用来找工作可以拿出来看看。
    试试自己到产品设计能力,前后端能力等等。
    中间遇到到一些有值得记录的点全部记录在此。

    Content

    json - model

    本地 jsonmodel 互转,主要用到了

    • json_serializiable
    • json_annotation
    • build_runner

    meta版本依赖问题

    由于使用的flutter版本是2.2.4,flutter_test与json_annotation同时依赖了不同版本的meta库,所以不得已,没有用上最新的json对应库:

    json_annotation: ^4.0.1,
    json_serializable: ^4.1.4
    

    类型拓展

    以下是模版,在原版对基础上新增了构造器参数,不然新版本会提醒 null safty 问题。
    由于vs code老是提醒有错误,所以这个文件命名为template.tmpl

    import 'package:json_annotation/json_annotation.dart';
    %t
    part '%s.g.dart';
    @JsonSerializable()
    class %s {
        %s(%c);
    
        %s
        factory %s.fromJson(Map<String,dynamic> json) => _$%sFromJson(json);
        Map<String, dynamic> toJson() => _$%sToJson(this);
    }
    

    以下是生成modeldart程序,新增了构造器参数和复杂类型的支持:

    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 = new File("template/template.tmpl").readAsStringSync();
      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();
          List<String> params = [];
          (map as Map<String, dynamic>).forEach((key, v) {
            if (key.startsWith("_")) return;
            attrs.write(getType(v, set, name));
            attrs.write(" ");
            attrs.write(key);
            attrs.writeln(";");
            attrs.write("    ");
            params.add("required this.$key");
          });
          //新增的构造器参数部分
          String conParams = "{${params.join(",")}}";
          String 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);
          dist = dist.replaceFirst("%c", conParams);
          //将生成的模板输出
          new File("$DIST$name.dart").writeAsStringSync(dist);
        }
      });
    }
    
    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 int) {
        return "int";
      } 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) {
        //自定义类型的支持
        if (v.startsWith("$TAG") && v.endsWith("$TAG")) {
          return v.substring(1, v.length - 1);
        }
        //处理特殊标志
        if (v.startsWith("$TAG[]")) {
          var className = changeFirstChar(v.substring(3), false);
          if (className.toLowerCase() != current) {
            set.add('import "$className.dart"');
          }
          return "List<${changeFirstChar(className)}>";
        } else if (v.startsWith(TAG)) {
          var fileName = changeFirstChar(v.substring(1), false);
          if (fileName.toLowerCase() != current) {
            set.add('import "$fileName.dart"');
          }
          return changeFirstChar(fileName);
        }
        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();
    }
    
    

    生成脚本没有变动

    dart ./lib/mo.dart
    flutter packages pub run build_runner build --delete-conflicting-outputs
    

    实际结果

    普通类型

    //record.json
    {
        "content":"拉屎",
        "datetime":"$DateTime$",//复杂类型的传入方式
        "cost":30,
        "useful":true
    }
    

    生成结果:

    import 'package:json_annotation/json_annotation.dart';
    
    part 'record.g.dart';
    @JsonSerializable()
    class Record {
        Record({required this.content,required this.datetime,required this.cost,required this.useful});
    
        String content;
        DateTime datetime;
        int cost;
        bool useful;
        
        factory Record.fromJson(Map<String,dynamic> json) => _$RecordFromJson(json);
        Map<String, dynamic> toJson() => _$RecordToJson(this);
    }
    

    嵌入类型

    //mock.json
    {
        "version":1,
        "targets":"$[]target",
        "records":"$[]record",
        "motivations":"$[]motivation"
    }
    

    生成结果

    import 'package:json_annotation/json_annotation.dart';
    import "target.dart";
    import "record.dart";
    import "motivation.dart";
    part 'mock.g.dart';
    @JsonSerializable()
    class Mock {
        Mock({required this.version,required this.targets,required this.records,required this.motivations});
    
        int version;
        List<Target> targets;
        List<Record> records;
        List<Motivation> motivations;
        
        factory Mock.fromJson(Map<String,dynamic> json) => _$MockFromJson(json);
        Map<String, dynamic> toJson() => _$MockToJson(this);
    }
    

    Reference

  • 相关阅读:
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Navicat查询哪些表有指定字段名
  • 原文地址:https://www.cnblogs.com/adoontheway/p/15188096.html
Copyright © 2011-2022 走看看