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

Flutter通用API响应封装求助:实现可自动映射的泛型ApiResponse类

Dart 泛型API响应包装类实现

当前项目为每个API响应单独定义模型类,现需重构为通用的ApiResponse泛型包装类,实现JSON与Dart对象的自动映射,其中items字段需支持映射到任意自定义模型。以下是针对给定JSON结构的完整实现方案:

1. 分页结果泛型类

用于包装包含总数和列表数据的响应结果:

class PagedResult<T> {
  final int totalCount;
  final List<T> items;

  PagedResult({
    required this.totalCount,
    required this.items,
  });

  // 从JSON解析,需传入具体模型的解析函数
  factory PagedResult.fromJson(
    Map<String, dynamic> json,
    T Function(Map<String, dynamic>) fromJsonT,
  ) {
    return PagedResult(
      totalCount: json['totalCount'] as int,
      items: (json['items'] as List)
          .map((itemJson) => fromJsonT(itemJson))
          .toList(),
    );
  }

  // 转换为JSON
  Map<String, dynamic> toJson(Object Function(T) toJsonT) {
    return {
      'totalCount': totalCount,
      'items': items.map((item) => toJsonT(item)).toList(),
    };
  }
}

2. 通用API响应包装类

核心泛型包装类,适配给定的JSON结构:

class ApiResponse<T> {
  final PagedResult<T>? result;
  final String? targetUrl;
  final bool success;
  final dynamic error;
  final bool unAuthorizedRequest;
  final bool abp;

  ApiResponse({
    this.result,
    this.targetUrl,
    required this.success,
    this.error,
    required this.unAuthorizedRequest,
    required this.abp,
  });

  // 静态解析方法,传入具体模型的解析函数
  factory ApiResponse.fromJson(
    Map<String, dynamic> json,
    T Function(Map<String, dynamic>) fromJsonT,
  ) {
    return ApiResponse(
      result: json['result'] != null
          ? PagedResult.fromJson(json['result'] as Map<String, dynamic>, fromJsonT)
          : null,
      targetUrl: json['targetUrl'] as String?,
      success: json['success'] as bool,
      error: json['error'],
      unAuthorizedRequest: json['unAuthorizedRequest'] as bool,
      abp: json['__abp'] as bool,
    );
  }

  // 转换为JSON
  Map<String, dynamic> toJson(Object Function(T) toJsonT) {
    return {
      'result': result?.toJson(toJsonT),
      'targetUrl': targetUrl,
      'success': success,
      'error': error,
      'unAuthorizedRequest': unAuthorizedRequest,
      '__abp': abp,
    };
  }
}

3. 具体业务模型类

以示例中的里程记录为例,定义对应的模型类及解析方法:

// 类型选项模型
class TypeItem {
  final String item;
  final int itemValue;

  TypeItem({
    required this.item,
    required this.itemValue,
  });

  factory TypeItem.fromJson(Map<String, dynamic> json) {
    return TypeItem(
      item: json['item'] as String,
      itemValue: json['itemValue'] as int,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'item': item,
      'itemValue': itemValue,
    };
  }
}

// 里程记录模型
class MileageRecord {
  final String? vehicleUsedby;
  final String from;
  final String to;
  final String odoStart;
  final String odoEnd;
  final String personalMileage;
  final String businessMileage;
  final String distanceCovered;
  final String tollGate;
  final String litersRefueled;
  final String amount;
  final String siteOrPlaceVisitedAndReason;
  final TypeItem type;
  final DateTime date;
  final String id;

  MileageRecord({
    this.vehicleUsedby,
    required this.from,
    required this.to,
    required this.odoStart,
    required this.odoEnd,
    required this.personalMileage,
    required this.businessMileage,
    required this.distanceCovered,
    required this.tollGate,
    required this.litersRefueled,
    required this.amount,
    required this.siteOrPlaceVisitedAndReason,
    required this.type,
    required this.date,
    required this.id,
  });

  factory MileageRecord.fromJson(Map<String, dynamic> json) {
    return MileageRecord(
      vehicleUsedby: json['vehicleUsedby'] as String?,
      from: json['from'] as String,
      to: json['to'] as String,
      odoStart: json['odoStart'] as String,
      odoEnd: json['odoEnd'] as String,
      personalMileage: json['personalMileage'] as String,
      businessMileage: json['businessMileage'] as String,
      distanceCovered: json['distanceCovered'] as String,
      tollGate: json['tollGate'] as String,
      litersRefueled: json['litersRefueled'] as String,
      amount: json['amount'] as String,
      siteOrPlaceVisitedAndReason: json['siteOrPlaceVisitedAndReason'] as String,
      type: TypeItem.fromJson(json['type'] as Map<String, dynamic>),
      date: DateTime.parse(json['date'] as String),
      id: json['id'] as String,
    );
  }

  Map<String, dynamic> toJson() {
    return {
      'vehicleUsedby': vehicleUsedby,
      'from': from,
      'to': to,
      'odoStart': odoStart,
      'odoEnd': odoEnd,
      'personalMileage': personalMileage,
      'businessMileage': businessMileage,
      'distanceCovered': distanceCovered,
      'tollGate': tollGate,
      'litersRefueled': litersRefueled,
      'amount': amount,
      'siteOrPlaceVisitedAndReason': siteOrPlaceVisitedAndReason,
      'type': type.toJson(),
      'date': date.toIso8601String(),
      'id': id,
    };
  }
}

4. 使用示例

解析给定的JSON字符串:

import 'dart:convert';

void main() {
  String jsonString = '''{"result": {"totalCount": 3,"items": [{"vehicleUsedby": null,"from": "Malamulele ","to": "Soshanguve ","odoStart": "1234","odoEnd": "1740","personalMileage": "0","businessMileage": "450","distanceCovered": "450","tollGate": "Diamond hill","litersRefueled": "40","amount": "900","siteOrPlaceVisitedAndReason": "Auction","type": {"item": "Personal","itemValue": 1},"date": "2022-12-24T00:00:00","id": "e2c0df8d-c752-43ba-938d-d5c8a2ecc058"},{"vehicleUsedby": null,"from": "Malamulele ","to": "Soshanguve ","odoStart": "1234","odoEnd": "1740","personalMileage": "0","businessMileage": "450","distanceCovered": "450","tollGate": "Diamond hill","litersRefueled": "40","amount": "900","siteOrPlaceVisitedAndReason": "Auction","type": {"item": "Personal","itemValue": 1},"date": "2022-12-24T00:00:00","id": "d0c6b195-95d0-4f1a-b349-a68dba1f4d91"},{"vehicleUsedby": null,"from": "mat","to": "jj","odoStart": "","odoEnd": "","personalMileage": "","businessMileage": "","distanceCovered": "","tollGate": "Diamond hill","litersRefueled": "","amount": "","siteOrPlaceVisitedAndReason": "","type": {"item": "Business","itemValue": 2},"date": "2022-12-24T00:00:00","id": "b60aace4-d513-458c-b7ee-28d1275bd75a"}]},"targetUrl": null,"success": true,"error": null,"unAuthorizedRequest": false,"__abp": true}''';

  Map<String, dynamic> jsonMap = jsonDecode(jsonString);
  ApiResponse<MileageRecord> response = ApiResponse.fromJson(
    jsonMap,
    (itemJson) => MileageRecord.fromJson(itemJson),
  );

  // 访问解析后的数据
  print('总记录数: ${response.result?.totalCount}');
  print('第一条记录ID: ${response.result?.items.first.id}');
}

内容的提问来源于stack exchange,提问作者Moses Matimba Chavani Hlongwan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 09:01:32