On this page
上传文件
插件 egg-oss
安装
shell
npm i egg-oss --save
文档
https://www.npmjs.com/package/egg-oss
配置
config/plugin.js
js
oss: {
enable: true,
package: 'egg-oss',
}
配置:config/config.default.js
js
config.oss = {
client: {
accessKeyId: "LTAI4DS1yG3E9z3dGijcqEvv",
accessKeySecret: "cwFVsXF5S5n75a8NZIz0IS2EO5pqvl",
bucket: "demo-mp3",
endpoint: "oss-cn-shenzhen.aliyuncs.com",
timeout: "60s",
},
};
// 上传格式和大小限制
config.multipart = {
// fileSize: '50mb',
fileSize: 1048576000,
// mode: 'stream',
mode: "file",
fileExtensions: [
// images
".jpg",
".jpeg", // image/jpeg
".png", // image/png, image/x-png
".gif", // image/gif
".bmp", // image/bmp
".wbmp", // image/vnd.wap.wbmp
".webp",
".tif",
".psd",
// text
".svg",
".js",
".jsx",
".json",
".css",
".less",
".html",
".htm",
".xml",
// tar
".zip",
".gz",
".tgz",
".gzip",
// video
".mp3",
".mp4",
".avi",
],
};
创建数据迁移表
shell
npx sequelize migration:generate --name=file
1.执行完命令后,会在database / migrations / 目录下生成数据表迁移文件,然后定义
js
"use strict";
module.exports = {
up: (queryInterface, Sequelize) => {
const { INTEGER, STRING, DATE, ENUM, TEXT } = Sequelize;
return queryInterface.createTable("file", {
id: {
type: INTEGER(20),
primaryKey: true,
autoIncrement: true,
},
name: {
type: STRING(100),
allowNull: false,
defaultValue: "",
comment: "文件名",
},
ext: {
type: STRING(50),
allowNull: true,
defaultValue: "",
comment: "文件扩展名",
},
md: {
type: STRING,
allowNull: true,
defaultValue: "",
comment: "文件MD5",
},
file_id: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "父级id",
},
user_id: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "用户id",
references: {
model: "user",
key: "id",
},
onDelete: "cascade",
onUpdate: "restrict", // 更新时操作
},
size: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "文件大小",
},
url: {
type: STRING,
allowNull: true,
defaultValue: "",
comment: "图片真实url",
},
isdir: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "是否为文件夹",
},
created_time: DATE,
updated_time: DATE,
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable("file");
},
};
- 执行 migrate 进行数据库变更
shell
npx sequelize db:migrate
模型创建
js
// app/model/file.js
module.exports = (app) => {
const { STRING, INTEGER, DATE, ENUM, TEXT } = app.Sequelize;
const File = app.model.define("file", {
id: {
type: INTEGER(20),
primaryKey: true,
autoIncrement: true,
},
name: {
type: STRING(100),
allowNull: false,
defaultValue: "",
comment: "文件名",
},
ext: {
type: STRING(50),
allowNull: true,
defaultValue: "",
comment: "文件扩展名",
},
md: {
type: STRING,
allowNull: true,
defaultValue: "",
comment: "文件MD5",
},
file_id: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "父级id",
},
user_id: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "用户id",
references: {
model: "user",
key: "id",
},
onDelete: "cascade",
onUpdate: "restrict", // 更新时操作
},
size: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "文件大小",
},
url: {
type: STRING,
allowNull: true,
defaultValue: "",
comment: "图片真实url",
},
isdir: {
type: INTEGER,
allowNull: false,
defaultValue: 0,
comment: "是否为文件夹",
},
created_time: DATE,
updated_time: DATE,
});
// 删除后
File.afterBulkDestroy(async (data, option) => {
console.log("删除后", data.where);
let files = await app.model.File.findAll({
where: {
file_id: data.where.id,
user_id: data.where.user_id,
isdir: 1,
},
});
let ids = files.map((item) => item.id);
if (ids.length > 0) {
app.model.File.destroy({
where: {
id: ids,
user_id: data.where.user_id,
},
});
}
});
return File;
};
控制器:app/controller/file.js
js
// 引入
const fs = require('fs');
const path = require('path');
// 上传
async upload() {
const { ctx, app } = this;
const currentUser = ctx.authUser;
if (!ctx.request.files) {
return ctx.apiFail('请先选择上传文件');
}
ctx.validate({
file_id: {
type: "int",
required: true,
defValue: 0,
desc: 'file_id'
},
});
const file_id = ctx.query.file_id;
// 文件id是否存在
if (file_id > 0) {
// 目录是否存在
await this.service.file.isDirExist(file_id);
}
const file = ctx.request.files[0];
const name = 'egg-oss-demo/' + ctx.genID(10) + path.extname(file.filename);
// 验证用户剩余内存是否满足要求
let s = await (new Promise((resolve, reject) => {
fs.stat(file.filepath, (err, stats) => {
resolve((stats.size / 1024).toFixed(1));
});
}));
if ((currentUser.total_size - currentUser.used_size) < s) {
return ctx.apiFail('你的可用内存不足');
}
let result;
try {
result = await ctx.oss.put(name, file.filepath);
} catch (err) {
console.log(err);
}
if (result) {
// 写入数据表
let addData = {
name: file.filename,
ext: file.mimeType,
md: result.name,
file_id,
user_id: currentUser.id,
size: parseInt(s),
isdir: 0,
url: result.url
};
if (file_id > 0) {
addData.file_id = file_id;
}
let res = await app.model.File.create(addData);
// 更新user表的使用内存
currentUser.used_size = currentUser.used_size + parseInt(s);
currentUser.save();
return ctx.apiSuccess(res);
}
ctx.apiFail('上传失败');
}
服务:app/service/file.js
js
// 目录是否存在
async isDirExist(id) {
let f = await this.app.model.File.findOne({
where: {
id,
// 当前用户id
user_id: this.ctx.authUser.id,
isdir: 1
}
});
if (!f) {
return this.ctx.throw(404, '目录不存在');
}
return f
}
扩展:app/extend/context.js
js
// 生成唯一id
genID(length) {
return Number(Math.random().toString().substr(3, length) + Date.now()).toString(36);
}
路由:app/router.js
js
router.post("/upload", controller.file.upload);