Flutter地图数据映射生成插件map_mapper_generator的使用
Flutter地图数据映射生成插件map_mapper_generator的使用
map_mapper_generator
该包及其配套的map_mapper_annotations包旨在显著减少将Dart业务模型类暴露给NoSQL数据库存储库的工作量。这些存储库以Map<String, dynamic>形式持久化数据,而不是强类型对象。
该项目深受json_serializable包的启发。然而,虽然序列化逻辑相对相似,但其暴露方式有所不同。json_serializable包生成私有方法,而本包则生成MapMapper<TEntity>的子类,该类包含一个将实例转换为Map<String, dynamic>的方法(Map<String, dynamic> toMap(TEntity instance)
)和一个从Map<String, dynamic>恢复实体的方法(TEntity fromMap(Map<String, dynamic>) map
)。
这种做法的目的是能够开发通用的服务处理代码,该代码能够处理任何类型的 TEntity,将其序列化并发送到数据库,或从数据库检索并反序列化。
具体来说,通过这种方法,更容易开发一个处理gRPC请求的通用混入(mixin),并处理典型的CRUD请求。
此外,生成的代码还定义了类扩展,使得在序列化的类中无需创建工厂构造函数。
例如,如果我们有一个 Recipe 类,只需添加 @mapMap 属性即可使其可序列化,而无需添加其他方法或工厂:
[@mapMap](/user/mapMap)
class Recipe {
final String key;
final String title;
final List<Ingredient> ingredients;
Recipe({
this.key = '',
required this.title,
required this.ingredients,
});
// 不需要在此处添加支持序列化的代码
}
相反,由于生成的代码为 Recipe 和 Map<String, dynamic> 添加了扩展,序列化和反序列化变得非常简单:
final recipe = Recipe(/* 初始化参数 */);
// 这将创建一个包含属性的 Map<String, dynamic>
// 注意我们实际上不需要在 recipe 中添加 toMap() 方法,
// 因为在 recipe.g.dart 中已经创建了一个该方法的扩展。
final recipeMap = recipe.toMap();
// 这将重新创建一个 Recipe。
// 这也是可能的,因为我们还为 Map<String, dynamic> 添加了一个扩展,
// 该扩展添加了名为 toRecipe() 的方法。
final recipe2 = recipeMap.toRecipe();
多态性
多态性允许我们将超类类型的变量引用子类,并以这样的方式序列化对象,使序列化的Map包含所有子类属性以及类型标识符。这使得我们能够在仅事先知道超类类型的情况下反序列化子类对象。该包支持多态性,但有一个限制:所有支持的子类类型必须在生成时已知,并且用 MapMapped() 注解的 knownSubClasses 属性注册。
以下是一个示例:
@mapMapped
class Car extends Vehicle {
Car({
required this.numberOfDoors,
required super.weight,
});
final int numberOfDoors;
}
@mapMapped
class Airplane extends Vehicle {
Airplane({
required super.weight,
required this.wingspan,
});
final int wingspan;
}
// 注意我们正在识别所有已知的子类
@MapMapped(knownSubClasses: [
Car,
Airplane,
])
abstract class Vehicle { // 可以是非抽象的
final int weight;
Vehicle({
required this.weight,
});
}
void main() {
final car = Car(numberOfDoors: 4, weight: 1500);
final Vehicle airplane = Airplane(wingspan: 13, weight: 1500);
final vehicles = <Vehicle>[car, airplane];
// 从此处我们可以得到一个包含每个 Vehicle 序列化的列表
final maps = vehicles.map((v) => v.toMap()).toList();
// 注意我们调用了 .toVehicle,因为我们知道它们都是车辆
final deserVehicles = maps.map((m) => m.toVehicle()).toList();
final deserCar = deserVehicles[0] as Car; // 它真的是一个汽车
final deserAirplane = deserVehicles[1] as Airplane; // 它真的是一个飞机
print(deserCar.numberOfDoors); // 应该打印 4
print(deserAirplane.wingspan); // 应该打印 13
}
入门指南
要开始使用,请查看示例项目:
https://gitlab.com/dartaculous/dartaculous/-/tree/main/map_mapper/example
更多关于Flutter地图数据映射生成插件map_mapper_generator的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地图数据映射生成插件map_mapper_generator的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
map_mapper_generator
是一个用于 Flutter 的代码生成插件,它可以帮助你将 Dart 类映射到地图(Map)数据结构,或者从地图数据结构生成 Dart 类。这个插件特别适用于需要将对象序列化为 JSON 或从 JSON 反序列化的场景。
安装
首先,你需要在 pubspec.yaml
文件中添加依赖:
dependencies:
map_mapper_annotation: ^1.0.0
dev_dependencies:
build_runner: ^2.1.0
map_mapper_generator: ^1.0.0
使用步骤
- 定义模型类:使用
[@MapMapper](/user/MapMapper)()
注解来标记你的模型类。
import 'package:map_mapper_annotation/map_mapper_annotation.dart';
part 'user.g.dart';
[@MapMapper](/user/MapMapper)()
class User {
final String name;
final int age;
final String email;
User({
required this.name,
required this.age,
required this.email,
});
}
- 生成代码:使用
build_runner
生成映射代码。
在终端中运行以下命令:
flutter pub run build_runner build
这将会生成一个 user.g.dart
文件,其中包含了 User
类的映射逻辑。
- 使用生成的映射代码:你可以使用生成的
toMap
和fromMap
方法来序列化和反序列化对象。
import 'user.dart';
import 'user.g.dart';
void main() {
var user = User(name: 'John Doe', age: 30, email: 'john.doe@example.com');
// Serialize to Map
var userMap = UserMapper.toMap(user);
print(userMap); // Output: {name: John Doe, age: 30, email: john.doe@example.com}
// Deserialize from Map
var newUser = UserMapper.fromMap(userMap);
print(newUser.name); // Output: John Doe
}
自定义映射
你可以通过 @MapField()
注解来自定义字段的映射方式。例如:
[@MapMapper](/user/MapMapper)()
class User {
@MapField(name: 'full_name')
final String name;
final int age;
@MapField(ignore: true)
final String email;
User({
required this.name,
required this.age,
required this.email,
});
}
在这个例子中,name
字段将被映射为 full_name
,而 email
字段将被忽略。
处理嵌套对象
如果你的类中包含嵌套对象,map_mapper_generator
也可以处理这种情况。例如:
[@MapMapper](/user/MapMapper)()
class Address {
final String city;
final String country;
Address({
required this.city,
required this.country,
});
}
[@MapMapper](/user/MapMapper)()
class User {
final String name;
final int age;
final Address address;
User({
required this.name,
required this.age,
required this.address,
});
}