一、前言
MVC(Model-View-Controller)是一种软件设计模式,用于将应用程序的逻辑、数据和界面进行分离,使得各个部分职责明确、便于开发、维护以及扩展。
以下是一个在 Node.js 中使用 Mongoose、MVC 架构并额外添加了services
层来实现对书籍资源进行增、删、改、查操作的示例,同样以返回 JSON 数据的方式来处理请求与响应,基于 Express 框架搭建:
二、项目结构
book-app/
├── models
│ └── book.js
├── services
│ └── bookService.js
├── controllers
│ └── bookController.js
└── app.js
1. 模型(Model)定义(models/book.js
)
const mongoose = require('mongoose');
const bookSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
author: {
type: String,
required: true
},
publicationYear: {
type: Number
}
});
const Book = mongoose.model('Book', bookSchema);
module.exports = Book;
2. 服务(Service)层定义(services/bookService.js
)
服务层主要用于封装对数据库的具体操作逻辑,使得业务逻辑更加清晰,便于复用和维护。
const Book = require('../models/book');
// 获取所有书籍的服务函数
const getAllBooks = async () => {
try {
return await Book.find();
} catch (error) {
throw new Error('Internal Server Error');
}
};
// 创建新书的服务函数
const createBook = async (bookData) => {
try {
const newBook = new Book(bookData);
return await newBook.save();
} catch (error) {
throw new Error('Bad Request');
}
};
// 更新书籍的服务函数
const updateBook = async (bookId, updatedData) => {
try {
const updatedBook = await Book.findByIdAndUpdate(bookId, updatedData, {
new: true
});
if (!updatedBook) {
throw new Error('Book not found');
}
return updatedBook;
} catch (error) {
throw new Error('Internal Server Error');
}
};
// 删除书籍的服务函数
const deleteBook = async (bookId) => {
try {
const deletedBook = await Book.findByIdAndDelete(bookId);
if (!deletedBook) {
throw new Error('Book not found');
}
return { message: 'Book deleted successfully' };
} catch (error) {
throw new Error('Internal Server Error');
}
};
module.exports = {
getAllBooks,
createBook,
updateBook,
deleteBook
};
3. 控制器(Controller)定义(controllers/bookController.js
)
控制器层负责接收来自路由的请求,调用服务层的相应函数来处理业务逻辑,并将处理结果返回给客户端。
const bookService = require('../services/bookService');
// 获取所有书籍的控制器函数
const getBooks = async (req, res) => {
try {
const books = await bookService.getAllBooks();
res.status(200).json(books);
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message });
}
};
// 创建新书的控制器函数
const createBook = async (req, res) => {
try {
const newBook = await bookService.createBook(req.body);
res.status(201).json(newBook);
} catch (error) {
console.error(error);
res.status(400).json({ error: error.message });
}
};
// 更新书籍的控制器函数
const updateBook = async (req, res) => {
try {
const { id } = req.params;
const updatedBook = await bookService.updateBook(id, req.body);
res.status(200).json(updatedBook);
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message });
}
};
// 删除书籍的控制器函数
const deleteBook = async (req, res) => {
try {
const { id } = req.params;
const result = await bookService.deleteBook(id);
res.status(200).json(result);
} catch (error) {
console.error(error);
res.status(500).json({ error: error.message });
}
};
module.exports = {
getBooks,
createBook,
updateBook,
deleteBook
};
4. 应用程序入口及路由配置(app.js
)
const express = require('express');
const app = express();
const bookController = require('./controllers/bookController');
// 配置中间件,用于解析POST请求中的JSON数据
app.use(express.json());
// 定义路由
// 获取所有书籍的路由
app.get('/books', bookController.getBooks);
// 创建新书的路由
app.post('/books', bookController.createBook);
// 更新书籍的路由,注意这里接收书籍的id作为路由参数
app.put('/books/:id', bookController.updateBook);
// 删除书籍的路由,同样接收书籍的id作为路由参数
app.delete('/books/:id', bookController.deleteBook);
const port = 3000;
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
5. 使用示例
- 查询所有书籍:发送
GET
请求到http://localhost:3000/books
,服务器会返回状态码为200
的包含所有书籍信息的 JSON 数组。 - 创建新书:发送
POST
请求到http://localhost:3000/books
,在请求体中以 JSON 格式传递书籍的相关信息(如{ "title": "New Book", "author": "Author Name", "publicationYear": 2024 }
),成功后服务器返回状态码201
以及新创建书籍的信息(以 JSON 格式)。 - 更新书籍:发送
PUT
请求到http://localhost:3000/books/[book_id]
(其中[book_id]
是要更新书籍的实际MongoDB
文档_id
),同时在请求体中以 JSON 格式传递要更新的书籍信息,若更新成功,服务器返回状态码200
及更新后的书籍信息(以 JSON 格式),若找不到对应书籍则返回状态码404
及相应错误提示信息(以 JSON 格式)。 - 删除书籍:发送
DELETE
请求到http://localhost:3000/books/[book_id]
(其中[book_id]
是要删除书籍的实际MongoDB
文档_id
),若删除成功,服务器返回状态码200
及表示成功删除的消息(以 JSON 格式),若找不到对应书籍则返回状态码404
及相应错误提示信息(以 JSON 格式)。
三、注意
要运行这个示例,首先要确保已经安装了 Node.js、Express、Mongoose(可以通过 npm install express mongoose
命令安装),然后在项目根目录下使用 node app.js
命令启动服务器,即可按照上述使用示例进行相应的操作。
这样的分层架构使得代码结构更加清晰,不同层专注于不同的职责,便于后续的扩展和维护。例如,如果后续需要更改数据库操作逻辑或者添加更多复杂的业务逻辑,只需要在对应的服务层或者控制器层进行修改,而不会对其他层造成太大影响。