vue+node+Sequelize+mysql+mysql2驱动实现简单增删改查

引言

由于前端部分设计到数据交互,而前端做的只是发送请求获取数据之后进行处理,大部分的数据逻辑写在后端,这段时间就学习了一部分内容用node+mysql实现后端的简单业务:

准备内容:

  1. vue2

  1. nodejs

  1. mysql数据库

  1. navicat

正文:

一、首先准备mysql连接本地的数据库,网上都有教程,建议使用navicat去连接,使用命令行的方式个人认为比较麻烦~

二、创建一个文件夹module,创建一个db.js文件

const {Sequelize, Model} =  require('sequelize')
const loger = require("../log.config")

//创建数据库
const db = new Sequelize('sso','root','zjh123456',{
    host: 'localhost',
    dialect: "mysql",
    ssl: true,
    protocol: "postgres",

    logging: (msg)=>{
        loger.sqlLoger.info(msg)
    },
    dialectOptions: {
        ssl: {
            require: true,
            rejectUnauthorized: false 
        }
    }
})
/**
 * 数据库的验证方法
 * @method
 * @authenticate
 */
db.authenticate().then(() => {
    console.log("链接数据库成功-----");
}).catch(err => {
    console.error("不能连接到数据------",err);
})

//输出数据库
module.exports = db

这里我使用sequelize来连接数据库,sequelize是基于NodeJs的ORM框架,它适用于不同的数据库,可以通过sequelize对数据库进行一系列的操作,new Sequelize来创建一个连接池,他的参数有:

@param {String} database 要连接的数据库name

@param {String} username 登陆数据库时的用户名

@param {String} password 登陆数据库时的密码

@param {Object} options 选项配置参数,为一个对象,内含许多配置属性

比如:

{
    host: 数据库主机,
    port:数据库端口号
    dialect: 指定要连接哪种类型的数据库,如:mysql,postgres等
    define: 为模型定义默认选项
    timezone: 时区
}

里面的loger是我自己设置的日志,这里可以先忽略;这里写完之后可以运行来看看是否成功,成功以后可以进行下一步的操作;

三、创建好数据库并连接之后,下来就是创建表,和设置表关系,并配置表里的数据模型,创建需要的表文件比如:book.js或者登陆要实用的user.js或者公司人员person.js

/**
 * 数据库通过ORM框架链接并创建表
 */

const db = require('./db') 

const Sequelize =  require('sequelize') 

const User = db.define('user',{
    id:{
        type:Sequelize.INTEGER, //对应的是列的数据类型
        primaryKey:true //表示该属性对应的是表的主键列
    },
    username:{
        type:Sequelize.STRING,
    },
    pass:{
        type:Sequelize.STRING,
    },
    token:{
        type:Sequelize.STRING,
    },
},{
    tableName:"zjh_sso_demo_user", //生成表名
    freezeTableName: true,//映射表名的设置:true表示使用用户给定的表名,false表示MySQL自动生成表名(为类名后加s)
    timestamps: false,//是否自动生成时间戳列(createAt列、updateAt列),false表示不生成
    paranoid:true, //数据不会真正删除
})

module.exports =  User

以上的文件看个人的需求来设置;引入的db文件,就为数据库连接以后sequlize提供的对象,可以使用define定义数据库表的默认项:他的参数有:

* @param {String} type 字段数据类型

* @param {Boolean} allowNull 是否允许为空

* @param {Boolean} autoIncrement 自增

* @param {Boolean,String} unique 唯一性

* @param {Boolean} primaryKey 对主键的设置

* @param {String} defaultValue 默认值的设置

* @param {String} field 表头

* @param autoIncrement 解释说明

举个例子:

 * userId :{
    field: 'user_id',
    primaryKey: true,
    type: Sequelize.BIGINT,
    allowNull: false
 * }

而导出的这个对象,就可以进行简单的增删改查如:

 * @create 增
 * 例:
 * User.create ({
    userId: 23,
    userName: '老杨',
    updateTime: '2016-01-22 18:37:22'
 * })
* @destroy 删
 * 例:
 * User.destroy ({
    where: {id:5}
 * })
* @update 改
 * 例:
 * User.update (
      {
        room_status: '0'
      }, {
        'where': { 'id': 1 }
      }
    ).then(ra => {
      res.send({
        code: 200,
        data: r,
        mess: ra
 * })
* @findOne 查
 * 例:
 * User.findOne ({
    where: {id:5}
 * })

这里只是列举一部分,还有sequelize提供的更多的一个接口函数,这里就不一一列举,具体可以上nodejs官网上搜这个sequelize模块;

接下来就是设置表关系,我这里统一创建一个文件进行设置表关系,然后再统一的进行模型匹配,这里创建两个文件分别是relationship.js和aync.js:

/**
 * 表关系
 */

const compony = require('./compony')
const person  = require('./person')

compony.hasMany(person);
person.belongsTo(compony);
/**
 * 同步数据库的表
 */

require("./user");
require("./compony");
require("./person");
require('./relationship')
require('./Book')

const sequelize = require('./db')
sequelize.sync({alter: true}).then(() => {
  console.log("所有模型同步完成");
});

这里解释一下,现在使用的这个sequelize操作都会转化为sql内部的这个语言,我这里使用的表关系,相当于操作navicat里面的设置主键;这里我也尝试了用导入mysql2驱动的模式,使用js进行连接数据库也是可以的:

/**
 * 验证连接数据库,使用sql语句
 */

const mysql = require("mysql2/promise");
const pool = mysql.createPool({
  host: "localhost",
  user: "root",
  password: "zjh123456",
  database: "sso-demo",
  multipleStatements: true,
});

async function test(id) {
  // 创建一个数据库连接
  const sql = `select * from employee where \`name\` like concat('%', ?, '%') ;`;
  const [results] = await pool.execute(sql, [id]);
  console.log(results);
}
test("4");

只不过,使用工具库肯定是方便的,而且实用这个还需要写sql语言,又得花费一部分精力去学习,我们直接可以使用工具肯定是无可厚非的。

这里我们运行一下,然后刷新数据库,就可以看到库里面对应的表,以及他的键,但是还暂时没有数据,像user.js这种就可以使用上面的方法进行添加删除修改查找,但是有一个问题就是像那种很多的数据,这里不可能去手动添加,太浪费时间,这里我使用mockjs去给数据量大的表里添加数据如下

我单独创建一个mock文件夹对compony和person这两个表进行添加数据,需要数据的时候我可以直接运行这个js文件就可以了

/**
 * 快速生成表数据
 */

const mock = require('mockjs')
const result = mock.mock({
    "datas|10-50":[
        {
            "id|1-20000":0,
            name:"@cname",
            mobile:/1\d{10}/,
            location: "@city(true)",
            "componyId|1-16":0,
        }
    ]
}).datas;
// console.log(result);
require('../module/relationship')
const person = require('../module/person')
person.bulkCreate(result)

之前导出的一个person的sequelize().define定义出来的对象,有一个bulkCreate方法可以批量导入数据。

四、逻辑层和API层

数据层我们建立好了之后就需要,有逻辑层和对外的API层(也就是相当于java上说的三层架构的web层,对应的是给前端提供的APi接口)

const compony = require("../module/compony");
exports.addcompony = async function (obj) {
  const ins = await compony.create(obj);
  return ins.toJSON();
};

exports.deletecompony = async function (id) {
  return await compony.destroy({
    where: {
      id,
    },
  });
};

exports.updatecompony = async function (id, obj) {
  return await compony.update(obj, {
    where: {
      id,
    },
  });
};
exports.getcomponyById = async function (id) {
  const result = await compony.findByPk(id);
  if (result) {
    return result.toJSON();
  }
  return null;
};

exports.getcomponyes = async function () {
  const result = await compony.findAll();
  return JSON.parse(JSON.stringify(result));
};

这里我只示范一个compony数据库的增删改查的简单js文件,创建这个文件之后,我们可以去创建一个js文件,导入上面第二个题目中的创建,连接数据库的文件,然后再引入这个compony.js,然后调用函数,node compony.js运行试一试是否可以成功,成功之后进行这里我是用的是express框架编写本地的服务,我

/**
 * 后端服务
 */

const express = require("express")
const app = express()
const path = require("path")
const cors = require("cors");

// const whiteList = ["null", "http://localhost:5008"];
app.use(
  cors({
    origin(origin, callback) {
      if (!origin) {
        callback(null, "*");
        return;
      }
      // if (whiteList.includes(origin)) {
      //   callback(null, origin);
      // } else {
      //   callback(new Error("not allowed"));
      // }
      callback(null,origin)
    },
    credentials: true,
  })
);

const staticRoot = path.resolve(__dirname,"../public")
app.use("/static",express.static(staticRoot))

const cookieParser = require("cookie-parser")
app.use(cookieParser())

// 应用cookies中间件
app.use(require("../route/cookieMiddleware"));
// 应用session中间件
// app.use(require("../route/sessionMiddleware"));
// 应用jwt中间件
// app.use(require("../route/jwtMiddleware"));

app.use(express.urlencoded({
    extended:true
}))

app.use(express.json())

app.use(require("../route/apiMiddleware"))
//处理api的请求
console.log("引入中间件----");
// app.use("/api/user",require("../route/api/userJwt"))
app.use("/api/user",require("../route/api/userToken"))
// app.use("/api/user",require("../route/api/userSession"))
app.use("/api/person",require("../route/api/person"))
app.use("/api/compony",require("../route/api/compony"))
app.use("/api/book",require("../route/api/book"))
app.use("/api/upload",require("../route/api/upload"))
console.log("引入中间件----");

//处理错误的中间件
app.use(require("../route/errorMiddleware"))

const port = 5008
app.listen(port,()=>{
    console.log(`server listen on ${port}`);
})

这里用网上的描述来解释吧,Express 是一个第三方模块,用于快速搭建服务器(替代http模块) 基于 Node.js 平台,快速、开放、极简的 web 开发框架。保留了http模块的基本API,使用express的时候,也能使用http的APIexpress还额外封装了一些新方法,能让我们更方便的搭建服务器。

上述的代码中我使用了很多中间件,其中有处理错误的,处理请求头的,处理api接口的,处理token,session,jwt的,解析请求头,请求提的,还有访问静态资源的,还有一个这个cors跨域的,下面我直接把代码放上面,可以看看,代码中我有比较详细的注释。

/**
 * 用于解析token
 */
const { getErr } = require("./getResult");
const cryptor = require("../util/crypt")

const { pathToRegexp } = require("path-to-regexp");
//需要认证的api
const needTokenApi = [
  { method: "POST", path: "/api/person" },
  { method: "PUT", path: "/api/person/:id" },
  { method: "GET", path: "/api/user/auth" },
];

// 用于解析token
module.exports = (req, res, next) => {
  let token = req.cookies.token;

// 获取cokkie
// let token = req.signedCookies.token;

  if(!token){
    //其他的端获取token
    token = req.headers.authorization
  }

  if(!token){
    handleNonToken(req,res,next)
    return;
  }
  const userId = cryptor.decrypt(token)
  console.log(userId,"认证通过啦~~~");
  next()
};

//处理没有认证的情况
function handleNonToken(req, res, next) {
  res
    .status(403)
    .send(getErr("不好意思,您没有token令牌无法登陆哦~", 403));
}
//处理错误的中间件
const getMsg = require("./getResult")
module.exports = (err,req,res,next) => {
    if(err){
        const errObj =  err instanceof Error? err.message:err
        res.status(500).send(getMsg.getErr(errObj))
    }else{
        next()
    }
}
/**
 * 这里是提供一些函数,供其他的中间件实用
 * @param {*} err 
 * @param {*} errCode 
 * @returns 
 */

exports.getErr = function(err= "server error",errCode = 500){
    return {
        code: errCode,
        msg:err
    }
}

/**
 * 
 * @param {*} result 
 * @returns 
 */
exports.getResult = function(result){
    return {
        code:0,
        msg:"请求成功啦,恭喜你",
        data:result
    }
}

exports.asyncHandler = (handler) =>{
    return async (req,res,next) => {
        try {
        const result =  await handler(req,res,next)
        console.log(result);
        res.send(exports.getResult(result))
        } catch (error) {
            console.log("调用api错误啦~~~~");
            next(error)
        }
    }
}
/**
 * jwt认证
 */
const { getErr } = require("./getResult");
// const { pathToRegexp } = require("path-to-regexp");
const jwt = require("./jwt");
// const needTokenApi = [
//   { method: "POST", path: "/api/person" },
//   { method: "PUT", path: "/api/person/:id" },
//   { method: "GET", path: "/api/user/auth" },
// ];

// 用于解析token
module.exports = (req, res, next) => {
  // const apis = needTokenApi.filter((api) => {
  //   const reg = pathToRegexp(api.path);
  //   return api.method === req.method && reg.test(req.path);
  // });
  // if (apis.length === 0) {
  //   next();
  //   return;
  // }
  const result = jwt.verify(req);
  if (result) {
    //认证通过
    req.userId = result.id;
    next();
  } else {
    //认证失败
    handleNonToken(req, res, next);
  }
};

//处理没有认证的情况
function handleNonToken(req, res, next) {
  res
    .status(403)
    .send(getErr("不好意思,您没有token令牌无法登陆哦~", 403));
}

这里我使用express提供的router方法来定义对外的API接口服务。

const express = require("express")
const router = express.Router()
const person = require("../../serveAPI/personService")
const {asyncHandler} = require("../getResult")

router.get("/", asyncHandler(
    async (req,res,next) =>{
        const page = req.query.page || 1;
        const limit = req.query.limit || 10;
        const id = req.query.id || null;
        return await person.getpersons(page,limit,id)
    }
))

router.get("/:id", asyncHandler(
    async (req,res,next) =>{
        return await person.getpersonById(req.params.id)
    }
))

router.post("/", asyncHandler(
    async (req,res,next) =>{
       return await person.addperson(req.body)
    }
))

router.delete("/:id",asyncHandler(
    async (req,res,next) =>{
       return await person.deleteperson(req.params.id)
    }
))

router.put("/:id",asyncHandler(
    async (req,res,next) =>{
       return await person.updateperson(req.params.id,req.body)
    }
))

module.exports = router

当这些写完之后,就可以运行服务了,要测试的话,可以使用postman,也可以直接使用服务地址+ router拼接的方式去测试,我也是这么做的,这里推荐大家是用npx nodemoon来启动服务,这样的话,修改服务的内容,就不用重新启动服务,很方便。

五、vue-cli搭建vue2项目

上述写的服务,由于是在vue-cli搭建的工程内写的,所以我不用安装各类插件,我直接写在vue的package.json中,下载依赖的时候就可以使用了,当然有些小伙伴不习惯这种commonjs的规范不喜欢这种module.export或者require的方式,也可以使用es6中的export,import的方法,不过在启动的时候,就需要配置babelnode去解析一下运行,服务可以自己去单独启动,也可以配置在package里,在vscode中断启动如:

"starta": "cross-env NODE_ENV=ssoa babel-node server/index.js",这样启动有一个好处就是,可以不用手动在js文件中加这种node_env参数,在启动配置好以后,就可以直接在js文件中使用,这是比较方便的

这里的依赖,可以根据需要去下载配置,我这里有很多测试的东西,所以比较杂。

这里的配置,我就不一一的看了,大致就是vuex,还有api的service,再有就是路由router,还有主页面,大家可以使用axios调用接口,处理数据,写页面还是非常有意思的东西,我这里写的是一个登陆的页面,其中登陆模块下一个再去记录,就到这里吧。。。

猜你喜欢

转载自blog.csdn.net/weixin_72913454/article/details/128696581
今日推荐