Vapor 教程
控制器与 MVC 架构
路由只有两三条时,全写进 routes.swift 还凑合;等到几十条,就成了灾难。Vapor 用「控制器」把相关路由收拢成模块,背后的思想就是经典的 MVC。
一、为什么需要控制器
Web 开发里有个流行套路叫 MVC:
- Model(模型):数据库里的数据结构,比如「缩略语」。
- View(视图):展示给用户的页面(HTML)。
- Controller(控制器):决定「数据怎么被取出来、怎么呈现」的那层逻辑。
把路由按主题塞进各自的控制器,routes.swift 就只剩「挂载」这件事,清爽得多。
二、控制器长什么样
一个控制器就是一个遵循 RouteCollection 的结构体,在 boot() 里注册自己的路由:
import Vapor
import Fluent
struct AcronymsController: RouteCollection {
func boot(routes: RoutesBuilder) throws {
routes.post("api", "acronyms", use: createHandler)
}
func createHandler(_ req: Request) throws -> EventLoopFuture<Acronym> {
let data = try req.content.decode(CreateAcronymData.self)
let acronym = Acronym(short: data.short, long: data.long)
return acronym.save(on: req.db).map { acronym }
}
}版本提示:上面是 Vapor 4 写法(用
RoutesBuilder 和 req.db)。Vapor 3 里对应的是 func boot(router: Router) 以及 req 上的 .save(on: req) 返回 Future。思路一致,只是 API 名字不同。三、把控制器挂上去
routes.swift 退居「接线员」角色,只负责创建并注册控制器:
import Vapor
func routes(_ app: Application) throws {
let acronymsController = AcronymsController()
try app.register(collection: acronymsController)
let websiteController = WebsiteController()
try app.register(collection: websiteController)
}这样「接口类路由」和「网页类路由」各归各家,文件不再是一坨。
四、RouteGroup:给路由加统一前缀
当控制器里多条路由都挂在 api/acronyms 下,每条都写完整路径就太啰嗦。用 RouteGroup 提一次前缀:
func boot(routes: RoutesBuilder) throws {
let group = routes.grouped("api", "acronyms")
group.post(use: createHandler)
group.get(use: getAllHandler)
group.get(":acronymID", use: getHandler)
group.delete(":acronymID", use: deleteHandler)
}四条路由自动带上 /api/acronyms 前缀,少写很多重复字符串,也少了拼错路径的机会。
五、控制器里能做什么
控制器是真正的「业务中枢」:
- 调 Fluent 读写数据库(下一篇细讲);
- 调 Leaf 渲染网页(做网站时);
- 调用中间件做鉴权、日志等横切逻辑。
把路由逻辑从 routes.swift 搬到控制器,是你项目从「玩具」走向「能维护」的关键一步。