Flutter客户端插件dizzbase_client的使用
Flutter客户端插件dizzbase_client的使用
dizzbase
是一个为 Node.js Express 服务器设计的实时 PostgreSQL 后端即服务。客户端(如 Flutter/Dart 或 JavaScript/React)可以发送查询,并且这些查询会自动实时更新。
dizzbase
可以作为自托管 Supabase 的替代方案,如果需要一个轻量级且易于安装的解决方案。此外,如果您需要关系型数据库而不是文档数据库,也可以用它代替 Firebase。
此包是 dizzbase
的 Dart/Flutter 客户端。要了解如何安装和运行 Node.js 后端及其与 PostgreSQL 的集成,请参阅 npm 包。
功能
该客户端通过 Dart Stream 提供对数据库查询的实时反馈。利用 Flutter StreamBuilder,当数据库中的数据发生变化时,小部件内容会自动更新。此外,Flutter/Dart 客户端还提供了用于更新/插入/删除 PostgreSQL 数据的接口,以及直接发送 SQL 语句的功能。
开始使用
客户端适用于 dizzbase
后端服务。首先在您的后端服务器上安装并配置 dizzbase
:npm 包
安装客户端:
flutter pub add dizzbase_client
将包导入到您的 Flutter 应用程序中:
import 'package:dizzbase_client/dizzbase_client.dart';
在 Flutter 应用的主函数 main()
中,调用 DizzbaseConnection.configureConnection(...)
来配置您的后端服务的 URL 和访问令牌。
查看 pub.dev
上的“示例”页面,了解如何使用 API。
要了解 Dart/Flutter dizzbase
客户端的工作原理,请查看 flutter 演示客户端:
演示客户端的 README.md 文件提供了有关如何使用 dizzbase_client
API 的指导。
注意 StatefulWidget
的 initState()
和 dispose()
方法覆盖,了解如何创建和清理 dizzbase
连接,从而避免长生命周期客户端导致的后端内存泄漏。
使用方法
请参考以下示例详细说明如何使用客户端。
初始化
在 main()
中初始化 dizzbase
客户端。为了测试,您可以调用登录功能使用管理员演示用户(设置 main()
为异步以等待登录)。否则,您需要显示一个登录屏幕。请注意,只有在后端启用 JWT 时才需要登录并提供访问令牌。请参阅 dizzbase
npm 后端包的 README.md 文件,了解如何启用/禁用 JWT 以及如何创建 API 访问令牌。
void main() async {
DizzbaseConnection.configureConnection("http://localhost:3000", "...api access token...");
await DizzbaseAuthentication.login(userName: "admin", password: "admin");
runApp(const MyApp());
}
使用 StreamBuilder 获取带有实时更新的数据
对于每个需要流式更新的小部件,创建/销毁 DizzbaseConnection
并创建如下所示的 Stream:
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
late DizzbaseConnection myDizzbaseConnection;
Stream<DizzbaseResultRows>? _stream_1;
Stream<DizzbaseResultRows>? _stream_2;
Stream<DizzbaseResultRows>? _stream_3;
Stream<DizzbaseResultRows>? _stream_4;
@override
void initState() {
super.initState();
// 创建一个新的连接到后端
myDizzbaseConnection = DizzbaseConnection();
// 通过主键检索单行
_stream_1 = myDizzbaseConnection.streamFromQuery(DizzbaseQuery(table: MainTable("employee", pkey: 3)));
// 演示如何在添加新订单时自动更新订单列表
_stream_2 = myDizzbaseConnection.streamFromQuery(DizzbaseQuery(
table: MainTable("order"),
joinedTables: [JoinedTable('employee', joinToTableOrAlias: 'order', foreignKey: 'sales_rep_id')],
filters: [Filter('employee', 'employee_id', 2)]
));
// 使用 LIKE 语句进行搜索
_stream_3 = myDizzbaseConnection.streamFromQuery(DizzbaseQuery(table: MainTable("employee"),
filters: [Filter('employee', 'employee_email', '%hotmail%', comparison: 'LIKE')]
));
// 复杂查询
_stream_4 = myDizzbaseConnection.streamFromQuery(DizzbaseQuery(
table: MainTable('order'),
joinedTables: [
JoinedTable('customer'),
JoinedTable('employee', joinToTableOrAlias: 'order', foreignKey: 'sales_rep_id', columns: ['employee_name', 'employee_email'], alias: 'seller'),
JoinedTable('employee', joinToTableOrAlias: 'order', foreignKey: 'services_rep_id', columns: ['employee_name'], alias: 'consultant'),
],
sortFields: [
SortField('seller', 'employee_name', ascending: false),
SortField('order', 'order_id', ascending: false),
],
filters: [
Filter('order', 'order_revenue', 50, comparison: ">="),
]
));
}
@override
void dispose() {
// 重要!
myDizzbaseConnection.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return StreamBuilder<DizzbaseResultRows>(
stream: _stream_1,
builder: (context, snapshot) {
if (snapshot.hasData) {
// 使用 snapshot.data!.rows![rowNumber][fieldName] 访问数据
return Text(snapshot.data!.rows![0]['employee_name']);
} else if (snapshot.hasError) {
throw Exception("Snapshot has error: ${snapshot.error}");
} else {
// 显示进度指示器
return CircularProgressIndicator();
}
},
);
}
}
注意:不要在小部件的 build()
或 builder()
方法中创建流,因为这会导致多次创建流(因此性能低下),并且会给服务器带来大量开销。
实时更新基于流的查询
基于流的查询将在查询中的行被更新或删除时自动更新。对于连接表,如果连接表的主键记录插入了新记录,则查询也会更新。例如:
SELECT * FROM orders JOIN customers ON orders.customer_id = customers.id;
在这种情况下,如果为 customers
记录创建了一个新的 orders
行,则查询将被更新。
执行 UPDATE/DELETE/INSERT 事务
使用 DizzbaseUpdate
, DizzbaseInsert
, DizzbaseDelete
类以及 DizzbaseConnection().updateTransaction()
, DizzbaseConnection().insertTransaction()
, DizzbaseConnection().deleteTransaction()
方法。返回的结果是一个 Future
,要么是 DizzbaseResultRowCount
(表示受影响的行数),要么是 DizzbaseResultPkey
(表示新行的主键):
// 更新操作,类似 DELETE
DizzbaseConnection().updateTransaction(
DizzbaseUpdate(table: "employee", fields: ["employee_name", "employee_email"],
values: [_controllerName.text, _controllerEmail.text], filters: [Filter('employee', 'employee_id', 2)])
).then((result) {
if (result.error != "") { throw Exception(result.error); }
setState(() => rowsAffected = result.rowCount);
});
// 插入操作
DizzbaseConnection().insertTransaction(
DizzbaseInsert(table: "order", fields: ["order_name", "customer_id", "sales_rep_id", "services_rep_id", "order_revenue"],
values: [_controllerName.text, 1, 2, 2, _controllerRevenue.text], nickName: "InsertOrder")
).then((data) => setState(() => insertedRowPrimaryKey = data.pkey));
更多关于Flutter客户端插件dizzbase_client的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter客户端插件dizzbase_client的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中集成和使用dizzbase_client
插件的一个示例。假设dizzbase_client
是一个提供数据库客户端功能的Flutter插件,以下代码将展示如何安装、配置和使用它。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加dizzbase_client
依赖:
dependencies:
flutter:
sdk: flutter
dizzbase_client: ^latest_version # 替换为实际的最新版本号
然后运行flutter pub get
来获取依赖。
2. 导入插件
在你的Dart文件中导入dizzbase_client
:
import 'package:dizzbase_client/dizzbase_client.dart';
3. 初始化客户端
通常,数据库客户端需要一些配置信息来初始化连接。以下是一个假设的初始化过程:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 假设需要一些配置信息来初始化客户端
final DizzbaseClientConfig config = DizzbaseClientConfig(
endpoint: 'https://your-database-endpoint.com',
apiKey: 'your-api-key',
);
// 初始化客户端
DizzbaseClient client = await DizzbaseClient.initialize(config);
runApp(MyApp(client: client));
}
4. 使用客户端进行数据操作
假设DizzbaseClient
提供了基本的CRUD(创建、读取、更新、删除)操作,以下是如何使用这些操作:
class MyApp extends StatelessWidget {
final DizzbaseClient client;
MyApp({required this.client});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Dizzbase Client Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () async {
// 创建一个新记录
Map<String, dynamic> newRecord = {
'name': 'John Doe',
'email': 'john.doe@example.com',
};
await client.createRecord('users', newRecord);
},
child: Text('Create Record'),
),
ElevatedButton(
onPressed: () async {
// 读取记录
List<Map<String, dynamic>> records = await client.readRecords('users');
print(records);
},
child: Text('Read Records'),
),
ElevatedButton(
onPressed: () async {
// 更新记录
Map<String, dynamic> updatedRecord = {
'name': 'Jane Doe',
};
await client.updateRecord('users', 'record-id', updatedRecord); // 替换'record-id'为实际记录ID
},
child: Text('Update Record'),
),
ElevatedButton(
onPressed: () async {
// 删除记录
await client.deleteRecord('users', 'record-id'); // 替换'record-id'为实际记录ID
},
child: Text('Delete Record'),
),
],
),
),
),
);
}
}
注意事项
- 错误处理:在实际应用中,你应该添加适当的错误处理来捕获和处理可能出现的异常。
- 配置管理:将配置信息(如API密钥和端点)硬编码在应用中通常不是一个好主意。考虑使用环境变量或配置文件来管理这些信息。
- 安全性:确保敏感信息(如API密钥)在客户端存储和传输时的安全性。
由于dizzbase_client
是一个假设的插件,具体的API和方法可能会有所不同。请参考实际的dizzbase_client
文档来获取准确的API信息和用法示例。