Nodejs MVC体系结构是此通心粉代码



我是一个初级nodejs dev,目前在加密货币交换平台上工作。这是项目文件夹结构。

/app
    /controllers
        /user
        /order
        /settings
        ...
        index.js
    /middlewares
    /models
    /routes
        user.js
        order.js
    /services
        user.js
        order.js
        ...
    /views
    index.js
/config
/migrations
/public
/utils
server.js
.env
...

现在,起初,这有点让人感到不知所措,但是后来,我变得很自在。
除了一个特定的文件!控制器目录中的index.js,这是设置的方式。

const { readdirSync, lstatSync } = require('fs');
const { validationSchema } = require('../../utils/validator');
module.exports = readdirSync('app/controllers')
  .filter(name => lstatSync(`app/controllers/${name}`).isDirectory())
  .reduce((controllersAccumulator, dir) => Object.assign(
    controllersAccumulator,
    {
      [`${dir}Controller`]: readdirSync(`app/controllers/${dir}`)
        .map(fileName => require(`./${dir}/${fileName}`))
        .reduce((accum, controllerFile) => Object.assign(
          accum,
          Object.keys(controllerFile).reduce(validationSchema.bind(null, dir, controllerFile), {}),
        ), {}),
    },
  ), {});

我必须承认,这对我来说总是很恐怖,只是为了看!因此,它用简单的话来说,它将路由请求映射到控制器目录中的处理程序。

例如

// in the routes dir, user.js 
const { userCOntroller } = require('../controllers/');
router.post('/registration', userController.registration);
// in the /controllers, then /user, there will be a registration.js that includes:
const UserService = require('../../services/user');
exports.registration = async (req, res) => await UserService.create(req.body);
//then in the /services directory, user.js
...
class UserService {
  static create(body) { ... }
  ...
}
module.exports = UserService

所以我仍然无法理解的是,我们是如何将userController的出现在上一段中的用户路由中导入的?因此,这就是/controllers中的index.js文件!
当我问团队中的高级人员时,他们说,是的,很难阅读,但代码较少。好吧,好:

所以,可以做些不同的事情以使该文件更可读,换句话说,有没有办法重构?预先感谢!

解释第一个代码段的最简单方法是重写并添加适当的评论:

//Get all file names inside the controllers directory
const fileList = readdirSync('app/controllers');
//Get only directories from the file list
const onlyDirectories = fileList.filter(name => lstatSync(`app/controllers/${name}`).isDirectory());
//Create an empty object that will be exported from this module. Properties of this object will be assigned in the "for of" loop
const objectToExport = {};
//Import all files from the given directory and assign them to objectToExport
for (let directoryName of onlyDirectories){
    //First get all file names
    const controllerFiles = readdirSync(`app/controllers/${directoryName}`);
    //Then require each of these files
    const controllerModules = controllerFiles.map(fileName => require(`./${directoryName}/${fileName}`));
    //Assign the imported modules to `objectToExport`
    controllerModules.forEach((controllerModule) => {
        //Validate each module and assign it only if it passes validation
        if (validationSchema(directoryName, controllerModule)){
            objectToExport[`${directoryName}Controller`] = controllerModule;
        }
    });
}
module.exports = objectToExport;

下面我会从评论中解决您的后续问题。结果对象现在看起来像这样:

{
    userController: {
        registration: [Function],
        ...
    },
    orderController: {
        ...
    },
    ...
}

注册函数最终在userController属性中最终出现,因为它是由registration.js导出的,然后由我的第一个代码段中的requient语句导入导入。为了直接在其他文件中使用此函数,您必须以以下方式破坏它:

const { userController: {registration} } = require('../controllers/');
//now you can use it like this:
router.post('/registration', registration);

您的最后一个问题是关于req.body。如您所见,该功能采用两个参数: REQ res

exports.registration = async (req, res) => await UserService.create(req.body);

然后将其作为中间件传递给您的路由器。我假设您将Express.js用作您的框架。如果是这样,路由器会自动传递reqresregistration功能。这就是UserService在此功能中可以使用它们的方式。如下所述,body属性是通过Express自动创建的。

最新更新