记录使用Node.js开发服务端的过程(2)

开头

你好!这是记录下我第一次使用 Node.js 开发服务端的全过程

目录的设计

为了确保项目的可维护性和扩展性,良好的项目结构设计至关重要。以下是个人使用的Koa.js项目目录结构示例,以及每个目录和文件的作用说明:

my-koa-app/
│
├── config/            # 存放配置文件,如数据库连接、环境变量等
│   └── db.js          # 数据库配置示例
│
├── controllers/       # 控制器,处理业务逻辑
│   └── userController.js  # 示例用户控制器文件
│
├── middlewares/       # 中间件,用于处理请求前后的逻辑
│   └──                
│
├── models/            # 数据模型,与数据库交互
│   └── user.js        # 示例用户数据模型
│
├── routes/            # 路由定义,映射HTTP请求到具体的控制器方法
│   └── userRoutes.js  # 示例用户路由文件
│
├── services/          # 服务层,封装复杂的业务逻辑或第三方API调用
│   └── userService.js   # 示例用户服务
│
├── utils/             # 工具函数或类,提供通用功能
│   └── response.js    # 示例返回工具函数
│
├── app.js             # 应用入口文件
├── server.js          # 启动服务器的脚本
└── package.json       # npm包管理文件

这样下来项目整体看下来就非常的清晰

对应的文件示例

我用本地数据库中的users表先做一个示例

package.json

mysql2 和 sequelize 后面有做说明

{
    
    
  "name": "hd-djb",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    
    
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    
    
    "koa": "^2.16.0",
    "koa-router": "^13.0.1",
    "mysql2": "^3.13.0",
    "sequelize": "^6.37.6"
  }
}

config/db.js

Sequelize 是一个对象关系映射(ORM)工具,它允许你使用面向对象的方式来操作数据库。你可以定义模型(Model),这些模型对应数据库中的表,通过操作模型实例来完成对数据库记录的增删改查,避免了直接编写大量复杂的 SQL 语句。

npm install mysql2 sequelize
const {
    
     Sequelize } = require('sequelize');

// 创建并导出 Sequelize 实例
module.exports = new Sequelize('demo', 'root', '123456', {
    
    
  host: 'localhost',
  dialect: 'mysql'
});

controllers/userController.js

const userService = require("../services/userService");
const {
    
     successResponse, errorResponse } = require("../utils/response");

exports.getAllUsers = async (ctx) => {
    
    
  try {
    
    
    const users = await userService.getAllUsers();
    successResponse(ctx, users);
  } catch (error) {
    
    
    errorResponse(ctx, error.message);
  }
};

middlewares/logger.js

先没用到

models/user.js

这一块我的表里的字段有点多,跟数据表对应就行了

const {
    
     DataTypes } = require("sequelize");
const sequelize = require("../config/db");

const User = sequelize.define(
  "User",
  {
    
    
    id: {
    
    
      type: DataTypes.INTEGER,
      allowNull: false,
      primaryKey: true,
      autoIncrement: true,
    },
    username: {
    
    
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
    },
    password: {
    
    
      type: DataTypes.STRING,
      allowNull: false,
    },
    email: {
    
    
      type: DataTypes.STRING,
      unique: true,
      allowNull: true,
    },
    first_name: {
    
    
      type: DataTypes.STRING,
      allowNull: true,
    },
    last_name: {
    
    
      type: DataTypes.STRING,
      allowNull: true,
    },
    full_name: {
    
    
      type: DataTypes.STRING,
      allowNull: true,
    },
    gender: {
    
    
      type: DataTypes.ENUM("male", "female", "other"),
      allowNull: true,
    },
    phone: {
    
    
      type: DataTypes.STRING,
      allowNull: true,
    },
    role: {
    
    
      type: DataTypes.ENUM("admin", "user", "student", "teacher"),
      allowNull: true,
    },
    student_id: {
    
    
      type: DataTypes.STRING,
      allowNull: true,
    },
    created_at: {
    
    
      type: DataTypes.DATE,
      defaultValue: DataTypes.NOW,
    },
    updated_at: {
    
    
      type: DataTypes.DATE,
      defaultValue: DataTypes.NOW,
      onUpdate: DataTypes.NOW,
    },
  },
  {
    
    
    tableName: "users",
    timestamps: true,
    underscored: true,
  }
);

module.exports = User;

routes/userRoutes.js

这里就写了一个get接口简单的测试一下

const Router = require("koa-router");
const router = new Router();
const {
    
     getAllUsers } = require("../controllers/userController");

router.get("/users", getAllUsers);
module.exports = router;

services/userService.js

const User = require('../models/user');

exports.getAllUsers = async () => {
    
    
  return await User.findAll();
};

utils/response.js

这一部分是做了一个简单的返回内容的规范

const successResponse = (
  ctx,
  data,
  message = "Operation successful",
  code = 200
) => {
    
    
  ctx.status = code; // 设置HTTP状态码
  ctx.body = {
    
    
    code, // 使用数字类型的code字段
    message,
    data,
  };
};

const errorResponse = (ctx, message = "An error occurred", code = 500) => {
    
    
  ctx.status = code; // 设置HTTP状态码
  ctx.body = {
    
    
    code, // 使用数字类型的code字段
    message,
  };
};

module.exports = {
    
    
  successResponse,
  errorResponse,
};

app.js

const Koa = require("koa");
const logger = require("./middlewares/logger");
const userRoutes = require("./routes/userRoutes");

const app = new Koa();

// 使用中间件
app.use(logger);

// 加载路由
app.use(userRoutes.routes()).use(userRoutes.allowedMethods());

module.exports = app;

server.js

const app = require("./app");

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
    
    
  console.log(`Server running on port ${
      
      PORT}`);
});

运行项目

npm start

现在,访问 http://localhost:3000/users,能查到user表里的所有数据。大体就是这样

{
    
    
  "code": 200,
  "message": "Operation successful",
  "data": [
    {
    
    
      "id": 1,
      "username": "Philip Parker",
      "password": "SWs7lv9VxN",
      "email": "[email protected]",
      "first_name": "Philip Parker",
      "last_name": "Philip Parker",
      "full_name": "Philip Parker",
      "gender": "female",
      "phone": "312-265-8773",
      "role": "student",
      "student_id": "aii1ia1bVL",
      "created_at": "2013-04-04T20:55:53.000Z",
      "updated_at": "2005-08-14T20:26:11.000Z",
      "createdAt": "2013-04-04T20:55:53.000Z",
      "updatedAt": "2005-08-14T20:26:11.000Z"
    },
    {
    
    
      "id": 2,
      "username": "Mak Suk Yee",
      "password": "KNRdoOFDPU",
      "email": "[email protected]",
      "first_name": "Mak Suk Yee",
      "last_name": "Mak Suk Yee",
      "full_name": "Mak Suk Yee",
      "gender": "female",
      "phone": "838-934-5155",
      "role": "student",
      "student_id": "Hg05USmAdm",
      "created_at": "2018-05-18T20:52:02.000Z",
      "updated_at": "2017-06-30T01:44:42.000Z",
      "createdAt": "2018-05-18T20:52:02.000Z",
      "updatedAt": "2017-06-30T01:44:42.000Z"
    }
  ]
}