Express篇-连接mysql

news/2024/3/29 17:55:36/文章来源:https://blog.csdn.net/qq_54379580/article/details/129000170
  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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_256889.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第一部分:简单句——第一章:简单句的核心——二、简单句的核心变化(主语/宾语/表语的变化)

二、简单句的核心变化 简单句的核心变化其实就是 一主一谓&#xff08;n. v.&#xff09; 表达一件事情&#xff0c;谓语动词是其中最重要的部分&#xff0c;谓语动词的变化主要有四种&#xff1a;三态加一否&#xff08;时态、语态、情态、否定&#xff09;&#xff0c;其中…

IC封装常见形式

参考&#xff1a;https://blog.csdn.net/dhs888888/article/details/127673300?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-127673300-blog-115610343.pc_relevant_multi_platform_whitelistv4&spm1001.2101.3001.4242…

Mysql 增删改查(一) —— 查询(条件查询where、分页limits、排序order by、分组 group by)

查询 select 可以认为是四个基本操作中使用最为频繁的操作&#xff0c;然而数据量比较大的时候&#xff0c;我们不可能查询所有内容&#xff0c;我们一般会搭配其他语句进行查询&#xff1a; 假如要查询某一个字段的内容&#xff0c;可以使用 where假如要查询前几条记录&#…

【LeetCode】每日一题(2)

目录 题目&#xff1a;1138. 字母板上的路径 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;1138. 字母板上的路径 - 力扣&am…

C# Lambda表达式含义及各种写法

Lambda表达式在各个语言中的表达方式都不太相同&#xff0c;本文重点介绍C#的Lambda表达式。 首先&#xff0c;Lambda表达式就是一个匿名的方法/函数。 以下面的一个完整版作为例子&#xff0c;前面是参数&#xff0c;后面是返回值&#xff1a; 由于 Lambda表达式和委托常常一起…

Windows11 安装Apache24全过程

Windows11 安装Apache24全过程 一、准备工作 1、apache-httpd-2.4.55-win64-VS17.zip - 蓝奏云 2、Visual Studio Code-x64-1.45.1.exe - 蓝奏云 二、实际操作 1、将下载好的zip文件解压放到指定好的文件夹。我的是D:\App\PHP下 个人习惯把版本号带上。方便检测错误。 2…

GhostNet v2(NeurIPS 2022 Spotlight)原理与代码解析

paper&#xff1a;GhostNetV2: Enhance Cheap Operation with Long-Range Attentioncode&#xff1a;https://github.com/huawei-noah/Efficient-AI-Backbones/tree/master/ghostnetv2_pytorch背景在智能手机和可穿戴设备上部署神经网络时&#xff0c;不仅要考虑模型的性能&…

发生异常: AttributeError ‘xxx’ object has no attribute ‘ooo’

python 发生异常: AttributeError ‘xxx’ object has no attribute ‘ooo’ 原因&#xff1a; 函数调用发生在变量定义之前 示例分析&#xff1a; 在apple.py文件中代码如下&#xff1a; class Apple():def __init__(self):self.eat()self.pricedef eat(self):print("吃…

基于javaee的电影碟片租赁管理系统的设计

技术&#xff1a;Java、JSP、框架等摘要&#xff1a;随着信息技术在管理中的广泛应用&#xff0c;管理信息系统(MIS)的实施在技术上逐渐成熟。为了适应时代的发展&#xff0c;降低管理成本&#xff0c;提高工作效率&#xff0c;企业需要加强对内部资源(人、钱、物)的有效管理&a…

AI_News周刊:第一期

2023.02.06—2023.02.12 关于ChatGPT的前言&#xff1a; 在去年年末&#xff0c;OpenAI的ChatGPT在技术圈已经火了一次&#xff0c;随着上周它的二次出圈&#xff0c;ChatGPT算得上是人工智能领域的一颗明星&#xff0c;它在聊天机器人领域有着不可忽视的影响力。其准确、快速…

【前端vue2面试题】2023前端最新版vue模块,高频17问(上)

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;博主收集的关于vue2面试题(上) 目录 vue2面试题 1、$route 和 $router的区别 2、一个…

七大设计原则之单一职责原则应用

目录1 单一职责原则介绍2 单一职责原则应用1 单一职责原则介绍 单一职责&#xff08;Simple Responsibility Pinciple&#xff0c;SRP&#xff09;是指不要存在多于一个导致类变更的原因。假设我们有一个 Class 负责两个职责&#xff0c;一旦发生需求变更&#xff0c;修改其中…

有什么免费好用的全球天气api?

简单介绍几个&#xff0c;选你觉得合适的就行。&#xff08;下面推荐的国内外的都有&#xff0c;访问速度会有些差别&#xff09; 高德天气 API -天气查询-API文档-开发指南-Web服务 API | 高德地图API知心天气 API -HyperData 数据产品简介 心知天气和风天气 API -和风天气开…

Java、JSP动漫网站的设计与实现

技术&#xff1a;Java、JSP等摘要&#xff1a;随着科技的迅速发展&#xff0c;计算机技术已应用到社会的各个领域。随着计算机技术和通信技术的迅速发展&#xff0c;网络的规模也逐渐增大&#xff0c;网络的元素也随之不断增加&#xff0c;有的利用其通信&#xff0c;有的利用其…

架构方法论

0.缘起最近在和同事以及相关领域的人沟通时&#xff0c;大家都在强调架构、架构图&#xff0c;于是兴起了一片关于架构的方法论介绍。本文对内容的组织按照顶层设计思路&#xff0c;先对架构本身进行剖析&#xff1a;什么是架构&#xff1f;为什么架构很重要&#xff1f;这些是…

SNI生效条件 - 补充nginx-host绕过实例复现中SNI绕过的先决条件

文章目录1.前置环境搭建2.测试SNI生效条件(时间)3. 证书对SNI的影响3.1 双方使用同一个证书&#xff1a;3.2 双方使用不同的证书与私钥4. 端口号区分测试4.1 端口号区分&#xff0c;证书区分&#xff1a;4.2 端口号区分,证书不区分&#xff1a;5.总结SNI运行机制6. SNI机制绕过…

SpringBoot+Vue实现智能物流管理系统

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

线程和QObjects

QObject的可重入性&#xff1a; QThread继承了QObject&#xff0c;它发出信号以指示线程开始或完成执行&#xff0c;并提供一些插槽。 QObjects可以在多个线程中使用发出调用其他线程中槽的信号&#xff0c;并将事件发布到在其他线程中“活动”的对象。这是可能的&#xff0…

一个测试人员,在现阶段的环境下如何在测试行业发展和自我价值。

前言周末和几个测试圈子里的大佬饭局上聊了一些职场和测试职业发展相关的话题&#xff0c;我将聊天的内容做了整理和阐述。。朋友圈有测试同学对这篇文章提了比较深刻的建议&#xff0c;下面是他的评价和建议&#xff1a;评价&#xff1a;据说是大佬饭桌总结&#xff0c;有两点…

ThingsBoard-实现定时任务调度器批量RPC

1、概述 ThingsBoard-CE版是不支持调度器的,只有PE版才支持,但是系统中很多时候需要使用调度器来实现功能,例如:定时给设备下发rpc查询数据,我们如何来实现呢?下面我将教你使用巧妙的方法来实现。 2、使用什么实现 我们可以使用规则链提供的一个节点来实现,这个节点可…