# 项目结构推荐

URL: https://caijiao.org/express/chapter9/1-structure
Source: docs/express/chapter9/1-structure.md
Description: 本章节将介绍在开发 Express 应用时如何设计项目结构，确保项目在扩展和维护时更加高效和清晰。合理的项目结构是实现可维护、可扩展 Web 应用的关键。

一个良好的项目结构对于开发和维护 Web 应用至关重要。在开发 Express 应用时，合理组织代码可以让项目更加清晰、模块化，并且容易扩展和维护。在本章节中，我们将介绍如何设计一个符合最佳实践的 Express 项目结构。

## 1. 基本项目结构

一个典型的 Express 项目结构通常包含以下几个主要部分：

```plaintext
my-express-app/
│
├── bin/                # 启动脚本目录
│   └── www             # 应用启动文件
│
├── config/             # 配置文件目录
│   └── default.js      # 默认配置文件
│
├── controllers/        # 控制器目录，处理路由和业务逻辑
│   └── userController.js
│
├── middleware/         # 中间件目录
│   └── auth.js         # 身份验证中间件
│
├── models/             # 数据模型目录
│   └── user.js         # 用户模型
│
├── routes/             # 路由文件目录
│   └── userRoutes.js   # 用户相关路由
│
├── services/           # 服务层目录，处理复杂的业务逻辑
│   └── userService.js  # 用户服务
│
├── views/              # 视图文件目录（如果使用模板引擎）
│   └── index.ejs       # 主页视图文件
│
├── public/             # 公共资源目录，存放静态文件（如图片、CSS、JS等）
│   ├── images/
│   └── stylesheets/
│
├── node_modules/       # Node.js 依赖包
│
├── package.json        # 项目元数据和依赖管理文件
└── README.md           # 项目说明文件
````

### 1.1 目录和文件简介

* **bin/**：存放启动脚本，`www` 文件是启动应用的入口文件，它通常用来启动 Express 服务器。
* **config/**：存放配置文件，`default.js` 存储一些默认配置项，如数据库连接、端口等。
* **controllers/**：控制器目录，负责处理路由和应用的核心业务逻辑。
* **middleware/**：存放中间件文件，包含身份验证、日志记录等功能。
* **models/**：数据模型目录，通常与数据库进行交互。每个模型文件通常对应数据库中的一张表。
* **routes/**：路由文件目录，定义不同的 API 路由并与控制器进行关联。
* **services/**：服务层，处理复杂的业务逻辑，可以调用多个控制器来完成一个请求。
* **views/**：视图文件，通常与模板引擎（如 EJS、Pug）配合使用，生成动态的 HTML 页面。
* **public/**：存放静态文件，如图片、样式表和前端脚本。
* **node\_modules/**：存放所有项目的 Node.js 依赖包。
* **package.json**：管理项目依赖、脚本和项目配置。
* **README.md**：项目说明文件，提供项目介绍、安装和使用文档。

## 2. 项目结构的优化建议

### 2.1 按功能模块组织

除了基本的项目结构外，按功能模块组织代码也是一种常见的做法。这种方式将相关的代码、路由、模型和视图集中在同一文件夹中，便于维护和扩展。

例如，如果你的应用有“用户管理”功能，那么你可以创建一个 `user` 文件夹，包含与用户相关的所有内容：

```plaintext
my-express-app/
├── user/
│   ├── controllers/      # 用户相关控制器
│   │   └── userController.js
│   ├── models/           # 用户相关模型
│   │   └── user.js
│   ├── routes/           # 用户相关路由
│   │   └── userRoutes.js
│   └── services/         # 用户相关服务
│       └── userService.js
```

### 2.2 配置文件管理

在 `config` 文件夹中管理应用的配置项。常见的配置包括数据库连接、环境变量、API 密钥等。你可以使用类似 `config.js` 或 `config.json` 的文件来存储这些信息。

```js
// config/default.js
module.exports = {
  db: {
    host: 'localhost',
    port: 27017,
    name: 'myapp'
  },
  port: 3000,
  jwtSecret: 'your-secret-key'
};
```

为了确保项目的灵活性，可以根据不同的环境（开发、测试、生产）创建不同的配置文件，并在启动时加载相应的配置。

### 2.3 使用环境变量

将敏感信息（如 API 密钥、数据库连接字符串）存储在环境变量中，而不是硬编码在代码中。你可以使用 `dotenv` 库来加载 `.env` 文件中的配置项：

```bash
npm install dotenv
```

在项目根目录创建一个 `.env` 文件：

```plaintext
DB_HOST=localhost
DB_PORT=27017
DB_NAME=myapp
JWT_SECRET=your-secret-key
```

然后在代码中加载环境变量：

```js
require('dotenv').config();

const dbHost = process.env.DB_HOST;
const jwtSecret = process.env.JWT_SECRET;
```

### 2.4 错误处理

为项目添加全局错误处理机制，将错误捕获和处理逻辑集中管理，可以提高项目的可维护性和可靠性。

```js
// errorHandler.js
function errorHandler(err, req, res, next) {
  console.error(err.stack);
  res.status(500).send('Something went wrong!');
}

module.exports = errorHandler;
```

然后在 `app.js` 中使用：

```js
const errorHandler = require('./middleware/errorHandler');

app.use(errorHandler);
```

## 3. 示例代码

以下是一个基本的 Express 应用结构示例，展示了如何按功能模块组织代码：

```plaintext
my-express-app/
├── user/
│   ├── controllers/
│   │   └── userController.js
│   ├── models/
│   │   └── user.js
│   ├── routes/
│   │   └── userRoutes.js
│   └── services/
│       └── userService.js
├── app.js
├── config/
│   └── default.js
├── public/
├── views/
├── middleware/
│   └── errorHandler.js
└── package.json
```

### 3.1 用户路由（userRoutes.js）

```js
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');

// 获取用户列表
router.get('/', userController.getUsers);

// 用户注册
router.post('/register', userController.register);

module.exports = router;
```

### 3.2 用户控制器（userController.js）

```js
const userService = require('../services/userService');

exports.getUsers = (req, res) => {
  const users = userService.getAllUsers();
  res.json(users);
};

exports.register = (req, res) => {
  const { username, password } = req.body;
  const user = userService.createUser(username, password);
  res.status(201).json(user);
};
```

### 3.3 用户服务（userService.js）

```js
const users = [];

exports.getAllUsers = () => {
  return users;
};

exports.createUser = (username, password) => {
  const newUser = { username, password };
  users.push(newUser);
  return newUser;
};
```

## 4. 总结

通过合理的项目结构设计，可以让 Express 项目更加模块化、易于扩展和维护。在本章节中，我们介绍了：

* **基本项目结构**：推荐的文件夹和文件布局，包括 `controllers`、`models`、`routes` 等。
* **按功能模块组织代码**：将与特定功能相关的代码集中在一个文件夹中，便于管理和扩展。
* **配置和环境变量管理**：使用 `config` 文件和 `.env` 文件管理应用配置，避免硬编码敏感信息。
* **错误处理机制**：集中处理全局错误，保证系统的健壮性。

合理的项目结构不仅能提高开发效率，也能使团队协作更加顺畅，是开发高质量应用的基础。
