You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart中创建模型类并解析服务器返回的嵌套JSON?

优先使用json_annotation+json_serializable解析嵌套JSON

对于你提供的这种多层嵌套的JSON结构,强烈推荐使用json_annotation和json_serializable库,手动解析不仅容易因字段拼写、类型转换出错,后续维护成本也极高——一旦JSON结构变更,你需要逐一修改所有解析逻辑,效率极低。

一、库的使用步骤

1. 添加依赖

在pubspec.yaml中添加以下依赖:

dependencies:
  json_annotation: ^4.8.1

dev_dependencies:
  build_runner: ^2.4.4
  json_serializable: ^6.7.0

执行dart pub get安装依赖。

2. 创建嵌套模型类

从最内层的结构开始定义类,逐层向外扩展:

import 'package:json_annotation/json_annotation.dart';

// 自动生成的代码会放在这个文件中
part 'user_models.g.dart';

// 最内层:收藏颜色
@JsonSerializable()
class FavColors {
  final List<String> colors;

  FavColors({required this.colors});

  factory FavColors.fromJson(Map<String, dynamic> json) => _$FavColorsFromJson(json);
  Map<String, dynamic> toJson() => _$FavColorsToJson(this);
}

// 照片信息
@JsonSerializable()
class Photos {
  final String avatar;
  final FavColors favColors;

  Photos({required this.avatar, required this.favColors});

  factory Photos.fromJson(Map<String, dynamic> json) => _$PhotosFromJson(json);
  Map<String, dynamic> toJson() => _$PhotosToJson(this);
}

// 状态信息
@JsonSerializable()
class Status {
  final String text;

  Status({required this.text});

  factory Status.fromJson(Map<String, dynamic> json) => _$StatusFromJson(json);
  Map<String, dynamic> toJson() => _$StatusToJson(this);
}

// 用户主体
@JsonSerializable()
class User {
  final int id;
  final String name;
  final int age;
  final Status status;
  final Photos photos;

  User({
    required this.id,
    required this.name,
    required this.age,
    required this.status,
    required this.photos,
  });

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

// 最外层响应结构
@JsonSerializable()
class ApiResponse {
  final List<User> users;

  ApiResponse({required this.users});

  factory ApiResponse.fromJson(Map<String, dynamic> json) => _$ApiResponseFromJson(json);
  Map<String, dynamic> toJson() => _$ApiResponseToJson(this);
}

3. 生成解析代码

在终端执行以下命令,自动生成user_models.g.dart文件:

dart pub run build_runner build

4. 实际解析示例

拿到服务器返回的JSON字符串后,直接调用生成的fromJson方法解析:

import 'dart:convert';
import 'user_models.dart';

void main() {
  String jsonResponse = '''
  {"api_data": {   
    "users": [
      {
        "id": 100,
        "name": "Jhon",
        "age": 34,
        "status": {
          "text": "Hello, World!"
        },
        "photos": {
          "avatar": "https://",
          "favColors": {
            "colors": ["#FFFFFF", "#09927F"]
          }
        }
      }
    ]
  }}
  ''';

  Map<String, dynamic> jsonMap = jsonDecode(jsonResponse);
  ApiResponse response = ApiResponse.fromJson(jsonMap['api_data']);
  
  print(response.users.first.name); // 输出:Jhon
  print(response.users.first.status.text); // 输出:Hello, World!
}

二、手动解析的适用场景

只有当JSON结构极其简单(比如只有几个平级字段)时,手动解析才值得考虑。以你的JSON为例,手动解析的代码会非常繁琐:

import 'dart:convert';

void manualParse() {
  String jsonResponse = '''...'''; // 同上JSON字符串
  Map<String, dynamic> root = jsonDecode(jsonResponse);
  List<dynamic> usersJson = root['api_data']['users'];
  List<UserManual> users = [];

  for (var userJson in usersJson) {
    StatusManual status = StatusManual(text: userJson['status']['text']);
    FavColorsManual favColors = FavColorsManual(colors: List<String>.from(userJson['photos']['favColors']['colors']));
    PhotosManual photos = PhotosManual(avatar: userJson['photos']['avatar'], favColors: favColors);
    UserManual user = UserManual(
      id: userJson['id'],
      name: userJson['name'],
      age: userJson['age'],
      status: status,
      photos: photos,
    );
    users.add(user);
  }

  print(users.first.name);
}

// 手动解析对应的实体类
class UserManual {
  final int id;
  final String name;
  final int age;
  final StatusManual status;
  final PhotosManual photos;

  UserManual({required this.id, required this.name, required this.age, required this.status, required this.photos});
}

class StatusManual {final String text; StatusManual({required this.text});}
class PhotosManual {final String avatar; final FavColorsManual favColors; PhotosManual({required this.avatar, required this.favColors});}
class FavColorsManual {final List<String> colors; FavColorsManual({required this.colors});}

这种方式不仅容易遗漏字段,还可能因类型转换(比如把int写成String)导致运行时错误,完全不适合复杂嵌套结构。

内容的提问来源于stack exchange,提问作者Heike Heinrich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:23:26