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
相关产品推荐
相关产品推荐

