在之前的文章中,已经可以实现url与处理器函数之间的映射。但是把代码直接写在app.js中似乎十分不妥,一个是会造成app.js文件的冗长,二是不好扩展和修改。为了解决这个问题,可以将处理函数封装为一个个模块,在启动服务器时再将url和处理器模块映射起来。这样就可以解决如上所述的问题。
但是除了将处理器函数封装为单独的模块之外,还需要一段将url和处理器模块映射起来的代码用于在服务器启动的时候执行。
首先创建一个controllers目录,在此目录下编写处理器模块。一个简单的示例如下:
var hello = async (ctx, next) => {
var name = ctx.params.name;
ctx.response.body = `<h1>Hello, ${name}!</h1>`;
};
module.exports = {
'GET /hello/:name':hello
};
然后再加上一个controller.js模块,在此模块中映射url和处理器模块,代码如下:
const fs = require('fs');
function addMapping(router, mapping) {
for (var url in mapping) {
if (url.startsWith('GET ')) {
var path = url.substring(4);
router.get(path, mapping[url]);
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith('POST ')) {
var path = url.substring(5);
router.post(path, mapping[url]);
console.log(`register URL mapping: POST ${path}`);
} else {
console.log(`invalid URL: ${url}`);
}
}
}
function addControllers(router) {
var files = fs.readdirSync(__dirname + '/controllers');
var js_files = files.filter((f) => {
return f.endsWith('.js');
});
for (var f of js_files) {
console.log(`process controller: ${f}...`);
let mapping = require(__dirname + '/controllers/' + f);
addMapping(router, mapping);
}
}
module.exports = function (dir) {
let
controllers_dir = dir || 'controllers', // 如果不传参数,扫描目录默认为'controllers'
router = require('koa-router')();
addControllers(router, controllers_dir);
return router.routes();
};
controller.js文件一般不需要变动。接下来是app.js的代码:
'use strict';
const Koa = require('koa');
// 创建一个Koa对象表示web app本身:
const app = new Koa();
const controller = require('./controller');
app.use(controller());
// 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');
可以看到app.js的代码简化了许多,而且即使有代码的修改和扩展也不会受到影响。真正做到了开闭原则。