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函数,并传入ctxnext参数。

我们可以对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.urlctx.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框架入门的更多相关文章

  1. 教程:Visual Studio 中的 Django Web 框架入门

    教程:Visual Studio 中的 Django Web 框架入门 Django 是高级 Python 框架,用于快速.安全及可扩展的 Web 开发. 本教程将在 Visual Studio 提供 ...

  2. Python Flask Web 框架入门

    Python Flask 目录 本文主要借鉴 letiantian 的文章 http://www.letiantian.me/learn-flask/ 一.简介 二.安装 三.初始化Flask 四.获 ...

  3. 比我的脸还干的gan货——Python Flask Web 框架入门

    Flask是一个轻量级的基于Python的web框架. 本文适合有一定HTML.Python.网络基础的同学阅读. 1. 简介 这份文档中的代码使用 Python 3 运行.是的,所以读者需要自己在电 ...

  4. Django Web框架入门

    一.Django介绍 Django是一个开放源代码的Web应用框架,由Python写成,采用了MVC的框架模式.Django的主要目的是简便.快速的开发数据库驱动的网站.它强调代码复用,多个组件可以很 ...

  5. Express NodeJs Web框架 入门笔记

    Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速地搭建一个完整功能的网 ...

  6. 最快的 Python Web 框架入门

    速度比较 框架 实现基础 每秒请求数 平均时间 Sanic Python 3.5 + uvloop 30,601 3.23ms Wheezy gunicorn + meinheld 20,244 4. ...

  7. Koa – 更加强大的下一代 Node.js Web 框架

    Koa 是 Express 的开发团队设计的下一代 Web 框架,其目的是为 Web 应用程序提供更小,更具表现力,更坚实的基础.Koa 没有核捆绑任何中间件,并提供了一​​套优雅的方法,使服务器端开 ...

  8. koa : Express出品的下一代基于Node.js的web框架

    https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434501579966a ...

  9. 新一代web框架Koa源码学习

    此文已由作者张佃鹏授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Koa 就是一种简单好用的 Web 框架.它的特点是优雅.简洁.表达力强.自由度高.本身代码只有1000多行 ...

  10. 参考KOA,5步手写一款粗糙的web框架

    我经常在网上看到类似于KOA VS express的文章,大家都在讨论哪一个好,哪一个更好.作为小白,我真心看不出他两who更胜一筹.我只知道,我只会跟着官方文档的start做一个DEMO,然后我就会 ...

随机推荐

  1. js前端去除HTML标签返回纯字符串正则/<[^>]*>/g

    点击查看代码 let stra = `<p>公告:我们于2024年5月3日下午13:00下架本小程序,请您搜索"好故事"进行观看,您的会员和书豆不会受到影响.感谢您的理 ...

  2. Unicode 14 标准发布

    本文为翻译,原文地址Unicode 博客: 宣布 Unicode 标准, 版本 14.0 Unicode 标准版本 14.0 现已可用,包括核心规范.附件和数据文件.此版本增加了 838 个字符,总共 ...

  3. [chatGPT]unity中,我希望一个角色有一个链表能获取到场上所有“creature”的transform,当creature增加或减少时刷新这个链表,我该怎么做?

    关键字:unity游戏对象管理,unity,unity实例管理,unity触发方法 我 unity中,我希望一个角色有一个链表能获取到场上所有"creature"的transfor ...

  4. vue xlsx组件 导出的excel表头插入内容

    主要就是sheet_add_dom这个方法, dom是带有table标签元素的dom节点. timeData是个二维数组:[["条件1","条件2"],[&qu ...

  5. wpf 空间坐标系下,画一个立方体轮廓

    代码: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Worignpt ...

  6. 007. gitlab仓库管理

    1. gitlab创建组 创建后: 组管理: 组创建完成后,开始创建用户 2. gtilab创建用户 这里无法直接创建密码,需要创建用户后在对用户进行操作修改密码 密码和权限设置,取消和开启创建组权限 ...

  7. 【论文笔记】AlexNet

    [深度学习]总目录 由于受到计算机性能的影响,虽然LeNet在图像分类中取得了较好的成绩,但是并没有引起很多的关注. 直到2012年,Alex等人提出的AlexNet网络在ImageNet大赛上以远超 ...

  8. 「C++」论高精度

    大家好,我是Charzie.在编程领域,高精度计算是一个常见的问题.当标准的整型或浮点型无法满足我们的计算需求时,高精度计算就显得尤为重要.在C++中,虽然标准库没有直接提供高精度数据类型,但我们可以 ...

  9. 『手撕Vue-CLI』拷贝模板

    开篇 经过上篇文章的介绍,实现了可以根据用户选择的模板名称加上对应的版本号,可以下载对应的模板,并且将下载之后的文件存放在用户目录下的 .nue-template文件夹中. 接下来这篇文章主要实现内容 ...

  10. springboot项目中一些小技巧

    一.使用命令创建maven工程 1.例如我们想在IDEA的工作空间目录下E:\Gitee\springboot,创建maven项目,首先先进入该目录下 2.去掉原来的目录,输入cmd,然后回车,进入命 ...