DevToolBox免费
博客

JSON 转 Dart:Flutter 模型类完全指南

10 分钟阅读作者 DevToolBox

将 JSON 转换为 Dart 模型类是 Flutter 开发中最常见的任务之一。无论是从 REST API 获取数据还是读取本地配置,你都需要结构良好的 Dart 类来安全地解析和使用 JSON 数据。

为什么需要模型类

  • 类型安全 — 在编译时而非运行时捕获错误
  • IDE 自动补全和重构支持
  • 前后端之间清晰的数据契约
  • 更容易测试和维护

基本 JSON 到 Dart 类型映射

JSON 类型Dart 类型示例
stringString"hello" → "hello"
number (int)int42 → 42
number (float)double3.14 → 3.14
booleanbooltrue → true
nullNull / dynamicnull → null
arrayList<T>[1,2,3] → [1,2,3]
objectMap / Class{} → User()

手动模型类(fromJson / toJson)

最直接的方法是手写模型类。以下是完整示例:

// JSON input
{
  "id": 1,
  "name": "John Doe",
  "email": "john@example.com",
  "isActive": true,
  "score": 95.5
}

// Dart model class
class User {
  final int id;
  final String name;
  final String email;
  final bool isActive;
  final double score;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.isActive,
    required this.score,
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      email: json['email'] as String,
      isActive: json['isActive'] as bool,
      score: (json['score'] as num).toDouble(),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'name': name,
      'email': email,
      'isActive': isActive,
      'score': score,
    };
  }
}

处理嵌套对象

当 JSON 包含嵌套对象时,为每一层创建单独的 Dart 类:

// JSON with nested object
{
  "id": 1,
  "name": "John",
  "address": {
    "street": "123 Main St",
    "city": "Springfield",
    "zipCode": "62701"
  }
}

// Dart classes
class Address {
  final String street;
  final String city;
  final String zipCode;

  Address({required this.street, required this.city, required this.zipCode});

  factory Address.fromJson(Map<String, dynamic> json) {
    return Address(
      street: json['street'] as String,
      city: json['city'] as String,
      zipCode: json['zipCode'] as String,
    );
  }

  Map<String, dynamic> toJson() => {
    'street': street, 'city': city, 'zipCode': zipCode,
  };
}

class User {
  final int id;
  final String name;
  final Address address;

  User({required this.id, required this.name, required this.address});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      address: Address.fromJson(json['address'] as Map<String, dynamic>),
    );
  }

  Map<String, dynamic> toJson() => {
    'id': id, 'name': name, 'address': address.toJson(),
  };
}

处理列表和数组

JSON 数组映射为 Dart 的 List 类型。处理简单和复杂数组:

// JSON with arrays
{
  "name": "John",
  "hobbies": ["coding", "reading", "gaming"],
  "orders": [
    {"id": 1, "product": "Laptop", "price": 999.99},
    {"id": 2, "product": "Mouse", "price": 29.99}
  ]
}

// Dart
class User {
  final String name;
  final List<String> hobbies;
  final List<Order> orders;

  User({required this.name, required this.hobbies, required this.orders});

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      name: json['name'] as String,
      hobbies: List<String>.from(json['hobbies'] as List),
      orders: (json['orders'] as List)
          .map((e) => Order.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }
}

空安全最佳实践

使用 Dart 的健全空安全,你需要正确处理可空字段:

  • 对必须存在的字段使用 `required` 关键字
  • 对可空类型使用 `?` 后缀(如 `String?`)
  • 在 fromJson 中使用 `??` 运算符提供默认值
  • 仅在确定值会被初始化时使用 `late` 关键字
class User {
  final int id;
  final String name;
  final String? bio;        // nullable
  final String avatarUrl;   // with default

  User({
    required this.id,
    required this.name,
    this.bio,
    this.avatarUrl = 'https://example.com/default-avatar.png',
  });

  factory User.fromJson(Map<String, dynamic> json) {
    return User(
      id: json['id'] as int,
      name: json['name'] as String,
      bio: json['bio'] as String?,
      avatarUrl: json['avatarUrl'] as String? ?? 'https://example.com/default-avatar.png',
    );
  }
}

使用 json_serializable 包

对于大型项目,json_serializable 包可以自动化模板代码:

步骤 1:添加依赖

# pubspec.yaml
dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  json_serializable: ^6.7.1
  build_runner: ^2.4.6

步骤 2:创建带注解的模型

import 'package:json_annotation/json_annotation.dart';

part 'user.g.dart';

@JsonSerializable()
class User {
  final int id;
  final String name;
  final String email;

  @JsonKey(name: 'is_active')
  final bool isActive;

  @JsonKey(defaultValue: 0.0)
  final double score;

  User({
    required this.id,
    required this.name,
    required this.email,
    required this.isActive,
    required this.score,
  });

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

步骤 3:运行 Build Runner

dart run build_runner build --delete-conflicting-outputs

使用 Freezed 创建不可变模型

freezed 包生成带有 copyWith、相等性和 JSON 序列化的不可变类:

import 'package:freezed_annotation/freezed_annotation.dart';

part 'user.freezed.dart';
part 'user.g.dart';

@freezed
class User with _$User {
  const factory User({
    required int id,
    required String name,
    required String email,
    @Default(false) bool isActive,
  }) = _User;

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

常见错误与修复

错误修复
使用 `json['key']` 但不检查 null使用 `json['key'] as String? ?? ''` 或处理 null
忘记转换嵌套对象对对象调用 `NestedClass.fromJson(json['key'])`
所有数字都使用 `int`使用 `num` 并转换:`(json['price'] as num).toDouble()`
不处理缺失的键使用 `json.containsKey('key')` 或提供默认值
toJson 返回错误类型确保嵌套对象调用自己的 `.toJson()`

常见问题

将 JSON 转换为 Dart 类的最佳方法是什么?

小项目手动转换即可。大型项目使用 json_serializable 或 freezed 包自动生成模板代码。在线工具如我们的 JSON to Dart 转换器可以帮助生成初始代码。

如何处理 Dart 中的动态 JSON 键?

对未知键的对象使用 Map<String, dynamic>。例如:final Map<String, dynamic> metadata = json['metadata'] as Map<String, dynamic>;

应该使用 json_serializable 还是 freezed?

简单 JSON 序列化用 json_serializable。如果还需要不可变性、copyWith、联合类型和密封类,用 freezed。Freezed 内部使用 json_serializable 进行 JSON 支持。

如何处理 JSON 到 Dart 转换中的日期?

JSON 没有原生日期类型。用 DateTime.parse(json['date']) 解析 ISO 8601 字符串。在 toJson 中使用 dateTime.toIso8601String()。

𝕏 Twitterin LinkedIn
这篇文章有帮助吗?

保持更新

获取每周开发技巧和新工具通知。

无垃圾邮件,随时退订。

试试这些相关工具

DTJSON to Dart{ }JSON FormatterKTJSON to KotlinTSJSON to TypeScript

相关文章

YAML 语法与验证:常见错误及修复方法

掌握 YAML 语法:缩进规则、常见解析错误、数据类型和配置文件最佳实践。

JSON转Kotlin数据类:kotlinx.serialization、Moshi和Gson完整指南

在线将JSON转换为Kotlin数据类。学习使用kotlinx.serialization、Moshi和Gson进行JSON解析。