Skip to content

第19章:拓展学习方向

19.1 Dart 后端开发

19.1.1 Dart 后端框架

  • Aqueduct:Dart 官方推荐的后端框架,提供完整的 RESTful API 开发能力
  • Angel:轻量级后端框架,支持路由、中间件、数据库集成等
  • Shelf:Dart 官方提供的 HTTP 服务器框架,简洁灵活

19.1.2 数据库集成

  • PostgreSQL:通过 aqueductpostgres 库集成
  • 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 serve

19.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.txt

19.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 开发者。

© 2026 编程马·菜鸟教程 版权所有