node.js + express + mysql 简单运用

主要是学习下如何简单得运用,自己可以写出一个后台

目录

  1. 初始化一个项目
  2. 创建web服务
  3. get请求
  4. post put delete 三个请求
  5. 引入ejs 模板
  6. 中间件
  7. cookie
  8. session
  9. 路由模块化
  10. 官方推荐应用程序生成器(创建项目得脚手架)
  11. 图片上传 multer
  12. mysql 运用(案例)
  13. mysql事务

1.初始化一个项目

1.安装Node.js
2新建一个文件夹,初始化项目 npm init
3.npm install express --save 安装express
4.新建一个index.js

2.创建web服务

index.js 内容
var express = require("express");
app.get("/", (req, res) => {
    // 使用ejs
    res.send("hello 默认");
});
app.listen(3000);

启动 node index.js
在这里插入图片描述
3.get请求

//浏览器直接打开
app.get("/login", (req, res) => {
    //参数传值  怎么取  req.query
    res.send("hello 默认");
});
app.get("/news/getNews/:id", (req, res) => {
    // 动态路由
    var id = req.params["id"];
    res.send("获取 新闻" + id);
});

4.post put delete 三个请求

不能直接浏览器打开,可以通过psotman来测试(post put delete差不多写法)

app.post("/news/postNews", (req, res) => {
    // 动态路由
    res.send("增加 新闻");
});

在这里插入图片描述
5.引入ejs 模板

这种基本用于一些比较老得项目,前后端不分离得。ejs 有兴趣得可以取单独学学,express本身就自带了ejs,所以直接安装ejs后,直接用

直接使用ejs
1.先安装ejs
2.app.set(“view engine”, “ejs”)
3.默认为当前目录下得views文件夹,所以新建views
4.创建一个index.ejs

使用html ejs模板
1.先安装ejs
2.var ejs = require(“ejs”);
3.app.engine(“html”, ejs.__express);
4.app.set(“view engine”, “html”);
5.默认为当前目录下得views文件夹,所以新建views
6.创建一个index.html

ejs内容
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2>这是一个EJS的动态模板</h2>

    <h5><%=message%></h5>

    <form action="./submitData" method="post">
        用户名:<input type="text" value="yangjie" name="username"><br>
        密码<input type="password" value="123" name="password"><br>
        <button type="submit">提交</button>
    </form>
</body>

</html>

app.set("view engine", "ejs")
app.get("/login", (req, res) => {
    res.render("index", {
        message: "666",
    });
    // res.send("hello 登录");
});

在这里插入图片描述
6.中间件
应用级中间件:所有得匹配路由前都会调用这个中间件(用于权限判断)

app.use((req, res, next) => {
    console.log("应用级中间件");
    next();
});

路由级中间件(用得比较少) 为了能news/add能继续执行下去

app.get("/news/add", (req, res, next) => {
    // res.send("获取 新闻" + id);
    next();
});
app.get("/news/:id", (req, res) => {
    // 动态路由
    res.send("获取 新闻" + id);
});

内置中间件 访问static文件夹 得静态资源(不是路由)

app.use(express.static("static"));

第三方中间件 (很多 比如获取post传参得中间件)

安装body-parser

// 第三方中间件 (很多 比如获取post传参得中间件)
var bodyParser = require("body-parser");
// create application/json parser
var jsonParser = bodyParser.json();

// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false });
app.post("/add", jsonParser, (req, res) => {
    // 动态路由
    console.log("参数:" + req.query.name);
    console.log("参数:" + req.body);
    res.send("第三方中间件");
});

错误处理中间件(用于路由匹配完成) 匹配不到

app.use((req, res, next) => {
    console.log("错误处理");
    res.status(404).send("404");
});

7.cookie
浏览器得缓存——cookie

特点:
1.大小4k左右
2.与服务端交互
3.可以设置时效性
4.方法需要自己封装
5.cookie数量20个得限制

1.安装npm i cookie-parser -s
2.const cookieParser = require(“cookie-parser”);
3.app.use(cookieParser());

app.get("/", (req, res) => {
    // 使用ejs
    // 存username 60秒后过期  获取方式 req.cookies.username  maxAge:多少毫秒之后失效  path:"/aaa"
    //  限制只能在哪个路由下访问  domain:".jd.com"  这样就可以多域名共享  比如 www.jd.com  aaa.jd.com等
    res.cookie("username", "张三", { maxAge: 1000 * 60 });
    // cookie加密 
    // 1.app.use(cookieParser("asdasd"));
    // 2.res.cookie("username", "张三", { maxAge: 1000 * 60,signed:true });
    // 3.获取 req.signedCookies
    res.send("hello 默认");
});

8.session

1.安装npm install express-session -s
2.使用

// 设置session 基于 cookie
const session = require("express-session");
app.use(
    session({
        secret: "keyboard cat", //服务端生成得session签名
        name: "aaa", //修改session对应得cookie名
        resave: false, //强制保存,即使它没有变化
        saveUninitialized: true, //强制将未初始化得session 存储
        cookie: {
            secure: false, //true只有Https协议才能访问cookie
            maxAge: 1000 * 60,
        },
        // rolling: true,  //重新设置过期时间
    })
);
app.get("/", (req, res) => {
    req.session.username = "杨接";
    req.session.name = "杨接111";
    console.log(req.session.username);
    console.log(req.session.name);
    res.send("hello 默认");
});

session存储到mysql

npm i mysql -s
npm i express-mysql-session -s

var mysql = require("mysql");
const session = require("express-session");
var MySQLStore = require("express-mysql-session")(session);
var option = {
    host: "localhost",
    user: "root",
    password: "123456",
    database: "session",    //数据库名
};
var connection = mysql.createConnection(option);
// session存储mysql
var sessionStore = new MySQLStore(
    {
        expiration: 10800000,
        createDatabaseTable: true, //是否创建表
        schema: {
            tableName: "session_tab", //表名
            columnNames: {
                //列选项
                session_id: "session_id",
                expires: "expires",
                data: "data",
            },
        },
    },
    connection
);

connection.connect();

app.listen(80); 可以省略端口号
效果
在这里插入图片描述
9.路由模块化

1,上面代码中得一些中间件 改变写法 例如

// create application/json parser
app.use(bodyParser.json());
// create application/x-www-form-urlencoded parser
app.use(bodyParser.urlencoded({ extended: false }));

2.创建 两个js
在这里插入图片描述

login.js  news 也差不多
var express = require("express");
var router = express.Router("express");

router.get("/", (req, res) => {
    // 设置
    req.session.username = "杨接";
    req.session.name = "杨接111";
    // 获取
    console.log(req.session.username);
    console.log(req.session.name);
    // 销毁
    // 1.req.session.cookie.maxAge=0 所有都销毁
    // 2.req.session.username=""  销毁指定得值
    // 3.req.session.destroy()
    res.send("hello 默认");
});
// 使用ejs 先安装ejs 然后直接使用   app.set("view engine", "ejs"); express本身就封装了ejs
router.get("/login", (req, res) => {
    res.render("index", {
        message: "666",
    });
    // res.send("hello 登录");
});

router.post("/doLogin", (req, res) => {
    // 获取参数传值
    var body = req.body;
    console.log(body);
    res.send("hello 登录");
});

module.exports = router;

3.index.js中引入

const login = require("./routes/login");
const news = require("./routes/news");
// 挂载模块
app.use("/", login);
app.use("/news", news); //news.js中前缀/news要去掉

10,官方推荐应用程序生成器(创建项目得脚手架)

1.安装 npm i express-generator -g 全局安装
2.express -h 能查看 安装成功
3.express --view=pug 项目名称 (要提前cd到你要创建项目得目录)
4.运行bin 中得www.js
在这里插入图片描述

11.图片上传 multer
需求:上传文件(可以多个上传)根据日期自动生成文件夹(分类)

安装插件
1.npm i multer -s
2.npm i silly-datetime -s
3.npm i mkdirp -s // 这个是用来创建文件夹的

封装一个uploadFileService.js

/**
 * 文件上传
 * @returns {Promise<void>}
 */
var path = require("path");
var multer = require("multer");
var sd = require("silly-datetime");
const mkdirp = require("mkdirp");
/*
    *上传图片的方法调用 upload()是因为在别的地方调用来这个js 需要先执行upload()
    单张图片调用upload().single("avatar")  avatar 是input的name
    多张图片调用
    1.upload().array("avatar",12)  name为avatar最多12张
    2.upload().fields(
        [
            {name:"avatar",maxCount:1},{name:"aa",maxCount:2}
        ]
    )
*/
var uploadFileService = {
    // 文件上传
    upload: () => {
        var storage = multer.diskStorage({
            // 配置上传目录
            destination: async (req, file, cb) => {
                // 1.获取当前日期
                let day = sd.format(new Date(), "YYYYMMDD");
                let dir = path.join("uploads/", day);
                // 2.按照日期生成目录  mkdirp 是异步方法,返回的是一个promise异步对象
                await mkdirp(dir);
                cb(null, dir);
            },
            // 修改文件名
            filename: (req, file, cb) => {
                // 获取后缀名
                // let extname = path.extname(file.originalname);
                let arr = file.originalname.split(".");
                cb(null, arr[0] + "-" + Date.now() + "." + arr[1]);
            },
        });

        var upload = multer({ storage: storage });
        return upload;
    },
};

module.exports = uploadFileService;

表单提交

<form action="./doLogin" method="post" enctype="multipart/form-data">
        用户名:<input type="text" value="yangjie" name="username"><br>
        图片1:<input type="file" name="avatar" /><br>
        图片2:<input type="file" name="aaa" /><br>
        密码<input type="password" value="123" name="password"><br>
        <button type="submit">提交</button>
    </form>

/doLogin 路由

var { upload } = require("../util/uploadFileService");
var express = require("express");
var router = express.Router("express");
router.post(
    "/doLogin",
    upload().fields([
        { name: "avatar", maxCount: 1 },
        { name: "aaa", maxCount: 1 },
    ]),
    (req, res) => {
        // 获取参数传值
        var body = req.body;
        var file = req.file;
        console.log(body, file);
        res.send("执行 登录");
    }
);

在这里插入图片描述
12.mysql 运用
路由这里不配了,主要写下这里的增删改查(删除没弄)

/**
 * 用户注册
 * 1.发送验证码
 * 2.登录
 * 3.判断是否是第一次登录
 * 4.是的话 注册用户信息
 * 5.是的话 创建用户附表
 * 6.获取用户信息
 * @returns {Promise<void>}
 */
var dbConfig = require("../util/dbconfig");
let codeArr = [];
/*------------------接口--------------------------*/
// 发送验证码
let sendCode = (req, res) => {
    // 获取手机号
    let phone = req.body.phone;
    let code = fourNum(1000, 9999);
    // 验证是否已发送
    let isSend = codeArr.some((item) => {
        return item.phone == phone;
    });
    if (isSend) {
        // 可以用阿里云 极光等短信服务
        res.send({
            data: {},
            resultCode: 1001,
            msg: "验证码已发送!",
        });
    } else {
        codeArr.push({
            code: code,
            phone: phone,
        });
        // 有效性
        setTimeout((re) => {
            codeArr = codeArr.filter((item) => {
                return item.phone != phone;
            });
        }, 60 * 1000 * 10);
        res.send({
            data: {
                code: code,
                phone: phone,
            },
            resultCode: 1,
            msg: "发送成功",
        });
    }
};

// 验证码登录
let login1 = async (req, res) => {
    let { phone, code } = req.body;
    let arr = codeArr.filter((item) => {
        return item.phone == phone;
    });
    if (arr.length == 0 || arr[0].code != code) {
        res.send({
            data: {},
            resultCode: 1002,
            msg: "验证码错误!",
        });
    } else {
        let data = await phoneBind(phone);
        console.log("结束");
        res.send({
            data: data,
            resultCode: 1,
            msg: "登录成功!",
        });
    }
};

// 修改用户信息接口
let saveInfo = async (req, res) => {
    let params = req.body;
    let { age, sex, school, user_id } = params;
    let sql = `update userinfo set age=?,sex=?,school=? where user_id=?`;
    let arr = [age, sex, school, user_id];
    let data = await dbConfig.asyncSqlConnect(sql, arr);
    if (data.affectedRows == 1) {
        let userInfo = await getUserInfo(user_id);
        userInfo[0].userInfo = await getUserInfoDetail(user_id);
        res.send({
            data: userInfo[0],
            resultCode: 1,
            msg: "登录成功!",
        });
    } else {
        res.send({
            data: null,
            resultCode: 1003,
            msg: "修改失败",
        });
    }
};

// 删除用户信息接口
// 删除有多个关联表的时候需要用的事务,  多步操作的时候一旦出错 回滚,保护数据库
let deleteInfo = async (req, res) => {};

/*------------------方法--------------------------*/

// 判断用户是否注册
let phoneBind = async (phone) => {
    // 判断用户是否注册
    let sqlArr = [];
    let data = await dbConfig.asyncSqlConnect(
        "select * from user where phone=" + phone + " or username=" + phone,
        sqlArr
    );
    let userInfo = {};
    if (data.length && data.length != 0) {
        data[0].userInfo = await getUserInfoDetail(data[0].id);
        console.log(data[0]);
        return data[0];
    } else {
        // 用户未注册,需要写入数据
        userInfo = await register(phone);
        userInfo[0].userInfo = await getUserInfoDetail(userInfo[0].id);
        return userInfo[0];
    }
};
// 用户注册
let register = async function (phone) {
    // 建立参数
    var sql = `insert into user (username,phone,create_time) values (?,?,?)`;
    var sqlArr = [phone, phone, timestampToTime(new Date().getTime())];
    // 调用连接池
    let data = await dbConfig.asyncSqlConnect(sql, sqlArr);
    // 添加数据成功与否判断
    if (data.affectedRows == 1) {
        // 执行成功 获取用户信息
        let info = await getUserInfo(phone);
        // 创建用户的附表(详情表)
        let userInfo = await createUserInfo(info[0].id, phone);
        return info;
    } else {
        return false;
    }
};
// 获取用户信息
let getUserInfo = (username) => {
    // 建立参数
    var sql = `select * from user where id=? or phone=? or username=?`;
    var sqlArr = [username, username, username];
    return dbConfig.asyncSqlConnect(sql, sqlArr);
};
// 创建用户附表
let createUserInfo = (user_id, phone) => {
    // 建立参数
    var sql = `insert into userinfo(user_id,name,phone) values (?,?,?)`;
    var sqlArr = [user_id, phone, phone];
    return dbConfig.asyncSqlConnect(sql, sqlArr);
};

// 获取用户详情
let getUserInfoDetail = (user_id) => {
    // 建立参数
    var sql = `select name,age,phone,sex,school from userinfo where user_id=?`;
    var sqlArr = [user_id];
    console.log(user_id);
    return dbConfig.asyncSqlConnect(sql, sqlArr);
};

// 随机生成四位数
function fourNum(min, max) {
    return Math.floor(Math.random() * (max - min)) + min;
}
function timestampToTime(timestamp) {
    var date = new Date(timestamp); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
    var Y = date.getFullYear() + "-";
    var M =
        (date.getMonth() + 1 < 10
            ? "0" + (date.getMonth() + 1)
            : date.getMonth() + 1) + "-";
    var D = (date.getDate() < 10 ? "0" + date.getDate() : date.getDate()) + " ";
    var h =
        (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":";
    var m =
        (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) +
        ":";
    var s =
        date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
    return Y + M + D + h + m + s;
}

module.exports = { sendCode, login1, saveInfo };

连接池

const mysql = require("mysql");
module.exports = {
    // 基本配置
    config: {
        host: "localhost",
        user: "root",
        port: 3306,
        password: "123456",
        database: "students", //数据库名
    },
    // 连接数据库,使用mysql的连接池的方式
    // 连接池对象
    // 这里要用function 不要用es6 不然this指向有问题
    sqlConnect: function (sql, sqlArr, callBack) {
        var pool = mysql.createPool(this.config);
        pool.getConnection((err, conn) => {
            if (err) {
                console.log("连接失败", err);
                return;
            }
            // 事件驱动回调
            conn.query(sql, sqlArr, callBack);
            // 释放连接
            conn.release();
        });
    },

    // 异步回调
    asyncSqlConnect: function (sql, sqlArr) {
        return new Promise((resolve, reject) => {
            var pool = mysql.createPool(this.config);
            pool.getConnection((err, conn) => {
                if (err) {
                    console.log("连接失败", err);
                    reject(err);
                } else {
                    //开启事务
                    // conn.beginTransaction((err) => {
                    //     if (err) {
                    //         console.log("开启事务失败", err);
                    //         reject(err);
                    //     } else {
                    // 事件驱动回调
                    conn.query(sql, sqlArr, (err, data) => {
                        if (err) {
                            console.log("连接失败1", err);
                            reject(err);
                        } else {
                            console.log("成功");
                            resolve(data);
                        }
                    });
                    // 释放连接
                    conn.release();
                    //     }
                    // });
                }
            });
        });
    },
};

13.mysql事务
同时执行多条语句,一旦失败 回滚

封装的函数

const mysql = require("mysql");
var config = {
    host: "localhost",
    user: "root",
    port: 3306,
    password: "123456",
    database: "myself", //数据库名
};
var pool = mysql.createPool(config);
const execTransection = (sqlArr) => {
    return new Promise((resolve, reject) => {
        var promiseArr = [];
        pool.getConnection(function (err, connection) {
            if (err) {
                return reject(err);
            }
            connection.beginTransaction((err) => {
                if (err) {
                    return reject("开启事务失败");
                }
                // 将所有需要执行的sql封装为数组
                promiseArr = sqlArr.map(({ sql, values }) => {
                    return new Promise((resolve, reject) => {
                        connection.query(sql, values, (e, rows, fields) => {
                            e ? reject(e) : resolve(rows);
                        });
                    });
                });
                // Promise调用所有sql,一旦出错,回滚,否则,提交事务并释放链接
                Promise.all(promiseArr)
                    .then((res) => {
                        connection.commit((error) => {
                            if (error) {
                                console.log("事务提交失败");
                                reject(error);
                            }
                        });
                        connection.release(); // 释放链接
                        resolve(res);
                    })
                    .catch((err) => {
                        connection.rollback(() => {
                            console.log("数据操作回滚");
                        });
                        reject(err);
                    });
            });
        });
    });
};
module.exports = execTransection;

使用

let resp = await dbConfig([
        {
            sql: "select * from subjecttype",
            values: [],
        },
        {
            sql: "select * from subjecttype",
            values: [],
        },
    ]);
    ctx.body = {
        data: resp,
        // data: {
        //     list: resp,
        //     total: 0,
        // },
        resultCode: 1,
        msg: "获取成功!",
    };
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值