今天,我们着手做一个仓储管理,原材入库的模块,以实际的项目来进一步了解node.js,学以致用,反补理论知识。
工程结构
创建一个仓储管理的原材入库模块,使用Node.js作为后端服务,可以采用以下工程结构:
warehouse-management/
├── node_modules/ # 依赖的npm包
├── src/ # 源代码目录
│ ├── controllers/ # 控制器目录
│ │ └── material.js # 原材入库控制器
│ ├── models/ # 数据模型目录
│ │ └── material.js # 原材入库模型
│ ├── routes/ # 路由目录
│ │ └── material.js # 原材入库路由
│ ├── services/ # 服务目录
│ │ └── material.js # 原材入库服务(如数据库操作)
│ ├── utils/ # 工具目录
│ │ └── ... # 工具函数或类
│ ├── app.js # 主应用文件
│ └── config/ # 配置目录
│ └── database.js # 数据库配置文件
├── package.json # 项目依赖和配置
├── .gitignore # Git忽略文件
├── README.md # 项目说明文档
└── ... # 其他可能需要的文件,如日志配置、测试文件等
以下是每个目录和文件的简单说明:
node_modules/
存放项目依赖的npm包。
src/
源代码目录,包含项目的所有核心代码。
controllers/
存放控制器文件,这些文件负责处理HTTP请求并返回响应。material.js
将处理与原材入库相关的请求。
models/
存放数据模型文件,这些文件定义了与数据库表对应的对象结构。material.js
将定义原材入库相关的数据模型。
routes/
存放路由文件,这些文件定义了URL路径与控制器方法的映射关系。material.js
将定义原材入库相关的路由。
services/
存放服务文件,这些文件包含与业务逻辑相关的代码,例如数据库操作、文件操作等。material.js
将包含与原材入库相关的数据库操作逻辑。
utils/
存放工具函数或类,这些函数或类在整个项目中可能都会被使用到。
app.js
主应用文件,用于初始化应用,设置中间件,加载路由等。
config/
存放配置文件,例如数据库配置、应用环境配置等。database.js
将包含数据库连接配置。
package.json
项目依赖和配置文件,包含项目名称、版本、描述、脚本命令、依赖项等信息。
.gitignore
Git忽略文件,指定哪些文件和目录不应被Git跟踪。
README.md
项目说明文档,包含项目的安装、使用、配置等说明。
其他文件
可能还包括日志文件配置、测试文件等,在这里我们先不配置,后期有需要再加。
大家注意,前期设计一个工程的时候要综合考虑投产比,并不一定是最全的就是最好的,最合适的才是最好的
工程代码
以下是基于上述工程结构,每个目录和文件中可能包含的代码:
src/controllers/material.js
javascript
const MaterialService = require('../services/material');
class MaterialController {
async createMaterial(req, res) {
try {
const material = await MaterialService.createMaterial(req.body);
res.status(201).json(material);
} catch (error) {
res.status(500).json({ message: 'Error creating material' });
}
}
// 可以添加其他与材料入库相关的控制器方法
}
module.exports = new MaterialController();
src/models/material.js
javascript
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = require('../config/database');
const Material = sequelize.define('material', {
materialCode: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
description: {
type: DataTypes.STRING,
allowNull: false
},
quantity: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
// 可以添加其他字段
}, {
timestamps: true
});
module.exports = Material;
src/routes/material.js
javascript
const express = require('express');
const router = express.Router();
const MaterialController = require('../controllers/material');
router.post('/materials', MaterialController.createMaterial);
// 可以添加其他与材料入库相关的路由
module.exports = router;
src/services/material.js
javascript
const Material = require('../models/material');
class MaterialService {
async createMaterial(materialData) {
const material = await Material.create(materialData);
return material;
}
// 可以添加其他与材料入库相关的服务方法
}
module.exports = new MaterialService();
src/app.js
javascript
const express = require('express');
const bodyParser = require('body-parser');
const materialRoutes = require('./routes/material');
const app = express();
app.use(bodyParser.json());
app.use('/api', materialRoutes);
// 可以添加其他中间件和路由
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
src/config/database.js
javascript
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: 'mysql', // 根据你的数据库类型选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 等
logging: false // 在生产环境中,你可能想要禁用日志或将其记录到文件
});
module.exports = sequelize;
package.json
json
{
"name": "warehouse-management",
"version": "1.0.0",
"description": "Warehouse Management System - Material Inbound Module",
"main": "src/app.js",
"scripts": {
"start": "node src/app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1",
"sequelize": "^6.3.5" // 根据你的数据库类型安装相应的驱动,例如 'mysql2'
},
"devDependencies": {
// 开发时需要的依赖项,例如测试工具等
}
}
.gitignore
node_modules/
.env
README.md
Warehouse Management - Material Inbound Module
This is a module for managing the inbound materials in a warehouse
system.
注意事项
在上面的工程结构和代码中,有几个需要特别注意的注意事项:
目录和文件结构
-
模块化:确保每个目录和文件都遵循单一职责原则,即每个模块只做一件事情。这有助于代码的可维护性和可读性。
-
命名规范:文件名和目录名应该使用小写字母,多个单词之间可以使用短横线分隔。避免使用空格或特殊字符。
-
配置文件 :配置文件(如
database.js
)应该包含敏感信息(如数据库用户名和密码)的占位符,并在实际部署时通过环境变量或安全的方式提供这些值。
代码质量
-
错误处理 :确保所有的异步操作都有适当的错误处理逻辑。在上面的代码中,我们使用了
try...catch
块来捕获并处理可能发生的错误。 -
输入验证:在控制器层,应该验证所有来自客户端的输入数据,以确保其有效性和安全性。这可以通过使用中间件或直接在控制器方法中完成。
-
日志记录 :虽然示例代码中没有显式展示日志记录,但在实际开发中,记录重要的操作和错误信息是很有必要的。可以使用专门的日志库(如
winston
或pino
)来实现。
安全性
-
防止SQL注入:使用ORM(对象关系映射)工具(如Sequelize)可以大大减少SQL注入的风险,因为它会自动处理查询的转义。但是,仍然需要小心处理用户输入,避免直接在SQL查询中拼接字符串。
-
保护敏感信息:不要在代码中硬编码敏感信息,如数据库凭据、API密钥等。这些信息应该通过环境变量或配置文件(确保配置文件不被公开)来提供。
-
中间件:使用中间件可以方便地处理跨多个路由的通用任务,如身份验证、授权、日志记录等。确保正确配置和使用中间件。
可扩展性和可维护性
-
代码注释:为代码添加适当的注释,解释每个函数、类和模块的作用和用法。这有助于其他开发者理解和维护代码。
-
测试:编写单元测试和功能测试以确保代码的正确性。这有助于在代码变更时快速发现并修复问题。
-
文档:为项目编写文档,包括API文档、系统使用说明等。这有助于其他开发者或用户了解和使用你的系统。
环境配置
-
环境变量:使用环境变量来配置不同环境(如开发、测试、生产)的设置。这可以避免在代码中直接包含这些配置,从而提高代码的可移植性和安全性。
-
.gitignore :确保
.gitignore
文件正确配置,以避免将敏感信息或不必要的文件提交到版本控制系统中。
遵循这些注意事项将有助于创建一个健壮、可维护和安全的仓库管理系统模块。
敏感数据-数据库使用环境变量
敏感数据不能直接放在代码层的配置文件中,因为这样谁都可以看到了,是一个巨大的安全风险,要使用环境变量来配置不同环境,并在database.js
中使用它们,你可以按照以下步骤操作:
1. 设置环境变量
首先,在你的系统上设置环境变量。这通常可以在操作系统的环境设置中进行,或者你可以在你的命令行界面中使用export
命令(在Unix/Linux/macOS中)或set
命令(在Windows中)。
例如,在Unix/Linux/macOS的bash shell中,你可以这样做:
bash
export DATABASE_URL="mysql://username:password@localhost:3306/database_name"
在Windows的cmd中,你可以这样做:
cmd
set DATABASE_URL=mysql://username:password@localhost:3306/database_name
或者,在Windows的PowerShell中:
powershell
$env:DATABASE_URL="mysql://username:password@localhost:3306/database_name"
2. 在database.js
中读取环境变量
在你的Node.js项目中,你可以使用process.env
对象来访问环境变量。在你的database.js
文件中,你可以这样做:
javascript
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize(
process.env.DATABASE_URL, // 使用环境变量中的数据库连接字符串
{
dialectOptions: {
// 在这里,你可以添加特定于数据库方言的选项,例如对于PostgreSQL的ssl选项
},
logging: console.log, // 或者设置为false来禁用日志,或者使用一个日志库
// 其他Sequelize配置选项...
}
);
module.exports = sequelize;
确保你的数据库连接字符串是正确格式的,并且与你所使用的数据库相匹配。上面的例子是一个通用的MySQL连接字符串格式。
3. 使用.env
文件(可选)
为了更方便地管理环境变量,你可以使用.env
文件来存储这些变量,特别是在开发环境中。然后,你可以使用dotenv
库来加载这些变量。
首先,安装dotenv
:
bash
npm install dotenv
然后,在你的项目根目录下创建一个.env
文件,并添加你的环境变量:
DATABASE_URL=mysql://username:password@localhost:3306/database_name
在你的database.js
(或任何启动脚本)文件的顶部,引入并使用dotenv
:
javascript
require('dotenv').config();
// 现在你可以像之前一样使用process.env.DATABASE_URL了
请注意,.env
文件应该不被版本控制系统(如Git)跟踪,所以确保在.gitignore
文件中添加.env
。
4. 为不同环境配置不同的变量
对于不同的环境(开发、测试、生产),你可以创建不同的.env
文件(例如.env.development
、.env.test
、.env.production
),并在你的启动脚本中根据当前的环境加载相应的文件。
或者,你可以直接在命令行中设置不同的环境变量,并在你的CI/CD流程或部署脚本中管理它们。
确保在生产环境中,敏感信息(如数据库凭据)不会被硬编码在代码中,并且不会被公开或泄露。使用环境变量和.env
文件是一种安全的做法,因为这些文件通常不会被包含在代码库中。