Nodejs+express后端学习笔记(1)

1 Node.js安装

1、下载安装包:进入官网(https://nodejs.org/en),下载左侧的稳定版。
在这里插入图片描述

2、选择安装位置,不用勾选自动安装必要工具。
其他都默认Next。
在这里插入图片描述
配置环境,具体参考本文章:

https://blog.csdn.net/WHF__/article/details/129362462

2 Node.js使用

nodejs用来开发Web服务器(后端)。本文使用Visual Studio Code进行编写和调试。

2.1 REPL环境使用

命令行状态下输入:node,就可以进入。
可以进行简单的函数编写和计算。
1、输入函数:

> function add(a,b){
	return a+b;
}
> add(1,2)

会输出3。
在这里插入图片描述

2、输入调试:

console.log("hello")

在这里插入图片描述

2.2 基本知识、程序运行方法

1、JS文件的执行方式:js单线程执行,有异步任务,同步任务。

2、模块、包与commonjs规范:

  • 内置(Nodejs自带)
  • 第三方模块(安装在node-modules文件夹中)
    • npm
    • npm install 模块名 --save
    • npm uninstall 模块名
  • 自定义(项目里独立的js文件,根据commonjs规范定义)

3、运行js代码:node ****.js

2.3 第一个js文件

1、console
新建一个文件夹,在文件夹内新建helloworld.js文件,文件内容如下:

//helloworld.js
console.log("hello, world!");

运行代码,在终端控制台输入:node helloworld.js,程序将会反馈出hello, world!

在这里插入图片描述

2、function函数定义和调用
代码如下:

console.log("hello, world!");

function add(a,b){
    return a+b;
}

console.log(add(1,2));

控制台输入输出:

PS G:\Visual Studio\Nodejs_Project\nodejs_test> node .\helloworld.js
hello, world!
3

2.4 外部js文件导入

如果要使helloworld.js文件能够引用其他js文件,需要使用require函数。
1、在同级文件夹下新建utils.js文件,文件内容如下:

function add(a,b){
    return a+b;
}
function about(){
    return "服务器";
}
const name = "utils"

module.exports = {
    add,
    about,
    msg:"你好",
    name,
}

文件内能够定义变量、函数,并通过module.exports引出,以便其他文件调用。

2、文件引入:
helloworld.js文件中,使用require函数引入utils.js文件,然后调用文件内的参数,具体代码如下:

const util = require('./utils.js');

console.log("hello, world!");

console.log(util);
console.log(util.add(1,2));
console.log(util.about());
console.log(util.msg);
console.log(util.name);

3、代码运行:

PS G:\Visual Studio\Nodejs_Project\nodejs_test> node .\helloworld.js
hello, world!
{
add: [Function: add],
about: [Function: about],
msg: ‘你好’,
name: ‘utils’
}
3
服务器
你好
utils

2.5 export导出方法

1、导出对象

module.exports = {
	add,
	about,
	msg,
	...
}

2、导出值/属性

module.exports.add = add;
module.exports.about = about;
module.exports.msg = msg;
...

3、导出

export.add = add;
export about = about;
...

2.6 fs库使用、同步异步

1、fs库使用:如果要使用fs,管理文件系统。
直接const fs = require('fs')
有同步和异步的读取方法,两者都会按照顺序执行程序,但同步方法必须阻塞程序,等到数据读取出来,再继续执行。而异步方法则不会阻塞住程序,而是另外开一个回调函数(类似于中断处理函数),先执行下方代码,等到数据读取出来,再调用回调函数。因此,同步和异步的数据的呈现顺序会出现差异。代码如下:

const fs = require('fs');       // 文件系统模块

console.log("-------------------------------")
// 异步读取,函数运行和读取到值的时间不同,读取到值之后,再调用function
console.log("a1");
fs.readFile("./text1.txt", "utf-8", function(error, res) {
    if(error){
        console.log(error);
        return;
    }
    console.log(res);
});
console.log("b1");
console.log("c1");

// 同步读取文件,读取到文件之间把值给data
console.log("-------------------------------")
console.log("a2");
const data = fs.readFileSync("./text2.txt", "utf-8");
console.log(data);
console.log("b2");
console.log("c2");

代码运行如下,可以发现异步读取的函数输出结果不是按照顺序来的,但这种方法对于网络请求来说非常重要,能够避免因为网络速度较慢造成程序长时间阻塞。

-------------------------------
a1
b1
c1
-------------------------------
a2
text2
b2
c2
text1

2、异步方法也可以使用这种方式:相当于设置一个回调函数,等文件读取完成后调用回调函数。

function readFileCompletedHandle(error, res) {
    if(error){
        console.log(error);
        return;
    }
    console.log(res);
}

fs.readFile("./text1.txt", "utf-8", readFileCompletedHandle);

2.7 更多官方库

链接:

https://nodejs.p2hp.com/api/v19/documentation/

3 express框架

3.1 初始化工程

使用命令npm init来创建新工程。里面的设置全部默认,设置完成后会出现一个package.json文件。

//package.json
{
  "name": "nodejs_test",
  "version": "1.0.0",
  "description": "",
  "main": "helloworld.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

3.2 npm

进入npm官网,查找需要的第三方函数库,比如gulp、express、mqtt等。
链接:

https://npm.p2hp.com/

3.3 引入express

在项目文件夹下,输入命令:

npm add express

然后项目中就会安装各种依赖包。
在这里插入图片描述

3.4 http构建服务器

新建http_demo.js文件,代码如下:

// http_demo.js
var http = require('http')

// 通过http模块,创建web应用
var app = http.createServer((req,res) => {
    res.writeHead(200,{"ContentType":"text/plain"});
    res.end("hello world");
});

// 通过监听端口启动
app.listen(3000,'localhost');
console.log("http://localhost:3000");

运行程序,启动服务器,终端输入:

node http_demo.js

可以看到程序输出:

http://localhost:3000

进入该网址,就可以看到:

在这里插入图片描述

如果想要停止服务器运行,使用Ctrl+C组合键关闭。

3.5 express构建服务器

express对http库进行了封装。
新建app.js文件,代码如下:

// 导入express
const express = require("express");

const app = express()

app.get('/',(req,res)=>{
    res.send('Hello World Express!');
})

app.listen(3000,()=>{
    console.log("Express app at: http://localhost:3000");
})

运行程序:

node app.js

得到输出:

Express app at: http://localhost:3000

进入网页:
在这里插入图片描述

4 express路由

4.1 get、post、put、delete四种请求

app.js代码如下:

// 导入express
const express = require("express");

const app = express()

// get请求
app.get('/',(req,res)=>{
    res.send('Get Express!');
})
// post请求
app.post('/',(req,res)=>{
    res.send('Post Express!');
})
// put请求
app.put('/',(req,res)=>{
    res.send('Put Express!');
})
// delete请求
app.delete('/',(req,res)=>{
    res.send('delete Express!');
})

app.listen(3000,()=>{
    console.log("Express app at: http://localhost:3000");
})

输入node app.js运行服务器。

浏览器能够看到Get Express!

在这里插入图片描述

4.2 下载Postman验证

参考链接: https://blog.csdn.net/qq_37591637/article/details/88655294

输入网址:http://localhost:3000,左侧选择get、post、put、delete请求。点击Send,在底部就可以查看服务器返回的数据。
在这里插入图片描述
2、发送JSON格式数据:

//app.js
// get请求
app.get('/',(req,res)=>{
    res.send({"name":"小美","age":"18","message":"刚满十八岁~"});    // json格式数据
})

保存后重启服务器,刷新网页,可以看到:

在这里插入图片描述
postman也可以获得数据:

在这里插入图片描述
重启服务器比较麻烦,因此以下可以采用热部署。

4.3 热部署 nodemon

1、安装nodemon:
命令行输入:

npm install nodemon -d -g

-d的意思是作为依赖,可以自动添加到package.json中。
-g的意思是全局安装。

2、在package.jsonscript中修改:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
	"start": "nodemon app.js"
  },

3、使用npm start命令来启动服务器。

在这里插入图片描述
修改并保存app.js内的数据:

// get请求
app.get('/',(req,res)=>{
    // res.send('Get Express!');
    res.send({"name":"小兰","age":"16","message":"刚满十六岁~"});    // json格式数据
})

刷新浏览器,不用重启服务器,就可以看到返回数据的变化。

在这里插入图片描述

注意:如果出现nodemon : 无法将“nodemon”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再 试一次。问题的另外一个解决方法:

https://blog.csdn.net/yan_danfeng/article/details/109306687

4.4 路由模块化

将多个请求放置到其他文件。
新建router-demo.js,将部分app.js的代码移植到文件内,需要创建router对象,并在最后使用module.exports导出。

var express = require("express");

// 创建router对象
var router = express.Router();

// get请求
router.get('/',(req,res)=>{
    res.send({"name":"小兰","age":"16","message":"刚满十六岁~"});    // json格式数据
})
// post请求
router.post('/',(req,res)=>{
    res.send('Post Express!');
})
// put请求
router.put('/',(req,res)=>{
    res.send('Put Express!');
})
// delete请求
router.delete('/',(req,res)=>{
    res.send('delete Express!');
})

module.exports = router;

app.js修改为:

// 导入 express
const express = require("express");
const router = require("./router-demo");
const app = express();
// 绑定路由
app.use(router);

app.listen(3000,()=>{
    console.log("Express app at: http://localhost:3000");
})

重启服务器,可以看到服务依旧可以使用。

5 express中间件

5.1 中间件的请求参数

1、 req.query:查询字符串传递参数。查询字符串时URL中?后面的参数。
2、 req.params:包含路由定义的动态路由参数。动态路由参数是通过在路由路径中使用冒号:定义的。
3、 req.body:包含通过请求主体传递的参数,通常用于POST、PUT和DELETE请求中发送数据。需要使用中间件(body-parser)来解析请求主体。
4、 req.headers:包含请求中的头部信息。

5.1.1 修改状态Status

如果要get先返回状态(201),可以使用:

router.get('/',(req,res)=>{
    res.stauts(201).send({"name":"小兰","age":"16","message":"刚满十六岁~"});    // json格式数据
})

postman再次send以下,可以发现状态变化,从200变成201。
在这里插入图片描述

5.1.2 修改头部Headers

.set()可以组装头部,.end()表示一次响应的结束。

// get请求
router.get('/',(req,res)=>{
    res.set({"aHeader":"bHeader"});
    res.status(201).send({"name":"小兰","age":"16","message":"刚满十六岁~"});    // json格式数据
    res.end();
})

可以发现Headers内数据变化。
在这里插入图片描述

5.1.3 修改路由路径

如果从http://localhost:3000/user发送Get请求。
则可以修改app.js中绑定路由的参数,前面加上路径。

app.use('/user',router);

postman结果如下:依旧可以正常工作。
在这里插入图片描述

5.1.4 服务器读取字符串传递参数 query方法

获取params内的键值对数据,也就是?后面的数据。
1、修改router-demo.js内get请求的函数:

var express = require("express");


// 创建router对象
var router = express.Router();

// get请求
router.get('/',(req,res)=>{
    // 请求对象
    console.log("req请求",req);

    // 响应对象
    res.set({"aHeader":"bHeader"});
    res.status(201).send({"name":"小红","age":"16","message":"刚满十六岁~"});    // json格式数据
    res.end();
})
// post请求
router.post('/',(req,res)=>{
    res.send('Post Express!');
})
// put请求
router.put('/',(req,res)=>{
    res.send('Put Express!');
})
// delete请求
router.delete('/',(req,res)=>{
    res.send('delete Express!');
})

module.exports = router;

使用浏览器/postman发送一次请求,在VS Code的终端能够看到服务器的console.log调试信息,可以发现非常的长。

req请求 <ref *2> IncomingMessage {
  _readableState: ReadableState {
    highWaterMark: 16384,
    buffer: BufferList { head: null, tail: null, length: 0 },
    length: 0,
    pipes: [],
    awaitDrainWriters: null,
    [Symbol(kState)]: 1185840
  },
  ...
  [Symbol(kHeadersCount)]: 28,
  [Symbol(kTrailers)]: null,
  [Symbol(kTrailersCount)]: 0
}

2、如果浏览器或postman发送了键值对:

gender: female

网址则变成:

http://localhost:3000/user?gender=female

在这里插入图片描述
服务器读取方法如下:req.query.*****,*****是params中的Key值,输出的是value。

// get请求
router.get('/',(req,res)=>{
    // 请求对象
    console.log("req请求: ",req.query.gender);

    // 响应对象
    res.set({"gender":req.query.gender});
    res.status(201).send({"name":"小红","age":"16","message":"刚满十六岁~"});    // json格式数据
    res.end();
})

服务器控制台可以看到:

在这里插入图片描述

postman可以看到服务器返回了键值对gender:female给自己。

在这里插入图片描述

5.1.5 服务器读取动态路由参数 params方法

对于路由路径/user/:id,当发送请求到/user/123时,req,params.id将返回“123”。也就是获取id

router-demo.js文件修改如下,修改router.get('/:id', ...),并添加读取req.params.id

// get请求
router.get('/:id',(req,res)=>{
    // 请求对象
    console.log("req请求: ",req.query.gender);
    console.log("id: " + req.params.id);

    // 响应对象
    res.set({"gender":req.query.gender});
    res.status(201).send({"name":"小红","age":"16","message":"刚满十六岁~"});    // json格式数据
    res.end();
})

因此在刚才的网址和字符串传递参数之间添加动态路由参数:

http://localhost:3000/user/123?gender=female

在这里插入图片描述

发送之后,服务器调试信息如下:

req请求: female
id: 123

5.1.6 服务器读取POST请求的body

注意与5.3.4.2、5.3.4.3区分。
1、安装body-parser,命令行输入:

npm install body-parser

2、引入包、添加中间件、使用req.body读取数据。

//router-demo.js
var express = require("express");
const bodyParser = require("body-parser");

// 创建router对象
var router = express.Router();
router.use(bodyParser.json());
router.use(bodyParser.urlencoded({ extended: false }));
// ...
// post请求
router.post('/', (req,res)=>{
    console.log("post");
    console.log(req.body);
    res.send(req.body);
})
// ...
module.exports = router;

3、postman发送数据:
选择body、选择x-www-form-urlencoded格式、添加键值对{“nation”:“china”},发送POST请求。
在这里插入图片描述

4、可以看到服务器调试端输出:

post
[Object: null prototype] { nation: ‘china’ }

postman接收到:

在这里插入图片描述

5.2 express中间件的调用流程

1、客户端发送请求给服务器。
2、express服务器中对数据经过多次处理。
3、express服务器响应客户端请求。

express中间件的本质是function处理函数:

app.get('/', function(req, res, next){
	// 处理请求对象 req
	// 处理响应对象 res
	// ...
	next();
})

注意:中间件函数的形参列表中,必须包含next参数。而路由处理函数中只包含req和res。

5.2.1 定义全局中间件函数

修改app.js,在绑定路由之前加入中间件:

// 路由方法:
// 导入 express服务器
const express = require("express");
const router = require("./router-demo");
const server = express();

// 定义中间件函数
const fw = function(req, res, next){
    console.log("执行所有请求的前置函数")
    next();
};
server.use(fw);// 实例化使用中间件函数,发出任何请求时执行

// 绑定路由
server.use('/user',router);

server.listen(3000,()=>{
    console.log("Express server at: http://localhost:3000");
})

浏览器刷新一下,就可以在服务器调试端口看见中间件反馈的信息。

Express server at: http://localhost:3000
执行所有请求的前置函数
req请求: female
id: 123

多个中间件之间,共享同一份req和res,因此可以在上游的中间件中,统一为req和res对象添加自定义的属性或方法,供下游的中间件使用。

如下定义的就是全局中间件:

// 定义中间件函数1
const fw1 = function(req, res, next){
    console.log("前置函数1")
    next();
};
server.use(fw1);         // 实例化使用中间件函数,发出任何请求时执行

// 定义中间件函数2
const fw2 = function(req, res, next){
    console.log("前置函数2")
    next();
};
server.use(fw2);         // 实例化使用中间件函数,发出任何请求时执行

5.2.2 定义局部中间件函数

编写中间件函数,然后将函数放在GET请求函数中间,可以放置多个。

router.get('/', [
	middleWareFunction1,
	middleWareFunction2,
	..., 
], (req, res)=>{
	res.send("express get");
})

5.2.1中app.js的代码不变,修改router-demo.js的代码:

// router-demo.js
var express = require("express");


// 创建router对象
var router = express.Router();

// 定义局部中间件函数
const mwf1 = function(req, res, next){
    console.log("中间件函数1");
    next();
};
const mwf2 = function(req, res, next){
    console.log("中间件函数2");
    next();
};

// get请求
router.get('/:id', [mwf1, mwf2], (req,res)=>{
    // 请求对象
    console.log("req请求: ",req.query.gender);
    console.log("id: " + req.params.id);

    // 响应对象
    res.set({"gender":req.query.gender});
    res.status(201).send({"name":"小红","age":"16","message":"刚满十六岁~"});    // json格式数据
    res.end();
})
// post请求
router.post('/',(req,res)=>{
    res.send('Post Express!');
})
// put请求
router.put('/',(req,res)=>{
    res.send('Put Express!');
})
// delete请求
router.delete('/',(req,res)=>{
    res.send('delete Express!');
})

module.exports = router;

postman发送GET请求后,服务器显示如下:

前置函数1
前置函数2
中间件函数1
中间件函数2
req请求: female
id: 123

postman发送POST请求后,服务器显示如下:

前置函数1
前置函数2

可以发现mwf作为局部中间件,在get请求中被调用,但在post请求中没有被调用。而在app.js文件中的两个全局中间件依然被调用。

注意:
1、在路由之前注册中间件。
2、客户端发送过来的请求,可以连续调用多个中间件进行处理。
3、执行完中间件的业务代码之后,一定要调用next()函数。
4、中间件调用next()之后,一定不要再写额外的代码。
5、连续调用多个中间件时,多个中间件之间,共享req和res对象。

5.3 中间件级别

5.3.1 应用级别的中间件

通过app.use()或app.get()或app.post(),绑定到app实例上的中间件

5.3.2 路由级别的中间件

绑定到express.Router()实例上的中间件。和应用级别的中间件没有区别,只不过一个是绑定到app实例上,一个是绑定到router实例上。

5.3.3 错误级别的中间件

当项目发生异常,从而防止项目异常崩溃。错误级别的中间件函数有四个形参,分别为(err, req, res, next)。

1、修改router-demo.js的delete请求:

// router-demo.js
router.delete('/',(req,res)=>{
    res.status(5000);
    throw new Error("服务器发送错误");
})

throw new Error()为手动抛出一个错误信息。

2、添加错误中间件,由于要全局有效,因此放在app.js内,还要放在绑定路由的后面。

// app.js

// 导入 express服务器
const express = require("express");
const router = require("./router-demo");
const server = express();

// 定义中间件函数1
const fw1 = function(req, res, next){
    console.log("前置函数1")
    next();
};
server.use(fw1);         // 实例化使用中间件函数,发出任何请求时执行

// 定义中间件函数2
const fw2 = function(req, res, next){
    console.log("前置函数2")
    next();
};
server.use(fw2);         // 实例化使用中间件函数,发出任何请求时执行
// 绑定路由
server.use('/user',router);

// 错误中间件
const errorfw = (error, req, res, next) => {
    if(error){
        console.log('异常:',error.message);
        res.status(500).send('服务器发生错误:' + error.message);
    }else{
        next();
    }
}
server.use(errorfw);

server.listen(3000,()=>{
    console.log("Express server at: http://localhost:3000");
})

运行顺序是:中间件请求函数1、中间件请求函数2、router内的请求函数、错误中间件请求函数。

3、Postman发送DELETE请求。
服务器后台显示如下:

前置函数1
前置函数2
异常: 服务器发送错误

postman显示如下:
在这里插入图片描述

5.3.4 express内置的中间件

5.3.4.1 express.static()

express.static 快速托管静态资源,比如html文件、图片、css样式。
新建resource文件夹,在app.js文件中添加server.use(express.static('resource'));
代码如下:

// ...
// 绑定路由
server.use('/user',router);

// 错误中间件
const  errorfw = function(error, req, res, next){
    if(error){
        console.log('异常:',error.message);
        res.status(500).send('服务器发生错误:' + error.message);
    }else{
        next();
    }
}
server.use(errorfw);

server.use(express.static('resource'));

server.listen(3000,()=>{
    console.log("Express server at: http://localhost:3000/1.jpg");
})

resource文件夹下资源如下:
在这里插入图片描述

使用该中间件以管理文件夹内的图片、html、css,资源可通过浏览器访问,地址为:

http://localhost:3000/1.jpg
http://localhost:3000/1.html
http://localhost:3000/1.css

5.3.4.2 express.json()

注意与5.1.6、5.3.4.3区分。
express.json 解析JSON格式的body请求体数据。

1、修改app.js文件,在路由之前添加express.json(),代码如下:

// app.js
// ...
server.use(express.json());
server.use('/user',router);	// 绑定路由
// ...

2、在router-demo.js文件内,修改post请求,代码如下:

//router-demo.js
var express = require("express");

// 创建router对象
var router = express.Router();
// ...
// post请求
router.post('/', (req,res)=>{
    console.log("post");
    console.log(req.body);
    //res.send('Post Express!');
    res.send(req.body);
})
// ...
module.exports = router;

3、postman发送数据:选择POST、Body、raw、JSON,文本输入:

{
	"name":"小明"
}

点击Send发送请求。
在这里插入图片描述
4、postman接收到的信息如上图下侧,服务器调试端口如下:

post
{ name: ‘小明’ }

5.3.4.3 express.urlencoded()

注意与5.1.6、5.3.4.3对比。
express.urlencoded 解析URL-encoded格式的params请求体数据,也就是网址?后面的数据。

1、修改app.js文件,在路由之前添加express.urlencoded({extended:false}),代码如下:

// app.js
server.use(express.json());
server.use(express.urlencoded({extended:false}));
// 绑定路由
server.use('/user',router);

2、在router-demo.js文件内,修改post请求,代码如下:

//router-demo.js
var express = require("express");

// 创建router对象
var router = express.Router();
// ...
// post请求
router.post('/', (req,res)=>{
    console.log("post");
    console.log(req.body);
    const {username, password} = req.body;
    console.log("username: " + username);
    console.log("password: " + password);
    res.send(req.body);
})
// ...
module.exports = router;

3、postman选择POST请求、Body、x-www-form-urlencoded,添加键值对{“username”:“john”,“password”:“123456789”},发送请求。

在这里插入图片描述
4、服务器调试端口:

post
[Object: null prototype] { username: ‘john’, password: ‘1234568789’ }
username: john
password: 1234568789

postman显示:
在这里插入图片描述

5.3.5 第三方的中间件

6 express连接Mysql数据库

6.1 Mysql数据库配置

1、安装Mysql和Mysql Workbench,其他管理工具也可以,当然只用命令行也行。
2、新建连接:
主界面点击加号添加新的连接。这里可以创建默认Schema。输入密码,测试连接。

在这里插入图片描述

3、新建表 Table,添加元素与其对应的数据类型。

在这里插入图片描述
4、插入数据:
insert into gps_fence.user_login values(2,"root","woshiroot","123456789@qq.com","18200000000","0123456789",true);
然后点击闪电执行代码,下方显示出具体数据。

在这里插入图片描述

6.2 后端js连接测试

6.2.1 引入mysql库

终端输入:

npm install -s mysql

6.2.2 连接数据库

新建文件mysql-demo.js,测试数据库连接。
代码如下:

const mysql = require("mysql");

const connection = mysql.createConnection({
    host:'localhost',
    user:'root',
    password:'woshiroot',
    database:'gps_fence'
});
const table = 'user_login';

// 连接数据库
connection.connect((err) =>{
    if(err){
        console.log('Error connecting to MYSQL database: ' + err.stack);
        return;
    }else{
        console.log('Connect to MYSQL database as id' + connection.threadId);
    }
})

6.2.3 查询数据

js代码如下:

// 发送查询请求
const sqlStr = `select * from ${table}`;
connection.query(sqlStr, (err, results)=>{
    if(err){
        return console.log(err.message);
    }else{
        console.log(results);
    }
})

调试输出:

[
  RowDataPacket {
    user_id: 1,
    username: 'root',
    password: 'woshiroot',
    email: '14*********5@qq.com',
    phonenumber: '18206170000',
    worknumber: '0123456789',
    valid: 1
  },
  RowDataPacket {
    user_id: 2,
    username: 'root',
    password: 'woshiroot',
    email: '123456789@qq.com',
    phonenumber: '18200000000',
    worknumber: '0123456789',
    valid: 1
  }
]

6.2.4 插入数据

js代码如下:

//插入数据请求
const user_data = {
    username:'joe',
    password:'iamjoe20240107',
    email:'20240107@gmail.com',
    phonenumber:'1119491001',
    worknumber:'007',
};
const sqlStr1 = `insert into ${table} (username,password,email,phonenumber,worknumber) values (?,?,?,?,?)`;
// console.log(sqlStr1);
connection.query(sqlStr1, [
    user_data.username,
    user_data.password,
    user_data.email,
    user_data.phonenumber,
    user_data.worknumber
], (err, results)=>{
    if(err){
        return console.log(err.message);
    }else{
        console.log(results);
    }
})

查看Mysql Workbench,发现数据已经添加到数据库。
在这里插入图片描述

插入方法2:

//插入数据请求
const user_data = {
    username:'tom',
    password:'tomcat19990101',
    email:'19990101@gmail.com',
    phonenumber:'1119491011',
    worknumber:'008',
};
const sqlStr1 = `insert into ${table} (username,password,email,phonenumber,worknumber) values `;
// console.log(sqlStr1);
const user_data_amended = `(${Object.values(user_data).map(value => `"${value}"`).join(',')})`;
console.log(user_data_amended);
connection.query(sqlStr1 + user_data_amended, (err, results)=>{
    if(err){
        return console.log(err.message);
    }else{
        console.log(results);
    }
})

mysql数据库显示如下:

在这里插入图片描述

6.2.5 修改数据

6.2.6 删除数据

6.3 前端后端连接

前端发送GET请求,后端访问数据库,查询数据并发送给前端。

1、安装库:express、body-parser、cors、mysql

npm install -s express body-parser cors mysql

2、新建文件db.js,代码如下:

// db.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const mysql = require('mysql');

const app = express();
app.use(bodyParser.json());
app.use(cors());

// 结合Mysql数据库
const connection = mysql.createConnection({
    host:'localhost',
    user:'root',
    password:'root',
    database:'test'
})
const table = 'user_login';

// 连接数据库
connection.connect((err) =>{
    if(err){
        console.log('Error connecting to MYSQL database: ' + err.stack);
        return;
    }else{
        console.log('Connect to MYSQL database as id' + connection.threadId);
    }
})

// 查询数据请求
const sqlStr = `select * from ${table}`;
connection.query(sqlStr,(err, results, fields)=>{
    if(err){
        return console.log(err.message);
    }else{
        console.log(results);
        app.post('/api',(req, res)=> {
            res.send("none");
        })

        app.get('/api',(req, res)=> {
            if(req.query.key === "1234"){
                res.send(results);
            }else{
                res.send("wrong key");
            }
        })

        app.listen(3000,()=>{
            console.log("Express server at: http://localhost:3000");
        })
    }
})

3、Postman相当于前端,给服务器发送Get请求:

在这里插入图片描述

4、服务器给Postman返回的信息如下,正是Mysql内的数据。

[
    {
        "user_id": 1,
        "username": "root",
        "password": "woshiroot",
        "email": "123456789@qq.com",
        "phonenumber": "18200000000",
        "worknumber": "0123456789",
        "valid": 1
    },
    ...
]

6.4 工程接口API

工程中最好使用sequelize进行数据库池的管理。

6.4.1 安装 sequelize

npm install sequelize

Sequelize常用基本方法,方便对数据库进行增删改查的操作:

  • create(values, options):创建一个新的数据实例。
  • bulkCreate(records, options):批量创建多个数据实例。
  • findAll(options):查询满足条件的所有数据实例。
  • findOne(options):查询满足条件的第一个数据实例。
  • findByld(identifier, options):根据逐渐或者ID查询数据实例。
  • update(values, options):更新满足条件的数据实例的值。
  • destroy(options):删除满足条件的数据实例。
  • count(options):统计满足条件的数据实例的数量。
  • increment(fields, options):自增满足条件的数据实例的指定字段值。
  • decrement(fields, options):自减满足条件的数据实例的指定字段值。

6.4.2 创建数据库配置文件

新建config文件夹,新建dbconfig.js,代码如下:

//dbconfig.js
const Sequelize = require('sequelize');

// 创建一个新的Sequelize实例
const DB = new Sequelize("test","root","root",{ //分别为数据库名、用户名、密码
    host:'localhost',
    port: 3306,
    dialect:'mysql',
    pool:{
        max:100,
        min:0,
        idle:10000, // 10秒没有使用,释放该连接
    },
    logging:console.log,   //Sequelize日志输出方法
})

// 测试数据库连接
DB.authenticate().then(()=>{
    console.log("数据库连接成功");
}).catch((err)=>{
    console.log("数据库连接失败: ",err)
});

module.exports = DB;

6.4.3 创建模型

由于数据库的表内不同的字段有不同的数据类型,比如INTEGER、VARCHAR、TINYINT等等,需要nodejs对相应的数据进行类型匹配。field内字符串需要与mysql内完全相同。
可以新建多个模型文件,管理数据库内不同的表(Table)。
创建Models文件夹,创建user-login_model.js,代码如下:

// user-login_model.js
const DB = require("../config/dbconfig.js");
const Sequelize = require('sequelize');

// user_login是数据库的表名 define('表名',{字段})
// 模型与数据库表名的映射
const user_login_model = DB.define("user_login",{
    id:{
        primaryKey: true,
        type: Sequelize.INTEGER,
        field:"user_id",
        autoIncrement:true
    },
    username:{
        type:Sequelize.STRING(45),
        allowNull:true,
        field:"username"
    },
    password:{
        type:Sequelize.STRING(45),
        allowNull:true,
        field:"password"
    },
    email:{
        type:Sequelize.STRING(45),
        allowNull:true,
        field:"email"
    },
    phonenumber:{
        type:Sequelize.STRING(45),
        allowNull:true,
        field:"phonenumber"
    },
    worknumber:{
        type:Sequelize.STRING(45),
        allowNull:true,
        field:"worknumber"
    },
    valid:{
        type:Sequelize.BOOLEAN,
        allowNull:false,
        defaultValue:false,
        field:"valid"
    }
},{
    freezeTableName: true,      // 防止sequelize自动在表名后加s
    timestamps: false           // 禁用createAt和updateAt
});

module.exports = user_login_model;

6.4.4 添加路由

可以新建多个路由文件,每个路由文件内对相同表单进行不同路由的数据处理。
新建routes文件夹,新建user_login.js文件,代码如下:

// user_login.js
// 导入express
const express = require('express');

const router = express.Router();
const user_login_model = require("../Models/user_login_model.js");

// 获取所有学生信息:http://localhost:3000/user_login/search
router.get('/search', async (req, res, next) => {
    try {
      const result = await user_login_model.findAll({ raw: true });
      res.json({
        code: 1001,
        msg: result,
      });
    } catch (err) {
        next(err);
    }
});

// 添加user信息:http://localhost:3000/user_login/add
router.post('/add', async (req, res, next) => {
    try {
        const { username, password, email, phonenumber, worknumber, vaild } = req.body;
        await user_login_model.create({ username, password, email, phonenumber, worknumber, vaild });
        await res.json({
            code: 1001,
            msg: '数据插入成功',
        });
    } catch (err) {
        next(err);
    }
});

// 删除学生信息:http://localhost:3000/user_login/delete
router.post('/delete', async (req, res, next) => {
    try {
        const { id } = req.body;
        await user_login_model.destroy({ where: { id } });
        await res.json({
            code: 1001,
            msg: '删除成功',
        });
    } catch (err) {
      next(err);
    }
});

// 更新某条信息:http://localhost:3000/user_login/update
router.put('/update', async (req, res, next) => {
    try {
        const { id, valid } = req.body;
        const user = await user_login_model.findOne({ where: { id } });
        if (!user) {
            return res.json({
                code: 1002,
                msg: '查询失败',
            });
        }
        await user.update({ valid });
        await res.json({
            code: 1001,
            msg: 'valid更新成功',
        });
    } catch (err) {
      next(err);
    }
  });

// 错误处理中间件
router.use((err, req, res, next) => {
    console.error(err);
    res.status(500).json({
        code: 1002,
        msg: '服务器发生错误',
    });
});

module.exports = router;

6.4.5 添加引用

app.js文件内,导入路由文件,如果有多个路由,需要可以使用path方法进行添加。

// app.js
// 导入 express服务器
const express = require("express");
// 导入router
const path = require('path');
const app = express();
const cors = require('cors');

//路由加载之前使用内置中间件
app.use(express.json());
app.use(express.urlencoded({extended:false}));
app.use(cors());
app.use(express.static('resource'));

// 导入路由
const user_loginRouter = require(path.join(__dirname, 'routes', 'user_login.js'));
app.use('/user_login',user_loginRouter);

const device_infoRouter = require(path.join(__dirname, 'routes', 'device_info.js'));
app.use('/device_info',device_infoRouter);

app.listen(3000,()=>{
    console.log("Express server at: http://localhost:3000");
})

6.4.6 代码测试

1、运行程序,命令行输入:

npm start

2、Postman发送请求:

6.4.6.1 Get请求,查询数据:

请求地址:localhost:3000/user_login/search
返回数据如下:
在这里插入图片描述

6.4.6.2 Post请求,添加信息:

请求地址:http://localhost:3000/user_login/add
选择body,选择x-www-form-urlencoded,在下方添加需要输入数据表的键值对。

在这里插入图片描述
点击发送,Postman收到回复:

{
“code”: 1001,
“msg”: “数据插入成功”
}

查看数据表user_login:
在这里插入图片描述

6.4.6.3 Post请求,删除信息:

请求地址:http://localhost:3000/user_login/delete
选择body,选择x-www-form-urlencoded,只要输入id。

在这里插入图片描述

返回数据:

{
“code”: 1001,
“msg”: “删除成功”
}

数据表情况:可以看到user_id为5的数据已经被删除。

在这里插入图片描述

6.4.6.4 Put请求,修改数据:

请求地址:http://localhost:3000/user_login/update
请求数据:这里使用原始数据JSON格式发送(用法都一样的)。

在这里插入图片描述
返回数据:

{
“code”: 1001,
“msg”: “valid更新成功”
}

数据表情况:
在这里插入图片描述

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

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

相关文章

Linux系统——nmap安装与使用

一、安装nmap 1、安装nmap 【操作命令】 yum install nmap 2、查看nmap版本 【操作命令】 nmap -version 【操作实例】 3、卸载nmap 【操作命令】 yum remove nmap 二、简单使用方法 1、扫描指定ip 【操作命令】 nmap 192.168.1.1 2、扫描指定端口 【操作命令】 …

数据库管理-第130期 JSON二元性(20240109)

数据库管理130期 2024-01-09 第130期 JSON二元性&#xff08;20240109&#xff09;1 简介2 关系型表和JSON存储的优劣3 Oracle JSON关系型二元性视图总结 第130期 JSON二元性&#xff08;20240109&#xff09; 上周&#xff0c;又双叒飞了一趟上海&#xff0c;也是2024年第一飞…

Java内存模型(JMM)是基于多线程的吗

Java内存模型&#xff08;JMM&#xff09;是基于多线程的吗 这个问题按我的思路转换了下&#xff0c;其实就是在问&#xff1a;为什么需要Java内存模型 总结起来可以由几个角度来看待「可见性」、「有序性」和「原子性」 面试官&#xff1a;今天想跟你聊聊Java内存模型&#…

即时设计:设计稿与PPT完美结合,让您的创意作品更具影响力

PPT助手 更多内容 在设计领域&#xff0c;将设计稿与PPT结合起来&#xff0c;可以让您的作品更具吸引力和影响力。为了满足这一需求&#xff0c;我们向您推荐一款强大的设计工具&#xff0c;它可以将设计稿导出为PPT文件&#xff0c;支持线上预览和编辑&#xff0c;让您的创意…

ADS仿真 之 容差/良率分析

之所以要进行容差分析&#xff0c; 是因为任何电子元器件均存在一定的误差&#xff0c; 如电感、电容的精度等。 例如一个标称为2.0nH0.1nH的电感&#xff0c;代表的意思产品有99.74%的概率落在2.0nH0.1nH范围内&#xff0c; 即满足6σ &#xff0c;σ是标准偏差或者说方差&…

OpenHarmony沙箱文件

一.前言 1.前景提要 DevEcoStudio版本&#xff1a;DevEco Studio 3.1 Release SDK版本&#xff1a;3.2.2.5 API版本&#xff1a;9 2.概念 在openharmony文件管理模块中&#xff0c;按文件所有者分类分为应用文件和用户文件和系统文件。 1&#xff09;沙箱文件。也叫做应…

C++类和动态内存分配

目录 1. C类的基本概念与使用 2. 动态内存分配与指针 3. 类与动态内存分配的结合应用 4. 注意事项与最佳实践 5.一个简单的示例代码 在C编程中&#xff0c;类是一种重要的概念&#xff0c;它允许我们将数据和操作封装在一起&#xff0c;以实现更加模块化和可维护的代码。而…

运用AI翻译漫画(二)

构建代码 构建这个PC桌面应用&#xff0c;我们需要几个步骤&#xff1a; 在得到第一次的显示结果后&#xff0c;经过测试&#xff0c;有很大可能会根据结果再对界面进行调整&#xff0c;实际上也是一个局部的软件工程中的迭代开发。 界面设计 启动Visual Studio 2017, 创建…

数据结构与算法 - 线性表

文章目录 第1关&#xff1a;实现一个顺序存储的线性表第2关&#xff1a;实现一个链接存储的线性表 第1关&#xff1a;实现一个顺序存储的线性表 编程要求 本关任务是实现 step1/Seqlist.cpp 中的SL_InsAt、SL_DelAt和SL_DelValue三个操作函数&#xff0c;以实现线性表中数据的…

[答疑]领域特定语言DSL属于伪创新吗(谷爱凌)

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 Zeyu 2024-1-4 9:20 马丁福勒的领域特定语言DSL是否有阅读的价值&#xff1f;属于伪创新吗&#xff1f; UMLChina潘加宇 这个问题就有点伪创新 &#xff0c;让人误以为DSL是Fowler发…

本地部署Canal笔记-实现MySQL与ElasticSearch7数据同步

背景 本地搭建canal实现mysql数据到es的简单的数据同步&#xff0c;仅供学习参考 建议首先熟悉一下canal同步方式&#xff1a;https://github.com/alibaba/canal/wiki 前提条件 本地搭建MySQL数据库本地搭建ElasticSearch本地搭建canal-server本地搭建canal-adapter 操作步骤…

shp与数据库(插入数据)

前言 正文 geopandas与shp文件创建表和录入数据 解释一下上面的代码 查询cd2表的geometry字段 查看一下表 前一篇博客的冲突 问题的解决 POLYGON与MUTLIPOLYGON的说明 解决问题的代码 修改表的创建 shapefile和sqlalchemy插入数据 数据库查询 最后 前言 前一篇讲解…

与AI合作 -- 写一个modern c++单例工厂

目录 前言 提问 bard给出的答案 AI答案的问题 要求bard改进 人类智能 AI VS 人类 前言 通过本文读者可以学到modern C单例模式工厂模式的混合体&#xff0c;同时也能看到&#xff1a;如今AI发展到了怎样的智能程度&#xff1f;怎样让AI帮助我们快速完成实现头脑中的想法&…

【hcie-cloud】【17】华为云Stack灾备服务介绍【灾备方案概述、备份解决方案介绍】【上】

文章目录 前言灾备方案概述灾备的定义灾备的重要性故障和灾难对业务连续性带来的挑战灾备系统的衡量指标RTO与RPO分析 灾备等级标准数据中心容灾解决方案全景图云灾备服务总结架构华为云Stack灾备服务总览 备份解决方案介绍云备份服务介绍备份服务架构介绍云备份服务组件功能介…

界面原型设计工具有哪些?看看这9个

界面原型设计是现代设计师必备的技能之一。在设计数字产品或应用程序时&#xff0c;界面原型是将概念转化为具体可交互界面的重要步骤。对于新手小白来说&#xff0c;选择一款易于上手且功能强大的界面原型设计工具至关重要。本文将介绍 9 个常用的界面原型设计工具&#xff0c…

计算机体系结构动态调度(计分板及Tomasulo)学习记录

1.动态调度核心思想&#xff1a;允许就绪指令越过前方停顿指令&#xff0c;提前进入运行&#xff08;乱序执行&#xff09; 就绪指令指不存在资源冲突、操作数已就绪的指令&#xff0c;例如&#xff0c;计分板算法使用计分板来实现&#xff0c;Tomasulo使用保留站来实现&#…

苹果电脑交互式原型设计软件Axure RP 9 mac特色介绍

Axure RP 9 for Mac是一款交互式原型设计软件&#xff0c;使用axure rp9以最佳的方式展示您的作品&#xff0c;优化现代浏览器并为现代工作流程设计。同时确保您的解决方案正确完整地构建。Axure RP 9 for Mac为您整理笔记&#xff0c;将其分配给UI元素&#xff0c;并合并屏幕注…

swing快速入门(三十九)进度对话框

&#x1f381;注释很详细&#xff0c;直接上代码 上一篇 &#x1f9e7;新增内容 &#x1f9e8;1.模拟耗时操作 &#x1f9e8;2.使用计时器更新进度对话框 &#x1f380;源码&#xff1a; package swing31_40;import javax.swing.*; import java.awt.event.ActionEvent; import …

【debug】为什么ansible中使用command出错

碎碎念 在使用ansible执行command的时候&#xff0c;遇到执行会出错的command 比如执行source打算读取环境变量的时候 错误提示为&#xff1a; 没有那个文件或目录:source 一开始以为是错误提示有问题&#xff0c;一直在testrc的路径上检查&#xff0c;但是同样一行命令使用…

C++八股学习心得.8

1.const知道吗&#xff1f;解释其作用 const 修饰类的成员变量&#xff0c;表示成员常量&#xff0c;不能被修改。 const修饰函数承诺在本函数内部不会修改类内的数据成员&#xff0c;不会调用其它非 const 成员函数。 如果 const 构成函数重载&#xff0c;const 对象只能调…