koa web框架入门
1.在hello-koa这个目录下创建一个package.json,这个文件描述了我们的hello-koa工程会用到哪些包。完整的文件内容如下:
{
"name": "hello-koa2",
"version": "1.0.0",
"description": "Hello Koa 2 example with async",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"keywords": [
"koa",
"async"
],
"author": "Michael Liao",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/michaelliao/learn-javascript.git"
},
"dependencies": {
"koa": "2.0.0"
}
}
其中,dependencies描述了我们的工程依赖的包以及版本号。其他字段均用来描述项目信息,可任意填写。
C:\...\hello-koa> npm install
2.创建koa2工程
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 对于任何请求,app将调用该异步函数处理请求:
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
}); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');

还可以直接用命令node app.js在命令行启动程序,或者用npm start启动。npm start命令会让npm执行定义在package.json文件中的start对应命令:
"scripts": {
"start": "node app.js"
}
koa middleware
让我们再仔细看看koa的执行逻辑。核心代码是:
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
});
每收到一个http请求,koa就会调用通过app.use()注册的async函数,并传入ctx和next参数。
我们可以对ctx操作,并设置返回内容。但是为什么要调用await next()?
原因是koa把很多async函数组成一个处理链,每个async函数都可以做一些自己的事情,
然后用await next()来调用下一个async函数。我们把每个async函数称为middleware,这些middleware可以组合起来,完成很多有用的功能。
例如,可以用以下3个middleware组成处理链,依次打印日志,记录处理时间,输出HTML:
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); app.use(async (ctx, next) => {
console.log(`${ctx.request.method} ${ctx.request.url}`); // 打印URL
await next(); // 调用下一个middleware
}); app.use(async (ctx, next) => {
const start = new Date().getTime(); // 当前时间
await next(); // 调用下一个middleware
const ms = new Date().getTime() - start; // 耗费时间
console.log(`Time: ${ms}ms`); // 打印耗费时间
}); app.use(async (ctx, next) => {
console.log('我开始了')
await next(); // 当下面没有use 后将不执行
ctx.response.type = 'text/html';
ctx.response.body = '<h1>Hello, koa2!</h1>';
console.log('我结束了')
}); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');
middleware的顺序很重要,也就是调用app.use()的顺序决定了middleware的顺序。
此外,如果一个middleware没有调用await next(),会怎么办?答案是后续的middleware将不再执行了。
这种情况也很常见,例如,一个检测用户权限的middleware可以决定是否继续处理请求,还是直接返回403错误:
app.use(async (ctx, next) => {
if (await checkUserPermission(ctx)) {
await next();
} else {
ctx.response.status = 403;
}
});
理解了middleware,我们就已经会用koa了!
最后注意ctx对象有一些简写的方法,例如ctx.url相当于ctx.request.url,ctx.type相当于ctx.response.type。
处理URL
正常情况下,我们应该对不同的URL调用不同的处理函数,这样才能返回不同的结果。例如像这样写:
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); app.use(async (ctx, next) => {
//ctx.request.path 判断访问路径
if (ctx.request.path === '/') {
ctx.response.body = 'index page';
//如果就有 就执行下一个use
} else {
await next();
}
}); app.use(async (ctx, next) => {
if (ctx.request.path === '/test') {
ctx.response.body = 'TEST page';
} else {
await next();
}
}); app.use(async (ctx, next) => {
if (ctx.request.path === '/error') {
ctx.response.body = 'ERROR page';
} else {
await next();
}
}); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');
这么写是可以运行的,但是好像有点蠢。
应该有一个能集中处理URL的middleware,它根据不同的URL调用不同的处理函数,这样,我们才能专心为每个URL编写处理函数。
koa-router
为了处理URL,我们需要引入koa-router这个middleware,让它负责处理URL映射。
先在package.json中添加依赖项:
{
"name": "hello-koa2",
"version": "1.0.0",
"description": "Hello Koa 2 example with async",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"keywords": [
"koa",
"async"
],
"author": "Michael Liao",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/michaelliao/learn-javascript.git"
},
"dependencies": {
"koa": "2.0.0",
"koa-router": "7.0.0"
}
}
然后用npm install安装。
接下来,我们修改app.js,使用koa-router来处理URL:
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建一个Koa对象表示web app本身:
const app = new Koa(); //log request URL:
app.use(async(ctx,next)=> {
console.log(`Process ${ctx.request.method} ${ctx.request.url}.....`)
await next();
}) //add url-route; 添加访问路径
router.get(`/hello/:name`,async(ctx,next)=> {
var name = ctx.params.name
ctx.response.body = `<h1>Hello,${name}</h1>` }) //add url-route;添加访问路径
router.get('/', async (ctx, next) => {
ctx.response.body = '<h1>Index</h1>';
}); // add router middlware
app.use(router.routes()); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');
注意导入koa-router的语句最后的()是函数调用:
const router = require('koa-router')();
相当于:
const fn_router = require('koa-router');
const router = fn_router();
然后,我们使用router.get('/path', async fn)来注册一个GET请求。可以在请求路径中使用带变量的/hello/:name,变量可以通过ctx.params.name访问。
再运行app.js,我们就可以测试不同的URL:
输入首页:http://localhost:3000/

处理post请求
用router.get('/path', async fn)处理的是get请求。如果要处理post请求,可以用router.post('/path', async fn)。
用post请求处理URL时,我们会遇到一个问题:post请求通常会发送一个表单,或者JSON,它作为request的body发送,但无论是Node.js提供的原始request对象,还是koa提供的request对象,都不提供解析request的body的功能!
所以,我们又需要引入另一个middleware来解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body中。
koa-bodyparser就是用来干这个活的。
1. 在package.json中添加依赖项:
"koa-bodyparser": "3.2.0"
2.引入koa-bodyparser:
const bodyParser = require('koa-bodyparser');
在合适的位置加上:
app.use(bodyParser());
由于middleware的顺序很重要,这个koa-bodyparser必须在router之前被注册到app对象上。
现在我们就可以处理post请求了。写一个简单的登录表单:
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); //log request URL:
app.use(async(ctx,next)=> {
console.log(`Process ${ctx.request.method} ${ctx.request.url}.....`)
await next();
}) //get 请求返回一个body html文本
router.get('/', async (ctx, next) => {
// 响应html文本
ctx.response.body = `<h1>Index</h1>
<form action="/signin" method="post">
<p>Name: <input name="name" value="koa"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="submit" value="Submit"></p>
</form>`;
}); //处理用户提交过来的 post请求
router.post('/signin', async (ctx, next) => {
// 获取用户提交上来的值
var
name = ctx.request.body.name || '',
password = ctx.request.body.password || '';
console.log(`signin with name: ${name}, password: ${password}`); // 对用户提交上来的值进行判断
if (name === 'koa' && password === '12345') {
//如果成功 返回登录成功
ctx.response.body = `<h1>Welcome, ${name}!</h1>`;
} else {
// 如果登录失败 返回登录失败,然后尝试 再次登录
ctx.response.body = `<h1>Login failed!</h1>
<p><a href="/">Try again</a></p>`;
}
}); // add middlware 这个要放前面
app.use(bodyParser()); // add router middlware
app.use(router.routes()); // 在端口3000监听:
app.listen(3000);
console.log('app started at port 3000...');
注意到我们用var name = ctx.request.body.name || ''拿到表单的name字段,如果该字段不存在,默认值设置为''。
类似的,put、delete、head请求也可以由router处理。
重构
现在,我们已经可以处理不同的URL了,但是看看app.js,总觉得还是有点不对劲。
所有的URL处理函数都放到app.js里显得很乱,而且,每加一个URL,就需要修改app.js。随着URL越来越多,app.js就会越来越长。
如果能把URL处理函数集中到某个js文件,或者某几个js文件中就好了,然后让app.js自动导入所有处理URL的函数。这样,代码一分离,逻辑就显得清楚了。最好是这样:
url2-koa/
|
+- .vscode/
| |
| +- launch.json <-- VSCode 配置文件
|
+- controllers/
| |
| +- login.js <-- 处理login相关URL
| |
| +- users.js <-- 处理用户管理相关URL
|
+- app.js <-- 使用koa的js
|
+- package.json <-- 项目描述文件
|
+- node_modules/ <-- npm安装的所有依赖包
于是我们把url-koa复制一份,重命名为url2-koa,准备重构这个项目。
我们先在controllers目录下编写index.js:
var fn_index = async (ctx, next) => {
ctx.response.body = `<h1>Index</h1>
<form action="/signin" method="post">
<p>Name: <input name="name" value="koa"></p>
<p>Password: <input name="password" type="password"></p>
<p><input type="submit" value="Submit"></p>
</form>`;
};
var fn_signin = async (ctx, next) => {
var
name = ctx.request.body.name || '',
password = ctx.request.body.password || '';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'koa' && password === '12345') {
ctx.response.body = `<h1>Welcome, ${name}!</h1>`;
} else {
ctx.response.body = `<h1>Login failed!</h1>
<p><a href="/">Try again</a></p>`;
}
};
module.exports = {
'GET /': fn_index,
'POST /signin': fn_signin
};
这个index.js通过module.exports把两个URL处理函数暴露出来。
类似的,hello.js把一个URL处理函数暴露出来:
var fn_hello = async (ctx, next) => {
var name = ctx.params.name;
ctx.response.body = `<h1>Hello, ${name}!</h1>`;
};
module.exports = {
'GET /hello/:name': fn_hello
};
现在,我们修改app.js,让它自动扫描controllers目录,找到所有js文件,导入,然后注册每个URL:
路径分发url
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 先导入fs模块,然后用readdirSync列出文件
var fs = require('fs'); // 这里可以用sync是因为启动时只运行一次,不存在性能问题:
// __dirname === 当前根目录名
// fs.readdirSync 读出文件夹中的文件
var files = fs.readdirSync(__dirname + '/controllers'); // 过滤出.js文件: [ 'hello.js', 'index.js', 'login.js' ]
var js_files = files.filter((f)=>{
return f.endsWith('.js');
}); // 处理每个js文件:
for (var f of js_files) {
// console.log(`process controller: ${f}...`);
// 导入js文件: 当前目录controllers+当前循环文件 { 'GET /hello/:name': [AsyncFunction: fn_hello] }
let mapping = require(__dirname + '/controllers/' + f) for (var url in mapping) {//GET /hello/:name GET / POST /signin
// 如果url以"GET xxx"开头:
if (url.startsWith('GET ')) {
var path = url.substring(4); // 去除字符串前面的4个字符。 GET /(这四个)
//取到路径 path == /hello/:name, mapping[url] == [AsyncFunction: fn_hello]
router.get(path, mapping[url])
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith(`POST`)){ //处理post请求
// 去除前面的post加一个空格 POST
var path = url.substring(5);
router.post(path,mapping[url]);
console.log(`register URL mapping: POST ${path}`)
} else {
// 无效的的url
console.log(`invalid URL: ${url}`)
}
}
} // add middlware 这个要放前面
app.use(bodyParser()); // add router middlware
app.use(router.routes()); app.listen(3000)
console.log('app started at port 3000...');
处理请求页面
var fn_login = async (ctx, next)=> {
ctx.response.body = `
<form action="/mark" method="POST">
<input type="text" name="use" value="riven">
<input type="password" name="pwd">
<input type="submit" >
</form>
`
}
var fn_login_post = async (ctx,next) => {
var name = ctx.request.body.use || '';
var password = ctx.request.body.pwd ||'';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'riven' && password ==='123456') {
ctx.response.body = `<h1> Welcome,${name}!<h1>`
} else {
ctx.response.body = `<h1>Login failed!<h1>
<p><a href='/'>Try agein</a></p>
`
}
}
module.exports = {
'GET /': fn_login,
'POST /mark': fn_login_post
};
如果上面的大段代码看起来还是有点费劲,那就把它拆成更小单元的函数:(简化函数版)
处理url
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 先导入fs模块,然后用readdirSync列出文件
var fs = require('fs'); // 读取文件 处理路径
function fileControllers(router){
// 这里可以用sync是因为启动时只运行一次,不存在性能问题:
// __dirname === 当前根目录名
// fs.readdirSync 读出文件夹中的文件
var files = fs.readdirSync(__dirname + '/controllers'); // 过滤出.js文件: [ 'hello.js', 'index.js', 'login.js' ]
var js_files = files.filter((f)=>{
return f.endsWith('.js');
}); // 处理每个js文件:
for (var f of js_files) {
// console.log(`process controller: ${f}...`);
// 导入js文件: 当前目录controllers+当前循环文件 { 'GET /hello/:name': [AsyncFunction: fn_hello] }
let mapping = require(__dirname + '/controllers/' + f)
requestControllers(router,mapping) }
} // 处理request请求
function requestControllers(router, mapping){
for (var url in mapping) {//GET /hello/:name GET / POST /signin
// 如果url以"GET xxx"开头:
if (url.startsWith('GET ')) {
var path = url.substring(4); // 去除字符串前面的4个字符。 GET /(这四个)
//取到路径 path == /hello/:name, mapping[url] == [AsyncFunction: fn_hello]
router.get(path, mapping[url])
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith(`POST`)){ //处理post请求
// 去除前面的post加一个空格 POST
var path = url.substring(5);
router.post(path,mapping[url]);
console.log(`register URL mapping: POST ${path}`)
} else {
// 无效的的url
console.log(`invalid URL: ${url}`)
}
}
} fileControllers(router) // add middlware 这个要放前面
app.use(bodyParser()); // add router middlware
app.use(router.routes()); app.listen(3000)
console.log('app started at port 3000...');
页面
var fn_login = async (ctx, next)=> {
ctx.response.body = `
<form action="/mark" method="POST">
<input type="text" name="use" value="riven">
<input type="password" name="pwd">
<input type="submit" >
</form>
`
}
var fn_login_post = async (ctx,next) => {
var name = ctx.request.body.use || '';
var password = ctx.request.body.pwd ||'';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'riven' && password ==='123456') {
ctx.response.body = `<h1> Welcome,${name}!<h1>`
} else {
ctx.response.body = `<h1>Login failed!<h1>
<p><a href='/'>Try agein</a></p>
`
}
}
module.exports = {
'GET /': fn_login,
'POST /mark': fn_login_post
};
Controller Middleware
最后,我们把扫描controllers目录和创建router的代码从app.js中提取出来,作为一个简单的middleware使用,命名为controller.js:
这样一来,我们在app.js的代码又简化了: ... // 导入controller middleware:
const controller = require('./controller'); ... // 使用middleware:
app.use(controller());
经过重新整理后的工程url2-koa目前具备非常好的模块化,所有处理URL的函数按功能组存放在controllers目录,今后我们也只需要不断往这个目录下加东西就可以了,app.js保持不变。

login.js 页面
var fn_login = async (ctx, next)=> {
ctx.response.body = `
<form action="/mark" method="POST">
<input type="text" name="use" value="riven">
<input type="password" name="pwd">
<input type="submit" >
</form>
`
}
var fn_login_post = async (ctx,next) => {
var name = ctx.request.body.use || '';
var password = ctx.request.body.pwd ||'';
console.log(`signin with name: ${name}, password: ${password}`);
if (name === 'riven' && password ==='123456') {
ctx.response.body = `<h1> Welcome,${name}!<h1>`
} else {
ctx.response.body = `<h1>Login failed!<h1>
<p><a href='/'>Try agein</a></p>
`
}
}
module.exports = {
'GET /': fn_login,
'POST /mark': fn_login_post
};
controllers.js
// 先导入fs模块,然后用readdirSync列出文件
var fs = require('fs'); // 读取文件 处理路径
function fileControllers(router,dir){
// 这里可以用sync是因为启动时只运行一次,不存在性能问题:
// __dirname === 当前根目录名
// fs.readdirSync 读出文件夹中的文件
var files = fs.readdirSync(__dirname + `/${dir}`); // 过滤出.js文件: [ 'hello.js', 'index.js', 'login.js' ]
var js_files = files.filter((f)=>{
return f.endsWith('.js');
}); // 处理每个js文件:
for (var f of js_files) {
// console.log(`process controller: ${f}...`);
// 导入js文件: 当前目录controllers+当前循环文件 { 'GET /hello/:name': [AsyncFunction: fn_hello] }
let mapping = require(__dirname + `/${dir}/` + f)
requestControllers(router,mapping) }
} // 处理request请求
function requestControllers(router, mapping){
for (var url in mapping) {//GET /hello/:name GET / POST /signin
// 如果url以"GET xxx"开头:
if (url.startsWith('GET ')) {
var path = url.substring(4); // 去除字符串前面的4个字符。 GET /(这四个)
//取到路径 path == /hello/:name, mapping[url] == [AsyncFunction: fn_hello]
router.get(path, mapping[url])
console.log(`register URL mapping: GET ${path}`);
} else if (url.startsWith(`POST`)){ //处理post请求
// 去除前面的post加一个空格 POST
var path = url.substring(5);
router.post(path,mapping[url]);
console.log(`register URL mapping: POST ${path}`)
} else {
// 无效的的url
console.log(`invalid URL: ${url}`)
}
}
} module.exports = function (dir){
let
controllers_dir = dir || `controllers` // 如果不传参数,扫描目录默认为'controllers'
// 注意require('koa-router')返回的是函数:koa-router的语句最后的()是函数调用:
const router = require('koa-router')();
fileControllers(router, controllers_dir)
return router.routes() };
app.js
// 导入koa,和koa 1.x不同,在koa2中,我们导入的是一个class,因此用大写的Koa表示:
const Koa = require('koa'); // 创建一个Koa对象表示web app本身:
const app = new Koa(); // 创建提供解析request的body的功能
const bodyParser = require('koa-bodyparser'); // 导入controller middleware:
const controller = require('./controller') // add middlware 这个要放前面
app.use(bodyParser()); // 使用middleware: app.use(router.routes())
app.use(controller()); app.listen(3000)
console.log('app started at port 3000...');
经过重新整理后的工程url2-koa目前具备非常好的模块化,所有处理URL的函数按功能组存放在controllers目录,今后我们也只需要不断往这个目录下加东西就可以了,app.js保持不变。

koa web框架入门的更多相关文章
- 教程:Visual Studio 中的 Django Web 框架入门
教程:Visual Studio 中的 Django Web 框架入门 Django 是高级 Python 框架,用于快速.安全及可扩展的 Web 开发. 本教程将在 Visual Studio 提供 ...
- Python Flask Web 框架入门
Python Flask 目录 本文主要借鉴 letiantian 的文章 http://www.letiantian.me/learn-flask/ 一.简介 二.安装 三.初始化Flask 四.获 ...
- 比我的脸还干的gan货——Python Flask Web 框架入门
Flask是一个轻量级的基于Python的web框架. 本文适合有一定HTML.Python.网络基础的同学阅读. 1. 简介 这份文档中的代码使用 Python 3 运行.是的,所以读者需要自己在电 ...
- Django Web框架入门
一.Django介绍 Django是一个开放源代码的Web应用框架,由Python写成,采用了MVC的框架模式.Django的主要目的是简便.快速的开发数据库驱动的网站.它强调代码复用,多个组件可以很 ...
- Express NodeJs Web框架 入门笔记
Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速地搭建一个完整功能的网 ...
- 最快的 Python Web 框架入门
速度比较 框架 实现基础 每秒请求数 平均时间 Sanic Python 3.5 + uvloop 30,601 3.23ms Wheezy gunicorn + meinheld 20,244 4. ...
- Koa – 更加强大的下一代 Node.js Web 框架
Koa 是 Express 的开发团队设计的下一代 Web 框架,其目的是为 Web 应用程序提供更小,更具表现力,更坚实的基础.Koa 没有核捆绑任何中间件,并提供了一套优雅的方法,使服务器端开 ...
- koa : Express出品的下一代基于Node.js的web框架
https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434501579966a ...
- 新一代web框架Koa源码学习
此文已由作者张佃鹏授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Koa 就是一种简单好用的 Web 框架.它的特点是优雅.简洁.表达力强.自由度高.本身代码只有1000多行 ...
- 参考KOA,5步手写一款粗糙的web框架
我经常在网上看到类似于KOA VS express的文章,大家都在讨论哪一个好,哪一个更好.作为小白,我真心看不出他两who更胜一筹.我只知道,我只会跟着官方文档的start做一个DEMO,然后我就会 ...
随机推荐
- js前端去除HTML标签返回纯字符串正则/<[^>]*>/g
点击查看代码 let stra = `<p>公告:我们于2024年5月3日下午13:00下架本小程序,请您搜索"好故事"进行观看,您的会员和书豆不会受到影响.感谢您的理 ...
- Unicode 14 标准发布
本文为翻译,原文地址Unicode 博客: 宣布 Unicode 标准, 版本 14.0 Unicode 标准版本 14.0 现已可用,包括核心规范.附件和数据文件.此版本增加了 838 个字符,总共 ...
- [chatGPT]unity中,我希望一个角色有一个链表能获取到场上所有“creature”的transform,当creature增加或减少时刷新这个链表,我该怎么做?
关键字:unity游戏对象管理,unity,unity实例管理,unity触发方法 我 unity中,我希望一个角色有一个链表能获取到场上所有"creature"的transfor ...
- vue xlsx组件 导出的excel表头插入内容
主要就是sheet_add_dom这个方法, dom是带有table标签元素的dom节点. timeData是个二维数组:[["条件1","条件2"],[&qu ...
- wpf 空间坐标系下,画一个立方体轮廓
代码: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Worignpt ...
- 007. gitlab仓库管理
1. gitlab创建组 创建后: 组管理: 组创建完成后,开始创建用户 2. gtilab创建用户 这里无法直接创建密码,需要创建用户后在对用户进行操作修改密码 密码和权限设置,取消和开启创建组权限 ...
- 【论文笔记】AlexNet
[深度学习]总目录 由于受到计算机性能的影响,虽然LeNet在图像分类中取得了较好的成绩,但是并没有引起很多的关注. 直到2012年,Alex等人提出的AlexNet网络在ImageNet大赛上以远超 ...
- 「C++」论高精度
大家好,我是Charzie.在编程领域,高精度计算是一个常见的问题.当标准的整型或浮点型无法满足我们的计算需求时,高精度计算就显得尤为重要.在C++中,虽然标准库没有直接提供高精度数据类型,但我们可以 ...
- 『手撕Vue-CLI』拷贝模板
开篇 经过上篇文章的介绍,实现了可以根据用户选择的模板名称加上对应的版本号,可以下载对应的模板,并且将下载之后的文件存放在用户目录下的 .nue-template文件夹中. 接下来这篇文章主要实现内容 ...
- springboot项目中一些小技巧
一.使用命令创建maven工程 1.例如我们想在IDEA的工作空间目录下E:\Gitee\springboot,创建maven项目,首先先进入该目录下 2.去掉原来的目录,输入cmd,然后回车,进入命 ...