一、基本的配置
在
eggjs
中上传文件的官方文档
-
1、配置上传的路由
module.exports = (app) => { const { router, controller } = app; router.resources('file', '/api/v1/file', controller.file); };
-
2、在
config/config.default.js
中配置上传的基本配置(可以参考官方文档)... // 配置上传 config.multipart = { fileSize: '50mb', mode: 'stream', fileExtensions: ['.xls', '.txt'], // 扩展几种上传的文件格式 }; ...
-
3、安装几个基本的包
npm install await-stream-ready stream-wormhole dayjs
二、使用form
表单上传
-
1、模板的代码
<form method="POST" action="/api/v1/file" enctype="multipart/form-data"> title: <input name="title" /> file: <input name="file" type="file" /> <button type="submit">Upload</button> </form>
- 2、在控制器中使用
fs
及数据流写入文件(在控制器层)
async create() {
// 获取文件流
const stream = await this.ctx.getFileStream();
// 定义文件名
const filename = Date.now() + path.extname(stream.filename).toLocaleLowerCase();
// 目标文件
const target = path.join('app/public/uploads', filename);
//
const writeStream = fs.createWriteStream(target);
console.log('-----------获取表单中其它数据 start--------------');
console.log(stream.fields);
console.log('-----------获取表单中其它数据 end--------------');
try {
//异步把文件流 写入
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
//如果出现错误,关闭管道
await sendToWormhole(stream);
// 自定义方法
this.error(err);
}
// 自定义方法
this.success({ url: '/public/uploads/' + filename });
}
- 3、可以将生成的
url
地址传递服务层,存到数据库中
三、使用ajax
上传文件
-
1、基本的
html
页面<h1>ajax提交</h1> <input type="text" id="username" /> <input name="file" type="file" id="file" /> <button id="btn">提交</button>
-
2、
jq
的ajax
<script> $('#btn').on('click', function() { console.log('提交按钮'); let formData = new FormData(); formData.append('title', $('#username').val()); formData.append('image', $('#file')[0].files[0]); console.log(formData); $.ajax({ url: '/api/v1/file', data: formData, method: 'post', contentType: false, processData: false, success: function(result) { console.log(result); }, }); }); </script>
四、对上传的文件根据时间分类归档
-
1、修改上传代码的控制器
const fs = require('fs'); const path = require('path'); //故名思意 异步二进制 写入流 const awaitWriteStream = require('await-stream-ready').write; //管道读入一个虫洞。 const sendToWormhole = require('stream-wormhole'); const dayjs = require('dayjs'); async create() { const stream = await this.ctx.getFileStream(); console.log('-----------获取数据 start--------------'); console.log(stream.fields); console.log('-----------获取数据 end--------------'); // 基础的目录 const uplaodBasePath = 'app/public/uploads'; // 生成文件名 const filename = `${Date.now()}${Number.parseInt( Math.random() * 1000, )}${path.extname(stream.filename).toLocaleLowerCase()}`; // 生成文件夹 const dirname = dayjs(Date.now()).format('YYYY/MM/DD'); function mkdirsSync(dirname) { if (fs.existsSync(dirname)) { return true; } else { if (mkdirsSync(path.dirname(dirname))) { fs.mkdirSync(dirname); return true; } } } mkdirsSync(path.join(uplaodBasePath, dirname)); // 生成写入路径 const target = path.join(uplaodBasePath, dirname, filename); // 写入流 const writeStream = fs.createWriteStream(target); try { //异步把文件流 写入 await awaitWriteStream(stream.pipe(writeStream)); } catch (err) { //如果出现错误,关闭管道 await sendToWormhole(stream); this.error(); } this.success({ url: path.join('/public/uploads', dirname, filename) }); }
-
2、其它的都不变
-
3、上传生成的目录
2019 └── 06 └── 21 ├── 1561097630832563.png └── 1561097675536863.jpeg
五、提取到基类的控制器中并且进行传递参数分类
-
1、在基类的控制器中
const { Controller } = require('egg'); const fs = require('fs'); const path = require('path'); //故名思意 异步二进制 写入流 const awaitWriteStream = require('await-stream-ready').write; //管道读入一个虫洞。 const sendToWormhole = require('stream-wormhole'); const dayjs = require('dayjs'); class BaseController extends Controller { // 上传文件的通用方法 async uploadFile(category = '') { const stream = await this.ctx.getFileStream(); // 基础的目录 const uplaodBasePath = 'app/public/uploads'; // 生成文件名 const filename = `${Date.now()}${Number.parseInt( Math.random() * 1000, )}${path.extname(stream.filename).toLocaleLowerCase()}`; // 生成文件夹 const dirname = dayjs(Date.now()).format('YYYY/MM/DD'); function mkdirsSync(dirname) { if (fs.existsSync(dirname)) { return true; } else { if (mkdirsSync(path.dirname(dirname))) { fs.mkdirSync(dirname); return true; } } } mkdirsSync(path.join(uplaodBasePath, category, dirname)); // 生成写入路径 const target = path.join(uplaodBasePath, category, dirname, filename); // 写入流 const writeStream = fs.createWriteStream(target); try { //异步把文件流 写入 await awaitWriteStream(stream.pipe(writeStream)); } catch (err) { //如果出现错误,关闭管道 await sendToWormhole(stream); return { error: '错误', }; } return { url: path.join('/public/uploads', category, dirname, filename), fields: stream.fields, }; } } module.exports = BaseController;
-
2、在上传文件的控制器中使用
const Controller = require('./../core/base_controller'); class FileController extends Controller { async create() { // 上传头像的,会在uploads文件夹下有个avatar的文件夹下面才是2019、06、21 const { url, fields } = await this.uploadFile('avatar'); const result = await 服务层; this.success(url); } }
- 3、其它的都不变