实现方式
安装VSCode相关插件
Json to Dart Model Enhanced
: 用于直接将json生成dart的实体类和json<-->dart实体
的转换类Dart build_runner
: 根据dart实体类中的json_annotation
注解, 生成json<-->dart实体
的转换类Build Runner
: 和Dart build_runner
插件的功能一样
添加依赖
shell
dart pub add collection json_annotation freezed_annotation
dart pub add dev:build_runner dev:json_serializable dev:freezed
全自动化生成
复制json字符串 ,vscode的资源管理器的代码目录下,点击右键选择JSON to Dart: From Clipboard to Code Generation Classes
, 此时Json to Dart Model Enhanced
插件会根据json直接生成带注解的dart实体类,然后再通过build_runner
生成xx.g.dart
的转换类
示例:
- 以如下json为例,先复制到剪贴板(
ctrl+c
)
json
{
"keyword": "果汁茶饮料",
"branch_code": "4402 ",
"gtin": "06971196385407",
"f_id": "QfDJ8I345ukI52xOhiXQdgY5FiOWWKmlDtmV1q3f56k5BdULB8kKnuP5ppwZ6MWxU_8h8Gb2KVK4FMzk-WxFdd-aNwo42y1Fn_Q3n_kBSngtZEYFix45VA6cm34w6qg_dbMIXur_3KJdATWIxvfYHs6PcsvEAHJxCQTyFiX9HnExPUAu42pF5GmErKXVWg2Wli0eEh55Uz7zTqbihbSUGZVmUhC",
"specification": "450毫升",
"brandid": "4fDJ8I345ukI52xOhiXQdgY5FiO581PvMkpwWjYfjR22qIfwQH1jBedp9AqmncgQAm3qpOc9OXf-ZA7a2PRJI8qnmCQxJwKvMhg0D90NpT4SZnIxrFis7WrA_UwLyh0qO9XQ_1B5JC17gOA4z7CcE8mCW8nNn06hf6ZhxBzOL37_weYrnYff5-Qe6FuKXRVxPVfW4r0aHWVLlUtz-Nt0Yah2nhC",
"base_id": "AfDJ8I345ukI52xOhiXQdgY5FiMd64Ylky-sPivS6c5hBN1BK14Ya6Ck5jZ8uZF28imXdD-p96fJHbMxjQYMU02VtainJV_QZesabEt4oo68GnZxXoC3FVpmUY7p168F_QyIqRmRFNQ3jmAIduTj0Mpr5ccJ5cvUvO7UTc-WoqJqjn56rrOGZjtMCL1L2d92xE6r8aTn_i6ktSjtSQmQYFGPiBC",
"is_private": false,
"firm_name": "深圳市品道餐饮管理有限公司",
"brandcn": "奈雪的茶",
"picture_filename": "/userfile/2023224/593945533.png",
"description": "奈雪柠檬茶鸭屎香柠檬茶(果汁茶饮料)",
"logout_flag": "0",
"have_ms_product": 0,
"base_create_time": "2022-07-20T09:58:10.8",
"branch_name": "深圳分中心",
"base_source": "WWW",
"gpc": "10000313",
"gpcname": "液体/即饮型水果花草混合茶",
"saledate": "2023-02-24T00:00:00",
"saledateyear": 2023,
"base_last_updated": "2023-05-04T23:36:26.137",
"base_user_id": "1563092",
"code": "697119638",
"levels": null,
"levels_source": null,
"valid_date": "2029-08-01T00:00:00",
"logout_date": null,
"gtinstatus": 1
}
在vscode的资源管理器的代码目录下,点击右键选择JSON to Dart: From Clipboard to Code Generation Classes
此时Json to Dart Model Enhanced
会询问一系列问题,如:实体类名,是否生成xx方法,所有东西填完之后,会生成一个目录和两个文件
goods.dart
中是dart的实体类定义
dart
import 'package:collection/collection.dart';
import 'package:json_annotation/json_annotation.dart';
part 'goods.g.dart';
@JsonSerializable()
class Goods {
String? keyword;
@JsonKey(name: 'branch_code')
String? branchCode;
String? gtin;
@JsonKey(name: 'f_id')
String? fId;
String? specification;
String? brandid;
@JsonKey(name: 'base_id')
String? baseId;
@JsonKey(name: 'is_private')
bool? isPrivate;
@JsonKey(name: 'firm_name')
String? firmName;
String? brandcn;
@JsonKey(name: 'picture_filename')
String? pictureFilename;
String? description;
@JsonKey(name: 'logout_flag')
String? logoutFlag;
@JsonKey(name: 'have_ms_product')
num? haveMsProduct;
@JsonKey(name: 'base_create_time')
DateTime? baseCreateTime;
@JsonKey(name: 'branch_name')
String? branchName;
@JsonKey(name: 'base_source')
String? baseSource;
String? gpc;
String? gpcname;
String? saledate;
num? saledateyear;
@JsonKey(name: 'base_last_updated')
DateTime? baseLastUpdated;
@JsonKey(name: 'base_user_id')
String? baseUserId;
String? code;
dynamic levels;
@JsonKey(name: 'levels_source')
dynamic levelsSource;
@JsonKey(name: 'valid_date')
String? validDate;
@JsonKey(name: 'logout_date')
dynamic logoutDate;
num? gtinstatus;
Goods({
this.keyword,
this.branchCode,
this.gtin,
this.fId,
this.specification,
this.brandid,
this.baseId,
this.isPrivate,
this.firmName,
this.brandcn,
this.pictureFilename,
this.description,
this.logoutFlag,
this.haveMsProduct,
this.baseCreateTime,
this.branchName,
this.baseSource,
this.gpc,
this.gpcname,
this.saledate,
this.saledateyear,
this.baseLastUpdated,
this.baseUserId,
this.code,
this.levels,
this.levelsSource,
this.validDate,
this.logoutDate,
this.gtinstatus,
});
@override
String toString() {
return 'Goods(keyword: $keyword, branchCode: $branchCode, gtin: $gtin, fId: $fId, specification: $specification, brandid: $brandid, baseId: $baseId, isPrivate: $isPrivate, firmName: $firmName, brandcn: $brandcn, pictureFilename: $pictureFilename, description: $description, logoutFlag: $logoutFlag, haveMsProduct: $haveMsProduct, baseCreateTime: $baseCreateTime, branchName: $branchName, baseSource: $baseSource, gpc: $gpc, gpcname: $gpcname, saledate: $saledate, saledateyear: $saledateyear, baseLastUpdated: $baseLastUpdated, baseUserId: $baseUserId, code: $code, levels: $levels, levelsSource: $levelsSource, validDate: $validDate, logoutDate: $logoutDate, gtinstatus: $gtinstatus)';
}
factory Goods.fromJson(Map<String, dynamic> json) => _$GoodsFromJson(json);
Map<String, dynamic> toJson() => _$GoodsToJson(this);
Goods copyWith({
String? keyword,
String? branchCode,
String? gtin,
String? fId,
String? specification,
String? brandid,
String? baseId,
bool? isPrivate,
String? firmName,
String? brandcn,
String? pictureFilename,
String? description,
String? logoutFlag,
num? haveMsProduct,
DateTime? baseCreateTime,
String? branchName,
String? baseSource,
String? gpc,
String? gpcname,
String? saledate,
num? saledateyear,
DateTime? baseLastUpdated,
String? baseUserId,
String? code,
dynamic levels,
dynamic levelsSource,
String? validDate,
dynamic logoutDate,
num? gtinstatus,
}) {
return Goods(
keyword: keyword ?? this.keyword,
branchCode: branchCode ?? this.branchCode,
gtin: gtin ?? this.gtin,
fId: fId ?? this.fId,
specification: specification ?? this.specification,
brandid: brandid ?? this.brandid,
baseId: baseId ?? this.baseId,
isPrivate: isPrivate ?? this.isPrivate,
firmName: firmName ?? this.firmName,
brandcn: brandcn ?? this.brandcn,
pictureFilename: pictureFilename ?? this.pictureFilename,
description: description ?? this.description,
logoutFlag: logoutFlag ?? this.logoutFlag,
haveMsProduct: haveMsProduct ?? this.haveMsProduct,
baseCreateTime: baseCreateTime ?? this.baseCreateTime,
branchName: branchName ?? this.branchName,
baseSource: baseSource ?? this.baseSource,
gpc: gpc ?? this.gpc,
gpcname: gpcname ?? this.gpcname,
saledate: saledate ?? this.saledate,
saledateyear: saledateyear ?? this.saledateyear,
baseLastUpdated: baseLastUpdated ?? this.baseLastUpdated,
baseUserId: baseUserId ?? this.baseUserId,
code: code ?? this.code,
levels: levels ?? this.levels,
levelsSource: levelsSource ?? this.levelsSource,
validDate: validDate ?? this.validDate,
logoutDate: logoutDate ?? this.logoutDate,
gtinstatus: gtinstatus ?? this.gtinstatus,
);
}
@override
bool operator ==(Object other) {
if (identical(other, this)) return true;
if (other is! Goods) return false;
final mapEquals = const DeepCollectionEquality().equals;
return mapEquals(other.toJson(), toJson());
}
@override
int get hashCode =>
keyword.hashCode ^
branchCode.hashCode ^
gtin.hashCode ^
fId.hashCode ^
specification.hashCode ^
brandid.hashCode ^
baseId.hashCode ^
isPrivate.hashCode ^
firmName.hashCode ^
brandcn.hashCode ^
pictureFilename.hashCode ^
description.hashCode ^
logoutFlag.hashCode ^
haveMsProduct.hashCode ^
baseCreateTime.hashCode ^
branchName.hashCode ^
baseSource.hashCode ^
gpc.hashCode ^
gpcname.hashCode ^
saledate.hashCode ^
saledateyear.hashCode ^
baseLastUpdated.hashCode ^
baseUserId.hashCode ^
code.hashCode ^
levels.hashCode ^
levelsSource.hashCode ^
validDate.hashCode ^
logoutDate.hashCode ^
gtinstatus.hashCode;
}
goods.g.dart
中是dart的json<-->dart实体类
的转换逻辑实现
dart
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'goods.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Goods _$GoodsFromJson(Map<String, dynamic> json) => Goods(
keyword: json['keyword'] as String?,
branchCode: json['branch_code'] as String?,
gtin: json['gtin'] as String?,
fId: json['f_id'] as String?,
specification: json['specification'] as String?,
brandid: json['brandid'] as String?,
baseId: json['base_id'] as String?,
isPrivate: json['is_private'] as bool?,
firmName: json['firm_name'] as String?,
brandcn: json['brandcn'] as String?,
pictureFilename: json['picture_filename'] as String?,
description: json['description'] as String?,
logoutFlag: json['logout_flag'] as String?,
haveMsProduct: json['have_ms_product'] as num?,
baseCreateTime: json['base_create_time'] == null
? null
: DateTime.parse(json['base_create_time'] as String),
branchName: json['branch_name'] as String?,
baseSource: json['base_source'] as String?,
gpc: json['gpc'] as String?,
gpcname: json['gpcname'] as String?,
saledate: json['saledate'] as String?,
saledateyear: json['saledateyear'] as num?,
baseLastUpdated: json['base_last_updated'] == null
? null
: DateTime.parse(json['base_last_updated'] as String),
baseUserId: json['base_user_id'] as String?,
code: json['code'] as String?,
levels: json['levels'],
levelsSource: json['levels_source'],
validDate: json['valid_date'] as String?,
logoutDate: json['logout_date'],
gtinstatus: json['gtinstatus'] as num?,
);
Map<String, dynamic> _$GoodsToJson(Goods instance) => <String, dynamic>{
'keyword': instance.keyword,
'branch_code': instance.branchCode,
'gtin': instance.gtin,
'f_id': instance.fId,
'specification': instance.specification,
'brandid': instance.brandid,
'base_id': instance.baseId,
'is_private': instance.isPrivate,
'firm_name': instance.firmName,
'brandcn': instance.brandcn,
'picture_filename': instance.pictureFilename,
'description': instance.description,
'logout_flag': instance.logoutFlag,
'have_ms_product': instance.haveMsProduct,
'base_create_time': instance.baseCreateTime?.toIso8601String(),
'branch_name': instance.branchName,
'base_source': instance.baseSource,
'gpc': instance.gpc,
'gpcname': instance.gpcname,
'saledate': instance.saledate,
'saledateyear': instance.saledateyear,
'base_last_updated': instance.baseLastUpdated?.toIso8601String(),
'base_user_id': instance.baseUserId,
'code': instance.code,
'levels': instance.levels,
'levels_source': instance.levelsSource,
'valid_date': instance.validDate,
'logout_date': instance.logoutDate,
'gtinstatus': instance.gtinstatus,
};
通过定义带注解的实体类,手动生成xx.g.dart
文件
看到这里可能你会有疑问,都能自动生成了,还手写干嘛?
- json中可能缺少部分字段
- 可能生成的实体类字段类型不完全正确
- 全自动生成方式,无法使用泛型
手动定义支持泛型的实体类,再自动生成xx.g.dart
文件
手动定义支持泛型的实体类
base_entity.dart
dart
import 'package:json_annotation/json_annotation.dart';
// 这个文件即使还没有,也先写上,自动生成的转换逻辑文件,就是这种命名风格
part 'base_bean.g.dart';
//genericArgumentFactories以支持泛型
@JsonSerializable(genericArgumentFactories: true)
class BaseBean<T> {
@JsonKey(name: 'code')
int? code;
@JsonKey(name: 'data')
T? data;
BaseBean({this.data, this.code});
factory BaseBean.fromJson(
Map<String, dynamic> json, T Function(dynamic json) fromJsonT) =>
// 这个方法即使还没有(方法出自base_bean.g.dart文件),也写上
_$BaseBeanFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
// 这个方法即使还没有(方法出自base_bean.g.dart文件),也写上
_$BaseBeanToJson(this, toJsonT);
}
生成xx.g.dart
文件
方式一: 通过Dart build_runner
插件的界面点击生成
方式二: 通过Build Runner
插件的快捷键生成
P.S. 需要先将光标定位到VSCode的资源管理器的任意一个目录
ctrl + shift + b
生成的效果:base_bean.g.dart
dart
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'base_bean.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BaseBean<T> _$BaseBeanFromJson<T>(
Map<String, dynamic> json,
T Function(Object? json) fromJsonT,
) =>
BaseBean<T>(
data: _$nullableGenericFromJson(json['data'], fromJsonT),
code: json['code'] as int?,
);
Map<String, dynamic> _$BaseBeanToJson<T>(
BaseBean<T> instance,
Object? Function(T value) toJsonT,
) =>
<String, dynamic>{
'code': instance.code,
'data': _$nullableGenericToJson(instance.data, toJsonT),
};
T? _$nullableGenericFromJson<T>(
Object? input,
T Function(Object? json) fromJson,
) =>
input == null ? null : fromJson(input);
Object? _$nullableGenericToJson<T>(
T? input,
Object? Function(T value) toJson,
) =>
input == null ? null : toJson(input);
使用这个泛型实体类
dart
import 'dart:convert';
import 'package:demo_01/base_bean/base_bean.dart';
import 'package:demo_01/person/person.dart';
void main() {
String jsonStr =
'{"code":1,"data":{"name":"张三","age":12,"male":true,"hobby":["吃饭","睡觉"]}}';
BaseBean<Person> bean =
BaseBean.fromJson(jsonDecode(jsonStr), (json) => Person.fromJson(json));
print(bean.toString());
print(bean.code);
print(bean.data?.name);
print(bean.data?.age);
print(bean.data?.hobby);
print(bean.data?.toJson());
}
参考资料
Flutter 使用json_annotation创建数据模型 - 简书 (jianshu.com)
Flutter使用json_serializable泛型化的问题_flutter 序列化 泛型-CSDN博客
Flutter 使用 json_serializable 解析 JSON 支持泛型 - 掘金 (juejin.cn)
Flutter 基于Dio封装网络请求+泛型解析返回数据_flutter http返回值解析-CSDN博客
lib/generated/json/base/json_convert_content.dart · 江沨/flutter_demo - 码云 - 开源中国 (gitee.com)