主要是学习下如何简单得运用,自己可以写出一个后台
目录
- 初始化一个项目
- 创建web服务
- get请求
- post put delete 三个请求
- 引入ejs 模板
- 中间件
- cookie
- session
- 路由模块化
- 官方推荐应用程序生成器(创建项目得脚手架)
- 图片上传 multer
- mysql 运用(案例)
- 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: "获取成功!",
};