【Node.js从基础到高级运用】十六、代码组织与项目结构(服务层和仓储模式)

引言

在Node.js项目中,除了MVC之外,还有一些其他流行的设计模式,可以帮助我们更好地组织代码和项目结构。本次我们将探讨服务层(Service Layer)仓储模式(Repository Pattern)。这两种模式非常适用于构建结构清晰、可维护性强的大型应用。

服务层(Service Layer)

服务层是位于应用程序的业务逻辑层和表示层之间的一个逻辑层。它的主要职责是实现应用程序的业务逻辑,为表示层(如Web API)提供数据和操作。通过引入服务层,我们可以将业务逻辑从表示层中分离出来,提高代码的复用性和维护性。

示例代码

假设我们有一个简单的用户管理系统,需要实现用户的增删改查功能。下面是使用服务层设计模式的一个实例:

userModel.js - 定义用户模型

// 引入mongoose,用于定义模型和操作MongoDB
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  username: { type: String, required: true },
  password: { type: String, required: true },
  email: { type: String, required: true }
});

// 导出用户模型
module.exports = mongoose.model('User', userSchema);

userRepository.js - 实现仓储模式,封装对用户模型的直接操作

// 引入用户模型
const User = require('./userModel');

class UserRepository {
  async createUser(userData) {
    const user = new User(userData);
    return await user.save(); // 保存用户到数据库
  }

  async findUserById(userId) {
    return await User.findById(userId); // 根据ID查找用户
  }

  // 其他需要的用户操作方法...
}

// 导出仓储实例
module.exports = new UserRepository();

userService.js - 定义服务层,封装业务逻辑

// 引入用户仓储
const userRepository = require('./userRepository');

class UserService {
  async registerUser(userData) {
    // 可以在这里添加注册用户前的业务逻辑,如校验数据格式等
    return await userRepository.createUser(userData); // 创建用户
  }

  async getUserById(userId) {
    // 可以添加获取用户信息前的业务逻辑,如检查用户是否存在等
    return await userRepository.findUserById(userId); // 查找用户
  }

  // 其他业务逻辑方法...
}

// 导出服务实例
module.exports = new UserService();

userController.js - 控制器,处理来自前端的请求,通过服务层与业务逻辑交互

// 引入服务层
const userService = require('../models/userService');

const express = require('express');
const router = express.Router();

// 注册用户的路由处理
router.post('/users', async (req, res) => {
  try {
    const user = await userService.registerUser(req.body);
    res.status(201).send(user);
  } catch (error) {
    res.status(500).send(error);
  }
});

// 获取用户信息的路由处理
router.get('/users/:id', async (req, res) => {
  try {
    const user = await userService.getUserById(req.params.id);
    if (!user) {
      return res.status(404).send('User not found');
    }
    res.send(user);
  } catch (error) {
    res.status(500).send(error);
  }
});

// 导出路由
module.exports = router;

test16.js - 创建运行示例

const express = require('express');
const mongoose = require('mongoose');
const userRoutes = require('./controllers/userController');

const app = express();
app.use(express.json());
app.use(userRoutes);
//在Mongoose 4.x版本中,useNewUrlParser和useUnifiedTopology这两个选项并没有被引入
mongoose.connect('mongodb://localhost:27017/userDB');

app.listen(3000, () => {
  console.log('Server is running on port 3000');
});

module.exports = app;

开启mongo服务

mongo

注册
在这里插入图片描述
使用_id查找
在这里插入图片描述

仓储模式(Repository Pattern)

仓储模式用于将数据访问逻辑抽象化,并将其从业务逻辑中分离出来。这样,业务逻辑就不需要直接与数据存储交互,而是通过仓储接口进行。这使得代码更容易维护和测试,同时也更容易实现数据访问技术的更换,比如从一个数据库切换到另一个数据库。

在上面的例子中,userRepository.js文件就是实现了仓储模式的典型例子。通过这种方式,我们可以看到业务逻辑(在userService.js中实现)和数据访问逻辑(在userRepository.js中实现)是如何被清晰地分离开来的。

测试用例

// 引入mongoose,用于操作MongoDB数据库
const mongoose = require('mongoose');
// 引入mongodb-memory-server,用于创建MongoDB内存服务器,便于进行测试
const { MongoMemoryServer } = require('mongodb-memory-server'); //版本@6.9.6
// 引入supertest,用于模拟HTTP请求
const supertest = require('supertest');
// 引入你的app,用于测试
const app = require('../test16');
// 引入用户模型
const User = require('../models/userModel');

// 定义一个变量,用于存储MongoDB内存服务器的实例

let mongoServer;

// 在所有测试用例执行前,启动MongoDB内存服务器并连接
beforeAll(async () => {
  mongoServer = new MongoMemoryServer();
  const mongoUri = await mongoServer.getUri();
  mongoose.connect(mongoUri);
});

// 在所有测试用例执行完毕后,断开数据库连接并停止MongoDB内存服务器
afterAll(async () => {
  mongoose.disconnect();
  await mongoServer.stop();
});

// 定义一个测试集,描述用户管理功能
describe('User Management', () => {
  // 定义一个测试用例,测试创建新用户的功能
  it('should create a new user', async () => {
    // 使用supertest模拟POST请求,创建新用户
    const res = await supertest(app)
      .post('/users')
      .send({
        username: 'testUser',
        email: 'test@example.com',
        password: 'password123',
      });

    // 断言:响应的状态码应为201,表示创建成功
    expect(res.statusCode).toEqual(201);
    // 断言:响应的数据中应包含用户名和邮箱
    expect(res.body).toHaveProperty('username', 'testUser');
    expect(res.body).toHaveProperty('email', 'test@example.com');
  });

  // 定义一个测试用例,测试通过ID查询用户的功能
  it('should retrieve a user by id', async () => {
    // 先创建一个新用户,用于测试查询功能
    const user = new User({
      username: 'findByIdTest',
      email: 'findbyid@example.com',
      password: 'password123',
    });
    await user.save();

    // 使用supertest模拟GET请求,查询刚才创建的用户
    const res = await supertest(app)
      .get(`/users/${user._id}`);

    // 断言:响应的状态码应为200,表示查询成功
    expect(res.statusCode).toEqual(200);
    // 断言:响应的数据中应包含用户名和邮箱
    expect(res.body).toHaveProperty('username', 'findByIdTest');
    expect(res.body).toHaveProperty('email', 'findbyid@example.com');
  });
});

注意
在运行测试用例之前test16.js文件中包含了一个在应用启动时就会被执行的数据库连接操作。这可能是导致“Trying to open unclosed connection”错误的原因:

// mongoose.connect('mongodb://localhost:27017/userDB');

// app.listen(3000, () => {
//   console.log('Server is running on port 3000');
// });

// app.listen(3000, () => {
//   console.log('Server is running on port 3000');
// });

总结

通过引入服务层和仓储模式,我们不仅提高了代码的可维护性和可测试性,也使得业务逻辑和数据访问逻辑的分离更加清晰。这种分离是构建大型、可扩展应用的关键,能够帮助开发团队更有效地协作开发和维护项目。

  • 12
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将Node.js项目部署到阿里云服务器(centos),您可以按照以下步骤进行操作: 1. 首先,登录到您的阿里云服务器。您可以使用SSH客户端(如PuTTY)连接到服务器。 2. 在服务器上安装Node.js。您可以使用Node.js官方网站提供的安装包进行安装,也可以使用包管理工具(如yum)进行安装。 3. 检查Node.js是否成功安装。通过运行命令`node -v`和`npm -v`分别检查Node.js和npm的版本号,确保它们都已安装成功。 4. 在服务器上创建一个目录来存储您的Node.js项目文件。您可以选择在默认的`/var/www/html/`目录下创建一个新目录,或者根据您的需求选择其他位置。 5. 将您的Node.js项目文件上传到服务器的目录中。您可以使用FTP客户端(如FileZilla)将项目文件上传到服务器,或者通过git命令将文件从本地仓库推送到服务器上。 6. 在服务器上安装项目所需的依赖。在项目文件的根目录下,运行`npm install`命令安装项目的依赖模块。 7. 使用PM2进程管理工具来启动Node.js应用程序。运行`npm install -g pm2`命令来全局安装PM2,然后使用`pm2 start app.js`命令启动您的Node.js应用程序。 8. 配置防火墙规则以允许对Node.js应用程序的访问。您可以在阿里云控制台中配置安全组规则,确保服务器的80端口(或您的Node.js应用程序使用的任何其他端口)是开放的。 9. 进行域名解析(可选)。如果您有一个域名,您可以将其解析到服务器的IP地址上,以便用户可以通过域名访问您的Node.js应用程序。 通过以上步骤,您的Node.js项目将成功部署到阿里云服务器上,并可以通过服务器的IP地址或域名进行访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值