Flutter 使用json_annotation创建数据模型

一.引入三个依赖

dependencies:
  json_annotation: ^4.4.0

dev_dependencies:
  build_runner: ^2.1.8
  json_serializable: ^6.1.5

二.创建数据模型PersonModel

/// 1.引入json_annotation
import 'package:json_annotation/json_annotation.dart';

/// 2.指定此类的代码生成文件(格式:part '类名.g.dart';)
part 'person_model.g.dart';

/// 3.添加序列化标注
@JsonSerializable()
class PersonModel {
  @JsonKey(name: 'first_name')
  String? firstName;

  @JsonKey(name: 'last_name')
  String? lastName;

  PersonModel({this.firstName, this.lastName});

  /// 4.添加反序列化方法(格式:factory 类名.fromJson(Map<String, dynamic> json) => _$类名FromJson(json);)
  factory PersonModel.fromJson(Map<String, dynamic> json) => _$PersonModelFromJson(json);

  /// 5.添加序列化方法(格式:Map<String, dynamic> toJson() => _$类名ToJson(this);)
  Map<String, dynamic> toJson() => _$PersonModelToJson(this);
}

三.生成对于的.g.dart文件

1.一次性构建

flutter packages pub run build_runner build

2.删除后重新构建

flutter packages pub run build_runner build --delete-conflicting-outputs

3.文件监听,自动为后续创建得实体类生成对应得.g.dart文件

flutter packages pub run build_runner watch

四.JsonKey

  • nullable:默认为true,表示该字段可为null
  • defaultValue:如果源JSON不包含该key或该keyvaluenull,提供一个默认值。
  • name:别名,若为null则默认为字段名。
  • required:默认为false,若为真会检查JSON是否包含该key,若没有则抛出异常(keynull也是有效的)。
  • unknownEnumValue:当提供的值不在枚举字段中时,将会使用该默认值。JsonKey.nullForUndefinedEnumValue是当遇到未定义的值时默认值为null。
  • fromJson: 通过一个顶层方法将JSON数据转换为自己想要的数据类型,例如:服务器返回的1为true、2为false转为bool类型:
bool boolFromInt(int? value) => value == 1;

// ignore: avoid_positional_boolean_parameters
int boolToInt(bool? value) => (value ?? false) ? 1 : 2;

/// 是否未读
@JsonKey(name: 'is_unread', fromJson: boolFromInt, toJson: boolToInt)
bool? isUnread;
  • readValue:用于从源JSON里面读取映射值,例如读取Map里面的多层映射值:
"data": {
    "list": {
        "item": [
            {
                "id": 2,
                "name": "名字",
            }
        ],
        "total": 1
    }
}
/// 上面的JSON我们只需要里面的list数组,但是服务器多返回一层item包裹了,此时我们可以使用readValue
Object? listMapper(Map json, String field) => (json['list'] as Map)['item'];

@JsonKey(readValue: listMapper)
List<ActivityModel>? list;

五.JsonConverter

/// 实现这个类为特定的[Type]提供自定义转换器。
///
/// [T]是需要转换的类型。
///
/// [S]是存储在JSON中的值的类型,必须是有效的JSON类型
/// 例如[String]、[int]或[Map<String, dynamic>]。
abstract class JsonConverter<T, S> {
  const JsonConverter();

  T fromJson(S json);
  S toJson(T object);
}

例如下面一个文章json,里面的content_pic是一个字符串,需要转换为一个Model:

{
    "id":28,
    "content":"这是一篇主题区测试文章1",
    "admiration_num":1,
    "collect_num":1,
    "comment_num":0,
    "block":1,
    "member_id":1,
    "content_pic":"[{\"type\":\"image\",\"url\":\"https://storage.googleapis.com/mr486/topic/image/2022042020/62600304d24fd--compress.jpeg\"},{\"type\":\"video\",\"cover_url\":\"https://storage.googleapis.com/mr486/topic/video_cover/2022042020/62600304aa34e--compress.jpeg\",\"url\":\"https://storage.googleapis.com/mr486/topic/video/2022042020/6260030614271--1645415153.609362_o_IMG_0277.mp4\"}]"
}

@JsonSerializable()
class ArticleModel {
  @JsonKey(name: 'id')
  int? id;

  @JsonKey(name: 'content_pic')
  @_ArticleAssetConverter()
  List<ArticleAssetModel>? contentAssets;

  ArticleModel({
    this.id,
    this.contentAssets,
  });

  factory ArticleModel.fromJson(Map<String, dynamic> json) => _$ArticleModelFromJson(json);

  Map<String, dynamic> toJson() => _$ArticleModelToJson(this);
}

class _ArticleAssetConverter implements JsonConverter<List<ArticleAssetModel>?, String?> {
  const _ArticleAssetConverter();

  @override
  List<ArticleAssetModel>? fromJson(String? value) {
    final List<ArticleAssetModel> models = [];
    if (value.isNotBlank) {
      final json = jsonDecode(value!);
      if (json is List) {
        /// 格式不对的数据剔除掉
        for (final element in json) {
          if (element is Map<String, dynamic>) {
             models.add(ArticleAssetModel.fromJson(element));
          }
        }
      }
    }
    return models;
  }

  @override
  String? toJson(List<ArticleAssetModel>? object) {
    // TODO: implement toJson
    throw UnimplementedError();
  }
}

@JsonSerializable()
class ArticleAssetModel {
  @JsonKey(name: 'type')
  String? type;

  @JsonKey(name: 'url')
  String? url;

  @JsonKey(name: 'cover_url')
  String? coverUrl;

  ArticleAssetModel({
    this.url,
    this.type,
    this.coverUrl
  });

  factory ArticleAssetModel.fromJson(Map<String, dynamic> json) => _$ArticleAssetModelFromJson(json);

  Map<String, dynamic> toJson() => _$ArticleAssetModelToJson(this);
}

六.JsonEnum

  • fieldRename:定义名称转换时的命名策略,使用@JsonValue的值优先于该选项。

可以用JsonValue定义枚举的value特殊值,值类型可以为Stringint

/// 例如上述例子中[ArticleAssetModel]的[type]可以使用枚举定义
enum UploadFileType {
  @JsonValue('image')
  image,
  @JsonValue('video')
  video,
}

@JsonKey(name: 'type')
UploadFileType? type;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容