Flutter实现通用HTTP CRUD方法 解决泛型序列化及请求路径配置问题
Flutter通用HTTP CRUD封装解决方案
问题一:泛型T无法调用序列化方法的解决
Dart本身不支持泛型类型的静态方法直接调度,且Flutter禁用了dart:mirrors反射能力,因此最优解决方式是通过基础接口约束+全局序列化映射实现:
- 首先定义所有Model的公共父接口:
abstract class BaseModel<T> { Map<String, dynamic> toJson(); }
- 所有使用json_serializable生成序列化方法的Model类实现该接口:
@JsonSerializable() class User implements BaseModel<User> { final int id; final String name; User({required this.id, required this.name}); factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json); // 实现BaseModel接口的toJson方法 @override Map<String, dynamic> toJson() => _$UserToJson(this); }
- 在HTTP工具类中维护全局的类型->fromJson转换器映射,泛型方法中通过类型匹配获取对应转换器:
class HttpGenericClient { // 全局注册所有Model的反序列化方法,新增Model时只需在此处添加一条记录 static final Map<Type, T Function<T>(Map<String, dynamic>)> _fromJsonFactories = { User: (json) => User.fromJson(json), }; // 泛型添加BaseModel约束,确保可以调用toJson方法 static Future<T> create<T extends BaseModel<T>>(String path, {required T data}) async { final parsedData = data.toJson(); final Response<Map<String, dynamic>> response = await httpClient.post<Map<String, dynamic>>( path, data: parsedData, ); final fromJson = _fromJsonFactories[T]; if (fromJson == null) { throw Exception('未找到$T类型的反序列化注册信息,请先在_fromJsonFactories中配置'); } return fromJson(response.data!); } }
如果项目Model数量较多,可配合自定义build_runner生成器自动完成注册逻辑,无需手动维护映射表。
问题二:请求路径绑定优化
完全可以将请求路径和Model类绑定,无需每次调用时手动传入,改造方案如下:
- 在BaseModel中新增接口路径的getter约束:
abstract class BaseModel<T> { Map<String, dynamic> toJson(); // 新增接口路径约束,每个子类实现自身对应的接口路径 String get apiPath; }
- 在对应的Model类中实现该getter:
@JsonSerializable() class User implements BaseModel<User> { // ... 原有属性、构造、序列化方法不变 @override String get apiPath => '/users'; }
- 修改HTTP泛型方法,直接从传入的Model实例中获取路径:
static Future<T> create<T extends BaseModel<T>>({required T data}) async { final parsedData = data.toJson(); // 直接从实例取路径,无需外部传入 final Response<Map<String, dynamic>> response = await httpClient.post<Map<String, dynamic>>( data.apiPath, data: parsedData, ); // ... 原有反序列化逻辑不变 }
最终调用方式可简化为:
HttpGenericClient.create<User>(data: user);
如果涉及无需传Model实例的请求(比如查询列表、删除单条),可在HttpGenericClient中额外维护一份类型到路径的全局映射,调用时直接通过泛型类型匹配路径即可。
内容的提问来源于stack exchange,提问作者saibot
相关产品推荐
相关产品推荐

