启动/关闭服务
方式1: net start/stop mysql 启动/关闭服务(需在管理员身份的DOS中进行)
方式2: services.msc 找到对应MySQL服务启动
-
创建数据库配置文件config/sqlconfig.js
const sqlconfig = {
host: 'localhost', // 连接地址
user: 'root', //用户名
password: '****', //密码
port: 3306 , //端口号
database: 'mysql01_dbbooks' //数据库名
}
module.exports = sqlconfig
-
封装数据库管理工具 utils/mysqlUtils.js
连接数据库的两种简单方式:
-
使用mysql.createConnection连接数据库
-
使用连接池 pool.createPool()
const mysql = require('mysql')
const moment = require('moment')
// 加密模块中的随机生成数
const { randomInt } = require('crypto')
const sqlconfig = require('../config/sqlconfig')
// 方式1 使用mysql.createConnection连接数据库
/* let mySql = (req,res,sql)=>{
// console.log(sql);
//连接数据库
let conn= mysql.createConnection(sqlconfig)
// 执行SQL语句
conn.query(sql, (err, result)=>{
// 错误信息
if(err){
console.log(err);
return
}
console.log(result);
res.send({
message: '操作成功!',
result
})
})
} */
// 方式2 使用连接池 pool.createPool()
let pool = mysql.createPool(sqlconfig)
// 执行数据库
const exec2 = (sql,values) => {
return new Promise((resolve, reject) => {
pool.getConnection((err, conn) => {
if (err) {
//连接错误
reject(err)
} else {
//连接成功
// sql语句中使用?占位符, values传递是个数组
conn.query(sql,values, (err, data) => {
if (err) {
//操作失败
reject(err)
} else {
resolve({
code: 0,
message: '操作成功!',
data,
})
// resolve(data)
}
})
}
// 当连接不再使用时,用conn对象的release方法将其归还到连接池中
conn.release()
})
})
}
const exec = (sql) => {
return new Promise((resolve, reject) => {
pool.getConnection((err, conn) => {
if (err) {
//连接错误
reject(err)
} else {
//连接成功
conn.query(sql, (err, data) => {
if (err) {
//操作失败
reject(err)
} else {
resolve({
code: 0,
message: '操作成功!',
data,
})
// resolve(data)
}
})
}
// 当连接不再使用时,用conn对象的release方法将其归还到连接池中
conn.release()
})
})
}
// 查询
const searchList = (req, res, table = 'books') => {
// 根据输入的查询条件查找数据 若无参数则查询所有
let sql = `select * from ${table} where 1=1`
let keys = Object.keys(req.query)
let values = Object.values(req.query)
let keyArr = []
let valArr = []
let str = ''
let i = 0
keys.forEach((item,index)=>{
keyArr.push(item.trim())
console.log(item.trim());
valArr.push(`${values[index].trim()}`)
str += ` and ${keyArr[i]} like '%${valArr[i]}%' `
i++
})
sql += str
exec(sql).then(result=>{
res.send({
code: 1,
message: "查询成功!",
result
})
})
}
// 增加数据
// 封装对象的方法
const addObj = (obj,table) => {
if(table === 'books'){
let { isbn='',bookname,imgUrl='',publisher='',pubYear=null,pages=0,content='',price=0.0 } = obj;
if (pubYear !== null) {
pubYear = moment(pubYear,'YYYY-MM-DD').toDate();
}
// 随机生成 bid randomInt(x)返回0~x的随机整数
const bid = moment().get() + '_' + (randomInt(9999999) + 1) + '';
return Array.of(bid,isbn,bookname,imgUrl,publisher,pubYear,pages,content,price);
}
if(table === 'users'){
let { nickname='',password,phone,email,uImg=null } = obj;
// 随机生成 uid
const uid = moment().get() + '_' + (randomInt(9999999) + 1) + '';
return Array.of(uid,nickname,password,phone,email,uImg);
}
}
const addList = (req, res, table = 'books') => {
let { data } = req.body
let values = []
// data是个数组
if(Array.isArray(data)){
values = data.map(obj => addObj(obj,table))
} else {
// 对象
values= addObj(data,table);
}
let sql = ''
if(table === 'books'){
// sql语句中 ? 为占位符, 表该处有内容, 具体是什么,后边传值, 所传数据(数组中的元素)的个数必须要和占位符的个数一样, 要以数组的形式进行传递(不论有几个元素)
sql = ` insert into books(bid,isbn,bookname,imgUrl,publisher,pubYear,pages,content,price) values (?) `
}
if(table === 'users'){
sql = ` insert into users(uid,nickname,password,phone,email,uImg) values (?) `
}
console.log("values:",values);
// [values] 因为values本身是个数组,如果直接传递, 可能会有多个元素,与?个数不对应, [values]相当于定义数组, 故传递时,变成了二维数组
exec2(sql, [values]).then(data => {
res.send({
code: 1,
message: "添加成功!",
data
});
});
}
// 更新数据 根据id更新
const updateList = (req, res, id, table = 'books', str='bid') => {
const keys = Object.keys(req.body)
const val = Object.values(req.body)
let sql = ''
let items = []
keys.forEach((item, index) => {
items.push(`${item} = '${val[index]}'`)
})
sql = `update ${table} set ${items} where ${str} = '${id}'`
console.log(sql)
// mySql(req, res, sql)
exec(sql).then(result=>{
res.send({
code: 1,
result
})
})
}
// 删除
const deleteList = (req, res, table = 'books') => {
const keys = Object.keys(req.body)
const val = Object.values(req.body)
console.log(keys);
if (keys.length !== 0) {
// 按理来说, 需要查询数据库中是否有该数据
let sql = `delete from ${table} where 1=1`
let str = ''
keys.forEach((item, index) => {
str += ` and ${item} like '%${val[index]}%' `
})
console.log(sql);
// mySql(req, res, sql)
// let searchSQL= `select * from ${table} where 1=1 ${str}`
// exec(searchSQL).then(result=>{
// })
sql += str
exec(sql).then(result=>{
res.send({
code: 1,
message: "删除成功!",
result
})
})
} else {
res.send({
message: '删除条件为空!',
})
}
}
const login = (req,res)=>{
// 根据 phone / email 作为账号来登录 输入内容不为空, 判断是Email还是phone 根据对应信息查询数据, 如果能查到则登录成功, 否则登陆失败
let paramsArr = Object.values(req.body)
// 有数据
let flag = 0
if(paramsArr && paramsArr.length > 0){
// 遍历数组,并去空
paramsArr.forEach(item => {
if(item.trim().length === 0){
flag++
}
})
// 账号 密码存在
if(flag === 0 && req.body.password.length > 0){
let username = paramsArr.toString().indexOf('@') > 0 ? 'email' : 'phone'
let sql = `select * from users where `
if(username === 'email'){
const {password , email } = req.body
// 邮箱登录
sql += ` password = '${ password }' and email = '${email}' `
console.log(sql);
// 查询数据, 查到则登录成功
exec(sql).then(result=>{
console.log(result.data);
if(result.data.length > 0){
res.send({
code: 1,
message: '登录成功!',
result
})
}else{
res.send({
code: 0,
message: '登录失败!'
})
}
})
}
if(username === 'phone'){
const {password , phone } = req.body
// 邮箱登录
sql += ` password = '${ password }' and phone = '${phone}' `
console.log(sql);
// 查询数据, 查到则登录成功
exec(sql).then(result=>{
// console.log(result);
if(result.data.length > 0){
res.send({
code: 1,
message: '登录成功!',
result
})
}else{
res.send({
code: 0,
message: '登录失败!'
})
}
})
}
}else{
// 账号或密码为空
res.send({
code: -1,
message : "账号或密码不能为空!"
})
}
}else{
res.send({
code: -1,
message : "账号和密码不能为空!"
})
}
}
module.exports = {
searchList,
addList,
updateList,
deleteList,
login,
}
3.routes/user.js
var express = require('express');
const {searchList,addList,updateList,deleteList,login}= require('../utils/mysqlUtils')
var router = express.Router();
router.get('/searchList', function(req, res, next) {
searchList(req,res,'users')
})
router.post('/addList', function(req, res, next) {
addList(req,res,'users')
})
router.post('/updateList', (req,res,next)=>{
const {uid} = req.body
if(uid && uid.trim() != '') {
updateList(req,res,req.body.uid,'users','uid')
}else{
res.send({
message: 'uid不能为空!!!'
})
}
})
router.delete('/delList', (req,res,next)=>{
// const {bid} = req.body
// if(bid && bid.trim() != '') {
deleteList(req,res,'users')
// }else{
// res.send({
// message: 'bid不能为空!!!'
// })
// }
})
router.post('/login',(req,res,next)=>{
login(req,res)
})
module.exports = router
4.定时任务
在实际开发项目中,会遇到很多定时任务的工作。比如:定时导出某些数据、定时发送消息或邮件给用户、定时备份什么类型的文件等等。在nodejs中使用 node-schedule 完成定时任务。
安装:npm install node-schedule –save-dev
使用:
const schedule = require('node-schedule');
const scheduleCronstyle = ()=>{
//每分钟的第30秒定时执行一次:
schedule.scheduleJob('30 * * * * *',()=>{
console.log('scheduleCronstyle:' + new Date());
});
}
res.send(xss("<script> while(true){alert('111')}</script>"));举个栗子:每天凌晨2点0分0秒备份日志
const fs = require('fs');
const path = require('path');
const moment = require('moment');
server.listen(port, () => {
// 添加定时器
schedule.scheduleJob('0 0 2 * * *', () => {
// 使用pipe,stream
const source = path.resolve(__dirname, '../logs', 'access.log');
const target = path.resolve(__dirname, '../logs/bak', 'access.log' + moment().format('YYYYMMDDHHmmss') + '.bak');
const rs = fs.createReadStream(source);
const ws = fs.createWriteStream(target);
rs.pipe(ws);
ws.on('close', () => {console.log("备份完成!");
});
});
});
5.
MySQL安全问题
(1)sql注入:窃取数据
最原始,最简单的攻击手段。 攻击方式:输入一个sql片段(s0001′ or s.sid like ‘%%),最终拼接成一段攻击代码。
// 关键点解释
const arr = [1,2,3];
const [a,b,c]=arr;// 数组的解构
console.log("a=",a,"b=",b,"c=",c);
const arr2 = [arr]; // 定义数组
console.log(arr2);
// 结果
// a= 1 b= 2 c= 3
// [ [ 1, 2, 3 ] ]
bookRouter.post('/modify', (req, res, next) => {
const { bookid, bookname, isbn, publishinghouse } = req.body;
let sql = ` UPDATE books b SET b.bid = b.bid `;
const params = [];
if (bookname && bookname.trim() !== '') {
sql += ` , b.bookname= ? `;
params.push(bookname);
}
if (isbn && isbn.trim() !== '') {
sql += `, b.isbn=? `;
params.push(isbn);
}
if (publishinghouse && publishinghouse.trim() !== '') {
sql += ` , b.publishinghouse=? `;
params.push(publishinghouse);
}
sql += ` WHERE b.bid = ? `;
// 有多个占位符,(UPDATE books b SET b.bid = b.bid , b.isbn=? WHERE b.bid = ? ),
// 在传参时,数据的个数必须要和占位符的个数一样,要以数组的形式进行传递
params.push(bookid);
console.log('paramsType:', Object.prototype.toString.call(params), params);
exec2(sql,params).then(data => {
res.send(JSON.stringify({ code: 0, data }));
});
});
预防sql注入:
<1>使用mySql提供的escape函数
const escape = require('mysql').escape;
const sql = select * from users u where u.username=? and u.password=
${escape(password)} ;
<2>使用占位符
const sql = ` select * from users u where u.username=? and u.password= ? `;
exec2(sql, [username,password]);
-
预防xss攻击(xss攻击:窃取前端的cookie)
-
攻击方式:在页面展示内容中夹入js代码,以获取网页信息
-
预防措施:转换生成js的特殊字符1、安装xss: npm install xss -S
2、使用 xss(content);// content代表内容
res.send(xss("<script> while(true){alert('111')}</script>"));
源代码放在这里啦~~~,朋友们帮我提提下载量呗
https://download.csdn.net/download/qq_54379580/87442975