Appearance
第19章:拓展学习方向
19.1 Dart 后端开发
19.1.1 Dart 后端框架
- Aqueduct:Dart 官方推荐的后端框架,提供完整的 RESTful API 开发能力
- Angel:轻量级后端框架,支持路由、中间件、数据库集成等
- Shelf:Dart 官方提供的 HTTP 服务器框架,简洁灵活
19.1.2 数据库集成
- PostgreSQL:通过
aqueduct或postgres库集成 - MySQL:通过
mysql1库集成 - SQLite:通过
sqflite库集成 - MongoDB:通过
mongo_dart库集成
19.1.3 后端开发实战
示例:使用 Aqueduct 构建 RESTful API
步骤1:创建项目
bash
dart create -t aqueduct my_api
cd my_api
dart pub get步骤2:定义数据模型
dart
// lib/model/user.dart
import 'package:aqueduct/aqueduct.dart';
class User extends ManagedObject<_User> implements _User {
@primaryKey
int? id;
@Column(unique: true)
String? username;
String? email;
String? password;
}
class _User {
@primaryKey
int? id;
@Column(unique: true)
String? username;
String? email;
String? password;
}步骤3:创建控制器
dart
// lib/controller/user_controller.dart
import 'package:aqueduct/aqueduct.dart';
import '../model/user.dart';
class UserController extends ResourceController {
UserController(this.context);
final ManagedContext context;
@Operation.get()
Future<Response> getAllUsers() async {
final query = Query<User>(context);
final users = await query.fetch();
return Response.ok(users);
}
@Operation.post()
Future<Response> createUser(@Bind.body() User user) async {
final query = Query<User>(context)..values = user;
final insertedUser = await query.insert();
return Response.ok(insertedUser);
}
@Operation.get('id')
Future<Response> getUserById(@Bind.path('id') int id) async {
final query = Query<User>(context)..where((u) => u.id).equalTo(id);
final user = await query.fetchOne();
if (user == null) {
return Response.notFound();
}
return Response.ok(user);
}
@Operation.put('id')
Future<Response> updateUser(@Bind.path('id') int id, @Bind.body() User user) async {
final query = Query<User>(context)
..where((u) => u.id).equalTo(id)
..values = user;
final updatedUser = await query.updateOne();
if (updatedUser == null) {
return Response.notFound();
}
return Response.ok(updatedUser);
}
@Operation.delete('id')
Future<Response> deleteUser(@Bind.path('id') int id) async {
final query = Query<User>(context)..where((u) => u.id).equalTo(id);
final deletedCount = await query.delete();
if (deletedCount == 0) {
return Response.notFound();
}
return Response.ok({'message': 'User deleted'});
}
}步骤4:配置路由
dart
// lib/my_api.dart
import 'package:aqueduct/aqueduct.dart';
import 'controller/user_controller.dart';
import 'model/user.dart';
class MyApi extends Application {
@override
Future prepare() async {
final dataModel = ManagedDataModel.fromCurrentMirrorSystem();
final persistentStore = PostgreSQLPersistentStore.fromConnectionInfo(
'postgres', 'password', 'localhost', 5432, 'my_api');
context = ManagedContext(dataModel, persistentStore);
}
@override
Controller get entryPoint {
final router = Router();
router.route('/users/[:id]').link(() => UserController(context!));
return router;
}
ManagedContext? context;
}步骤5:运行服务
bash
dart run aqueduct serve19.2 Flutter 跨平台开发
19.2.1 Flutter 核心概念
- Widget:Flutter 的 UI 构建块,分为 StatelessWidget 和 StatefulWidget
- State:管理 Widget 的状态
- BuildContext:Widget 在树中的位置
- MaterialApp:Material Design 风格的应用容器
- CupertinoApp:iOS 风格的应用容器
19.2.2 Flutter 常用组件
- 布局组件:Container、Row、Column、Stack、GridView、ListView
- 交互组件:Button、TextField、Checkbox、Radio、Switch
- 导航组件:Navigator、Route、PageRoute
- 动画组件:AnimatedContainer、AnimatedOpacity、AnimationController
19.2.3 Flutter 状态管理
- setState:简单状态管理
- Provider:基于 InheritedWidget 的状态管理
- Riverpod:Provider 的改进版
- Bloc:基于流的状态管理
- GetX:轻量级状态管理
19.2.4 Flutter 网络请求
- http:Flutter 官方推荐的 HTTP 客户端
- dio:功能强大的 HTTP 客户端
- retrofit:RESTful API 客户端生成器
19.2.5 Flutter 本地存储
- shared_preferences:简单的键值对存储
- sqflite:SQLite 数据库
- hive:轻量级 NoSQL 数据库
19.2.6 Flutter 实战项目
示例:创建一个简单的 Todo 应用
步骤1:创建项目
bash
flutter create todo_app
cd todo_app步骤2:添加依赖
yaml
# pubspec.yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
provider: ^6.0.0
sqflite: ^2.0.0
path: ^1.8.0步骤3:创建数据模型
dart
// lib/models/todo.dart
class Todo {
int? id;
String title;
bool completed;
Todo({this.id, required this.title, this.completed = false});
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'completed': completed ? 1 : 0,
};
}
factory Todo.fromMap(Map<String, dynamic> map) {
return Todo(
id: map['id'],
title: map['title'],
completed: map['completed'] == 1,
);
}
}步骤4:创建数据库助手
dart
// lib/utils/database_helper.dart
import 'dart:async';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import '../models/todo.dart';
class DatabaseHelper {
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
DatabaseHelper._privateConstructor();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
Future<Database> _initDatabase() async {
String path = join(await getDatabasesPath(), 'todo.db');
return await openDatabase(
path,
version: 1,
onCreate: _createDb,
);
}
Future<void> _createDb(Database db, int version) async {
await db.execute('''
CREATE TABLE todos(
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
completed INTEGER NOT NULL DEFAULT 0
)
''');
}
Future<List<Todo>> getTodos() async {
Database db = await instance.database;
List<Map<String, dynamic>> maps = await db.query('todos');
return List.generate(maps.length, (i) => Todo.fromMap(maps[i]));
}
Future<int> insertTodo(Todo todo) async {
Database db = await instance.database;
return await db.insert('todos', todo.toMap());
}
Future<int> updateTodo(Todo todo) async {
Database db = await instance.database;
return await db.update('todos', todo.toMap(), where: 'id = ?', whereArgs: [todo.id]);
}
Future<int> deleteTodo(int id) async {
Database db = await instance.database;
return await db.delete('todos', where: 'id = ?', whereArgs: [id]);
}
}步骤5:创建状态管理
dart
// lib/providers/todo_provider.dart
import 'package:flutter/material.dart';
import '../models/todo.dart';
import '../utils/database_helper.dart';
class TodoProvider extends ChangeNotifier {
List<Todo> _todos = [];
List<Todo> get todos => _todos;
Future<void> loadTodos() async {
_todos = await DatabaseHelper.instance.getTodos();
notifyListeners();
}
Future<void> addTodo(String title) async {
Todo todo = Todo(title: title);
await DatabaseHelper.instance.insertTodo(todo);
await loadTodos();
}
Future<void> toggleTodo(int id) async {
Todo todo = _todos.firstWhere((t) => t.id == id);
todo.completed = !todo.completed;
await DatabaseHelper.instance.updateTodo(todo);
await loadTodos();
}
Future<void> deleteTodo(int id) async {
await DatabaseHelper.instance.deleteTodo(id);
await loadTodos();
}
}步骤6:创建 UI
dart
// lib/main.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'providers/todo_provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => TodoProvider(),
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Todo App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: TodoList(),
);
}
}
class TodoList extends StatefulWidget {
@override
_TodoListState createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> {
final _textController = TextEditingController();
@override
void initState() {
super.initState();
Provider.of<TodoProvider>(context, listen: false).loadTodos();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todo App'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
child: TextField(
controller: _textController,
decoration: InputDecoration(
hintText: 'Enter a todo',
),
),
),
ElevatedButton(
onPressed: () {
if (_textController.text.isNotEmpty) {
Provider.of<TodoProvider>(context, listen: false)
.addTodo(_textController.text);
_textController.clear();
}
},
child: Text('Add'),
),
],
),
),
Expanded(
child: Consumer<TodoProvider>(
builder: (context, provider, child) {
return ListView.builder(
itemCount: provider.todos.length,
itemBuilder: (context, index) {
Todo todo = provider.todos[index];
return ListTile(
title: Text(
todo.title,
style: TextStyle(
decoration: todo.completed
? TextDecoration.lineThrough
: TextDecoration.none,
),
),
leading: Checkbox(
value: todo.completed,
onChanged: (value) {
provider.toggleTodo(todo.id!);
},
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
provider.deleteTodo(todo.id!);
},
),
);
},
);
},
),
),
],
),
);
}
}19.3 Dart 命令行工具开发
19.3.1 命令行工具基础
- dart:io:用于文件 I/O、进程管理等
- args:用于解析命令行参数
- path:用于路径操作
- io:用于处理输入输出
19.3.2 命令行工具开发实战
示例:创建一个简单的文件处理工具
步骤1:创建项目
bash
dart create file_tool
cd file_tool步骤2:添加依赖
yaml
# pubspec.yaml
dependencies:
args: ^2.0.0
path: ^1.8.0步骤3:实现功能
dart
// bin/file_tool.dart
import 'dart:io';
import 'package:args/args.dart';
import 'package:path/path.dart' as path;
void main(List<String> arguments) {
final parser = ArgParser()
..addCommand('count')
..addCommand('rename')
..addCommand('copy');
final results = parser.parse(arguments);
if (results.command == null) {
print('Usage: file_tool <command> [options]');
print('Commands:');
print(' count: Count files in a directory');
print(' rename: Rename files');
print(' copy: Copy files');
return;
}
switch (results.command!.name) {
case 'count':
countFiles(results.command!.arguments);
break;
case 'rename':
renameFiles(results.command!.arguments);
break;
case 'copy':
copyFiles(results.command!.arguments);
break;
default:
print('Unknown command: ${results.command!.name}');
}
}
void countFiles(List<String> arguments) {
if (arguments.isEmpty) {
print('Usage: file_tool count <directory>');
return;
}
final directory = Directory(arguments[0]);
if (!directory.existsSync()) {
print('Directory does not exist: ${arguments[0]}');
return;
}
int count = 0;
directory.listSync(recursive: true).forEach((entity) {
if (entity is File) {
count++;
}
});
print('Number of files in ${arguments[0]}: $count');
}
void renameFiles(List<String> arguments) {
if (arguments.length < 3) {
print('Usage: file_tool rename <directory> <old_pattern> <new_pattern>');
return;
}
final directory = Directory(arguments[0]);
if (!directory.existsSync()) {
print('Directory does not exist: ${arguments[0]}');
return;
}
final oldPattern = arguments[1];
final newPattern = arguments[2];
directory.listSync().forEach((entity) {
if (entity is File) {
final fileName = path.basename(entity.path);
if (fileName.contains(oldPattern)) {
final newFileName = fileName.replaceAll(oldPattern, newPattern);
final newPath = path.join(path.dirname(entity.path), newFileName);
entity.renameSync(newPath);
print('Renamed: $fileName -> $newFileName');
}
}
});
}
void copyFiles(List<String> arguments) {
if (arguments.length < 2) {
print('Usage: file_tool copy <source> <destination>');
return;
}
final source = File(arguments[0]);
if (!source.existsSync()) {
print('Source file does not exist: ${arguments[0]}');
return;
}
final destination = File(arguments[1]);
source.copySync(destination.path);
print('Copied: ${arguments[0]} -> ${arguments[1]}');
}步骤4:运行工具
bash
# 计数文件
dart run bin/file_tool.dart count .
# 重命名文件
dart run bin/file_tool.dart rename . old new
# 复制文件
dart run bin/file_tool.dart copy source.txt destination.txt19.4 Dart 高级特性
19.4.1 元编程
- mirrors:Dart 的反射 API,用于在运行时检查和修改代码
- codegen:代码生成,通过
build_runner和注解生成代码 - source_gen:源代码生成库,用于创建代码生成器
19.4.2 反射
示例:使用反射获取类信息
dart
import 'dart:mirrors';
class Person {
String name;
int age;
Person(this.name, this.age);
void sayHello() {
print('Hello, my name is $name');
}
}
void main() {
// 获取 Person 类的镜像
ClassMirror classMirror = reflectClass(Person);
// 获取类名
print('Class name: ${MirrorSystem.getName(classMirror.simpleName)}');
// 获取类的属性
print('Fields:');
classMirror.declarations.forEach((symbol, declaration) {
if (declaration is VariableMirror) {
print(' - ${MirrorSystem.getName(symbol)}');
}
});
// 获取类的方法
print('Methods:');
classMirror.declarations.forEach((symbol, declaration) {
if (declaration is MethodMirror && !declaration.isConstructor) {
print(' - ${MirrorSystem.getName(symbol)}');
}
});
// 创建实例
var person = Person('Alice', 25);
InstanceMirror instanceMirror = reflect(person);
// 调用方法
instanceMirror.invoke(#sayHello, []);
// 修改属性
instanceMirror.setField(#name, 'Bob');
instanceMirror.invoke(#sayHello, []);
}19.4.3 代码生成
示例:使用 json_serializable 生成 JSON 序列化代码
步骤1:添加依赖
yaml
# pubspec.yaml
dependencies:
json_annotation: ^4.0.0
dev_dependencies:
build_runner: ^2.0.0
json_serializable: ^4.0.0步骤2:定义模型类
dart
// lib/models/user.dart
import 'package:json_annotation/json_annotation.dart';
@JsonSerializable()
class User {
final String id;
final String name;
final int age;
final String email;
User({required this.id, required this.name, required this.age, required this.email});
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}步骤3:生成代码
bash
dart run build_runner build步骤4:使用生成的代码
dart
import 'models/user.dart';
void main() {
// 从 JSON 创建对象
var json = {
'id': '1',
'name': 'Alice',
'age': 25,
'email': 'alice@example.com'
};
var user = User.fromJson(json);
print('User: ${user.name}, ${user.age}');
// 转换为 JSON
var userJson = user.toJson();
print('JSON: $userJson');
}19.4.4 Dart 性能优化高级技巧
- 使用 isolates:通过 isolates 实现并行计算
- 使用 typed_data:使用类型化数据提高性能
- 内存管理:合理使用内存,避免内存泄漏
- 编译优化:使用 AOT 编译提高运行时性能
示例:使用 isolates 进行并行计算
dart
import 'dart:isolate';
void main() async {
print('Main isolate started');
// 创建接收端口
var receivePort = ReceivePort();
// 启动新 isolate
await Isolate.spawn(heavyComputation, receivePort.sendPort);
// 接收计算结果
var result = await receivePort.first;
print('Result from isolate: $result');
print('Main isolate finished');
}
void heavyComputation(SendPort sendPort) {
print('Isolate started');
// 模拟耗时计算
int sum = 0;
for (int i = 0; i < 1000000000; i++) {
sum += i;
}
// 发送结果
sendPort.send(sum);
print('Isolate finished');
}小结
- Dart 后端开发:使用 Aqueduct、Angel、Shelf 等框架构建后端服务
- Flutter 跨平台开发:使用 Flutter 构建移动、桌面、Web 应用
- Dart 命令行工具开发:创建实用的命令行工具
- Dart 高级特性:元编程、反射、代码生成、性能优化
通过拓展学习这些方向,你可以充分发挥 Dart 的优势,在不同领域中应用 Dart 编程技术,成为一名全面的 Dart 开发者。
