[NestJS] 파일 업로드, 다운로드

jm4293·2024년 1월 6일
0

파일 업로드

  • Express의 파일 업로드 모듈을 사용할 것이다.
  • Multer는 요청과 핸들러 사이에서 파일을 처리해주는 미들웨어이다.
  • 이미 Multer는 기본적으로 설치되어있지만 NestJS는 타입스크립트로 동작하기 때문에 @types을 설치하자
  • npm i -D @types/multer

파일 2개 받아보기

  • board.controller.ts
  @Post('/uploads/multi')
  @UseInterceptors(
    FileFieldsInterceptor([
      { name: 'file1', maxCount: 1 },
      { name: 'file2', maxCount: 1 },
    ]),
  )
  uploadMultiFile(
    @UploadedFiles() files: { file1: Express.Multer.File; file2: Express.Multer.File },
  ) {
    console.log(files.file1[0], files.file2[0])
  }
  • UseInterceptors 데코레이터에 FileFieldsInterceptor 추가하여 파일을 한 개가아닌 여러개를 받을 수 있게 선언
  • 하지만 리스트의 갯수를 2개만 하였기때문에 2개만 받을 수 있는 상황이다.
  • 일단 컨트롤러에서 파일을 받을 수 있는지만 확인

받을 파일을 서버에 저장하기

  • board.controller.ts
  @Post('/uploads/multi')
  @UseInterceptors(
    FileFieldsInterceptor([
      { name: 'file1', maxCount: 1 },
      { name: 'file2', maxCount: 1 },
    ]),
  )
  uploadMultiFile(
    @UploadedFiles() files: { file1: Express.Multer.File; file2: Express.Multer.File },
  ) {
    return this.boardService.fileUpload(files.file1[0], files.file2[0]);
  }
  • board.service.ts
  fileUpload(file1: Express.Multer.File, file2: Express.Multer.File) {
    if (!file1 || !file2) {
      throw new BadRequestException('파일이 존재하지 않습니다.');
    }

    // 파일 처리 로직
    return { file1Path: file1.path, file2Path: file2.path };
  }
  • src/util/upload/multer.config.ts
import { Injectable } from '@nestjs/common';
import { MulterOptionsFactory } from '@nestjs/platform-express';
import * as path from 'path';
import * as fs from 'fs';
import * as multer from 'multer';

@Injectable()
export class MulterConfigService implements MulterOptionsFactory {
  dirPath: string;
  constructor() {
    this.dirPath = path.join(__dirname, '..', '..', '..', 'public', 'uploads');
    this.mkdir();
  }

  mkdir() {
    try {
      fs.readdirSync(this.dirPath);
    } catch (error) {
      fs.mkdirSync(this.dirPath);
    }
  }

  createMulterOptions() {
    const dirPath = this.dirPath;
    const options = {
      storage: multer.diskStorage({
        // 파일 저장위치 설정
        destination(req, file, done) {
          done(null, dirPath);
        },
        // 파일명 설정
        filename(req, file, done) {
          const ext = path.extname(file.originalname);
          const fileName = path.basename(file.originalname, ext) + new Date().valueOf() + ext;
          done(null, fileName);
        },
      }),
      // limit: { fileSize: 5 * 1024 * 1024 }, // 용량 제한
    };
    return options;
  }
}
  • board.modules.ts
import { Module } from '@nestjs/common';
import { BoardService } from './board.service';
import { BoardController } from './board.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Board } from './entities/board.entity';
import { MulterModule } from '@nestjs/platform-express';
import { MulterConfigService } from '../../util/upload/multer.config';

@Module({
  imports: [
    TypeOrmModule.forFeature([Board]),
    MulterModule.registerAsync({
      useClass: MulterConfigService,
    }),
  ],
  controllers: [BoardController],
  providers: [BoardService],
})
export class BoardModule {}
  • multer.config.ts 에서 받을 파일을 저장시킬 위치와 파일명을 설정을 한다.
  • board.service 에서 받을 파일을 서버에 저장시키는 로직인듯한데 아직까지 어떠한 방법으로 저장이되는지 이해를 못하고있다.
  • return 으로 브라우저에서 저장된 위치와 파일명을 볼 수가있다.

저장된 파일 다운로드 받아보기

  • board.controller.ts
  @Get('download/:filename')
  downloadFile(@Param('filename') filename: string, @Res() res: Response) {
    const filePath = path.join(__dirname, '..', '..', '..', 'public', 'uploads', filename);

    // 파일 존재 여부 확인
    if (!fs.existsSync(filePath)) {
      throw new NotFoundException('파일을 찾을 수 없습니다.');
    }

    // 응답 헤더 설정
    res.setHeader('Content-Disposition', `attachment; filename=${filename}`);
    // 파일 스트림 생성 및 응답으로 보내기
    const fileStream = fs.createReadStream(filePath);
    fileStream.pipe(res);
  }
  • 현재는 서버에 저장된 파일명과 파일위치를 db에 저장을 안하고있는 상황이라 하드코딩으로 api를 호출 해보았다.
  • axios.get("http://localhost:8080/board/download/image1704518412520.jpg")
  • api를 호출해본결과 저장된 사진이 response로 전달되는 것을 볼 수 있다.
profile
무언가를 만드는 것을 좋아합니다

0개의 댓글

관련 채용 정보