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

  • 相关阅读:
    C#多线程的简单理解
    CSS中图片水平垂直居中方法小结
    浅析JavaScript的prototype
    记kkpager分页控件的使用
    面试必问的 volatile
    观察者模式——从JDK到Spring
    Java 内存模型都不会,就敢在简历上写熟悉并发编程吗
    工厂模式,就这一篇搞定
    JVM解毒——类加载子系统
    JVM解毒——JVM与Java体系结构
  • 原文地址:https://www.cnblogs.com/adoontheway/p/15188096.html
Copyright © 2011-2022 走看看