Nodejs 服务端MVC架构

前言

之前分享了一篇 Nodejs 与 MySQL 数据库交互 的文章,这篇文章主要是讲 mysql模块的使用方式。今天准备分享一篇 Nodejs 服务端 MVC 架构,通过服务端提供的API来完成数据库的CRUD操作。

MVC 介绍

MVC是一种项目架构思想,即对项目进行分层,不同层负责的职责不同。

M层:model 模型,业务逻辑处理,更多体现的是数据库CRUD;

V 层:view 视图,负责数据的呈现;

C 层:controller 控制器,负责业务流程(V与M之间的沟通桥梁)

MVC在express项目里的体现:

数据库准备

-- 创建数据库(不存在时才创建)
CREATE DATABASE IF NOT EXISTS nodejs_mysql_db DEFAULT CHARSET utf8;

-- 创建users表(不存在时才创建)
CREATE TABLE IF NOT EXISTS `users` (
  `id` INT(8) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(10) NOT NULL,
  `age` INT(11) DEFAULT NULL,
  `sex` VARCHAR(10) DEFAULT NULL,
  `status` INT(1) DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

项目代码

由于我这个项目主要是用于服务端,提供API给前端使用,所以接下来我就省略调了 views 的内容。

1. app.js

项目启动文件

const express = require("express");
const app = express();
const {global} = require("./config/global");

const user = require("./routes/user");

app.use(user);

app.listen(global.port,global.hostname,function (){
    console.log('Express server listening at http://%s:%d',global.host,global.port);
})

2. config/global.js

全局配置文件

exports.global = {
    "host":"localhost",
    "port":8899
}

3. config/db.js

数据库配置文件

const mysql = require("mysql");

const pool = mysql.createPool({
    host:"localhost",
    port:3306,
    user:"root",
    password:"1234qwer"
})

exports.UserDB = ()=>{
    pool.config.connectionConfig.database = "nodejs_mysql_db";
    return pool;
}

/*
// 可以通过这种方式,切换不同的DB实例
exports.BookDB = ()=>{
    pool.config.connectionConfig.database = "ex_test";
    return pool;
}
*/

exports.mysql = mysql;

4. models/userDao.js

M层,user业务逻辑处理,主要是数据库的CRUD操作

const DB = require("../config/db");
const UserDB = DB.UserDB();

let DBResult = {};

DBResult.getUserList = function (cb){
    UserDB.getConnection(function (err,conn){
        if(err){return console.log(err)}
        conn.query("SELECT * FROM users",function (error,results){
            if(error){return console.log(error)}
            console.log(conn.threadId);
            conn.release();
            cb(results);
        })
    })
}
DBResult.addUser = function (args,cb){
    UserDB.getConnection(function (err,conn){
        if(err){return console.log(err)}
        // console.log(DB.mysql.format("INSERT INTO users(name,age,sex) VALUES ?",args));
        conn.query("INSERT INTO users(name,age,sex) VALUES ?",args,function (error,results){
            if(error){return console.log(error)}
            console.log(conn.threadId);
            conn.release();
            cb(results);
        })
    })
}
DBResult.updateUser = function (args,cb){
    UserDB.getConnection(function (err,conn){
        if(err){return console.log(err)}
        // console.log(DB.mysql.format("UPDATE users SET ? WHERE id = ?",args));
        conn.query("UPDATE users SET ? WHERE id = ?",args,function (error,results){
            if(error){return console.log(error)}
            console.log(conn.threadId);
            conn.release();
            cb(results);
        })
    })
}
DBResult.deleteUser = function (args,cb){
    UserDB.getConnection(function (err,conn){
        if(err){return console.log(err)}
        conn.query("DELETE FROM users WHERE id = ?",args,function (error,results){
            if(error){return console.log(error)}
            console.log(conn.threadId);
            conn.release();
            cb(results);
        })
    })
}

module.exports = DBResult;

5. routes/user.js

user路由文件,负责将API请求转发到model/userDao.js,完成数据库的CRUD操作,然后再将查询到的数据库数据返回给接口

const express = require("express");
const user = express.Router();

const userDao = require("../models/userDao");

user.all("*",express.json());

user.get("/users",function (req,res){
    userDao.getUserList(function (userList){
        res.send(userList);
    });
})

user.post("/users",function (req,res){
    userDao.addUser([req.body],function (addRes){
        res.send(addRes);
    })
})

user.put("/users/:id",function (req,res){
    userDao.updateUser([req.body,req.params.id],function (updateRes){
        res.send(updateRes);
    })
})

user.delete("/users/:id",function (req,res){
    userDao.deleteUser(req.params.id,function (deleteRes){
        res.send(deleteRes);
    })
})

module.exports = user;

演示效果

0. 刚建好的users 表中无任何数据

1. 新增数据

POST http://localhost:8899/users

2. 查询数据

GET http://localhost:8899/users

3. 更新数据

PUT http://localhost:8899/users/1

再调用查询接口,id=1的数据已更新

4. 删除数据

DELETE http://localhost:8899/users/2

删除id=2的数据后再查询,仅剩id=1的数据

关键代码分析

以 POST http://localhost:8899/users 为例

  1. 客户端在调用服务端接口后,请求进入app.js,app.use(user) 将请求转发到 routes/user.js 里user.post 方法;

  1. 在user.post方法里,调用model/userDao.js的addUser方法;

  1. 那么怎么将user.post路由参数传递给 addUser方法,又怎么将addUser方法从数据库拿到的数据返回给user.post呢?

(1)定义addUser方法接收两个参数,一个args参数,一个cb代表的回调函数,conn.query查询完数据库后,执行cb回调函数,将结果返回给调用者。

注意: args 可以是单个参数,也可以是数组,如果没有路由参数,args也可以省略,如
getUserList 方法就只有一个cb回调函数。
// models/userDao.js
DBResult.addUser = function (args,cb){
    UserDB.getConnection(function (err,conn){
        if(err){return console.log(err)}
        conn.query("INSERT INTO users(name,age,sex) VALUES ?",args,function (error,results){
            if(error){return console.log(error)}
            conn.release();
            cb(results);
        })
    })
}

(2)调用addUser方法时,传递req.body作为args参数,再传一个函数作为回调函数,这个函数也接收一个参数,此参数实际上就对应conn.query里返回的results,然后通过res.send返回给接口

// routes/user.js
user.post("/users",function (req,res){
    userDao.addUser([req.body],function (addRes){
        res.send(addRes);
    })
})


参考资料:

NodeJS整合MySQL

猜你喜欢

转载自blog.csdn.net/B11050729/article/details/129645671