NodeJS Express Sequelize

一、NodeJS

1、 全局变量

  • global:全局变量的宿主(类似于浏览器js中的window对象),这是一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问

  • __filename:当前正在执行的脚本的文件名(完整/绝对路径)

  • __dirname:当前执行脚本所在的目录路径(目录的绝对路径)

console.log(global); console.log(__filename); console.log(__dirname);

2、常用内置模块

更多内置模块及常用内置模块的更多API用法,可以参考:首页 | Node.js v20.3.1 文档

2.1、os模块

os(operation system)模块提供了与操作系统相关的实用方法和属性。

const os = require('os') // 换行符 os.EOL //根据操作系统生成对应的换行符 window \r\n,linux下面 \n

// cpu相关信息 os.cpus()

// 总内存大小 (单位 字节) os.totalmem()

// 空余内存大小 (单位 字节) os.freemem()

// 主机名 os.hostname()

// 系统类型 os.type()

2.2、path模块

path模块用于处理文件和目录(文件夹)的路径。

const path = require('path') // 获取路径最后一部内容,一般用它来获取文件名称

path.basename('c:/a/b/c/d.html') // d.html // 获取目录名,路径最后分隔符部分被忽略

path.dirname('c:/a/b/c/d.html') // c:/a/b/c // 获取路径中文件扩展名(后缀)

path.extname('c:/a/b/c/d.html') // .html // 给定的路径连接在一起

path.join('/a', 'b', 'c') // /a/b/c // resolve:模拟cd(切换目录)操作同时拼接路径

2.3、url模块

URL字符串是结构化的字符串,包含多个含义不同的组成部分。 解析字符串后返回的 URL 对象,每个属性对应字符串的各个组成部分。

const url = require('url');

const href = 'http://www.xxx.com:8080/pathname?id=100#bbb' // 解析网址,返回Url对象 // 参2 如果为true 则 query获取得到的为对象形式

url.parse(href,true) //以一种 Web 浏览器解析超链接的方式把一个目标 URL 解析成相对于一个基础 URL。

2.4、querystring模块

用于解析和格式化 URL 查询字符串(URL地址的get形式传参)的实用工具。

const querystring = require('querystring') // query字符串转为对象

querystring.parse('foo=bar&abc=xyz')

querystring.decode('foo=bar&abc=xyz') // 对象转为query字符串

querystring.stringify({ foo: 'bar',abc: 'xyz'})

querystring.encode({ foo: 'bar',abc: 'xyz'})

2.5、fs模块

fs(file system)模块提供了用于与文件进行交互相关方法。

注意:fs模块提供了2大类api方法

  • 同步操作

  • 异步操作

const fs = require('fs') // 写入数据(覆盖),追加写使用fs.appendFile

fs.writeFile(文件路径,待写入的数据,err => {}) // 读取文件中数据

fs.readFile(文件路径, 'utf8’,(err,data) => {}) // (同步)检查文件是否存在 返回true/false // async:异步 // sync:同步

let ret = fs.existsSync(path) // 获取文件信息(异步)

fs.stat(文件,(err,stats) => {

stats.isDirectory() // 是否是目录

stats.isFile() // 是否为文件

stats.size // 文件大小(以字节为单位)

})

// 删除文件(异步)

fs.unlink(文件路径,err => {})

// 友情提醒:fs模块有点小坑 // 关于相对路径,在fs模块中,读写文件都会使用文件的路径,如果是相对路径则相对路径相对于谁? // 答案:不会是相对于当前的js文件,而是相对于node命令执行的位置(即命令行的工作路径)。以后再用fs的时候建议文件的路径采用__dirname与文件名做拼接的方式来写文件名。

2.6、http模块

需要了解web服务器的相关内容。

2.6.1、创建web服务器

NodeJs是通过官方提供的http模块来创建 web服务器的模块。通过几行简单的代码,就能轻松的手写一个web服务,从而对外提供 web 服务。

// 导入http模块

const http = require('http')

// 创建web服务对象实例

const server = http.createServer()

// 绑定监听客户端请求事件request

server.on('request', (request, response) => {})

// request: 接受客户端请求对象,它包含了与客户端相关的数据和属性

request.url 客户端请求的uri地址

request.method 客户端请求的方式 get或post

request.headers 客户端请求头信息(对象)

// response:服务器对客户端的响应对象

设置响应头信息 ,用于响应时有中文时乱码解决处理

response.setHeader('content-type', 'text/html;charset=utf-8')

设置状态码

response.statusCode = 200

向客户端发送响应数据,并结束本次请求的处理过程

response.end('hello world')

// 启动服务

server.listen(8080, () => { console.log('服务已启动') })

案例:手写一个服务器软件,启动后要求用户访问根“/”输出hello world,用户访问/html5输出2021。

// 1. 导入http模块 const http = require("http"); // 2. 创建web服务实例 const server = http.createServer(); // 3. 监听request请求 server.on("request", (req, res) => { // 输出hello world // res.end("hello world"); if (req.url === "/") { res.end("hello world"); } if (req.url === "/html5") { res.end("2021"); } }); // 4. 启动服务 server.listen(8080, () => { // 仅是提示作用,可以不写,但是建议写 console.log("server is running at http://127.0.0.1:8080"); });

2.6.2、静态资源服务器

静态资源:常见的有html、css、js、图片、音频、视频等。特征:其展示的效果要想变化必须要更改文件的内容。

静态资源服务器:专门保存上述静态资源的服务器,称之为静态资源服务器。

  • 实现思路

客户端请求的每个资源uri地址,作为在本机服务器指定目录中的文件。通过相关模块进行读取文件中数据进行响应给客户端,从而实现静态服务器。

2.6.3、get数据获取

get数据通过地址栏使用query方式进行传递的数据 例?id=1&name=zhangsan

// 导入

const http = require('http');

const url = require('url');

// 创建实例&监听request事件&监听端口

http.createServer((req, res) => {

// 之前第3步中的回调函数 // 获取地址栏中 query数据

let { query } = url.parse(req.url, true);

console.log(query);

}).listen(8080)

2.6.4、post数据获取

表单数据多数为post进行提交到服务器端。需要监听req对象的data事件来获取客户端发送到服务器的数据。如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后分批次发送给服务器。所以data事件可能会被触发多次,每次触发data事件时,收到的数据只是全部数据的一部分,因此需要做数据的拼接才能得到完整的数据:

const http = require('http');

const queryString = require('querystring');

http.createServer((req, res) => {

let arr = [];

// 数据接受中

req.on('data', buffer => {

arr.push(buffer);

});

// 数据传输结束了

req.on('end', () => {

// 拼接接受到的所有数据

let buffer = Buffer.concat(arr);

let post = queryString.parse(buffer.toString())

console.log(post);

});

}).listen(8080)

二、 Express

网址:Express - 基于 Node.js 平台的 web 应用开发框架 - Express 中文文档 | Express 中文网

1、创建web服务

- 导入需要使用的express包

- 创建web实例

- 定义允许访问的地址(定义路由)【重复性步骤】

- 原先的输出:res.end()

- 现在的输出:res.send()

  • 启动服务(监听端口)

const express = require('express')

// 创建web服务

const app = express()

// 监听 get请求

// req 请求对象

// res 响应对象

app.get('请求URI',(req,res)=>{

// 向客户端响应数据

res.send({id:1,name:'张三'})

})

// 监听POST请求

app.post('请求URI',(req,res)=>{})

// 其他app.形式的api方法,put/delete/use 等

app.put()

app.delete()

// ....

// 启动服务

app.listen(8080,()=>{})

1.1、获取query字符串

获取get传值的参数。

通过 req.query 对象,可以访问到客户端通过查询字符串的形式发送到服务器的参数:

app.get('/',(req,res)=>{

console.log(req.query)

// 获取到的直接就是个对象

})

1.2、动态参数传递

默认情况下,express是不支持使用动态参数的,必须要声明路由后才支持。但是“?”号传参不需要声明。

Express也支持类似于Vue中动态路由的形式传递参数,传递的参数通过 req.params 对象可以访问到:

// 必须的路由参数(不传就匹配不上,返回404错误)

app.get('/:id',(req,res)=>{

console.log(req.params.id)

})

// 可选的路由参数(传递与否都不会报错)

app.get('/:id?',(req,res)=>{

console.log(req.params.id)

})

这个传参方式是符合restful传参规范的。

扩展Restful规范(规范不是标准!!!):

规范1:restful规范是一个接口开发的规范(一般用于后端,但前端也可以使用)

规范2:restful规范规定了多种请求类型来适配不同的操作,常见的如下:

​ GET请求类型:用于获取数据(获取xxx列表、获取xxx详情)

​ POST请求类型:用于数据新增(xxx添加)

​ PUT请求类型:用于数据修改(xxx修改、xxx编辑)

​ DELETE请求类型:用于数据删除(xxx删除)

1.3、静态资源托管

express提供了一个非常好用的方法(内置中间件),叫做 express.static(),通过此方法,可以非常方便地创建一个静态web资源服务器:

app.use(express.static('public'))

// app.use()表示使用(中间件),现在可以访问public目录下所有的文件

// 如public/aa.jpg文件,则可以通过 : http://xxxx/images/aa.jpg

express还支持给静态资源文件创建一个虚拟的文件前缀(实际上文件系统中并不存在),可以使用 express.static 函数指定一个虚拟的静态目录,就像下面这样:

app.use('/static', express.static('public'))

现在你可以使用 /static 作为前缀来加载 public 文件夹下的文件了:

http://localhost:3000/static/images/kitten.jpg

http://localhost:3000/static/css/style.css

http://localhost:3000/static/js/app.js

http://localhost:3000/static/hello.html

前缀前面的“/”必须要加,否则【404】

使用app.use()方法一般写在具体的路由监听之前。

前缀的使用意义:

  • 可以迷惑别人,一定程度上阻止别人猜测我们服务器的目录结构

  • 可以帮助我们更好的组织和管理静态资源

2、路由&&模块化

express为了路由的模块化管理功能,通过express.Router()方法创建路由模块化处理程序,可以将不同业务需求分开到不同的模块中,从而便于代码的维护和项目扩展。

路由模块化处理可以分为以下步骤来完成

a. 创建路由的主文件src/index.js

const express = require("express"); const app = express(); 
// 导入路由模块 
const usersRouter = require("./router/users.js"); 
const goodsRouter = require("./router/goods.js"); 
// 使用路由路由 
// app.use(usersRouter); 
// app.use(goodsRouter); 
// 路由也支持类似于静态资源托管的操作,设置特定的前缀 
// 将公共的"/admin"提取出来 
// 路由前缀:app.use(前缀,路由模块) 
app.use("/admin", usersRouter); 
app.use("/admin", goodsRouter); 
app.listen(3000, () => { console.log("server is running at http://127.0.0.1:3000"); });

b. 创建users模块路由文件src/router/users.js

// 获取router对象 
const express = require("express"); 
const router = express.Router(); 
// 编写路由规则 
// 用户列表 
// 路由地址的第一个斜杠是不能去除的 r
outer.get("/users", (req, res) => { res.send("你访问的是用户列表"); }); 
// 用户详情 
// 路由地址的第一个斜杠是不能去除的 
router.get("/users/:uid", (req, res) => { res.send("你访问的是用户详情,传递的id是" + req.params.uid); }); 
// 导出 
module.exports = router;

c. 创建goods模块的路由文件src/router/goods.js

const express = require("express"); const router = express.Router(); 
// 商品添加 
router.post("/goods", (req, res) => { res.send("你访问的是商品添加"); }); 
// 商品修改 
router.put("/goods/:gid", (req, res) => { res.send("你访问的是商品修改,传递的id是" + req.params.gid); }); 
// 商品删除 
router.delete("/goods/:gid", (req, res) => { res.send("你访问的是商品删除,传递的id是" + req.params.gid); }); 
// 导出 
module.exports = router;

2、中间件

2.1、内置中间件

2.1.1 express.static :

参考1、3

app.use('前缀',express.static('托管目录地址'))

2.1.2 express.json:

接收json格式提交的数据,其在接收完数据后,会将数据的对象形式挂载到req请求对象的body属性上

app.post("/", express.json(),(req, res) => { console.log(req.body); })

2.1.3 express.static:

处理post表单数据,其在接收完数据后,会将数据的对象形式挂载到req请求对象的body属性上

// 局部中间件,处理表单提交的数据

app.post("/post", express.urlencoded({ extended: false }), (req, res) => {

// 输出得到的请求体

console.log(req.body);

});

注意:关于urlencoded中间件中的配置项extended值的说明

  • 值默认为true,但是不建议使用默认的true

  • 值true与false的区别

    • false:使用querystring库去解析post数据

      • 去除获取到的数据对象的内置方法

      • 接收到的数据只有字符串与数组的形式

    • true:使用qs库去解析post数据

      • 使得获取到的数据对象更加面向对象化

2.2、自定义中间件
2.3、第三方中间件
2.4、错误类型中间件

三、sequelize

官网:Sequelize 简介 | Sequelize中文文档 | Sequelize中文网

Sequelize是一个基于 Node.js 的 ORM,用于在 JavaScript 中对 SQL 数据库进行一些操作。以下将简要介绍一些主要的函数和相应的用法。

1. 创建模型

使用Sequelize.define('name', attributes, options) 可以定义一个模型。

例如:

const { STRING, INTEGER, BOOLEAN, JSON, DATE } = sequelize

const User = sequelize.define('user', {

username: {

type: STRING,

field: 'user_name',

},

birthday: DATE

},

{

tableName: 'base_api',

timestamps: true,

timezone: '+08:00',

primaryKey: 'username'

}

);

以上代码即定义了一个名为‘user’的模型,并设置了username和birthday两个字段属性。

第二个参数是一个选项对象,用于指定模型的一些配置。其中:

  • tableName:指定模型对应的数据库表名。在这个例子中,模型对应的表名是 base_api。

  • timestamps:指定是否在模型中自动添加 createdAt 和 updatedAt 字段。如果设置为 true,Sequelize 会自动在每条记录中添加这两个字段,用于记录创建时间和更新时间。

  • timezone:指定时区。如果你的数据库使用的是 UTC 时间,可以使用这个选项来指定时区。

  • primaryKey: 指定主键

2. 同步数据库

可以使用 .sync() 方法来同步我们定义的模型到数据库中。

sequelize.sync().then(() => {});

这会创建一个与我们模型相匹配的表。如果已经存在,则不会重新创建。

也可以使用 sync({ force: true }) 来强制创建表。

sequelize.sync({force: true}).then(() => {});

这会删除先前存在的用户表,并新建一个空的用户表。

3. 插入数据

使用.create()方法:

User.create({username: 'John', birthday: new Date()})

.then(user => {})

.catch(err => {});

4. 查找数据

可以用.findAll() .findOne() 查找数据:

User.findAll({where: {username: 'John'}})

.then(users => {})

.catch(err => {});

5. 主键搜索

可以用.findById() .findByPk() 查找数据:

User.findByPk(1)

.then(user => {})

.catch(err => {});

这个示例会查询主键为 1 的用户记录,并输出它的名字。如果没有查询到记录,则输出一个错误信息。

5.1 主键

主键(Primary Key)是数据库表中用于唯一标识每一条记录的字段或字段组合。主键的作用是保证每一条记录都有一个唯一的标识,方便对记录进行操作和管理。

在关系型数据库中,每个表都必须有一个主键。主键可以由一个或多个字段组成,但是必须满足以下条件:

- 主键的值必须唯一,不能重复。

- 主键的值不能为空,不能为 NULL。

- 主键的值不能被修改,一旦确定就不能更改。

通常情况下,主键是由数据库自动生成的,比如自增长的整数或全局唯一的字符串。

在 Sequelize 中,每个模型都必须有一个主键。如果你没有指定主键,Sequelize 会自动为你创建一个名为 `id` 的整数类型主键。如果你需要指定其他的主键,可以在模型定义中使用 `primaryKey` 属性来指定。例如:

const User = sequelize.define('user', {

username: DataTypes.STRING,

email: DataTypes.STRING

}, {

primaryKey: 'email'

});

这个示例中,我们将 `email` 字段指定为主键。这样,每个用户记录都会有一个唯一的邮箱地址作为主键。

6. 更新数据

6.1、可以用.update()方法:

User.update({username: 'Jack'}, {where: {username: 'John'}})

.then(result => {})

.catch(err => {});

以上代码即把名字为 "John" 的用户修改为名字为 "Jack"。

6.2、可以用.bulkUpdate()方法:

User.bulkUpdate({username: 'Jack'}, {where: {username: ['John', 'Tom']}})

.then(result => {})

.catch(err => {});

以上代码即把名字为 "John" 和 "Tom"的用户修改为名字为 "Jack"。

7. 删除数据

7.1、可以用.destroy()方法:

User.destroy({where: {username: 'John'}})

.then(result => {})

.catch(err => {});

以上代码即删除名字为 "John" 的记录。

7.2、可以用.bulkDestroy()方法:

User.destroy({where: {username: ['John', 'Tom']}})

.then(result => {})

.catch(err => {});

以上代码即删除名字为 "John"和 'Tom' 的记录。

8.统计记录数

可以用.count()

const count = await User.count({

where: {

age: {

[Op.gte]: 18

}

}

})

where 属性用于指定查询条件,[Op.gte] 表示大于等于的运算符,即年龄大于等于 18 岁。执行 count 方法后,将返回符合条件的记录数

9.插入或更新

使用 upsert()

const [user, created] = await User.upsert({

name: '张三',

age: 20

}, {

where: {

name: '张三'

}

})

console.log(user) // 输出插入或更新的记录

console.log(created) // 输出是否插入了新记录const [user, created] = await User.upsert({

name: '张三',

age: 20

}, {

where: {

name: '张三'

}

})

where 属性用于指定查询条件,如果数据库中已经存在 name 为 '张三' 的记录,则更新该记录的 age 字段为 20,否则插入一条新记录。

执行 upsert 方法后,将返回插入或更新的记录和一个布尔值,表示是否插入了新记录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值