建立專案
執行命令
cnpm i egg-init -g
egg-init egg01 --type=simple
cd egg01
cnpm install
npm run dev
複製程式碼
終端效果
配置路由,模板,資料庫,中介軟體
路由
app\router.js
router.get('/', controller.user.index);
router.get('/add', controller.user.add);
router.get('/edit', controller.user.edit);
router.post('/doAdd', controller.user.doAdd);
複製程式碼
模板
安裝依賴egg-view-ejs
cnpm install egg-view-ejs --save
複製程式碼
配置模板
config\plugin.js
exports.ejs = {
enable: true,
package: 'egg-view-ejs',
};
複製程式碼
config\config.default.js
config.view = {
mapping: {
'.html': 'ejs',
},
};
複製程式碼
配置資料庫
安裝依賴egg-mongoose
cnpm install egg-mongoose --save
複製程式碼
配置資料庫
config\plugin.js
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
複製程式碼
config\config.default.js
config.mongoose = {
client: {
url: 'mongodb://egg01:123456@127.0.0.1/egg01',
options: {},
},
};
複製程式碼
資料庫對映
app\model\user.js
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: {
type: String,
},
password: {
type: String,
},
avator: {
type: String,
},
});
return mongoose.model('User', UserSchema, 'user');
};
複製程式碼
中介軟體csrf
安全驗證
app\middleware\auth.js
module.exports = (options, app) => {
return async function auth(ctx, next) {
ctx.state.csrf = ctx.csrf;
await next();
};
}
;
複製程式碼
config\config.default.js
config.middleware = [ 'auth' ];
複製程式碼
單檔案上傳
缺陷
圖片必須放在表單的最後面,並且圖片可能會丟失
view
程式碼
app\view\user\add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div>csrf:
<%= csrf %>
</div>
<form action="/doAdd?_csrf=<%=csrf%>" method="post" enctype="multipart/form-data">
<div>
<label>
<span>賬號</span>
<input type="text" name="username">
</label>
</div>
<div>
<label>
<span>密碼</span>
<input type="text" name="password">
</label>
</div>
<div>
<label>
<span>頭像</span>
<input type="file" name="avator">
</label>
</div>
<button type="submit">確定</button>
</form>
</body>
</html>
複製程式碼
效果
controller
app\controller\user.js
'use strict';
const Controller = require('egg').Controller;
const fs = require('fs');
const path = require('path');
const pump = require('mz-modules/pump');
class HomeController extends Controller {
async add() {
await this.ctx.render('user/add');
}
async doAdd() {
const stream = await this.ctx.getFileStream(); // 獲取表單提交的資料
if (!stream.filename) { // 注意如果沒有傳入圖片直接返回
return;
}
// 圖片上傳到靜態資料夾
let target = 'app/public/upload/' + path.basename(stream.filename); // "filename":"c:/images/291051166-5b20eca6448e8_articlex.png", path.basename => 291051166-5b20eca6448e8_articlex.png
const writeStream = fs.createWriteStream(target);
await pump(stream, writeStream); // stream.pipe(writeStream); //可以用, 但是不建議,因為不能處理失敗的情況
// 存入資料庫
target = target.slice(3);
const newUser = Object.assign(stream.fields, {
avator: target,
});
await this.ctx.service.user.doAdd(newUser);
// 跳轉
this.ctx.redirect('/');
}
}
module.exports = HomeController;
複製程式碼
service
app\service\user.js
'use strict';
const Service = require('egg').Service;
class UserService extends Service {
async doAdd(user) {
const newUser = new this.ctx.model.User(user);
newUser.save();
}
}
module.exports = UserService;
複製程式碼
上傳效果
表單
上傳後返回給前端
儲存到專案後臺靜態資料夾
多檔案上傳
view
把上傳按鈕悠為<input type="file" multiple="multiple" name="avator">
,檔案上傳變為多選
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div>csrf:
<%= csrf %>
</div>
<form action="/doAdd?_csrf=<%=csrf%>" method="post" enctype="multipart/form-data">
<div>
<label>
<span>賬號</span>
<input type="text" name="username">
</label>
</div>
<div>
<label>
<span>密碼</span>
<input type="text" name="password">
</label>
</div>
<div>
<label>
<span>頭像</span>
<input type="file" multiple="multiple" name="avator">
</label>
</div>
<button type="submit">確定</button>
</form>
</body>
</html>
複製程式碼
controller
async doAdd() {
// { autoFields: true }:可以將除了檔案的其它欄位提取到 parts 的 filed 中
// 多個圖片/檔案
const parts = this.ctx.multipart({
autoFields: true,
});
const files = [];
let stream;
while ((stream = await parts()) != null) {
if (!stream.filename) { // 注意如果沒有傳入圖片直接返回
return;
}
const fieldname = stream.fieldname; // file表單的名字 face
const target = 'app/public/upload/' + path.basename(stream.filename);
const writeStream = fs.createWriteStream(target);
await pump(stream, writeStream); // 寫入並銷燬當前流 (egg demo提供的)
files.push({
[fieldname]: target, // es6裡面的屬性名錶達式
});
}
const avator = files[0].avator.slice(3); //只選第一張圖片
const newUser = Object.assign(parts.field, {
avator,
});
await this.ctx.service.user.doAdd(newUser);
// 跳轉
this.ctx.redirect('/');
}
複製程式碼