如何在Dart/Flutter中解析API返回的含position嵌套对象的复杂JSON?
在Dart/Flutter中解析含动态键的嵌套复杂JSON数据
针对你遇到的position字段包含动态数字键(如"84"、"86")的嵌套JSON解析问题,下面是具体的实现方案:
核心思路
position里的键是不固定的字符串型数字,无法直接用固定类属性映射,因此我们用Map<String, PositionItem>来存储这些动态项,再为每个嵌套层级创建对应的实体类,逐层解析。
步骤1:创建实体类
根据JSON结构,从最底层的嵌套对象开始定义类,每个类实现fromJson工厂方法来完成解析:
class Product { final int id; final String name; final String slug; Product({required this.id, required this.name, required this.slug}); factory Product.fromJson(Map<String, dynamic> json) { return Product( id: json['id'] as int, name: json['name'] as String, slug: json['slug'] as String, ); } } class MainPrice { final int id; final int itemId; final String itemType; final String price; final String oldPrice; final DateTime? createdAt; final DateTime? updatedAt; MainPrice({ required this.id, required this.itemId, required this.itemType, required this.price, required this.oldPrice, this.createdAt, this.updatedAt, }); factory MainPrice.fromJson(Map<String, dynamic> json) { return MainPrice( id: json['id'] as int, itemId: json['item_id'] as int, itemType: json['item_type'] as String, price: json['price'] as String, oldPrice: json['old_price'] as String, createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : null, updatedAt: json['updated_at'] != null ? DateTime.parse(json['updated_at']) : null, ); } } class OfferProduct { final int id; final String priceValue; final Product product; final MainPrice mainPrice; OfferProduct({ required this.id, required this.priceValue, required this.product, required this.mainPrice, }); factory OfferProduct.fromJson(Map<String, dynamic> json) { return OfferProduct( id: json['id'] as int, priceValue: json['price_value'] as String, product: Product.fromJson(json['product'] as Map<String, dynamic>), mainPrice: MainPrice.fromJson(json['main_price'] as Map<String, dynamic>), ); } } class PositionItem { final String price; final int priceValue; final int id; final int itemId; final OfferProduct product; final String itemType; final int quantity; final int maxQuantity; final int weight; final String property; PositionItem({ required this.price, required this.priceValue, required this.id, required this.itemId, required this.product, required this.itemType, required this.quantity, required this.maxQuantity, required this.weight, required this.property, }); factory PositionItem.fromJson(Map<String, dynamic> json) { return PositionItem( price: json['price'] as String, priceValue: json['price_value'] as int, id: json['id'] as int, itemId: json['item_id'] as int, product: OfferProduct.fromJson(json['product'] as Map<String, dynamic>), itemType: json['item_type'] as String, quantity: json['quantity'] as int, maxQuantity: json['max_quantity'] as int, weight: json['weight'] as int, property: json['property'] as String, ); } } class PriceInfo { final String price; final int priceValue; PriceInfo({required this.price, required this.priceValue}); factory PriceInfo.fromJson(Map<String, dynamic> json) { return PriceInfo( price: json['price'] as String, priceValue: json['price_value'] as int, ); } } class Order { final int id; final Map<String, PositionItem> positions; final PriceInfo shippingPrice; final PriceInfo positionTotalPrice; final PriceInfo totalPrice; final int quantity; final int totalQuantity; final int weight; final int? paymentMethodId; final int? shippingTypeId; final dynamic userData; final dynamic shippingAddress; final dynamic billingAddress; final dynamic property; Order({ required this.id, required this.positions, required this.shippingPrice, required this.positionTotalPrice, required this.totalPrice, required this.quantity, required this.totalQuantity, required this.weight, this.paymentMethodId, this.shippingTypeId, this.userData, this.shippingAddress, this.billingAddress, this.property, }); factory Order.fromJson(Map<String, dynamic> json) { // 处理动态键的position字段 final positionMap = json['position'] as Map<String, dynamic>; final positions = positionMap.map((key, value) => MapEntry( key, PositionItem.fromJson(value as Map<String, dynamic>), )); return Order( id: json['id'] as int, positions: positions, shippingPrice: PriceInfo.fromJson(json['shipping_price'] as Map<String, dynamic>), positionTotalPrice: PriceInfo.fromJson(json['position_total_price'] as Map<String, dynamic>), totalPrice: PriceInfo.fromJson(json['total_price'] as Map<String, dynamic>), quantity: json['quantity'] as int, totalQuantity: json['total_quantity'] as int, weight: json['weight'] as int, paymentMethodId: json['payment_method_id'] as int?, shippingTypeId: json['shipping_type_id'] as int?, userData: json['user_data'], shippingAddress: json['shipping_address'], billingAddress: json['billing_address'], property: json['property'], ); } }
步骤2:解析API返回的JSON
拿到API返回的JSON字符串后,用jsonDecode转成Map,再通过Order.fromJson生成实体对象:
import 'dart:convert'; // 假设apiResponse是从接口获取的JSON字符串 final apiResponse = '''你的API返回的JSON内容'''; final jsonMap = jsonDecode(apiResponse) as Map<String, dynamic>; final order = Order.fromJson(jsonMap); // 访问动态键对应的项 final item84 = order.positions['84']; final item86 = order.positions['86']; // 示例:打印商品名称 if (item84 != null) { print(item84.product.product.name); }
可选:用json_serializable自动生成解析代码
如果项目中使用json_serializable库,可以简化解析代码的编写:
- 添加依赖到
pubspec.yaml:
dependencies: json_annotation: ^4.8.1 dev_dependencies: build_runner: ^2.4.4 json_serializable: ^6.7.0
- 给每个实体类添加
@JsonSerializable()注解,并生成对应的fromJson/toJson方法:
import 'package:json_annotation/json_annotation.dart'; part 'order.g.dart'; @JsonSerializable() class Product { final int id; final String name; final String slug; Product({required this.id, required this.name, required this.slug}); factory Product.fromJson(Map<String, dynamic> json) => _$ProductFromJson(json); Map<String, dynamic> toJson() => _$ProductToJson(this); } // 其他类同理添加@JsonSerializable()注解... @JsonSerializable() class Order { final int id; @JsonKey(name: 'position') final Map<String, PositionItem> positions; final PriceInfo shippingPrice; // 其他字段... Order({required this.id, required this.positions, required this.shippingPrice, ...}); factory Order.fromJson(Map<String, dynamic> json) => _$OrderFromJson(json); Map<String, dynamic> toJson() => _$OrderToJson(this); }
- 运行命令生成解析代码:
flutter pub run build_runner build
注意事项
- 动态键是字符串类型(如"84"),所以Map的键类型用
String而非int; - 处理JSON中的可选字段(如
created_at可能为null),用可空类型接收; - 带空格的价格字符串(如"1 000.00")直接用
String类型接收,后续可按需格式化处理。
内容的提问来源于stack exchange,提问作者Meylis Annagurbanov
相关产品推荐
相关产品推荐

