同一WebSocket端点不同JSON响应转Dart类的最优方案
基于WebSocket多类型JSON转换为Dart类的最优方案
针对你遇到的WebSocket返回不同type对应不同结构responseData的场景,最优方案是通过泛型基础类+分类型实体模型+分支解析的方式实现,既保证类型安全,又能灵活扩展。
1. 定义泛型基础响应类
先封装一个通用的WebSocket响应类,用泛型兼容不同类型的responseData:
class WebSocketResponse<T> { final int type; final List<T> responseData; WebSocketResponse({required this.type, required this.responseData}); // 通用构造函数,传入具体类型的解析方法 factory WebSocketResponse.fromJson( Map<String, dynamic> json, T Function(Map<String, dynamic>) itemParser, ) { return WebSocketResponse( type: json['type'] as int, responseData: (json['responseData'] as List) .map((item) => itemParser(item as Map<String, dynamic>)) .toList(), ); } }
2. 为每个type创建对应的数据实体类
根据不同type的responseData结构,分别定义强类型的Dart类:
// Type 1 对应的相册模型 class Album { final int albumId; final int id; final String title; final String url; Album({ required this.albumId, required this.id, required this.title, required this.url, }); factory Album.fromJson(Map<String, dynamic> json) { return Album( albumId: json['albumId'] as int, id: json['id'] as int, title: json['title'] as String, url: json['url'] as String, ); } } // Type 2 对应的品牌模型 class Brand { final String name; final String logoUrl; Brand({required this.name, required this.logoUrl}); factory Brand.fromJson(Map<String, dynamic> json) { return Brand( name: json['name'] as String, logoUrl: json['logoUrl'] as String, ); } } // Type 3 对应的商品模型 class Product { final String name; final int price; Product({required this.name, required this.price}); factory Product.fromJson(Map<String, dynamic> json) { return Product( name: json['name'] as String, price: json['price'] as int, ); } }
3. 在WebSocket消息处理中分支解析
接收到WebSocket消息后,先解析出type字段,再根据type选择对应的实体类解析:
import 'dart:convert'; void handleWebSocketMessage(String message) { final jsonMap = jsonDecode(message) as Map<String, dynamic>; final int type = jsonMap['type'] as int; switch (type) { case 1: final albumResponse = WebSocketResponse<Album>.fromJson( jsonMap, Album.fromJson, ); // 直接使用强类型的albumResponse.responseData处理业务 break; case 2: final brandResponse = WebSocketResponse<Brand>.fromJson( jsonMap, Brand.fromJson, ); // 处理品牌数据 break; case 3: final productResponse = WebSocketResponse<Product>.fromJson( jsonMap, Product.fromJson, ); // 处理商品数据 break; default: // 处理未知类型消息,比如打印日志或抛出异常 break; } }
4. 进阶优化:用代码生成简化序列化
如果觉得手动编写fromJson函数繁琐,可以用freezed+json_serializable库自动生成序列化代码,减少重复工作量:
- 在
pubspec.yaml添加依赖:
dependencies: freezed_annotation: ^2.4.1 json_annotation: ^4.8.1 dev_dependencies: build_runner: ^2.4.6 freezed: ^2.4.5 json_serializable: ^6.7.1
- 用freezed定义模型(以Album为例):
import 'package:freezed_annotation/freezed_annotation.dart'; part 'models.freezed.dart'; part 'models.g.dart'; @freezed class WebSocketResponse<T> with _$WebSocketResponse<T> { const factory WebSocketResponse({ required int type, required List<T> responseData, }) = _WebSocketResponse<T>; factory WebSocketResponse.fromJson( Map<String, dynamic> json, T Function(Object?) fromJsonT, ) => _$WebSocketResponseFromJson(json, fromJsonT); } @freezed class Album with _$Album { const factory Album({ required int albumId, required int id, required String title, required String url, }) = _Album; factory Album.fromJson(Map<String, dynamic> json) => _$AlbumFromJson(json); }
- 运行命令生成代码:
flutter pub run build_runner build
后续新增type时,只需添加对应的freezed模型即可,无需手动编写序列化逻辑。
内容的提问来源于stack exchange,提问作者dma
相关产品推荐
相关产品推荐

