使用mysql表达清理CRUD实现

时间:2018-01-17 22:53:49

标签: node.js express design-patterns web-frameworks

我是Nodejs的新手。我正在尝试用它写一些“干净”的代码。我正在使用MySQL作为我的数据库。

我想使用MVC作为我的设计模式。目前我想将“用户”实现为CRUD。我不喜欢我的所有代码都在app.ts 我不使用一些映射器或其他只是“正常”的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中使用它们? 非常感谢你的帮助,我真的很感激。

1 个答案:

答案 0 :(得分:1)

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

让我们以一个小示例项目为例,并将其作为您希望实现的设计的灵感。我们可以使用Mongoose / MongoDB。但是在您的场景中可以使用简单的SQL查询轻松切换。 / p>

文件夹结构类似于这样,

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

您的app.js将启动服务器并初始化所有中间件/路由。中间件可以处理会话/身份验证。

<强> 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');
            }
        });
    }));
};

db helper将连接到db并保存可在控制器中使用的连接实例。

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中使用。它还将保存模型特定的逻辑,如加密密码。在您的情况下,您只需在此处保存查询。

<强> 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);

这些路由将持有充当服务端点的快速中间件,并将占用控制器。如果您计划使用apidoc之类的东西,路由器也是保存api文档的适当位置。

<强>路由/ 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;

控制器将具有对模型起作用的逻辑。它们还保留模型的验证。

<强>控制器/ 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
};