当前位置: 首页 > news >正文

【Node.JS】koa

文章目录

  • 概述
  • koa和express对比
  • koa下载安装
  • 使用
    • 1.创建koa项目文件目录
    • 2. 创建koa服务
    • 3. 添加路由 koa-router
    • 4. 数据库服务 mongodb
    • 5. 添加请求参数json处理 koa-bodyparser
    • 6. 用户接口举例
    • 7.引入koa一些常用插件
    • 8.用户登录验证 koa-jwt
    • 9.webpack生产打包
  • 来源

概述

Koa 是一个新的 web 框架,由 Express 幕后的原班人马打造, 致力于成为 web 应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石。 通过利用 async 函数,Koa 帮你丢弃回调函数,并有力地增强错误处理。 Koa 并没有捆绑任何中间件, 而是提供了一套优雅的方法,帮助您快速而愉快地编写服务端应用程序。

koa和express对比

  • Koa采用洋葱模型

通常都会说Koa是洋葱模型,这重点在于中间件的设计。但是按照上面的分析,会发现Express也是类似的,不同的是Express中间件机制使用了Callback 实现,这样如果出现异步则可能会使你在执行顺序上感到困惑,因此如果我们想做接口耗时统计、错误处理Koa的这种中间件模式处理起来更方便些。最后一点响应机制也很重要,
Koa不是立即响应,是整个中间件处理完成在最外层进行了响应,而Express则是立即响应。

  • Koa更轻量

koa不提供内置的中间件;
koa不提供路由,而是把路由这个库分离出来了(koa/router)

  • Context对象

koa增加了一个Context的对象,作为这次请求的上下文对象(在koa2中作为中间件的第一个参数传入)。同时Context上也挂载了Request和Response两个对象。Express类似, 这两个对象都提供了大量的便捷方法辅助开发这样的话对于在保存一些公有的参 数的话变得更加合情合理。

  • 异步流程控制

express采用callback来处理异步,koa采用async/await。
async/await使用同步的写法来处理异步,明显好于callback和promise,

  • 中间件模型

express基于connect中间件,线性模型;
koa中间件采用洋葱模型(对于每个中间件,在完成了-些事情后,可以非常优雅的将控制权传递给下一个中间件,并能够等待它完成,当后续的中间件完成处理后,控制权又回到了自己)
在这里插入图片描述
同步代码
同步方法没有什么区别:

  • 01-express-同步.js
const express = require("express")
const app = express()app.use((req, res, next) => {console.log("111111")next()console.log("333333")res.send("hello world")
})app.use((req, res, next) => {// 同步操作console.log("22222")
})app.listen(3000)

运行输出

111111
22222
333333
  • 01-koa-同步 .js
const Koa = require("koa")
const app = new Koa()app.use((ctx, next) => {console.log("111111")next()console.log("333333")ctx.body("hello world")
})app.use((ctx, next) => {// 同步操作console.log("22222")
})app.listen(3000)

运行输出:

111111
22222
333333

异步代码
next()表示可以执行下一个中间件,当下一个中间件执行完成之后,如果上一个中间件没有执行完,再返回上一个中间件继续执行。

  • 01-express-异步.js
const express = require("express")
const app = express()app.use(async (req, res, next) => {console.log("111111")await next()console.log("444444")res.send("hello world")
})app.use(async (req, res, next) => {console.log("22222")// 异步操作await delay(1000)console.log("33333")
})function delay(time) {return new Promise((resolve, reject) => {setTimeout(resolve,time)})
}app.listen(3000)

运行输出:

111111
22222
444444
33333

由于next()返回的不是promise对象因此await不起作用,所以输出不会像我们所想输出

  • 01-koa-异步.js
const Koa = require("koa")
const app = new Koa()app.use((ctx, next) => {console.log("111111")next()console.log("444444")
})app.use((ctx, next) => {console.log("22222")// 异步操作delay(1000)console.log("33333")
})function delay(time) {return new Promise((resolve, reject) => {setTimeout(resolve,time)})
}
app.listen(3000)

运行输出:

111111
22222
33333
444444

koa洋葱模型,正常执行。

koa下载安装

npm init
npm i koa

Koa基本框架

const Koa = require("koa")const app = new Koa()// ctx=context 相当于res和req的合并
app.use((ctx, next) => {})app.listen(3000)

使用

1.创建koa项目文件目录

我们学习的第一步就是先搭好项目目录,这里会有我们项目中使用到的任何东西。

// 创建项目文件夹  也可手动创建
mkdir  koa-app// 进入项目文件
cd  koa-app// 添加koa依赖    
// 根据自己的包管理器执行自己的命令 我这里以yarn举例
yarn add koa -S// 新建入口文件
echo >index.js// 创建变量管理目录   constmkdir const// 创建数据库管理目录   databasemkdir database// 创建中间件管理目录   middlewaresmkdir middlewares// 创建路由管理目录   routermkdir router// 创建静态资源管理目录   staticmkdir static// 创建工具类管理目录   utilsmkdir utils// 创建html文件管理目录   view
// 主要用于测试自己接口
mkdir const// 创建webpack打包文件echo >webpack.config.js

这时候我们生成的目录结构大致如下

--koa-app--const--database--middlewares--router--static--utils--view-- index.js-- packjson.js-- webpack.config.js

2. 创建koa服务

这时候我们就可以创建koa服务,启动后就可以访问服务器目录了。

// index.jsconst Koa = require("koa");const app = new Koa();app.use(async ctx => {ctx.body = "hellO  欢迎使用koa"
})app.listen(3000);// 启动koa服务node  index.js// 访问服务在浏览器地址栏输入  localhost:3000

启动服务后我们打开浏览器就能看到"hellO 欢迎使用koa"说明我们koa程序运行成功。

3. 添加路由 koa-router

我们后台服务已经搭建好了,那下一步必不可少的就是路由管理了,这里我们使用koa-router插件

//  /router/index.js// 引入koa-router
const  Router = require('koa-router');
// 引入user路由对象
const user = require('./user/index.js');
const view = require('./view/index.js')
const goods = require('./goods/index.js');
const category = require('./category/index.js');
const upload = require('./upload/index.js')
const rule = require('./rule/index.js')
const menu = require('./menu/index.js')
const role = require('./role/index.js')
const managerUser = require('./managerUser/index.js')
const attribute = require('./attribute/index.js')// 生成新的router对象
let router = new Router();// 添加路由管理
router.use('/api/user', user.routes())
router.use('/view', view.routes())
router.use('/api/goods', goods.routes())
router.use('/api/category', category.routes())
router.use('/api/upload', upload.routes())
router.use('/api/rule', rule.routes())
router.use('/api/menu', menu.routes())
router.use('/api/role', role.routes())
router.use('/api/managerUser', managerUser.routes())
router.use('/api/attribute', attribute.routes())// 导出路由
module.exports = router

这里我是以自己写好的项目文件直接复制了,如果是测试的话不需要导入那么多路由对象,导入一个自己已经写好的就行了。

接下来我们就需要修改index.js文件与编写user路由

// /router/user/index.jsrouter.get('/list', async (ctx) => {ctx.body =  {code: 200,message: '访问成功'}
})// index.jsconst Koa = require("koa");
const router = require("./router/index.js"); // 路由
const app = new Koa();// 添加路由中间件
app.use(router.routes()).use(router.allowedMethods());
app.use(async ctx => {ctx.body = "hellO  欢迎使用koa"
})app.listen(3000);

这时候我们重新启动koa服务后,访问localhost/3000/api/user/list 就能获取ctx.body的内容了。 做到这里我们已经实现了自己的第一个接口了。剩下就是去数据库里面获取数据就形成了后台数据服务了。 是不是很棒呢!

4. 数据库服务 mongodb

这里因为学习的是mongodb数据库,所以例子都会是以mongodb数据库为例。其实用mysql的同学也可以自己去看一下mysql的引。

数据库的引入主要是做了2个步骤, 第一连接数据库,第二创建数据model对象,并执行数据库操作。 mongodb使用的是mdb语句去做的查询,mysql则是使用的sql语句。

当然每个数据库特性都不一样,在什么项目中使用什么数据库都需要在搭建项目目录的时候考虑到的,比如mysql, oracle 都是关系型的,在做一些数据关联性强的一些网站上更加适用比如电商,金融,证券,医疗等。 而非关系型的mongodb数据因为数据结构更加多变,适用与一些日记管理,博客,官网等

话不多说,我们来创建我们的数据库服务吧

添加依赖

// 添加依赖
yarn add glob mongoose  -S

创建mongosse文件

// 添加mongoose文件   /database/index.js
// 添加mongosse
const mongoose = require('mongoose')
// 数据库访问地址
const db = "mongodb://127.0.0.1/waimai"
// glob :提供匹配文件路径的方法,可以快速地找 到需要读取的文件
const glob  = require('glob');
const { resolve } = require('path')// 初始化文档模式
exports.initSchemas = async () => {await  glob.sync(resolve(__dirname, './schema', './*.js')).forEach((v) => {require(v)})
}exports.connect = () => {// 连接数据库mongoose.connect(db)return new Promise((resolve, reject) => {// 添加数据库断开监听事件mongoose.connection.on('disconnected', () => {console.log('数据库断开---------------')mongoose.connect(db)})// 添加数据库启动监听事件mongoose.connection.on('open', () => {console.log('数据库连接---------------1')mongoose.connect(db)resolve();})})
}// index.js   引入mongoose文件// moogose初始化
const { connect, initSchemas } = require("./database/index");(async () => {await connect();await initSchemas();
})();

我们重启服务后就能连接到mongodb数据库了, 在conosle里面我们能看到 数据库连接字样

5. 添加请求参数json处理 koa-bodyparser

添加新依赖

yarn add koa-bodyparser -D

更新index.js

const bodyParser = require("koa-bodyparser"); // requeast请求app.use(bodyParser());

6. 用户接口举例

添加新依赖

yarn add bcrypt -D

创建mongoose.model模型

const mongoose = require('mongoose');
const Schema = mongoose.Schema;
let ObjectId = Schema.Types.ObjectId;
// const bcrypt = require('bcrypt');const SALT_WORK_FACTOR = 10;// 前台用户表接口
const userSchema = new Schema({UserId: ObjectId,userName: {unique: true,type: String},passWord: String,avator: String,hashPassword: String,nikeName: String,address: String,isBlack: Boolean,sex: String,createAt: {type: Date,default: Date.now(),},lastLoginAt: {type: Date,default: Date.now(),},
})// 每次存储时都要执行,加盐加密
userSchema.pre('save', function (next){bcrypt.genSalt(SALT_WORK_FACTOR,(err,salt)=>{if(err) return next(err)bcrypt.hash(this.passWord,salt,(err,hash)=>{if(err) return next(err)this.hashPassword = hashnext()})})
})// 添加自定义方法
userSchema.methods = {// 对比密码一致性comparePassword: (_password, hashPassword) => {return new Promise((resolve, reject) => {// 对比密码方法bcrypt.compare(_password, hashPassword, (err, isMatch) => {if(!err) resolve(isMatch);reject(err)})}) }
}
// 发布模型
module.exports = mongoose.model('User', userSchema)

添加用户接口

const Router  = require('koa-router');
const mongoose = require('mongoose')
let router = new Router();
const User = require('../../database/schema/User')// 用户注册
router.post('/register', async (ctx) => {const userName = ctx.request.body.userName;const passWord = ctx.request.body.passWord;let newUser = new User({userName,passWord,}).save().then((res) => {ctx.body = {code: 200,message: "添加用户成功",};}).catch((err) => {ctx.body = {code: 500,message: "添加失败" + err,};});;
})router.get('/list', async (ctx) => {// 引入user模型// const User  = mongoose.model('User');const uid  = ctx.request.query.uid || '';//  分页 pagelet page = ctx.request.body.page || 1;//  分页每页数量let limit = ctx.request.body.limit || 8;// 上一次获取位置const start =(page - 1)*limit;// console.log( userName, User, 'User')const result =  await User.find().exec()console.log(result, 'result')ctx.body = {code: 200,data: result.slice((page-1)*limit, page*limit),page: {page: page,limit,total: result.length ,lastPage: parseInt(result.length / limit)}}// ctx.body = ctx.request.body;
})module.exports = router;

这时候我们就已经写好了用户添加接口与用户列表接口。因为用户的密码需要保密,我们在这里用了bcrypt去做了加盐加密,考虑到了bcrypt的加密是不可逆的所以我们这里用了passWord对原密码做了保存。

这里我们使用了schema的自定义方法与 schema的钩子函数

  • userSchema.methods

向由该 schema 编译的 model 构造的 document 添加一个实例方法.

  • userSchema.pre

给 schema 定义一个前置钩子 (pre hook)

7.引入koa一些常用插件

处理跨域问题 koa2-cors

yarn add koa2-cors -D// index,js
const koa2cors = require("koa2-cors"); // 配置跨域app.use(koa2cors({origin: "*",maxAge: 5,allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}));

添加静态文件目录 koa-static

yarn add koa-static -D// index.jsconst koaStatic = require("koa-static"); // 静态目录
app.use(koaStatic("./"));

添加websokit服务 koa-websocket

yanr add  koa-websocket -S// index.jsconst websocket = require("koa-websocket"); // socket// 这时候app需用被websoket包裹
const app = websocket(new Koa());// 建立socket连接
app.ws.use(async (ctx) => {// the websocket is added to the context as `ctx.websocket`.ctx.websocket.send("我是服务器");ctx.websocket.on("message", function (message) {// do somethingconst msg = message.toString("utf-8");console.log("客户端发来消息", msg);});
});

添加xss防御

yarn add xss -S// index.js
const xss = require('./middlewares/xss.js') // xssapp.use(xss())// /middlewares/xss.jsconst xss = require("xss"); // 需要 npm install xss -Sconst xssHandler = () => {return async (ctx, next) => {try {const body = ctx.request.body;for (const key in body) {if (typeof body[key] === "string") {body[key] = xss(body[key]);}}// 一定要添加awaitawait next();} catch (error) {// console.error(error)throw error;}};
};module.exports = xssHandler;

图片文件处理 koa-multer

yarn add koa-multer -D//  /router/upload/index.js
const Router  = require('koa-router');
let router = new Router();
const multer = require('koa-multer');//配置
const storage = multer.diskStorage({//配置图片上传的目录destination: function (req, file, cb) {console.log('destination')cb(null, 'static/images/'); //注意路径必须存在},//图片上传完成重命名filename: function (req, file, cb) {console.log('filename')// 获取后缀名var fileFormat = file.originalname.split('.');cb(null, Date.now() + '.' + fileFormat[fileFormat.length - 1]);},
});
const upload = multer({ storage: storage });
router.post('/img', upload.single('file'), async ctx => {console.log(ctx.req.file, 'ctx.req.file')ctx.body = {code: 200, data: {filename: ctx.req.file.filename,//返回文件名 path: ctx.req.file.destination + ctx.req.file.filename}} 
})module.exports = router;

请求参数验证 Joi

访问接口时会先校验参数是否传对,如果对继续后面的逻辑,如果参数校验不对则会直接返回错误信息给前端。

yarn add Joi -D// /router/user/index.jsconst Joi = require("joi");
const validateSchemaJoi = require("../../middlewares/validateSchemaJoi");
const userSchema = Joi.object({userName: Joi.string().min(1).required(),
});// 用户注册
router.post('/register', validateSchemaJoi("post", userSchema), async (ctx) => {// 注册流程
})// /middlewares/validateSchemaJoi
function validateSchemaJoi(method, schema) {async function validateSchema (ctx, next) {let data = undefined;if (method === 'get') {data = ctx.request.query;} else {data = ctx.request.body;}const { value, error } = schema.validate(data);if (error) {ctx.body = {code: 400,error};} else {next();}}return validateSchema;}module.exports =  validateSchemaJoi;

8.用户登录验证 koa-jwt

用户验证有3种方式

1。cookie 2. session 3. token

这里我们就以token来做用户验证。

添加依赖

yarn add koa-jwt jsonwebtoken -S

用户登录添加token返回

//  /router/user/index.jsvar jwt = require('jsonwebtoken');router.post('/login', async (ctx) => {const userName = ctx.request.body.userName;const passWord = ctx.request.body.passWord;// 查询用户是否存在await User.findOne({ userName: userName }).exec().then(async result => {// 如果用户名存在if(result) {let newUser = new User();// 校验用户密码await newUser.comparePassword(passWord, result.hashPassword).then(isMatch => {// 如果用户校验成功if(isMatch) {// 生成tokenconst token = jwt.sign({userName: result.userName}, 'secret', { expiresIn: '2h' });// 返回给前端ctx.body = {code: 200,message: isMatch,data: {token: token,uid: result._id}}}else {ctx.body = {code: 500,message: isMatch}}})}else {ctx.body = {code: 500,message: '用户名不存在!'}}}).catch(err => {// console.log('result----err')ctx.body = {code: 500,message: err,}})})

添加token白名单 不拦截请求

const { jwtWhiteList } = require("./const/jwtWhiteList"); // token白名单// /const/jwtWhiteList.jsconst jwtWhiteList  = [/^\/api\/user\/login/,/^\/view/,/^\/static/,"/api/managerUser/login","/api/goods/getGoodsDetailsInfo","/api/upload/img"
]
module.exports = {jwtWhiteList
}

添加路由token验证拦截

token路由拦截主要做了以下这几件事

1.koa-jwt对每个请求头部信息进行token校验,如果用户校验失败就返回401,过滤掉白名单的请求。

2.在路由中间件上面添加中间件,当用户token失效后我们就会走401步骤 返回用户token失效信息,让前端去重定向到登录页

3.用户token都是有时效性的,当然时效性越短越好,因为没用数据库去存储token所以在项目重启后可能会有失效问题,没验证过。我这默认是2小时,当小于一半的失效时间时我就会生成新的token交予前端重新生成。也就是所谓的token续存机制。

// index.jsconst jwt = require("koa-jwt"); // token验证
const jwtToken = require('jsonwebtoken');// 路由拦截器中间件
app.use(function (ctx, next) {// console.log("ce0", ctx.header.authorization)if (ctx.header && ctx.header.authorization) {const parts = ctx.header.authorization.split(" ");if (parts.length === 2) {//取出tokenconst scheme = parts[0];const token = parts[1];if (/^Bearer$/i.test(scheme)) {try {const decoded = jwtToken.verify(token, 'secret',{ complete: true });// iat: 签发时间  exp: 过期时间const { iat, exp, userName  } = decoded.payload;const nowTime = new Date().getTime()/1000;const lastTime  = (exp - nowTime)/60;// 当前事件离过期时间还剩一半的时候更新token 如果过期就走401if(decoded && 0 < lastTime &&  lastTime< ((exp-iat)/60)/2) {// console.log('更新token0')const newToken = jwtToken.sign({userName: userName}, 'secret', { expiresIn: '2h' });// console.log('更新token1', newToken)ctx.res.setHeader('Authorization', newToken)}} catch (error) {console.log("ce3")//token过期 }}}}return next().catch((err) => {if (401 == err.status || err.status === 301) {ctx.status = 401;ctx.body = {code: err.status,message: "token已经失效!!!!"};// ctx.body = {error: err.originalError ? err.originalError.message : err.message};} else {throw err;}});
});// 添加token中间件
app.use(jwt({ secret: "secret" }).unless({ path: jwtWhiteList }));

9.webpack生产打包

这里就做了简单的js打包,打包后的文件体积会变小,因为webpack设置mode为生产环境后默认就做了许多处理。

// webpack.config.js
const webpack = require("webpack");const path = require("path");const { CleanWebpackPlugin } = require("clean-webpack-plugin");const nodeExternals = require("webpack-node-externals");// const MinifyPlugin = require('babel-minify-webpack-plugin');const CopyWebpackPlugin = require('copy-webpack-plugin')module.exports = {entry: "./index.js",mode: "production",output: {path: path.resolve(__dirname, "./dist"),filename: "[name].js",},target: "node",externals: [nodeExternals()], //node 打包可去除一些警告module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: [{loader: "babel-loader",options: {presets: ["@babel/preset-env"], //兼容es6,并添加.babelrc},},],},],},plugins: [// 清楚distnew CleanWebpackPlugin(),// js压缩// split切片// 复制静态目录new CopyWebpackPlugin({patterns: [{from: path.resolve(__dirname, './static'),to: path.resolve(__dirname, './dist/static')}]})// new MinifyPlugin() //压缩js],};// packjson.js  添加启动指令"build": "webpack --progress  --config webpack.config.js",
"prd_server": "node ./dist/main.js"

来源

你需要的koa入门教学
koa框架

相关文章:

【Node.JS】koa

文章目录 概述koa和express对比koa下载安装使用1.创建koa项目文件目录2. 创建koa服务3. 添加路由 koa-router4. 数据库服务 mongodb5. 添加请求参数json处理 koa-bodyparser6. 用户接口举例7.引入koa一些常用插件8.用户登录验证 koa-jwt9.webpack生产打包 来源 概述 Koa 是一个…...

工作日志- 不定期更新

1. protobuf中使用import引用其他proto文件&#xff0c;生成后在go语言的go modules中import 包名报错问题。 public.proto文件 //protoc --go_outpluginsgrpc:. public.proto syntax "proto3";package public;option go_package "self/game-service/msg/pu…...

Qt使用opencv打开摄像头

1.效果图 2.代码 #include "widget.h"#include <QApplication>#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp>#include <QImage> #include <QLabel> #incl…...

Redis的Hash数据结构中100万对field和value,field是自增时如何优化?优化Hash结构。

ZipList使用是有条件的&#xff0c;当entry数据量太大时就会启用哈希结构&#xff0c;占用内存空间 1.设置bigkey的上限 在redis.config中设置 2.拆分为string类型 String底层结果没有太多优化&#xff0c;占用内存多 想要批量获取数据麻烦 3.拆分为小的hash 将id/100作为…...

二十四种设计模式与六大设计原则(一):【策略模式、代理模式、单例模式、多例模式、工厂方法模式、抽象工厂模式】的定义、举例说明、核心思想、适用场景和优缺点

目录 策略模式【Strategy Pattern】 定义 举例说明 核心思想 适用场景 优缺点 代理模式【Proxy Pattern】 定义 举例说明 核心思想 适用场景 优缺点 单例模式【Singleton Pattern】 定义 举例说明 核心思想 适用场景 优缺点 多例模式【Multition Pattern】…...

mac怎么删除python

mac 默认安装了python2&#xff1b;自己后面又安装了python3&#xff1b;为了方便&#xff0c;现在想将python3换成Anaconda3。 Anaconda是一个开源的Python发行版本&#xff0c;其包含了conda、Python等180多个科学包及其依赖项。 Python3安装之后&#xff0c;在系统中不同目…...

【笔记】Android U RILJ 中与运营商名称SPN显示相关的日志分析

源码阅读&#xff1a;AOSPXRef 常用日志关键字 Note&#xff1a;">"下发MD&#xff0c;"<"MD上报&#xff0c;[]中的id有请求和返回的对应关系 KEYComment> OPERATOR下发MD&#xff0c;请求运营商信息< OPERATORMD上报运营商注册信息> DA…...

蓝桥杯【奇怪的捐赠】c语言

我会将这题的解题的核心思路解为将10进制转化成7进制&#xff0c;毕竟题目上说的很清楚7的几次方 然后附上我认为的最优解 #include<stdio.h> int main() {int n 1000000;int sum 0;while (n ! 0){int a;a n % 7;n n / 7;sum a ;}printf("%d", sum);retu…...

【3月比赛合集】5场可报名的「创新应用」、「数据分析」和「程序设计」大奖赛,任君挑选!

CompHub[1] 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号会推送最新的比赛消息&#xff0c;欢迎关注&#xff01; 以下信息仅供参考&#xff0c;以比赛官网为准 目录 创新应用赛&#xff08;2场比赛&#xff09;数据分析赛&#…...

vue3 视频播放功能整体复盘梳理

回顾工作中对视频的处理&#xff0c;让工作中处理的问题的经验固化成成果&#xff0c;不仅仅是完成任务&#xff0c;还能解答任务的知识点。 遇到的问题 1、如何隐藏下载按钮&#xff1f; video 标签中的controlslist属性是可以用来控制播放器上空间的显示&#xff0c;在原来默…...

vue-ueditor-wrap上传图片报错:后端配置项没有正常加载,上传插件不能正常使用

如图所示&#xff0c;今天接收一个项目其中富文本编辑器报错 此项目为vue2项目&#xff0c;富文本编辑器为直接下载好的资源存放在public目录下的 经过排查发现报错的函数在ueditor.all.min.js文件内&#xff0c;但是ueditor.all.min.js文件夹是经过压缩的 所以直接&#xff…...

数据仓库的发展历程

数据仓库的概念可以追溯到20世纪60年代,但真正形成理论并被企业广泛应用还需要一个较长的发展过程。大致可以分为以下几个阶段: 决策支持系统(DSS)时期(1960s-1970s) 这一时期,随着管理信息系统(MIS)和电子计算机的兴起,企业开始尝试构建面向决策的数据处理系统。最初的决策支…...

MySQL开窗函数

测试环境&#xff1a;mysql8.0.18 官方文档&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/window-functions.html 一、窗口函数介绍二、语法结构三、自定义窗口1.rows&#xff08;重点&#xff09;2.range3.默认窗口 四、常用窗口函数示例1.row_number & rank &…...

Java学习笔记(23)

多线程 并发 并行 多线程实现方式 1.继承Thread类 自己创建一个类extends thread类 Start方法开启线程&#xff0c;自动执行重写之后的run方法 2.实现runable接口 自己创建一个类implements runnable Myrun不能直接使用getname方法&#xff0c;因为这个方法是thread类的方法…...

nodejs下载安装以及npm、yarn安装及配置教程

1、nodejs下载安装 ​ 1.1、使用nodejs版本管理工具下载安装&#xff0c;可一键安装、切换不同nodejs版本&#xff0c; nvm-setup.zip&#xff1a;安装版&#xff0c;推荐使用 本次演示的是安装版。 1、双击安装文件 nvm-setup.exe 选择nvm安装路径 例如&#xff1a;E:\Soft…...

Playwright库page.evaluate()方法执行JavaScript 表达式

page.evaluate() 方法是 Playwright 中常用的方法之一&#xff0c;用于在页面上下文中执行 JavaScript 代码。它允许在浏览器环境中执行各种操作&#xff0c;如操作 DOM 元素、获取页面数据、执行复杂的计算等&#xff0c;并将结果返回到 Node.js 或 Python 代码中。 在 Playw…...

【微服务】OpenFeign+Sentinel集中处理远程调用异常

文章目录 1.微服务基本环境调整1.对10004模块的application.yml调整2.启动nacos以及一个消费者两个提供者3.测试1.输入http://localhost:8848/nacos/index.html 来查看注册情况2.浏览器访问 http://localhost:81/member/nacos/consumer/get/13.结果 2.使用OpenFeign实现微服务模…...

集合嵌套,Collections,斗地主案例,日志框架

文章目录 集合嵌套List嵌套ListList嵌套MapMap嵌套Map Collections类方法排序 sort 乱序 shuffle 斗地主案例需求思路代码 日志框架介绍优势体系结构Logback概述快速入门配置详解 集合嵌套 List嵌套List public static void main(String[] args){//一个年级有许多班级&#xf…...

maven pom relativePath属性的作用

maven pom relativePath属性的作用 文章目录 maven pom relativePath属性的作用一、relativePath出现的地方二、relativePath默认值三、四、<relativePath>一个pom路径 一、relativePath出现的地方 搭建maven项目&#xff0c;子模块指定父模块试&#xff0c;经常会在par…...

【STM32 HAL库SPI/QSPI协议学习,基于外部Flash读取。】

1、SPI协议 简介 SPI 协议是由摩托罗拉公司提出的通讯协议 (Serial Peripheral Interface)&#xff0c;即串行外围设备接口&#xff0c;是 一种高速全双工的通信总线。它被广泛地使用在 ADC、LCD 等设备与 MCU 间&#xff0c;要求通讯速率 较高的场合。 SPI 物理层 SPI 通讯…...

Nginx入门--初识Nginx的架构

一、概述 Nginx的架构设计旨在高效处理并发的网络请求。它采用了事件驱动的、非阻塞的IO模型&#xff0c;可以同时处理成千上万个并发连接&#xff0c;而不会消耗太多的系统资源。 二、主要组件 Nginx的主要组件包括&#xff1a; Master Process&#xff08;主进程&#xf…...

网络性能提升10%,ZStack Edge 云原生超融合基于第四代英特尔®至强®可扩展处理器解决方案发布

随着业务模式的逐渐转变、业务架构逐渐变得复杂&#xff0c;同时容器技术的兴起和逐渐成熟&#xff0c;使得Kubernetes、微服务等新潮技术逐步应用于业务应用系统上。 为了充分释放性能、为业务系统提供更高效的运行环境&#xff0c;ZStack Edge 云原生超融合采用了第四代英特尔…...

双非计算机考研目标211,选11408还是22408更稳?

求稳得话&#xff0c;11408比22408要稳&#xff01; 很多同学只知道&#xff0c;11408和22408在考察的科目上有区别&#xff0c;比如&#xff1a; 11408考的是考研数学一和英语一&#xff0c;22408考察的是考研数学二和英语二&#xff1a; 考研数学一和考研数学二的区别大吗…...

简单了解策略模式

什么是策略模式&#xff1f; 策略模式提供生成某一种产品的不同方式 Strategy策略类定义了某个各种算法的公共方法&#xff0c;不同的算法类通过继承Strategy策略类&#xff0c;实现自己的算法 Context的作用是减少客户端和Strategy策略类之间的耦合&#xff0c;客户端只需要…...

算法——运动模型

智能驾驶中常用的速度计算算法包括基于GPS的速度计算、惯性测量单元&#xff08;IMU&#xff09;的速度计算、雷达测距的速度计算、视觉测距的速度计算等。这些算法可以单独使用或者结合使用&#xff0c;以提高速度计算的准确性和稳定性。 智能驾驶中常用的加速度计算算法包括…...

基于R语言lavaan结构方程模型(SEM)技术应用

结构方程模型&#xff08;Sructural Equation Modeling&#xff0c;SEM&#xff09;是分析系统内变量间的相互关系的利器&#xff0c;可通过图形化方式清晰展示系统中多变量因果关系网&#xff0c;具有强大的数据分析功能和广泛的适用性&#xff0c;是近年来生态、进化、环境、…...

本地虚拟机服务器修改站点根目录并使用域名访问的简单示例

说明&#xff1a;本文提及效果是使用vmware虚拟机&#xff0c;镜像文件是Rocky8.6 一、配置文件路径 1. /etc/httpd/conf/httpd.conf #主配置文件 2. /etc/httpd/conf.d/*.conf #调用配置文件 调用配置文件的使用&#xff1a; vim /etc/httpd/conf.d/webpage.conf 因为在主配…...

生信数据分析——GO+KEGG富集分析

生信数据分析——GOKEGG富集分析 目录 生信数据分析——GOKEGG富集分析1. 富集分析基础知识2. GO富集分析&#xff08;Rstudio&#xff09;3. KEGG富集分析&#xff08;Rstudio&#xff09; 1. 富集分析基础知识 1.1 为什么要做功能富集分析&#xff1f; 转录组学数据得到的基…...

微服务(基础篇-007-RabbitMQ)

目录 初识MQ(1) 同步通讯&#xff08;1.1&#xff09; 异步通讯&#xff08;1.2&#xff09; MQ常见框架&#xff08;1.3&#xff09; RabbitMQ快速入门(2) RabbitMQ概述和安装&#xff08;2.1&#xff09; 常见消息模型&#xff08;2.2&#xff09; 快速入门&#xff…...

汇总:五个开源的Three.js项目

Three.js 是一个基于 WebGL 的 JavaScript 库&#xff0c;它提供了一套易于使用的 API 用来在浏览器中创建和显示 3D 图形。通过抽象和简化 WebGL 的复杂性&#xff0c;Three.js 使开发者无需深入了解 WebGL 的详细技术就能够轻松构建和渲染3D场景、模型、动画、粒子系统等。 T…...

扶风做网站/企业网站建设门户

原型库网站—讲师金乌原创发布&#xff0c;可自由转载&#xff0c;请注明出处&#xff01;Axure中文官网&#xff1a;www.AxureRP.cn《AxureRP7.0部件详解》Inline Frame 内部框架使用内部框架&#xff0c;可以嵌入视频&#xff0c;地图&#xff0c;和HTML到您的原型设计中。使…...

温州本地论坛/百度seo搜索营销新视角

1725: [Usaco2006 Nov]Corn Fields牧场的安排 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1234 Solved: 878[Submit][Status][Discuss]Description Farmer John新买了一块长方形的牧场&#xff0c;这块牧场被划分成M列N行(1<M<12; 1<N<12)&#xff0c;每一格…...

wordpress 3.6 下载/市场营销课程

安装好某个python库后导致python版本发生了变化请按以下命令完成恢复1、wget -O conda-exec https://repo.anaconda.com/pkgs/misc/conda-execs/conda-4.7.11-linux-64.exechmod x conda-exec2、将Anaconda的路径临时添加到环境变量CONDA_ROOT_PREFIX。我的路径是/root/anacond…...

如何与导航网站做友情链接/国内电商平台有哪些

域名 通常 Internet 主机域名的一般结构为&#xff1a;主机名.三级域名.二级域名.顶级域名&#xff08;又称为一级域名&#xff09;。二级域名及其以上级别的域名&#xff0c;统称为子域名&#xff0c;有多少个点就是几级域名顶级域名分为两类&#xff1a;一个是按照国家&#…...

住房和城乡建设部网站买卖合同/网站建设方案推广

采用的技术为 java vue h5 微信小程序开发的。支持千万级别的数据量。 百度网盘扩容技术不断进化中&#xff0c;随之而来的是大容量网盘的资源如何展示给客户&#xff0c;这里就需要用到最新的百度网盘目录索引系统&#xff1a; 包含H5小程序 功能介绍&#xff1a; 1、支…...

越南网站怎么做/seo实战密码

前言 PowerShell是为系统管理员设计的基于任务的自动化命令行外壳(Shell)和相关脚本环境。 它建立在.NET框架上。 它是比命令提示符(cmd)强大的命令行解释器&#xff0c;可以解释PowerShell和批处理命令。 powershell一直都是内网渗透的大热门&#xff0c;微软是真正的在推行…...