Egg.js中实现单文件上传、多文件上传、按照日期存储

这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战

上传功能的实现

  1. 将上传表单的类型置为file.

注意:name属性不可缺少。

<li>菜品图片:<input type="file" name="picUrl" /></li>
复制代码
  1. 配置文件上传的模式
  // 配置文件上传的模式
  config.multipart = {
    mode: 'file'
  };
复制代码
  1. 配置csrf属性

enctype属性不可缺少。

 <form action="/<%=adminPath%>/product/doAdd?_csrf=<%=csrf%>" method="post" enctype="multipart/form-data">
复制代码
  1. 将路由设置为post
router.post(`/${config.adminPath}/product/doAdd`,controller.admin.product.doAdd);
复制代码
  1. 控制器中读取file
  async doAdd() {
    const {ctx} = this;
    const body = ctx.request.body;
    const file = ctx.request.files[0];
    ctx.body = {
      body: body,
      file: file
    }
  }
复制代码

将上传的文件保存在指定的位置

  1. 安装工具包
npm i mz mz-modules --save
复制代码
  1. 在控制器中引入相关工具包
const path = require('path');
const fs = require('mz/fs');
const pump = require('mz-modules/pump');
复制代码
  1. 创建上传到哪个文件夹,这个文件夹要提前创建好(public/upload)

image.png

  1. 控制器读写逻辑的实现
async doAdd() {
    const {ctx} = this;
    const body = ctx.request.body;
    const file = ctx.request.files[0];
    // 获取文件名称
    const filename = file.filename;
    const targetPath = path.join('app/public/upload',filename);
    // 读取文件
    const source = fs.createReadStream(file.filepath);
    // 创建写入流
    const target = fs.createWriteStream(targetPath);
    try {
      await pump(source,target);
    } finally {
      await ctx.cleanupRequestFiles();
    }
    ctx.body = "写入成功"
  }
复制代码

实现多文件上传

  1. 静态页面设置如下所示:

image.png

  1. 控制器的核心实现逻辑
  // 实现多文件上传
  async doAdd() {
    const { ctx } = this;
    const body = ctx.request.body;
    const files = ctx.request.files;
    try {
      for (let file of files) {
        const filename = file.filename;
        const targetPath = path.join('app/public/upload', filename);
        // 读取文件
        const source = fs.createReadStream(file.filepath);
        // 创建写入流
        const target = fs.createWriteStream(targetPath);
        await pump(source,target);
      }
    } finally {
      await ctx.cleanupRequestFiles();
    }
    ctx.body = {
      body, files
    }
  }
复制代码

以日期文件夹进行分类上传图片

下面是实现的效果:

image.png

  1. 在service中引入相关工具包
const sd = require('silly-datetime');
const path = require('path');
const mkdirp = require('mz-modules/mkdirp');
复制代码
  1. 在配置文件中定义上传的路径
  // 配置上传图片时的拼接路径
  config.uploadDir = "app/public/upload";
复制代码
  1. 在service中定义创建路径和文件夹的函数
  async getUploadFile(filename) {
    // 获取当前的日期
    let day = sd.format(new Date(),'YYYYMMDD');
    // 创建图片的保存路径
    let dir = path.join(this.config.uploadDir,day);
    await mkdirp(dir);

    // 生成文件名称
    let unix = this.getUnixTime();
    let saveDir = path.join(dir,unix + path.extname(filename));
    return saveDir;
  }
复制代码
  1. 在控制器中异步调用文件路径
const targetPath = await this.ctx.service.tools.getUploadFile(filename);
复制代码

下面附录下全部的控制器代码

async doAdd() {
    const { ctx } = this;
    const body = ctx.request.body;
    const files = ctx.request.files;
    try {
      for (let file of files) {
        const filename = file.filename;
        // const targetPath = path.join('app/public/upload', filename);
        const targetPath = await this.ctx.service.tools.getUploadFile(filename);
        // 读取文件
        const source = fs.createReadStream(file.filepath);
        // 创建写入流
        const target = fs.createWriteStream(targetPath);
        await pump(source,target);
      }
    } finally {
      await ctx.cleanupRequestFiles();
    }
    ctx.body = {
      body, files
    }
  }
复制代码

Guess you like

Origin juejin.im/post/7032801049362579487