Node.js教程-express框架
概述
Express
是基于Node.js
平台(建立在Node.js
内置的http模块上),快速、开放、极简的Web开发框架。
中文官网 http://www.expressjs.com.cn/。
Github地址:https://github.com/orgs/expressjs。
Express
核心特性:
- 可设置中间件来响应 HTTP 请求
- 定义了路由表用于执行不同的 HTTP 请求
- 可通过向模板传递参数来动态渲染 HTML 页面
安装
npm i express
以上命令会将express
安装在当前目录下的node_modules文件夹下,并且将其依赖的包也一并下载下来
以下几个和express
搭配使用的包:
- body-parser 用于处理 JSON、Raw、Text和URL中的请求数据
- cookie-parser 用于处理Cookie
- multer 用于处理**enctyoe=“multipart/form-data””**的表单数据
基本使用
基本使用步骤:
- 导入 express 模块
- 创建 express 实例
- 创建并启动HTTP服务
- 绑定请求事件
// 1. 导入 express 包
const express = require('express')// 2. 创建 express 实例
const app = express()// 3. 启动服务
app.listen(80, () => {console.log("Express server is starting ...")
})// 4. 绑定请求事件
app.get("/", (req, res) => {console.log("请求进来了 >>> " + req.url)res.end("Hello Node.js")
})
set 方法
set
方法用于指定变量的值
// 设置 端口
app.set("port", process.env.PORT)// 设定views变量,意为视图存放的目录
app.set('views', path.join(__dirname, 'views'));// 设定view engine变量,意为网页模板引擎
app.set('view engine', 'jade');
请求和响应
Express
处理请求中回调函数的参数:request和response对象来处理请求和响应。
request 对象
request
对象表示 HTTP请求,包含了请求查询的字符串,参数、内容、HTTP头部等属性。常见属性:
- request.app 当callback为外部文件时,用其访问express实例
- request.baseUrl 获取当前的 URL 路径
- request.method 获取请求方法
- request.body 获取请求体内容
- request.cookie 获取 Cookie 内容
- request.hostname 获取主机名
- request.ip 获取IP
- request.originalUrl 获取原始请求 URL
- request.params 获取请求参数(动态匹配的参数)
- request.path 获取请求路径
- request.protocol 获取请求协议
- request.query 获取URL的查询参数
- request.route 获取请求匹配的路由
- request.get() 获取指定的请求头
- request.is() 判断请求头Content-Type的MIME类型
// http://domain:port/x1/x2/wz?age=18
request.path // /x1/x2/wz
request.params // wz
request.query // age
// 引入express 模块
const express = require('express')// 创建 实例
const app = express()// 启动服务
app.listen(80, () => {console.log("Server is starting ...")
})// 绑定 get 请求事件
app.get('/user', (req, res) => {// req.protocol 获取请求协议console.log("protocol >>> ", req.protocol)// req.method 获取请求方法console.log("method >>> ", req.method)// req.hostname 获取主机名console.log("hostname >>> ", req.hostname)// req.ip 获取请求 IPconsole.log("ip >>> ", req.ip)// req.originalUrl 获取请求原始路径console.log("originalUrl >>> ", req.originalUrl)// req.path 获取请求路径console.log("path >>> ", req.path)// req.route 获取请求路由console.log("route >>> ", req.route)// req.params 获取请求参数console.log("params >>> ", req.params)// req.query 获取请求查询参数console.log("query >>> ", req.query)// req.body 获取请求体console.log("body >>> ", req.body)res.end("GET")
})// 绑定 post 请求事件
app.post('/user', (req, res) => {// req.protocol 获取请求协议console.log("protocol >>> ", req.protocol)// req.method 获取请求方法console.log("method >>> ", req.method)// req.hostname 获取主机名console.log("hostname >>> ", req.hostname)// req.ip 获取请求 IPconsole.log("ip >>> ", req.ip)// req.originalUrl 获取请求原始路径console.log("originalUrl >>> ", req.originalUrl)// req.path 获取请求路径console.log("path >>> ", req.path)// req.route 获取请求路由console.log("route >>> ", req.route)// req.params 获取请求参数console.log("params >>> ", req.params)// req.query 获取请求查询参数console.log("query >>> ", req.query)// req.body 获取请求体console.log("body >>> ", req.body)res.end("POST")
})
response 对象
response
对象表示 HTTP响应,即在接受到请求时向客户端发送的数据。常见属性:
- response.app 当callback为外部文件时,用其访问express实例
- response.cookie(name, value[, options]) 设置Cookie信息
- response.clearCookie() 清空Cookie
- response.download() 传送指定的文件
- response.get() 获取指定的HTTP头信息
- response.set(name, value) 设置响应头(Header)
- response.json() 响应JSON格式的数据
- response.render(view[, locals], callback) 渲染网页模版
- response.send() 发送响应
- response.sendFile(path[, options][, fn]) 传送文件
- response.status() 设置 HTTP 状态码
- response.type() 设置 Content-Type的 MIME类型
- response.redirect() 设置重定向
路由
路由
即路径映射。在Express
中,路由指客户端的请求与服务器处理函数的映射。
Express
中路由是一个单独的组件Express.Router
。
Express
中路由由三部分组成,分别为请求类型、请求URL、处理函数。其格式如下:
app.method(path, handler())
路由匹配过程
- 请求到达服务器时,先经过路由的匹配,匹配成功了,才会调用对应的处理函数
- 在匹配时,按照定义的顺序依次匹配,仅当请求类型和请求URL同时匹配成功了,才会调用对应的处理函数
// 导入 express 模块
const express = require('express')// 创建 express 实例
const app = express()// 创建路由实例
const router = express.Router()// 挂载路由
router.get('/user', (req, res) => {res.send("express router")
})// 注册路由
app.use('/api', router)// 启动服务
app.listen(80, () => {console.log("Server is starting ...")
})// 访问路径 http://domain:port/api/user
中间件
中间件(Middleware
)指业务流程的中间处理环节。其是一个函数,包含了request、respoonse、next三个参数,其中 next() 把流转交给下一个中间件或路由。
Express
中间件调用流程
注意:
- 在注册路由之前注册中间件(错误中间件除外)
- 多个中间件共享request和response对象
- next() 函数后不能再写逻辑代码
全局中间件
通过app.use()
注册的中间件为全局中间件
const express = require('express')const app = express()// 注册全局中间件
app.use((req, res, next) => {console.log("中间件A")
})// 注册全局中间件
app.use((req, res, next) => {console.log("中间件B")
})app.get('/user', (req, res) => {res.send("ok")
})app.listen(8888)
局部中间件
const express = require('express')const app = express()// 定义中间件
const mw1 = (req, res, next) => {console.log("中间件A")
}// 注册全局中间件
const mw2 = (req, res, next) => {console.log("中间件B")
}app.get('/user', mw1, mw2, (req, res) => {res.send("ok")
})app.post('/user', [mw1, mw2], (req, res) => {res.send("ok")
})app.listen(8888)
中间件分类
中间件按照作用可划分为三类:应用级别中间件、路由级别中间件、错误级别中间件。
应用级别中间件
通过app.use()
或app.method()
注册,即绑定到app实例上的中间件即为应用级别中间件。(其中method为get
、post
、put
、delete
等请求方法)
const express = require('express')const app = express()// 注册路由
app.use('/', (req, res, next) => {next()
})
路由级别中间件
通过router.use()
注册,即绑定到router实例上的中间件即为路由级别中间件。
const express = require('express')const app = express()
const router = express.Router()// 路由上注册中间件
router.use((req, res, next) => {next()
})// 注册路由
app.use('/', router)
错误级别中间件
错误级别中间件用来捕获整个项目中发生的异常,从而防止项目异常崩溃。
错误级别中间件的处理函数中必须有4个形参,即(error, request, response, next)
错误级别中间件必须注册在所有路由之后
const express = require('express')const app = express()// 请求处理 ...// 注册错误中间件
app.use((err, req, res, next) => {next()
})
内置中间件
Express
中内置了多个中间件,极大的提高了 Express 项目的开发效率。常见内置中间件:
-
express.static 快速托管静态资源
express.static(root[, options])
-
express.json 解析JSON格式的请求体数据
-
express.urlencoded 解析 url-encoded 格式的请求体数据
// 快速托管静态资源
app.use(express.static(path))// 通过 express.json() 这个中间件,解析表单中的 JSON 格式的数据
app.use(express.json())// 通过 express.urlencoded() 这个中间件,来解析表单中的 url-encoded 格式的数据
app.use(express.urlencoded({ extended: false }))
第三方中间件
cookie-parser
cookie-parser
用于处理请求中的Cookie。
https://github.com/expressjs/cookie-parser
设置Cookie
res.cookie(name, value[, options])
参数说明
- name cookie名称
- value cookie值
- options 配置参数
- domain 域名。默认为当前域名
- expires 失效时间。未设置或0,表示浏览器关闭后即失效
- maxAge 最大失效时间(指从当前时间开始多久后失效),单位毫秒
- secure 为 true时,cookie 在 http 失效,https 生效
- path cookie在什么路径下有效。默认为**/**
- httpOnly 只能被访问,防止 XSS攻击
- signed 是否签名。默认指为false
不签名实例
const express = require('express')
const cookieParser = require('cookie-parser')// 创建 app 实例
const app = express()// 注册 Cookie中间件
app.use(cookieParse())app.get('/setCookie', (req, res) => {res.cookie('name', '张三', {maxAge: 10000})res.send('cookie set success!')
})app.listen(8888)
签名实例
const express = require('express')
const cookieParser = require('cookie-parser')const app = express()app.use(cookieParser('^123$')) // ^123$ 为签名秘钥app.get('setCookie', (req, res) => {// 将cookie的name 进行签名res.cookie("name", "张三", {maxAge: 100000, signed: true})
})
获取Cookie
注意:
Cookie签名与不签名获取的方式不一样。req.cookies
获取不签名的cookie;req.signedCookies
获取签名的cookie。
不签名实例
const express = require('express')
const cookieParser = require('cookie-parser')// 创建 app 实例
const app = express()// 注册 Cookie中间件
app.use(cookieParser()) //app.get('/getCookie', (req, res) => {console.log(req.cookies)res.send("cookie got")
})app.listen(8888)
签名实例
const express = require('express')
const cookieParser = require('cookie-parser')// 创建 app 实例
const app = express()// 注册 Cookie中间件
app.use(cookieParser('^123$')) // ^123$ 为签名秘钥app.get('/getCookie', (req, res) => {console.log(req.signedCookies)res.send("cookie got")
})app.listen(8888)
删除Cookie
res.clearCookie(name[, options])
express-session
express-session
用于处理请求中的会话。
https://github.com/expressjs/session
配置 session
session(options)
参数说明:
- options 配置参数
- cookie cookie设置
- genid sessionid算法。默认为uid-safe库自动生成id
- name 会话名称。默认为 connect.sid
- secret 会话签名秘钥
- store 会话存储方式。默认为内存
- resave 是否强制保存会话,及时未被修改也被保存。默认为true
- saveUninitialized 强制将未初始化的会话保存至存储中。(会话是新的且未被修改即为未初始化)
- unset 是否保存会话。默认为keep,不保存可设置为destory
const express = require('express')
const session = require('express-session')const app = express()app.use(session({name: "session-cookie",secret: "^123456$", // 会话签名秘钥cookie: {maxAge: 2 * 60 * 60 * 1000}
}))
req.session
req.session
可用于存储或访问会话数据,以JSON的形式序列化。
const express = require('express')
const session = require('express-session')// 创建服务实例
const app = express()// 配置session,并注册session中间件
app.use(session({name: "express",secret: "^123456$",resave: false,saveUninitialized: true
}))app.get('/setSession', (req, res) => {// 存储会话req.session.name = "李四"res.send("set session success")
})app.get('/getSession', (req, res) => {// 获取会话console.log(req.session)res.send("session got")
})// 启动服务
app.listen(8888)
属性
属性 | 说明 |
---|---|
req.session.id | 会话ID |
req.session.sessionID | 会话ID |
req.session.cookie | 获取会话中的 cookie 对象, 而后可对其修改 |
req.session.cookie.maxAge | 会话有效剩余时长 |
req.session.cookie.originalMaxAge | 返回会话 cookie 的原始 maxAge, 以毫秒为单位 |
方法
方法 | 说明 |
---|---|
req.session.regenerate(callback) | 重新生成会话 |
req.session.destroy(callback) | 销毁会话并取消设置 req.session 属性 |
req.session.reload(callback) | 从存储重新加载会话数据并重新填充 req.session 对象 |
req.session.save(callback) | 讲会话保存至 store,用内存中的内容替换 store上的内容 |
req.session.touch() | 更新 .maxAge属性 |
JWT
JWT
(JSON Web Token)是由三部分组成:Header、Payload(真正的用户信息,加密后的字符串)、Signature。
JWT
工作原理:用户的信息以Token的字符串的形式,保存在客户端中。用户每次请求,将Token存放在请求头Authorization上,服务器拿到该值后进行解析处理。
Express
中jsonwebtoken
模块用于生成JWT字符串,express-jwt
用于将JWT字符串还原成JSON对象。
使用
- 安装模块
npm install jsonwebtoken express-jwt
- 引入模块
const jwt = requre('jsonwebtoken') const expressJWT = require('express-jwt')
- 生成 JWT 字符串
jwt.sign(payload, secret[, options[, callback]])
payload 存储的对象
secret 签名秘钥
options 配置参数。常见有 expiresIn(过期时间)、algorithm(签名算法)
callback 回调函数app.post('/api/login', (req, res) => {let token = jwt.sign({username: username}, '^123456$', {expireIn: '2h'}) })
- 还原 JWT 字符串
// 此处的 secret 值必须和jwt 生成时所使用的秘钥相同 // unless 指定了哪些接口无须携带Token访问 app.use(expressJWT({secret: '^123456$'}).unless({path:[/^\/api\//]}))
- 获取 JWT 信息
在访问权限的接口中,可通过req.user对象即可访问 JWT 字符串中解析的内容
- 捕获 JWT 异常
// 通过异常中间件来处理JWT解析失败 app.use((err, req, res, next) => {if(err.name === 'UnauthorizedError') {// TODO}next() })
multer
multer
是用于处理multipart/form-data
类型的表单数据,主要用于上传文件。(不会处理任何非 multipart/form-data 的数据
)
multer
在解析完请求体后,会向request对象上添加一个body对象和一个file或files对象。body对应表单中提交的文本字段,file或files包含了表单上传的文件。
https://github.com/expressjs/multer
multer(options)
参数说明:
- options 参数配置
- dest / storage 上传文件存放目录。
- fileFilter 文件过滤器
- limits 限制上传文件 (可有效防止Dos攻击)
- fieldNameSize field名字最大长度。默认为 100 bytes
- fieldSize field指最大长度。默认为1MB
- fields 非文件field的最大数量。默认为无限
- fileSize 文件最大长度,单位字节。默认为无限
- files 文件最大数量。默认为无限
- parts part传输的最大数量(field + file)。默认为无限
- headerPairs 键值对最大组数。默认为2000
- preservePath 保存包含文件名的完整路径
storage
storage
为存储引擎,multer
中具有DiskStorage、MemoryStorage和第三方等引擎。
DiskStorage
DiskStorage
为磁盘存储引擎,其有两个选项可用:destination和filename。
destination 用来确定上传的文件存放的位置。可提供一个 string或function。若没有设置则使用操作系统默认的临时文件夹。
注意:
若destination 是一个function,则需用手动创建文件夹;若destination 是一个string,multer 会自动创建。
filename用来确定文件夹中文件名。若未设置该参数,则文件将设置一个随机文件名且没有后缀名。
const storage = multer.DiskStorage({distination: function(req, file, cb) {cb(null, '/xxx/xxx')}filename: function(req, file, cb) {cb(null, file.fieldname + "_" + Date.now())}
})const upload = multer({storage: storage})
MemoryStorage
MemoryStorage
为内层存储引擎(将内容存储在Buffer中)
const storage = multer.memoryStorage()
const upload = multer({storage: storage})
注意:
当使用内层存储,上传文件非常大,或上传文件非常多时,可能会导致内层溢出。
方法
multer.single(fieldname)
multer.signle()
接受一个以filename命名的文件,文件保存至request.file中
multer.array(fieldname[, maxCount])
multer.array()
接受一个以fieldname命名的文件数组,可配置maxCount来限制上传文件数量,文件保存至request.files中
multer.fields(fields)
multer.fields()
接受fileds的混合文件,文件保存至request.files中
multer.none()
multer.none()
只接受文本域,和multer.fields([])
效果一样。若该模式有文件上传,则抛出LIMIT_UNEXPECTED_FILE
multer.any()
multer.any()
接受一切上传的文件。文件保存至request.files中
const multer = require('multer')// 存储设置
const storage = multer.DiskStorage({distination: function(req, file, cp) {cp(null, '/xxx/xx')}filename: function(req, file, cp)
})const upload = multer({storage:storage})app.post('/upload/photo', upload.single('avatar'), function (req, res) {// req.file 是 `avatar` 文件的信息// req.body 将具有文本域数据,如果存在的话
})app.post('/upload/file', upload.array('file', 3), function (req, res) {// req.files 是 `file` 文件组的信息// req.body 将具有文本域数据,如果存在的话
})app.post('/upload', upload.fields([{name: 'avatar', maxCount: 1},{name: 'file', maxCount: 3}]), function (req, res) {// req.files 是一个对象 (String -> Array) 键是文件名,值是文件数组// req.files['avatar'][0] -> File// req.files['file'] -> Array// req.body 将具有文本域数据,如果存在的话
})
文件属性
属性 | 说明 |
---|---|
fieldname | 表单定义的名称 |
originalname | 文件原始名称 |
encoding | 文件编码 |
mimetype | 文件的 MIME 类型 |
size | 文件大小 |
distination | 文件保存路径 |
filename | 保存至 distination 中的文件名 |
path | 已上传文件的完整路径 |
buffer | 存放整个文件的 Buffer |
自定义中间件
自定义中间件流程:
- 定义中间件
- 监听request对象的 data 事件
- 监听 request 对象的 end 事件
- 解析请求参数
- 封装模块
自定义中间件解析POST提交的数据
// querything 是 Node.js的内置模块
const qs = require('querything')// 定义中间件
const bodyParser = (req, res, next) => {let str = ''// 监听 req 的 data 事件req.on('data', (chunk) => {str += chunk})req.on('end', () => {// 解析数据,并将数据放在 req 的 body 中,供下游访问req.body = qs.parse(str)next()})
}module.exports = bodyParser
模板
Express
模板是用于渲染视图的文件,可以包含HTML、CSS、JavaScript等内容,用于构建 Web应用程序的图形界面。
使用Express
模板可以快速、方便地创建Web应用程序,并可轻松地将动态数据注入到模板中,以便呈现动态效果。常见的模版引擎有:EJS、Pug、Handlebars 等。
分类
Express
模板可分静态模板和动态模板两类:
- 静态模板 预先定义好的 HTML 文件,可通过路由直接呈现
- 动态模板 通过模版引擎加载动态数据来生成动态内容
Express
中常用的模板引擎:
- 基于
HTML
的模版引擎:Mustache、Handlebars - 基于
JavaScript
的模版引擎:EJS、Underscore.js - 基于
CSS
的模版引擎:LESS、SASS
使用
模版使用步骤
- 下载模板包
- 配置模版引擎
app.set("view engine", "xxx")
- 配置模板路径
app.set("views", path.resolve(__dirname, "views"))
(表示模板存放在当前目录下views文件夹中) - 在请求响应中设置渲染
res.render('xx',renderDataObj)
express-generator
express-generator
是 快速创建 express 项目生成器工具。
使用
## 1. 全局安装 express-generator
npm i -g express-generator## 2. 创建项目
#### 快速创建 [project_name[ 的项目,并且使用默认的 jade 模板引擎
express [project_name] #### 快速创建 [project_name[ 的项目,并且使用指定的 ejs 模板引擎
express [project_name] --view=ejs## 3.进入到项目根目录下执行 npm install
npm install## 4. 启动项目
#### npm 命令
npm run start 或 npm start#### node 命令
node ./bin/www## 5.访问 express-generator生成的项目服务默认端口为 3000
项目结构
相关文章:

Node.js教程-express框架
概述 Express是基于Node.js平台(建立在Node.js内置的http模块上),快速、开放、极简的Web开发框架。 中文官网 http://www.expressjs.com.cn/。 Github地址:https://github.com/orgs/expressjs。 Express核心特性: 可设置中间件来响应 HTTP…...

location.origin兼容
if (!window.location.origin) {window.location.origin window.location.protocol "//" window.location.hostname (window.location.port ? : window.location.port: );}...

spring boot集成mybatis和springsecurity实现权限控制功能
上一篇已经实现了登录认证功能,这一篇继续实现权限控制功能,文中代码只贴出来和上一篇不一样的修改的地方,完整代码可结合上一篇一起整理spring boot集成mybatis和springsecurity实现登录认证功能-CSDN博客 数据库建表 权限控制的意思就是根…...

按键修饰符
在键盘监听事件时,我们经常需要判断详细的按键,此时,可以为键盘相关的事件添加按键修饰符,例如: 键盘修饰符案例:...

新版IDEA中Git的使用(一)
说明:本文介绍如何在新版IDEA中使用Git 创建项目 首先,在GitLab里面创建一个项目(git_demo),克隆到桌面上。 然后在IDEA中创建一个项目,项目路径放在这个Git文件夹里面。 Git界面 当前分支&Commit …...

【性能测试】真实企业,性能测试流程总结分析(一)
目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 性能测试什么时候…...

20231224解决outcommit_id.xml1 parser error Document is empty的问题
20231224解决outcommit_id.xml1 parser error Document is empty的问题 2023/12/24 18:13 在开发RK3399的Android10的时候,出现:rootrootrootroot-X99-Turbo:~/3TB/Rockchip_Android10.0_SDK_Release$ make installclean PLATFORM_VERSION_CODENAMEREL…...

电子电器架构刷写方案——General Flash Bootloader
电子电器架构刷写方案——General Flash Bootloader 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 注:文章1万字左右,深度思考者入!!! 老规矩,分享一段喜欢的文字,避免…...

【Linux】僵尸与孤儿 进程等待
目录 一,僵尸进程 1,僵尸进程 2,僵尸进程的危害 二,孤儿进程 1,孤儿进程 三,进程等待 1,进程等待的必要性 2,wait 方法 3,waitpid 方法 4,回收小结…...

Java小案例-Sentinel的实现原理
前言 Sentinel是阿里开源的一款面向分布式、多语言异构化服务架构的流量治理组件。 主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 核心概念 要想理解一个新的技…...

【Leetcode Sheet】Weekly Practice 21
Leetcode Test 1901 寻找峰值Ⅱ(12.19) 一个 2D 网格中的 峰值 是指那些 严格大于 其相邻格子(上、下、左、右)的元素。 给你一个 从 0 开始编号 的 m x n 矩阵 mat ,其中任意两个相邻格子的值都 不相同 。找出 任意一个 峰值 mat[i][j] 并 返回其位置 [i,j] 。 …...

C语言使用qsort和bsearch实现二分查找
引言 在计算机科学领域,查找是一项基本操作,而二分查找是一种高效的查找算法。本博客将详细解释一个简单的C语言程序,演示如何使用标准库函数qsort和bsearch来对一个整数数组进行排序和二分查找。 代码解析 包含头文件 #include <stdi…...

MySQL的替换函数及补全函数的使用
前提: mysql的版本是8.0以下的。不支持树形结构递归查询的。但是,又想实现树形结构的一种思路 提示:如果使用的是MySQL8.0及其以上的,想要实现树形结构,请参考:MySQL数据库中,如何实现递归查询…...

2022第十二届PostgreSQL中国技术大会-核心PPT资料下载
一、峰会简介 本次大会以“突破•进化•共赢 —— 安全可靠,共建与机遇”为主题,助力中国数据库基础软件可掌控、可研究、可发展、可生产,并推动数据库生态的繁荣与发展。大会为数据库从业者、数据库相关企业、数据库行业及整个IT产业带来崭…...

2024 年 10大 AI 趋势
2025 年,全球人工智能市场预计将达到惊人的 1906.1 亿美元,年复合增长率高达 36.62%。 人工智能软件正在迅速改变我们的世界,而且这种趋势在未来几年只会加速。 我们分析了未来有望彻底改变 2024 年的 10 个AI趋势。从生成式人工智能的兴起到…...

Uboot
什么是Bootloader? Linux系统要启动就必须需要一个 bootloader程序,也就说芯片上电以后先运行一段bootloader程序。 这段 **bootloader程序会先初始化时钟,看门狗,中断,SDRAM,等外设,然后将 Linux内核从f…...

ECMAScript 的未来:预测 JavaScript 创新的下一个浪潮
以下是简单概括关于JavaScript知识点以及一些目前比较流行的比如:es6 想要系统学习: 大家有关于JavaScript知识点不知道可以去 🎉博客主页:阿猫的故乡 🎉系列专栏:JavaScript专题栏 🎉ajax专栏&…...

代码随想录算法训练营第十三天 | 239. 滑动窗口最大值、347.前 K 个高频元素
239. 滑动窗口最大值 题目链接:239. 滑动窗口最大值 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 文章讲解…...

推荐五个免费的网络安全工具
导读: 在一个完美的世界里,信息安全从业人员有无限的安全预算去做排除故障和修复安全漏洞的工作。但是,正如你将要学到的那样,你不需要无限的预算取得到高质量的产品。这里有SearchSecurity.com网站专家Michael Cobb推荐的五个免费…...

Cross-Drone Transformer Network for Robust Single Object Tracking论文阅读笔记
Cross-Drone Transformer Network for Robust Single Object Tracking论文阅读笔记 Abstract 无人机在各种应用中得到了广泛使用,例如航拍和军事安全,这得益于它们与固定摄像机相比的高机动性和广阔视野。多无人机追踪系统可以通过从不同视角收集互补的…...

【LeetCode刷题笔记】动态规划(二)
647. 回文子串 解题思路: 1. 暴力穷举 , i 遍历 [0, N) , j 遍历 [i+1, N] ,判断每一个子串 s[i, j) 是否是回文串,判断是否是回文串可以采用 对撞指针 的方法。如果是回文串就计数 +1...

(十七)Flask之大型项目目录结构示例【二扣蓝图】
大型项目目录结构: 问题引入: 在上篇文章讲蓝图的时候我给了一个demo项目,其中templates和static都各自只有一个,这就意味着所有app的模板和静态文件都放在了一起,如果项目比较大的话,这就非常乱…...

蓝牙技术在物联网中的应用
随着蓝牙技术的不断演进和发展,蓝牙已经从单一的传统蓝牙技术发展成集传统蓝牙。高速蓝牙和低耗能蓝牙于一体的综合技术,不同的应用标准更是超过40个越来越广的技术领域和越来越多的应用场景,使得目前的蓝牙技术成为包含传感器技术、识别技术…...

宝塔面板Linux服务器CentOS 7数据库mysql5.6升级至5.7版本教程
近段时间很多会员问系统更新较慢,也打算上几个好的系统,但几个系统系统只支持MYSQL5.7版本,服务器一直使用较低的MYSQL5.6版本,为了测试几个最新的系统打算让5.6和5.7并存使用,参考了多个文档感觉这种并存问题会很多。…...

掌握常用Docker命令,轻松管理容器化应用
Docker是一个开源的应用容器引擎,它可以让开发者将应用程序及其依赖打包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器或Windows机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。下面介…...

【数据结构1-2】P5076 普通二叉树(简化版)(c++,multiset做法)
文章目录 一、题目【深基16.例7】普通二叉树(简化版)题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1基本思路: 一、题目 【深基16.例7】普通二叉树(简化版) 题目描述 您需要写一种数据结构,来维…...

Linux系统安装及管理
目录 一、Linux应用程序基础 1.1应用程序与系统命令的关系 1.2典型应用程序的目录结构 1.3常见的软件包装类型 二、RPM软件包管理 1.RPM是什么? 2.RPM命令的格式 2,1查看已安装的软件包格式 2.2查看未安装的软件包 3.RPM安装包从哪里来? 4.挂…...

MySQL学生向笔记以及使用过程问题记录(内含8.0.34安装教程
MySQL 只会写代码 基本码农 要学好数据库,操作系统,数据结构与算法 不错的程序员 离散数学、数字电路、体系结构、编译原理。实战经验, 高级程序员 去IOE:去掉IBM的小型机、Oracle数据库、EMC存储设备,代之以自己在开源…...

obs video-io.c
video_frame_init 讲解 /* messy code alarm video_frame_init 函数用于初始化视频帧。它接受一个指向 struct video_frame 结构体的指针 frame, 视频格式 format,以及宽度 width 和高度 height。该函数根据视频格式的不同,计算出每个视频帧…...

简述 tcp 和 udp的区别?
简述 tcp 和 udp的区别? TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种不同的传输层协议,用于在计算机网络中进行数据传输。以下是它们的主要区别: 区别࿱…...