模块化设计
⏱️最后更新: 2025/07/27
1. 目录
bash
npm init -y
markdown
advance-002/
├── src/
│ ├── index.js # 入口文件(启动服务器、配置中间件)
│ ├── routes/ # 路由模块(定义接口路径)
│ │ └── userRoutes.js # 用户路由
│ ├── controllers/ # 控制器模块(处理请求/响应逻辑)
│ │ └── userController.js
│ ├── services/ # 服务模块(处理业务逻辑,与数据层交互)
│ │ └── userService.js
│ ├── utils/ # 工具模块(通用函数,如日期格式化、错误处理)
│ │ └── formatDate.js
│ └── middlewares/ # 中间件模块(全局/局部中间件)
│ └── errorHandler.js
├── .env # 环境变量配置
├── .gitignore # 忽略文件(如 node_modules、.env)
└── package.json # 项目配置
2. 安装依赖
bash
npm install express dotenv
npm install nodemon --save-dev
3. 编写模块化代码
3.1 环境变量配置(.env)
在项目根目录创建.env
文件,定义端口等变量:
bash
PORT=3000
API_PREFIX=/api
3.2 入口文件(src/index.js)
加载环境变量、配置 Express、挂载路由和中间件:
javascript
// src/index.js
import express from "express";
import dotenv from "dotenv";
import userRoutes from "./routes/userRoutes.js"; // 导入用户路由(注意扩展名.js)
import errorHandler from "./middlewares/errorHandler.js"; // 导入错误处理中间件
// 加载环境变量
dotenv.config();
// 创建Express实例
const app = express();
const port = process.env.PORT || 3000;
const apiPrefix = process.env.API_PREFIX || "/api";
// 全局中间件
app.use(express.json()); // 解析JSON请求体
app.use(express.urlencoded({ extended: true })); // 解析URL编码的请求体
// 挂载路由(带API前缀)
app.use(`${apiPrefix}/users`, userRoutes);
// 错误处理中间件(需放在所有路由之后)
app.use(errorHandler);
// 启动服务器
app.listen(port, () => {
console.log(`Server running on port ${port} (API prefix: ${apiPrefix})`);
});
3.3 路由模块(src/routes/userRoutes.js)
定义用户相关的路由,映射到控制器的方法:
javascript
// src/routes/userRoutes.js
import express from "express";
import userController from "../controllers/userController.js"; // 导入用户控制器
const router = express.Router();
// 定义路由:GET /api/users/:id(获取单个用户)
router.get("/:id", userController.getUserById);
// 定义路由:POST /api/users(创建用户)
router.post("/", userController.createUser);
export default router; // 导出路由实例
3.4 控制器模块(src/controllers/userController.js)
处理请求与响应逻辑,调用服务层的业务方法:
javascript
// src/controllers/userController.js
import userService from "../services/userService.js"; // 导入用户服务
import { formatDate } from "../utils/formatDate.js"; // 导入工具函数
const userController = {
// 获取单个用户(GET /api/users/:id)
getUserById: async (req, res, next) => {
try {
const userId = req.params.id;
const user = await userService.getUser(userId); // 调用服务层方法
if (!user) {
return res.status(404).json({ message: "User not found" });
}
// 使用工具函数格式化日期
user.createdAt = formatDate(user.createdAt);
res.json(user); // 返回JSON响应
} catch (err) {
next(err); // 将错误传递给错误处理中间件
}
},
// 创建用户(POST /api/users)
createUser: async (req, res, next) => {
try {
const userData = req.body;
const newUser = await userService.createUser(userData); // 调用服务层方法
res.status(201).json(newUser); // 返回创建的用户(201状态码)
} catch (err) {
next(err);
}
},
};
export default userController; // 导出控制器实例
3.5 服务模块(src/services/userService.js)
处理业务逻辑(如数据验证、数据库交互),不直接接触请求/响应:
javascript
// src/services/userService.js
// 模拟数据库(实际项目中可替换为MongoDB/MySQL查询)
const users = [
{ id: "1", name: "Alice", age: 25, createdAt: new Date() },
{ id: "2", name: "Bob", age: 30, createdAt: new Date() },
];
const userService = {
// 获取用户(业务逻辑:根据ID查找用户)
getUser: async (userId) => {
return users.find((user) => user.id === userId);
},
// 创建用户(业务逻辑:验证数据、添加用户)
createUser: async (userData) => {
// 模拟数据验证(实际项目中可使用Joi/Yup)
if (!userData.name || !userData.age) {
throw new Error("Name and age are required");
}
const newUser = {
id: String(users.length + 1),
...userData,
createdAt: new Date(),
};
users.push(newUser);
return newUser;
},
};
export default userService; // 导出服务实例
3.6 工具模块(src/utils/formatDate.js)
定义通用工具函数,可被多个模块导入使用:
javascript
// src/utils/formatDate.js
/**
* 格式化日期(如:2024-05-20 14:30:00)
* @param {Date} date - 日期对象
* @returns {string} 格式化后的日期字符串
*/
export function formatDate(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
3.7 错误处理中间件(src/middlewares/errorHandler.js)
处理全局错误(如 404、500 错误),返回统一的错误响应:
javascript
// src/middlewares/errorHandler.js
const errorHandler = (err, req, res, next) => {
console.error("Error:", err.message); // 打印错误日志(实际项目中可使用日志工具如winston)
// 统一错误响应格式
res.status(err.statusCode || 500).json({
message: err.message || "Internal Server Error",
errors: err.errors || [],
});
};
export default errorHandler;
4、测试项目
4.1 运行项目
bash
npm start # 或 npm run dev(热更新)
4.2 测试接口
使用 Postman 或浏览器测试以下接口:
- 获取用户:
GET http://localhost:3000/api/users/1
响应:
json
{
"id": "1",
"name": "Alice",
"age": 25,
"createdAt": "2024-05-20 14:30:00"
}
- 创建用户:
POST http://localhost:3000/api/users
(请求体为{"name": "Charlie", "age": 28}
) 响应(201 状态码):
json
{
"id": "3",
"name": "Charlie",
"age": 28,
"createdAt": "2024-05-20 14:35:00"
}