Controllers

控制器是一个继承自 Controller 的 Dart 类,用于将相关的请求处理程序组织在一起。每个处理程序方法都返回 Future<String>——即 HTTP 响应体。

Creating a Controller

import 'package:finch/finch_route.dart';

class UserController extends Controller {
  UserController();

  @override
  Future<String> index() async {
    return rq.renderData(data: {'message': 'User list'});
  }

  Future<String> show() async {
    var id = rq.getParam('id');
    return rq.renderData(data: {'id': id});
  }

  Future<String> profile() async {
    rq.addParam('title', 'User Profile');
    return rq.renderView(path: 'user/profile');
  }
}

rq 对象

在任何 Controller 子类内部,rq 是一个返回 Context.rq 的 getter——即当前的 Request 对象。它提供了对请求数据、session、cookie 以及所有响应方法的访问。

将控制器附加到路由

final userController = UserController();

FinchRoute(
  key: 'users.index',
  path: 'users',
  methods: Methods.ONLY_GET,
  controller: userController,  // 调用 userController.index()
),
FinchRoute(
  key: 'users.show',
  path: 'users/{id}',
  methods: Methods.ONLY_GET,
  index: userController.show,  // 调用一个特定的方法
),

controller 会使用其 index() 方法。index 接受一个 Future<String> Function()?——传入控制器中的某个方法引用即可调用不同的操作。

响应方法

所有响应方法都位于 rq 对象上:

方法 描述
rq.renderView(path: 'template/path') 从 widgetsPath 渲染 Jinja 模板
rq.renderData(data: {...}) JSON 响应
rq.renderString(text: '...') 纯文本响应
rq.renderHtml(html: '...') HTML 字符串响应
rq.renderTag(tag: Tag) 渲染 Htmler Tag
rq.renderError(404) 标准错误响应
rq.redirect('/path') HTTP 重定向
rq.renderSSE(stream) Server-Sent Events 流
rq.renderSocket() WebSocket 握手占位符

renderView

Future<String> dashboard() async {
  rq.addParams({
    'title': 'Dashboard',
    'user': currentUser,
  });
  return rq.renderView(path: 'pages/dashboard');
  // 加载路径:widgetsPath/pages/dashboard.{widgetsType}
}

renderData (JSON)

Future<String> apiUsers() async {
  var users = await UserCollection().getAll();
  return rq.renderData(data: {'users': users.map((u) => u.toJson()).toList()});
}

renderError

Future<String> notFound() async {
  return rq.renderError(404);
}

读取请求数据

// 读取 GET 或 POST 字段
var name = rq.get<String>('name', def: 'anonymous');
var age  = rq.get<int>('age', def: 0);

// 读取来自 {id} 的路径参数
var id = rq.getParam('id');

// 检查请求方法
if (rq.isPost) { ... }
if (rq.method == Methods.DELETE) { ... }

// API 端点?(路径以 /api/ 开头)
bool isApi = rq.isApiEndpoint;

向模板传递数据

Future<String> show() async {
  var user = await UserCollection().findById(rq.getParam('id'));

  // addParam / addParams 使数据在 Jinja 模板中可用
  rq.addParams({
    'user': user?.toJson(),
    'title': 'User Profile',
  });

  return rq.renderView(path: 'user/show');
}

在模板中:

<h1>{{ user.name }}</h1>

访问其他控制器

控制器就是普通的 Dart 对象。在顶层实例化它们并共享使用:

final authController = AppAuthController();
final homeController = HomeController();

// 在 AuthController.loginPost() 中:
return homeController.renderView('example/form');