zoukankan      html  css  js  c++  java
  • 从零开始的野路子React/Node(4)后端数据库

    今天说说后端的数据库,各种app的搭建里数据库往往少不了,所以应该也是后端非常重要(可能最重要)的环节。

    和之前一样,我们的后端还是采用node.js,node有一个常用ORM库叫Sequelize,用于间接操作数据库,这样一来我们不写SQL也可以进行各种数据库的操作了。

    1、一些设置

    首先,我们通过express database来创建一个名叫database的项目,然后我们通过npm install sequelize来安装Sequelize。安装完成后,我们还需要根据自己所用的数据库来安装数据库的驱动,这个可以见Sequelize的官网。假设我们使用Sqlite,那就npm install sqlite3。

    和之前一样,我们删去bin目录,并修改package.json,把“start”对应的值改成nodemon app.js(记得先安装nodemon)。这样我们每次更改后端就会自动刷新了,不用重新启动。

    我们修改一下app.js:

    var express = require('express');
    
    var app = express();
    app.use(express.urlencoded({extended: true}));  //解析json用
    app.use(express.json()); //解析json用
    
    app.listen(5000, function() {
        console.log('App listening on port 5000...')
    });

    接下来我们看一下后端的总体结构(忽略node_modules, public和views):

    其中app.js是我们后端的入口;

    Routes负责后端的路由,针对不同的请求,找不同的Controller及其函数回应。就像拿到某种请求找对应的仓管一样;

    Controllers负责处理请求并调用Model,每一个Controller相当于一个仓管;

    Models负责实际执行具体的数据库操作(增删查改),相当于仓管的具体行为(取货,盘货);

    Database则是数据库本体,定义了数据库中各个表的结构及不同表之间的交互,就相当于仓库本身。

    这里还多了一个Prepopulate目录,这个目录主要是用来存放一些预先准备好的测试数据,并在后端启动时加载到数据库中。当然,这里的做法可能不是特别规范(规范的做法貌似应该用sequelize-cli)。

    总体上来说,这个结构应该是比较符合MVC(Model-View-Controller)模式的。

    2、建立数据库和表

    现在我们来建立一个数据库并新建一张表,用于存放一些用户信息。

    这里一共2个文件,index.js负责数据库的一些总体设置,以及插入我们预先准备好的测试数据。而User目录下的User.js则是用户信息表的结构(schema)等的设置。

    我们首先看一下User.js:

    const Sequelize = require('sequelize');
    
    module.exports = (sequelize, DataTypes) => {
        class User extends Sequelize.Model {}
    
        User.init({
            id: {
                type: DataTypes.INTEGER, //数据类型为整型
                autoIncrement: true, //自增
                allowNull: false, //不允许空值
                primaryKey: true //主键
            },
            name: {
                type: DataTypes.STRING,
                allowNull: false
            },
            user_group: {
                type: DataTypes.STRING,
                allowNull: false
            }
        }, { sequelize, modelName:'users', timestamps: true});
    
        return User;
    }

    我们的用户信息表一共3个字段,id是一个自增的主键(1,2,3,4…),name用于存放用户的名字,user_group用于存放用户所述的分组,最后我们把表命名为users。这里注意一下timestamps这个东西,timestamps其实默认就是true,也就是说sequelize会自动为我们的表创建2个字段createdAt和updatedAt,用于存放每条数据插入和更新的时间,如果你不需要的话,将其设置成false即可。

    再来看看index.js:

    const Sequelize = require('sequelize');
    
    const sequelize = new Sequelize({
        host: 'localhost',
        dialect: 'sqlite',
        storage: './database.sqlite'
    }); //设置数据库
    
    var db = {};
    
    var model = require('./User/User.js')(sequelize, Sequelize.DataTypes)
    db[model.name] = model; //将表装入数据库
    
    db.sequelize = sequelize;
    db.Sequelize = Sequelize;
    
    module.exports = db;

    我们先对数据库进行设置,这里我们用的是sqlite作为数据库,它最终会被保存在硬盘上一个叫database.sqlite的文件里,另外我们建立一个Object,db,将表都放入其中,方便我们之后调用。这样一来,db中就会有我们之前建立的users表。

    3、插入测试数据

    现在我们要向表中插入一些事先准备好的测试数据,以供我们可以测试后端的内容。

    在Prepopulate下,Data目录用于存放需要插入的数据,一般都是json格式的,而InsertTables目录下的文件则用于执行插入数据的具体操作。

    user.json的内容如下:

    [
        {
            "name":"张三",
            "user_group":"A"
        }, 
        {
            "name":"李四",
            "user_group":"A"
        },
        {
            "name":"王五",
            "user_group":"B"
        },
        {
            "name":"马六",
            "user_group":"B"
        },
        {
            "name":"冯七",
            "user_group":"C"
        }
    ]

    InsertUser.js的内容如下:

    module.exports = async function InsertForm(db) {
        var users = require('../Data/user.json')
        var userPromises = []
        
        for (var user of users) {
            console.log(user);
            userPromises.push(await db['users'].create({
                name: user.name,
                user_group: user.user_group
            })
            .then(console.log('Data has been populated.'))
            .catch(err => {console.log(err)})
            )
        }
    
        return userPromises
    }

    本质上就是从user.json中提取Object,然后一个个在users表中create出来。

    完成之后,我们还需要再改一下Database目录下的index.js文件,让它执行插入数据的步骤:

    const Sequelize = require('sequelize');
    
    const sequelize = new Sequelize({
        host: 'localhost',
        dialect: 'sqlite',
        storage: './database.sqlite'
    }); //设置数据库
    
    var db = {};
    
    var model = require('./User/User.js')(sequelize, Sequelize.DataTypes)
    db[model.name] = model; //将表装入数据库
    
    //插入预置数据
    sequelize.sync({force:true})
    .then(() => {
        require('../Prepopulate/InsertTables/InsertUser')(db)
    });
    
    db.sequelize = sequelize;
    db.Sequelize = Sequelize;
    
    module.exports = db;

    4、加入针对表的操作

    数据库中的表和测试数据我们都已经准备好了,现在可以正式进入现实增删查改的环节了。

    我们在UserModel.js中实现之,由于sequelize的存在,增删查改一定程度上变得更简单了一些, 无须再写SQL了(当然你要写也是可以的)。

    var db = require('../Database/index');
    var { Sequelize, Op } = require('sequelize');
    
    //获取所有用户
    async function getAllUsers() {
        var users = await db.users.findAll()
        return users
    }
    
    //获取某个分组的用户
    async function getGroupUsers(group) {
        var users = await db.users.findAll({
            where:{
                user_group:group
            }
        })
        return users
    }
    
    //添加一个新用户
    async function addUser(name, group) {
        var newUser = await db.users.create({
            name:name,
            user_group:group
        })
        return newUser
    }
    
    module.exports = {
        getAllUsers,
        getGroupUsers,
        addUser
    }

    我们写了3个函数,2个用于查询,1个用于添加。第一个查询所有用户的函数,不需要任何参数;第二个查询某个分组所有用户的函数,需要一个参数group;第三个添加新用户,则需要2个参数。最后我们将它们导出,以便其他代码可以调用这些方法。

    然后我们来添加Controllers:

    Controller中的每个方法对应了Model里的相应方法。

    var express = require('express');
    var UserModel = require('../Models/UserModel');
    
    //获取所有用户
    exports.getAllUsers = (req, res) => {
        UserModel.getAllUsers()
        .then(response => {
            res.status(200).send(response)
        })
        .catch(err => {
            console.log(err)
            res.status(400).send('Error')
        })
    };
    
    //获取某个分组的用户
    exports.getGroupUsers = (req, res) => {
        UserModel.getGroupUsers(req.params.group)
        .then(response => {
            res.status(200).send(response)
        })
        .catch(err => {
            console.log(err)
            res.status(400).send('Error')
        })
    };
    
    //添加一个新用户
    exports.addUser = (req, res) => {
        UserModel.addUser(req.body.name, req.body.user_group)
        .then(response => {
            res.status(200).send(response)
        })
        .catch(err => {
            console.log(err)
            res.status(400).send('Error')
        })
    };

    可以看到我们在此所做的事情不过是调用、传参、返回结果以及捕获错误。

    此处需要说明的是,个人感觉在写Controllers之前,需要对每个方法所对应接受的请求有一个基本的设计。比如这里getAllUsers我希望它处理的是GET请求;我希望getGroupUsers也处理GET请求,但getGroupUsers需要一个参数(group),而GET请求只能从req.params中获取参数;最后addUser我希望它处理POST请求,而POST请求的参数则来自于req.body,这些都应当做好区分。

    5、对接路由

    现在我们可以将Controllers对接到路由系统上了。

    通过写Controller时我们脑洞中的设计,我们可以脑补出每种请求对应的路径和请求类型(GET/POST):

    var express = require('express');
    const UserController = require('../Controllers/UserController');
    
    var router = express.Router();
    
    router.get('/:group', UserController.getGroupUsers);
    router.get('/', UserController.getAllUsers);
    router.post('/', UserController.addUser);
    
    module.exports = router;

    我们将对应的请求类型、路径和对应的Controller的方法连接起来即可。

    最后,我们修改一下app.js,把我们的路由系统加入进去:

    var express = require('express');
    const UserRouter = require('./Routes/User');
    
    var app = express();
    app.use(express.urlencoded({extended: true})); //解析json用
    app.use(express.json()); //解析json用
    
    app.use('/', UserRouter)
    
    app.listen(5000, function() {
        console.log('App listening on port 5000...')
    });

    好啦,完工,现在我们来试试我们的后端系统。进入相应目录后通过npm start来启动后端,我们会发现两件事:

    第一,根目录下多出了一个database.sqlite,如前所述,这是储存数据库的文件。

    第二,我们可以看见后端启动后随之完成了一系列创建表、插入数据等操作。

    让我们用Postman测试一下看看。

    对”/”路径发送GET请求:

    对”/:group”路径发送GET请求(req.params在路径中体现):

    对”/”路径发送POST请求,参数在body中(JSON):

    所有的请求都成功了,大功告成,这就是一个非常简陋的后端搭建数据库的示例。

    代码见:

    https://github.com/SilenceGTX/node_back_db

  • 相关阅读:
    被@ResponseBoby注释的方法在拦截器的posthandle方法中设置cookie失效的问题
    python之异常处理
    python之url编码
    python之发送邮件
    python之使用request模块发送post和get请求
    python之小技巧积累
    python之sys.argv[]
    python之MD5加密
    python之os、sys和random模块
    python之time和datetime的常用方法
  • 原文地址:https://www.cnblogs.com/silence-gtx/p/13466061.html
Copyright © 2011-2022 走看看