使用 mysql 快速清理 CRUD 实现

Clean CRUD implementation with express using mysql

我真的是 Nodejs 新手。我正在尝试用它编写一些 "clean" 代码。我正在使用 MySQL 作为我的数据库。

我想使用 MVC 作为我的设计模式。目前我想将 "User" 实现为 CRUD。我不喜欢我所有的代码都在 app.ts 我不使用某些映射器或其他东西,只是 "normal" SQL 查询。

    import express = require('express')
    import bodyParser = require('body-parser')
    import db      = require('mysql')
    import session = require('express-session')
    import {Connection, MysqlError} from "mysql"

    let connection: Connection = db.createConnection({
      host: 'localhost',
      user: 'admin',
      password: 'secret',
      database: 'test'
    });

var app = express();

app.use('/views', express.static(__dirname + '/views'))
app.use('/public', express.static(__dirname + '/public'))


app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());

app.get('/', function (req, res) {
  connection.connect(function(err) {
    if (err) {
      console.error('error connecting: ' + err.stack);
      return;
    }

    console.log('connected as id ' + connection.threadId);
  });
});

app.listen(8080, function () {
  console.log('Listening on port 8080!');
  console.log('____________________________________')
  console.log('____________________________________')
  console.log('____________________________________')
  console.log("PLEASE VISIT ➡️ ➡️ ➡️ ➡️   http://localhost:8080/views/index.html   ⬅️ ⬅️ ⬅️ ⬅️")
  console.log('____________________________________')
});

通常连接应该在模型中吧?我如何使用控制器和模型?我如何在 app.js 中使用它们? 非常感谢您的帮助,我真的很感激。

Node 和 Express 没有严格的文件和文件夹结构。相反,您可以以任何方式构建您的 Web 应用程序 like.This 也让我们可以自由地遵循任何模式。

让我们以一个小示例项目为例,并将其用作您想要的设计的灵感 achieve.We 可以将 Mongoose/MongoDB 用于 this.But 这可以很容易地切换您的方案中的简单 sql 查询。

文件夹结构类似于这样,

project/
  controllers/
    users.js
  helpers/
    dbHelper.js
  middlewares/
    auth.js
  models/
    user.js
  routes/
    users.js
  tests/
  app.js
  package.json

您的 app.js 将启动服务器并初始化所有 middlewares/routes。中间件可以处理 session/authentication。

app.js

import express from 'express';
import bodyparser from 'body-parser';
import logger from 'logger-module';
import users from './routes/users';
import dbHelper from './helpers/dbHelper';

const app = express();
const port = process.env.PORT || 3000;

dbHelper.init();

logger.info('App is starting...');

app.use(cors());
app.use(bodyparser.json());
app.use(bodyparser.urlencoded({
    extended: true,
}));

app.use('/users', users);

app.use((err, req, res, next) => {
    logger.error(err);
    const message = err.message || 'Server Failure';
    const response = {
        error: {
            message,
            err.stack
        }
    };
    return res.status(500).send(response);
});

app.use((req, res) => {
    res.status(404).send("Sorry can't find that!");
});

app.listen(port, (err) => {
  if (err) {
    logger.error(err);
  }

  logger.info(`App listening on port ${port}`);
});

auth.js

import passportJwt from 'passport-jwt';
const JwtStrategy = passportJwt.Strategy;
const ExtractJwt = passportJwt.ExtractJwt;
import User from '../models/User';

module.exports = function(passport, jwtConfig) {
    var opts = {};
    opts.secretOrKey = jwtConfig.secret;
    opts.issuer = jwtConfig.issuer;
    opts.audience = jwtConfig.audience;
    opts.jwtFromRequest = ExtractJwt.fromAuthHeader();

    passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
        User.findOne({
            _id: jwt_payload.sub
        }).lean().exec(function(err, user) {
            if (err) {
                return done(err, false);
            }
            if (user) {
                done(null, user);
            } else {
                done(null, false, 'User found in token but not found in records');
            }
        });
    }));
};

数据库助手将连接到数据库并保存您可以在控制器中使用的连接实例。

import mongoose from 'mongoose';

function init() {
    const DB_PORT = process.env.BC_DB_PORT;
    const DB_HOST = process.env.IP;
    const DB_NAME = process.env.BC_DB_NAME;
    let url = `mongodb://${DB_HOST}:${DB_PORT}/${DB_NAME}`;
    mongoose.connect(url, function(err) {
        if (err) {
            console.log(`Database connectivity error - ${url}`);
        }
    });
}

function getMongoose() {
    return mongoose;
}

module.exports = {
    init,
    getMongoose
};

这些模型将保存您的架构并可以在 Controllers.It 中使用,还将保存模型特定的逻辑,例如加密 passwords.In 您的案例,您可以简单地在此处保存您的查询。

users.js

import mongoose from '../helpers/dbHelper.js';
import bcrypt from 'bcrypt';
var Schema = mongoose.getMongoose().Schema;
var User = new Schema({
    _id: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    firstname: String,
    lastname: String,
    email: {
        type: String,
        trim: true,
        unique: true,
        required: true
    },
    mobile: {
        type: String,
        trim: true,
        unique: true,
        required: true
    }
}, {
    timestamps: true
});

User.pre('save', function(next) {
    var user = this;
    if (this.isModified('password') || isNew) {
        bcrypt.genSalt(10, function(err, salt) {
            if (err) {
                return next(err);
            }
            bcrypt.hash(user.password, salt, function(err, hash) {
                if (err) {
                    return next(err);
                }
                user.password = hash;
                next();
            });
        });
    } else {
        return next();
    }
});

User.pre('findOneAndUpdate', function(next) {
    var user = this;
    if (this._update.password) {
        bcrypt.genSalt(10, function(err, salt) {
            if (err) {
                return next(err);
            }
            bcrypt.hash(user._update.password, salt, function(err, hash) {
                if (err) {
                    return next(err);
                }
                user._update.password = hash;
                next();
            });
        });
    } else {
        return next();
    }
});

User.methods.comparePassword = function(password, cb) {
    bcrypt.compare(password, this.password, function(err, isMatch) {
        if (err) {
            return cb(err);
        }
        cb(null, isMatch);
    });
};

module.exports = mongoose.model('User', User);

路由将包含充当服务端点的快速中间件,并将使用 controllers.The 路由器,如果您打算使用类似apidoc.

routes/users.js

import {router} from "express";
import userControllerfrom '../controllers/users';

router.get("/", function(req, res, next) {
    userController.findAllUsers(req, res, next);
});

router.delete("/:userId", function(req, res, next) {
    userController.deleteUser(req, res, next);
});

router.get("/:userId", function(req, res, next) {
    userController.findUser(req, res, next);
});

router.put("/:userId", function(req, res, next) {
    userController.updateUser(req, res, next);
});

module.exports = router;

控制器将具有作用于 models.They 的逻辑,同时对模型进行验证。

controllers/user.js

import HttpStatus from "http-status";
import User from '../models/User';

function deleteUser(req, res, next) {
    let userId = req.params.userId;
    User.remove({
        _id: userId
    }, function(err, {
        result
    }) {
        //Logic to handle
    });
}

function findUser(req, res, next) {
    let userId = req.params.userId;
    User.findOne({
        _id: userId
    }, {
        password: 0,
        __v: 0
    }).lean().exec().then(function(user) {
        //Logic to handle
    }).catch(function(err) {
        err["info"] = "Error when finding user";
        next(err);
    });
}

function findAllUsers(req, res, next) {
    User.find(req.query, {
        password: 0,
        __v: 0
    }).lean().exec().then(function(users) {
        //Logic to handle
    }).catch(function(err) {
        err["info"] = "Error when finding all users";
        next(err);
    });
}

function updateUser(req, res, next) {
    let userId = req.params.userId;
    User.findOneAndUpdate({
        _id: userId
    }, req.user, {
        new: true
    }, function(err, user) {
        //Logic to handle
    });
}

module.exports = {
    deleteUser,
    findUser,
    findAllUsers,
    updateUser
};