Express篇-连接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 = 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四、验证初始可以通过用户名:guest 密码guest来登录。报错:安装RabbitMQ出现Plugin configuration unchanged.问题…...
【成为架构师课程系列】一线架构师:6个经典困惑及其解法
目录 一线架构师:6个经典困惑及其解法 多阶段还是多视图? 内置最佳实践 架构方法论:3个阶段,一个贯穿 Pre-architecture阶段:ADMEMS矩阵方法 Conceptual Architecture阶段:重大需求塑造做概念架构 Refined Architecture…...
光耦合器的定义与概述
光耦合器或光电耦合器是一种电子元件,基本上充当具有不同电压电平的两个独立电路之间的接口。光耦合器是可在输入和输出源之间提供电气隔离的常用元件。它是一个 6 引脚器件,可以有任意数量的光电探测器。 在这里,光源发出的光束作为输入和输…...
谷粒商城--品牌管理详情
目录 1.简单上传测试 2.Aliyun Spring Boot OSS 3.模块mall-third-service 4.前端 5.数据校验 6.JSR303数据校验 7.分组校验功能 8.自定义校验功能 9.完善代码 1.简单上传测试 OSS是对象存储服务,有什么用呢?把图片存储到云服务器上能让所有人…...
stack、queue和priority_queue
目录 一、栈(stack) 1.stack的使用 2.容器适配器 3.stack的模拟实现 二、队列(queue) 1.queue的使用 2.queue的模拟实现 三、双端队列(deque) 1.vector,list的优缺点 2.认识deque 四…...
面试题(二十二)消息队列与搜索引擎
2. 消息队列 2.1 MQ有什么用? 参考答案 消息队列有很多使用场景,比较常见的有3个:解耦、异步、削峰。 解耦:传统的软件开发模式,各个模块之间相互调用,数据共享,每个模块都要时刻关注其他模…...
Spring Security in Action 第三章 SpringSecurity管理用户
本专栏将从基础开始,循序渐进,以实战为线索,逐步深入SpringSecurity相关知识相关知识,打造完整的SpringSecurity学习步骤,提升工程化编码能力和思维能力,写出高质量代码。希望大家都能够从中有所收获&#…...
Java面试——maven篇
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
基于微信小程序的游戏账号交易小程序
文末联系获取源码 开发语言:Java 框架:ssm JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7/8.0 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:Maven3.3.9 浏览器…...
Matlab绘制隐函数总结-二维和三维
1.二维隐函数 二维隐函数满足f(x,y)0f(x,y)0f(x,y)0,这里无法得到yf(x)yf(x)yf(x)的形式。不能通过普通函数绘制。 我们要关注的是使用fplot函数和fimplicit函数。 第1种情况:基本隐函数 基本的隐函数形式形如: x2y22x2(x2y2)12x^{2}y^{…...
如何直观地理解傅立叶变换?频域和时域的理解
如何直观地理解傅立叶变换 傅里叶变换连续形式的傅立叶变换如何直观地理解傅立叶变换?一、傅里叶级数1.1傅里叶级数的三角形式1.2 傅里叶级数的复指数形式二、傅里叶变换2.1一维连续傅里叶变换三、频谱和功率谱3.1频谱的获得3.2频谱图的特征3.3频谱图的组成频域(frequency do…...
STC15读取内部ID示例程序
STC15读取内部ID示例程序🎉本案例基于STC15F2K60S2为验证对象。 📑STC15 ID序列介绍 STC15系列STC最新一代STC15系列单片机出厂时都具有全球唯一身份证号码(ID号)。最新STC15系列单片机的程序存储器的最后7个字节单元的值是全球唯一ID号,用…...
Xml格式化与高亮显示
具体请参考:Xml格式化与高亮显示...
【GlobalMapper精品教程】045:空间分析工具(2)——相交
GlobalMapper提供的空间分析(操作)的方法有:交集、并集、单并集、差异、对称差集、相交、重叠、接触、包含、等于、内部、分离等,本文主要讲述相交工具的使用。 文章目录 一、实验数据二、符号化设置三、相交运算四、结果展示五、心灵感悟一、实验数据 加载配套实验数据(…...
4年外包终上岸,我只能说这类公司能不去就不去..
我大学学的是计算机专业,毕业的时候,对于找工作比较迷茫,也不知道当时怎么想的,一头就扎进了一家外包公司,一干就是4年。现在终于跳槽到了互联网公司了,我想说的是,但凡有点机会,千万…...
sklearn降维算法1 - 降维思想与PCA实现
目录1、概述1.1 维度概念2、PCA与SVD2.1 降维实现2.2 重要参数n_components2.2.1 案例:高维数据的可视化2.2.2 最大似然估计自选超参数2.2.3 按信息量占比选超参数1、概述 1.1 维度概念 shape返回的结果,几维几个方括号嵌套 特征矩阵特指二维的 一般来…...
「期末复习」线性代数
第一章 行列式 行列式是一个数,是一个结果三阶行列式的计算:主对角线的乘积全排列与对换逆序数为奇就为奇排列,逆序数为偶就为偶排列对换:定理一:一个排列的任意两个元素对换,排列改变奇偶性(和…...
伏并网低电压穿越技术
国内光伏并网低电压穿越要求 略: 低电压穿越方法 当前,光伏电站实现低电压穿越可通过两种方式,即增加硬件设备或者改变控制策略。本节对基于储能设备、基于无功补偿设备、基于无功电流电压支撑控制策略三种实现LVRT的典型方法进行介绍。 …...
opencv的环境搭建
大家好,我是csdn的博主:lqj_本人 这是我的个人博客主页: lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…...
C++智能指针
c11的三个智能指针 unique_ptr独占指针,用的最多 shared_ptr记数指针,其次 weak_ptr,shared_ptr的补充,很少用 引用他们要加上头文件#include unique_ptr独占指针: 1.只能有一个智能指针管理内存 2.当指针超出作用域…...
MongoDB--》MongoDB数据库以及可视化工具的安装与使用—保姆级教程
目录 数据库简介 MongoDB数据库的安装 MongoDB数据库的启动 MongoDB数据库环境变量的配置 MongoDB图形化管理工具 数据库简介 在使用MongoDB数据库之前,我们应该要知道我们使用它的原因: 在数据库当中,有常见的三高需求: Hi…...
JAVA 基础题
1. 面向对象有哪些特征?答:继承、封装、多态2. JDK与JRE的区别是什么?答:JDK是java开发时所需环境,它包含了Java开发时需要用到的API,JRE是Java的运行时环境,JDK包含了JRE,他们是包含…...
Flutter desktop端多屏幕展示问题处理
目前越来越多的人用Flutter来做桌面程序的开发,很多应用场景在Flutter开发端还不是很成熟,有些场景目前还没有很好的插件来支持,所以落地Flutter桌面版还是要慎重。 下面来说一下近期我遇到的一个问题,之前遇到一个需要双屏展示的…...
每天10个前端小知识 【Day 9】
👩 个人主页:不爱吃糖的程序媛 🙋♂️ 作者简介:前端领域新星创作者、CSDN内容合伙人,专注于前端各领域技术,成长的路上共同学习共同进步,一起加油呀! ✨系列专栏:前端…...
Elasticsearch的读写搜索过程
问题 Elasticsearch在读写数据的过程是什么样的?你该如何理解这个问题! Elasticsearch的写数据过程 客户端选择一个节点发送请求,这个时候我们所说的这个节点就是协调节点(coordinating node)协调节点对document进行了路由&am…...
线上服务质量的问题该如何去处理?你有什么思路?
线上服务质量的问题该如何去处理?你有什么思路? 目录:导读 发现线上故障 处理线上故障 修复线上故障 运营线上质量 就是前几天有个同学问了我一个问题:目前业内高可用部署主要采用方案? 看到这个问题,…...
IOC 配置,依赖注入的三种方式
xml 配置 顾名思义,就是将bean的信息配置.xml文件里,通过Spring加载文件为我们创建bean。这种方式出现很多早前的SSM项目中,将第三方类库或者一些配置工具类都以这种方式进行配置,主要原因是由于第三方类不支持Spring注解。 优点…...
自动机,即有限状态机
文章目录一、问题来源二、题目描述三、题解中的自动机四、自动机学习五、有限状态机的使用场景一、问题来源 今天做力克题目的时候看到了字符串转换整数的一道算法题,其中又看到了题解中有自动机的概念,所以在这里对自动机做个笔记。题目链接 二、题目描…...
第一部分:简单句——第一章:简单句的核心——二、简单句的核心变化(主语/宾语/表语的变化)
二、简单句的核心变化 简单句的核心变化其实就是 一主一谓(n. v.) 表达一件事情,谓语动词是其中最重要的部分,谓语动词的变化主要有四种:三态加一否(时态、语态、情态、否定),其中…...
做电子商务系统网站/晋城今日头条新闻
这个问题严格来说是肯定有的,kafka只能保证分区内的有序性。 下面是kafka作者Jay Kreps的blog中介绍kafka设计思想的一段话。 Each partition is a totally ordered log, but there is no global ordering between partitions (other than perhaps some wall-clock…...
做网站时如何给文字做超链接/企业seo整站优化方案
AI 科技评论按:近日,清华大学副教授、Arnetminer 创始人唐杰博士在微博上公开了开放学术组织(Open Academic Society)发布的亿级学术图谱——Open Academic Graph。据唐杰博士介绍,该图谱目前集成了两个最大的公开学术…...
企业做网站 里面都写什么/怎么做表格
目录 漏洞背景 漏洞影响版本 漏洞复现 漏洞利用 漏洞修复 漏洞背景 2020年09月08日微软发布漏洞通告:CVE-2020-16875 | Microsoft Exchange Server 远程执行代码漏洞 由于对cmdlet参数的验证不正确,Microsoft Exchange服务器中存在一个远程执行代码漏洞…...
做网站的 简历/临沂做网络优化的公司
霍夫变换将笛卡尔坐标系的直线用统计展示坐标系A中的点坐标系B中的线坐标系A中的线坐标系B中的点A中多点的连线B中多曲线的交点先理解这样一个思维左边的x-y坐标系中,设定k,b定值,则有一系列x,y值组成直线。相应的在右边k-b坐标系中ÿ…...
大兴高端网站建设/下载百度2024最新版
效果图 image.png 提供的方法 和 属性 ref.show() // ref 主动调用显示打开ref.hide() // ref 主动调用隐藏关闭modalBoxHeight: 300, // 盒子高度modalBoxBg: #fff, // 盒子背景色hide: function () { }, // 关闭时的回调函数transparentIsClick: true // 透明区域是否可以点…...
企业建网站选中企动力/大连seo优化
html input type text标签属性和方法事件 原创 2007年11月28日 16:36:00标签:html /input /autocomplete /文档 /microsoft /语言 10461 标签属性属性描述ACCESSKEYaccessKey设置或获取对象的快捷键。ATOMICSELECTION 指定元素及其内容是否可以一不可见单位统一选择…...