当前位置: 首页 > news >正文

Express篇-连接mysql

  1. 创建数据库配置文件config/sqlconfig.js

const sqlconfig = {host: 'localhost',  // 连接地址user: 'root',    //用户名password: '****',  //密码port:  3306 ,   //端口号database: 'mysql01_dbbooks'   //数据库名
}
module.exports = sqlconfig
  1. 封装数据库管理工具 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 = 0keys.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 += strexec(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;// 随机生成 uidconst uid = moment().get() + '_' + (randomInt(9999999) + 1) + '';return Array.of(uid,nickname,password,phone,email,uImg);}
}const addList = (req, res,  table = 'books') => {let { data } = req.bodylet 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 +=  strexec(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 = 0if(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.bodyif(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,streamconst 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

相关文章:

Express篇-连接mysql

创建数据库配置文件config/sqlconfig.jsconst sqlconfig {host: localhost, // 连接地址user: root, //用户名password: ****, //密码port: 3306 , //端口号database: mysql01_dbbooks //数据库名 } module.exports sqlconfig封装数据库管理工具 utils/mysqlUtils.…...

win10 安装rabbitMQ详细步骤

win10 安装rabbitMQ详细步骤 win10 安装rabbitMQ详细步骤win10 安装rabbitMQ详细步骤一、下载安装程序二、安装配置erlang三、安装rabbitMQ四、验证初始可以通过用户名&#xff1a;guest 密码guest来登录。报错&#xff1a;安装RabbitMQ出现Plugin configuration unchanged.问题…...

【成为架构师课程系列】一线架构师:6个经典困惑及其解法

目录 一线架构师:6个经典困惑及其解法 多阶段还是多视图&#xff1f; 内置最佳实践 架构方法论:3个阶段&#xff0c;一个贯穿 Pre-architecture阶段&#xff1a;ADMEMS矩阵方法 Conceptual Architecture阶段&#xff1a;重大需求塑造做概念架构 Refined Architecture…...

光耦合器的定义与概述

光耦合器或光电耦合器是一种电子元件&#xff0c;基本上充当具有不同电压电平的两个独立电路之间的接口。光耦合器是可在输入和输出源之间提供电气隔离的常用元件。它是一个 6 引脚器件&#xff0c;可以有任意数量的光电探测器。 在这里&#xff0c;光源发出的光束作为输入和输…...

谷粒商城--品牌管理详情

目录 1.简单上传测试 2.Aliyun Spring Boot OSS 3.模块mall-third-service 4.前端 5.数据校验 6.JSR303数据校验 7.分组校验功能 8.自定义校验功能 9.完善代码 1.简单上传测试 OSS是对象存储服务&#xff0c;有什么用呢&#xff1f;把图片存储到云服务器上能让所有人…...

stack、queue和priority_queue

目录 一、栈&#xff08;stack&#xff09; 1.stack的使用 2.容器适配器 3.stack的模拟实现 二、队列&#xff08;queue&#xff09; 1.queue的使用 2.queue的模拟实现 三、双端队列&#xff08;deque&#xff09; 1.vector&#xff0c;list的优缺点 2.认识deque 四…...

面试题(二十二)消息队列与搜索引擎

2. 消息队列 2.1 MQ有什么用&#xff1f; 参考答案 消息队列有很多使用场景&#xff0c;比较常见的有3个&#xff1a;解耦、异步、削峰。 解耦&#xff1a;传统的软件开发模式&#xff0c;各个模块之间相互调用&#xff0c;数据共享&#xff0c;每个模块都要时刻关注其他模…...

Spring Security in Action 第三章 SpringSecurity管理用户

本专栏将从基础开始&#xff0c;循序渐进&#xff0c;以实战为线索&#xff0c;逐步深入SpringSecurity相关知识相关知识&#xff0c;打造完整的SpringSecurity学习步骤&#xff0c;提升工程化编码能力和思维能力&#xff0c;写出高质量代码。希望大家都能够从中有所收获&#…...

Java面试——maven篇

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

基于微信小程序的游戏账号交易小程序

文末联系获取源码 开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 浏览器…...

Matlab绘制隐函数总结-二维和三维

1.二维隐函数 二维隐函数满足f(x,y)0f(x,y)0f(x,y)0&#xff0c;这里无法得到yf(x)yf(x)yf(x)的形式。不能通过普通函数绘制。 我们要关注的是使用fplot函数和fimplicit函数。 第1种情况&#xff1a;基本隐函数 基本的隐函数形式形如&#xff1a; x2y22x2(x2y2)12x^{2}y^{…...

如何直观地理解傅立叶变换?频域和时域的理解

如何直观地理解傅立叶变换 傅里叶变换连续形式的傅立叶变换如何直观地理解傅立叶变换?一、傅里叶级数1.1傅里叶级数的三角形式1.2 傅里叶级数的复指数形式二、傅里叶变换2.1一维连续傅里叶变换三、频谱和功率谱3.1频谱的获得3.2频谱图的特征3.3频谱图的组成频域(frequency do…...

STC15读取内部ID示例程序

STC15读取内部ID示例程序&#x1f389;本案例基于STC15F2K60S2为验证对象。 &#x1f4d1;STC15 ID序列介绍 STC15系列STC最新一代STC15系列单片机出厂时都具有全球唯一身份证号码(ID号)。最新STC15系列单片机的程序存储器的最后7个字节单元的值是全球唯一ID号&#xff0c;用…...

Xml格式化与高亮显示

具体请参考&#xff1a;Xml格式化与高亮显示...

【GlobalMapper精品教程】045:空间分析工具(2)——相交

GlobalMapper提供的空间分析(操作)的方法有:交集、并集、单并集、差异、对称差集、相交、重叠、接触、包含、等于、内部、分离等,本文主要讲述相交工具的使用。 文章目录 一、实验数据二、符号化设置三、相交运算四、结果展示五、心灵感悟一、实验数据 加载配套实验数据(…...

4年外包终上岸,我只能说这类公司能不去就不去..

我大学学的是计算机专业&#xff0c;毕业的时候&#xff0c;对于找工作比较迷茫&#xff0c;也不知道当时怎么想的&#xff0c;一头就扎进了一家外包公司&#xff0c;一干就是4年。现在终于跳槽到了互联网公司了&#xff0c;我想说的是&#xff0c;但凡有点机会&#xff0c;千万…...

sklearn降维算法1 - 降维思想与PCA实现

目录1、概述1.1 维度概念2、PCA与SVD2.1 降维实现2.2 重要参数n_components2.2.1 案例&#xff1a;高维数据的可视化2.2.2 最大似然估计自选超参数2.2.3 按信息量占比选超参数1、概述 1.1 维度概念 shape返回的结果&#xff0c;几维几个方括号嵌套 特征矩阵特指二维的 一般来…...

「期末复习」线性代数

第一章 行列式 行列式是一个数&#xff0c;是一个结果三阶行列式的计算&#xff1a;主对角线的乘积全排列与对换逆序数为奇就为奇排列&#xff0c;逆序数为偶就为偶排列对换&#xff1a;定理一&#xff1a;一个排列的任意两个元素对换&#xff0c;排列改变奇偶性&#xff08;和…...

伏并网低电压穿越技术

国内光伏并网低电压穿越要求 略&#xff1a; 低电压穿越方法 当前&#xff0c;光伏电站实现低电压穿越可通过两种方式&#xff0c;即增加硬件设备或者改变控制策略。本节对基于储能设备、基于无功补偿设备、基于无功电流电压支撑控制策略三种实现LVRT的典型方法进行介绍。 …...

opencv的环境搭建

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。

1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj&#xff0c;再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

WEB3全栈开发——面试专业技能点P4数据库

一、mysql2 原生驱动及其连接机制 概念介绍 mysql2 是 Node.js 环境中广泛使用的 MySQL 客户端库&#xff0c;基于 mysql 库改进而来&#xff0c;具有更好的性能、Promise 支持、流式查询、二进制数据处理能力等。 主要特点&#xff1a; 支持 Promise / async-await&#xf…...

MySQL体系架构解析(三):MySQL目录与启动配置全解析

MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录&#xff0c;这个目录下存放着许多可执行文件。与其他系统的可执行文件类似&#xff0c;这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中&#xff0c;用…...

如何通过git命令查看项目连接的仓库地址?

要通过 Git 命令查看项目连接的仓库地址&#xff0c;您可以使用以下几种方法&#xff1a; 1. 查看所有远程仓库地址 使用 git remote -v 命令&#xff0c;它会显示项目中配置的所有远程仓库及其对应的 URL&#xff1a; git remote -v输出示例&#xff1a; origin https://…...

CTF show 数学不及格

拿到题目先查一下壳&#xff0c;看一下信息 发现是一个ELF文件&#xff0c;64位的 ​ 用IDA Pro 64 打开这个文件 ​ 然后点击F5进行伪代码转换 可以看到有五个if判断&#xff0c;第一个argc ! 5这个判断并没有起太大作用&#xff0c;主要是下面四个if判断 ​ 根据题目…...

未授权访问事件频发,我们应当如何应对?

在当下&#xff0c;数据已成为企业和组织的核心资产&#xff0c;是推动业务发展、决策制定以及创新的关键驱动力。然而&#xff0c;未授权访问这一隐匿的安全威胁&#xff0c;正如同高悬的达摩克利斯之剑&#xff0c;时刻威胁着数据的安全&#xff0c;一旦触发&#xff0c;便可…...