You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
70 lines
2.9 KiB
70 lines
2.9 KiB
// 自动扫描 controllers 目录并注册路由
|
|
// 兼容传统 routes 方式和自动注册 controller 方式
|
|
import fs from "fs"
|
|
import path from "path"
|
|
|
|
/**
|
|
* 自动扫描 controllers 目录,注册所有导出的路由
|
|
* 自动检测 routes 目录下已手动注册的 controller,避免重复注册
|
|
* @param {Koa} app - Koa 实例
|
|
* @param {string} controllersDir - controllers 目录路径
|
|
* @param {string} prefix - 路由前缀
|
|
* @param {Set<string>} [manualControllers] - 可选,手动传入已注册 controller 文件名集合,优先于自动扫描
|
|
*/
|
|
export function autoRegisterControllers(app, controllersDir = path.resolve(__dirname, "../controllers")) {
|
|
let allRouter = []
|
|
async function scan(dir, routePrefix = "") {
|
|
for (const file of fs.readdirSync(dir)) {
|
|
const fullPath = path.join(dir, file)
|
|
const stat = fs.statSync(fullPath)
|
|
if (stat.isDirectory()) {
|
|
await scan(fullPath, routePrefix + "/" + file)
|
|
} else if (file.endsWith("Controller.js")) {
|
|
let controller
|
|
try {
|
|
controller = require(fullPath)
|
|
} catch (e) {
|
|
controller = (await import(fullPath)).default
|
|
}
|
|
const routes = controller.createRoutes || controller.default?.createRoutes || controller.default || controller
|
|
if (typeof routes === "function") {
|
|
allRouter.push(routes())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
;(async () => {
|
|
await scan(controllersDir)
|
|
// TODO: 存在问题:每个Controller都是有顺序的,如果其中一个Controller没有next方法,可能会导致后续的Controller无法执行
|
|
// allRouter.forEach(router => {
|
|
// app.use(router.middleware())
|
|
// })
|
|
// 聚合中间件:只分发到匹配的router
|
|
app.use(async (ctx, next) => {
|
|
let matched = false
|
|
for (const router of allRouter) {
|
|
// router._matchRoute 只在 router.js 内部,需暴露或用 middleware 包一层
|
|
if (typeof router._matchRoute === "function") {
|
|
const route = router._matchRoute(ctx.method.toLowerCase(), ctx.path)
|
|
if (route) {
|
|
matched = true
|
|
await router.middleware()(ctx, next)
|
|
break // 命中一个即停止
|
|
}
|
|
} else {
|
|
// fallback: 直接尝试middleware,若未命中会自动next
|
|
const before = ctx.status
|
|
await router.middleware()(ctx, next)
|
|
if (ctx.status !== before) {
|
|
matched = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (!matched) {
|
|
await next()
|
|
}
|
|
})
|
|
})()
|
|
}
|
|
|