Nest.js 文件上传之动态自定义文件保存路径、文件名称、文件过滤

5,113 阅读1分钟

上一章:Nest.js 文件上传及自定义文件名保存

上一章只讲了怎么动态设置上传的文件名称,本章进行扩展,主要实现如题功能。 不多说,直接上代码:

// file.module.ts
import { Module, BadRequestException } from '@nestjs/common';
import { MulterModule } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import * as dayjs from 'dayjs';
import * as nuid from 'nuid';
import { FileController } from './file.controller';
import { FileService } from './file.service';
import { checkDirAndCreate } from '../../utils/utils'
const image = ['gif', 'png', 'jpg', 'jpeg', 'bmp', 'webp'];
const video = ['mp4', 'webm'];
const audio = ['mp3', 'wav', 'ogg'];

@Module({
  imports: [
    MulterModule.register({
      storage: diskStorage({
        // 配置文件上传后的文件夹路径
        destination: (req, file, cb) => {
          // 根据上传的文件类型将图片视频音频和其他类型文件分别存到对应英文文件夹
          const mimeType = file.mimetype.split('/')[1];
          let temp = 'other';
          image.filter(item => item === mimeType).length > 0
            ? (temp = 'image')
            : '';
          video.filter(item => item === mimeType).length > 0
            ? (temp = 'video')
            : '';
          audio.filter(item => item === mimeType).length > 0
            ? (temp = 'audio')
            : '';
          const filePath = `public/uploads/${temp}/${dayjs().format(
            'YYYY-MM-DD',
          )}`;
          checkDirAndCreate(filePath); // 判断文件夹是否存在,不存在则自动生成
          return cb(null, `./${filePath}`);
        },
        filename: (req, file, cb) => {
          // 在此处自定义保存后的文件名称
          const fileType = file.originalname.split('.');
          const filename = `${nuid.next()}.${fileType[fileType.length - 1]}`;
          return cb(null, filename);
        },
      }), 
      fileFilter(req, file, cb) {
        const mimeType = file.mimetype.split('/')[1].toLowerCase();
        let temp = 'other';
        image.filter(item => item === mimeType).length > 0
          ? (temp = 'image')
          : '';
        video.filter(item => item === mimeType).length > 0
          ? (temp = 'video')
          : '';
        audio.filter(item => item === mimeType).length > 0
          ? (temp = 'audio')
          : '';
        if (temp === 'other') {
          return cb(new BadRequestException('文件格式错误!'), false);
        }
        return cb(null, true);
      },
    })
  ],
  controllers: [FileController],
  providers: [FileService]
})
export class FileModule {}

附上函数代码:checkDirAndCreate()

// src/utils/utils.ts
import * as fs from 'fs';

export const checkDirAndCreate = filePath => {
  const pathArr = filePath.split('/');
  let checkPath = '.';
  let item: string;
  for (item of pathArr) {
    checkPath += `/${item}`;
    if (!fs.existsSync(checkPath)) {
      fs.mkdirSync(checkPath);
    }
  }
};

// file.controller.ts
import { Controller, Post, UploadedFile, UseInterceptors } from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';

@Controller('file')
export class FileController {

  @Post('upload')
  @UseInterceptors(FileInterceptor('file'))
  uploadFile(@UploadedFile() file): any {
    file.path = file.path.replace(/\\/g, '/'); // 转换正反斜线,转换结果如: `"path": "public/uploads/image/2020-04-08/V0QYQ0VN3GH6ASHXCGC901.jpg",`
    return file
  }
}

文件结果效果如下图中的 public 效果图