如何将逻辑分解为控制器和节点中的模型



在使用后端应用程序时,我不太明白如何正确地破坏nodeJS中控制器和模型的逻辑。假设我有一个的例子

这段代码在我的应用程序模型中,从逻辑上讲,我知道模型只负责从数据库中进行选择,控制器和其他一切都应该由控制器完成,但我不太明白如何做到这一点,我试图将部分代码传输到控制器并导出它,但我没有成功(请帮忙,至少在这个例子中!对我来说,最重要的是理解在节点中使用MVC的原理!!!

exports.currentPostPage = function(req, res){

db.query('SELECT * FROM `posts`', function (err, result) {
if (err){
console.log(err);
}
var post = result.filter(item => {return (item.id == req.params.id)? item: false})[0];
if (post === undefined){
res.render('pages/404');
} else {
res.render('pages/post-page', {postId: req.params.id, item: post});
}
});
};

所以,你走在了正确的轨道上。根据偏好,有很多不同的方法可以做到这一点,但我经常看到的一种模式是使用回调作为集成的一种方式。例如,假设您有自己的模型文件:

exports.getPostById = (id, cb) => {
db.query('SELECT * FROM `posts` WHERE id=?', [id], function (err, result) {
if (err){
return cb(err); // or, alternatively, wrap this error in a custom error
}
// here, your logic is just returning whatever was returned
return cb(null, result); 
});
};

注意,我还让DB处理ID查找,因为对于较大的数据集,这样做可能更有效。您没有说明您使用的是什么DB模块,但所有好的模块都有一些进行参数化查询的方法,所以请使用任何与您的DB驱动程序一起工作的模块。

无论如何,模型文件因此只处理数据交互,然后控制器处理网络交互:

// postController.js
const model = require('../models/postModel.js'); // or whatever you named it
exports.populatePost = (req, res, next, id) => {
model.getPostById(id, (err, post) => {
if (err) return next(err); // centralized error handler
req.post = post;
next(); 
});
}
export.getOnePost = (req, res, next) => {
if (req.post) {
return res.render('pages/post-page', req.post);
}
// again, central error handling
return next({ status: 404, message: 'Post not found' });
}

我已经提到了中央错误处理;我非常喜欢它,而不是把错误处理逻辑分散在各处。所以我要么自定义错误来表示内容,要么像上面那样将状态和消息附加到匿名对象。任何一种都符合我们的目的。然后,在中间件文件中,您可以有一个或多个处理程序,最简单的如下:

// middleware/errors.js
module.exports = (err, req, res, next) => {
console.error(err); // log it
if (err.status) {
return res.status(err.status).render(`errors/${err.status}`, err.message);
} 
return res.status(500).render('errors/500', err.message);
}

最后,在你的路由设置中,你可以这样做:

const postController = require('../controllers/postController');
const errorHandler = require('../middleware/errors.js');
const postRouter = express.Router();
postRouter.param('postId', postController.populatePost);
postRouter.get('/:postId', postController.getOnePost);
// other methods and routes
app.use('/posts', postRouter)
// later
app.use(errorHandler);

正如评论中所指出的,有些人更喜欢使用Promise语法来进行回调。我个人并没有发现更干净的,除非你也使用async/await语法。例如,如果您的数据库库支持promise,则可以将模型代码更改为如下所示:

exports.getPostById = async (id, cb) => {
// again, this assumes db.query returns a Promise
return await db.query('SELECT * FROM `posts` WHERE id=?', [id]);
}

然后你的控制器代码同样需要更改来处理这个问题:

// postController.js
const model = require('../models/postModel.js'); // or whatever you named it
exports.populatePost = async (req, res, next, id) => {
try {
const post = await model.getPostById(id)
req.post = post
return next()
} catch (err) {
return next(err)
}
}

最新更新