Flutter json_serializable实现JSON解析映射及新旧字段兼容方案
Flutter 推荐板块JSON解析与字段兼容实现
前置依赖配置
首先在pubspec.yaml中添加所需依赖:
dependencies: flutter: sdk: flutter dio: ^最新稳定版 json_annotation: ^最新稳定版 dev_dependencies: build_runner: ^最新稳定版 json_serializable: ^最新稳定版
配置完成后执行flutter pub get安装依赖。
Model类定义与自动映射实现
共定义3层Model,完全匹配给定的JSON结构:
1. 单个健身房信息实体类(含字段兼容逻辑)
对应JSON中城市数组下的单个健身房对象,同时实现name字段的新旧键兼容:
import 'package:json_annotation/json_annotation.dart'; part 'gym_info.g.dart'; @JsonSerializable() class GymInfo { @JsonKey(name: 'gym_id') final String gymId; // 配置新旧键兼容读取规则 @JsonKey(readValue: _readNameValue) final String name; final String address; @JsonKey(name: 'city_id') final String cityId; @JsonKey(name: 'gym_logo') final String gymLogo; @JsonKey(name: 'no_of_ratings') final String? noOfRatings; @JsonKey(name: 'total_ratings') final String? totalRatings; @JsonKey(name: 'average_ratings') final String? averageRatings; @JsonKey(name: 'city_name') final String cityName; GymInfo({ required this.gymId, required this.name, required this.address, required this.cityId, required this.gymLogo, this.noOfRatings, this.totalRatings, this.averageRatings, required this.cityName, }); factory GymInfo.fromJson(Map<String, dynamic> json) => _$GymInfoFromJson(json); Map<String, dynamic> toJson() => _$GymInfoToJson(this); // 自定义字段读取逻辑:优先读新键name,不存在则读旧键aStupidName static Object? _readNameValue(Map json, String key) { return json['name'] ?? json['aStupidName']; } }
2. 推荐板块内容实体类
对应JSON中data字段的动态结构(键为城市名,值为对应城市的健身房列表):
import 'package:json_annotation/json_annotation.dart'; import 'gym_info.dart'; part 'recommended_data.g.dart'; @JsonSerializable() class RecommendedData { final Map<String, List<GymInfo>> cityGymMap; RecommendedData({required this.cityGymMap}); factory RecommendedData.fromJson(Map<String, dynamic> json) { final parsedMap = json.map((cityName, gymList) { return MapEntry( cityName, (gymList as List).map((e) => GymInfo.fromJson(e as Map<String, dynamic>)).toList(), ); }); return RecommendedData(cityGymMap: parsedMap); } Map<String, dynamic> toJson() { return cityGymMap.map((cityName, gymList) { return MapEntry(cityName, gymList.map((e) => e.toJson()).toList()); }); } }
3. 推荐板块最外层实体类
对应recommended字段的完整结构:
import 'package:json_annotation/json_annotation.dart'; import 'recommended_data.dart'; part 'recommended_section.g.dart'; @JsonSerializable() class RecommendedSection { @JsonKey(name: 'section_title') final String sectionTitle; @JsonKey(name: 'section_sub_title') final String sectionSubTitle; final RecommendedData data; RecommendedSection({ required this.sectionTitle, required this.sectionSubTitle, required this.data, }); factory RecommendedSection.fromJson(Map<String, dynamic> json) => _$RecommendedSectionFromJson(json); Map<String, dynamic> toJson() => _$RecommendedSectionToJson(this); }
Dio响应自动映射配置
编写通用解析方法,配合Dio请求逻辑实现响应数据自动转Model:
import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; /// 推荐板块接口响应解析方法 RecommendedSection? parseRecommendedResponse(Response response) { if (response.statusCode == 200 && response.data is Map) { try { final recommendedJson = response.data['recommended'] as Map<String, dynamic>; return RecommendedSection.fromJson(recommendedJson); } catch (e) { debugPrint('推荐板块JSON解析失败: $e'); return null; } } return null; } // 接口调用示例 void fetchRecommendedGyms() async { final dio = Dio(); final res = await dio.get('对应业务接口地址'); final recommendedData = parseRecommendedResponse(res); // 后续直接操作recommendedData对象即可 }
序列化代码生成
写完所有Model类后,在项目根目录执行以下命令,自动生成json_serializable对应的序列化/反序列化代码:flutter pub run build_runner build --delete-conflicting-outputs
兼容逻辑说明:上述
GymInfo类中的自定义读值方法已实现版本向下兼容,不管是新接口返回的name字段,还是旧版本本地缓存、老接口返回的aStupidName字段,都能正确读取赋值,不会出现字段解析为空的问题。
内容的提问来源于stack exchange,提问作者Arun99178
相关产品推荐
相关产品推荐

