본문 바로가기
Backend/NestJS

이미지 파일 업로드

by 찬찬2 2024. 6. 25.

핵심

@nestjs/common : UseInterceptor, UplodedFile

@nestjs/platform-express : FileInterceptor, MulterModule

multer

uuid

path : extname, join

class-transformer : Transform

fs : promises

 

핵심은 위에 밑줄 친 메서드와 모듈.포스트맨에서 테스트할때 body 부분을 form-data 형식으로 보내야 한다. 그리고 당연히 Text 가 아닌 File 로...

 

파일을 저장할때 유니크한 파일명으로 저장해야하는데, 보통 Date 객체를 포함시킨 래덤 문자열을 사용하는데여기서는 uuid() 메서드로 대체한다.

 

모듈

 

import { BadRequestException, Module } from '@nestjs/common';
import { CommonService } from './common.service';
import { CommonController } from './common.controller';
import { MulterModule } from '@nestjs/platform-express';
import { extname } from 'path';
import * as multer from 'multer'
import { TEMP_FOLDER_PATH } from 'src/common/const/path.const';
import { v4 as uuid } from 'uuid';

@Module({
  imports: [
    MulterModule.register({
      limits: {
        fileSize: 10000000 // bytes
      },
      fileFilter: (req, file, callBack) => {
        const ext = extname(file.originalname) // 만약 xxx.jpg 의 확장자가 jpg라면 .jpg를 반환합니다.
        if(ext !== '.jpg' && ext !== '.jpeg' && ext !== '.png') {
          return callBack(new BadRequestException('jpg/jpeg/png 파일만 업로드 가능합니다.'), false);
        };
        return callBack(null, true)
      },
      storage: multer.diskStorage({
        destination: (req, file, callBack) => {
          callBack(null, TEMP_FOLDER_PATH) // 디렉토리가 있는지 꼭 확인해야함.
        },
        filename: (req, file, callBack) => {
          callBack(null, `${uuid()}${extname(file.originalname)}`); // 123123-123123-123123-123123.jpg
        }
      })
    })
  ],
  controllers: [CommonController],
  providers: [CommonService],
  exports: [CommonService]
})
export class CommonModule {}

 

컨트롤러

 

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

@Controller('common')
export class CommonController {

  @Post('image')
  @UseInterceptors(FileInterceptor('image')) // 이미지를 업로드 할 때 사용하는 인터셉터
  postImage(
    @UploadedFile() file: Express.Multer.File
  ){
    return {
      fileName: file.filename
    };
  }

}

 

여기 까지가 업로드와 관련된 코드들이다. 아래는 추가하면 편리한 코드로, 상황에 맞게 활용하면 좋다


 

폴더 경로를 글로벌 변수로 만들어 서비스 모든 곳에서 사용하기.

경로가 변경될 경우 모든 파일을 일일이 바꾸는 번거로움이 줄어서 관리하기 편리하다.

 

import { join } from "path";

//  서버 프로젝트의 루트 폴더
export const PROJECT_ROOT_PATH = process.cwd(); // Current Working Directory, 현재 서버를 실행한 폴더의 경로입니다.

// 외부에서 접근 가능한 파일들을 모아둔 폴더 이름
export const PUBLIC_FOLDER_NAME = 'public';

// 포스트 이미지들을 저장할 폴더 이름
export const POST_FOLDER_NAME ='posts';

// 임시폴더 이름
export const TEMP_FOLDER_NAME = 'temp';

// {프로젝트 경로}/public
// join 함수는 경로를 만들어주는 함수입니다. 예를 들어 join('a', 'b', 'c') 는 'a/b/c' 를 반환합니다.
export const PUBLIC_FOLDER_PATH = join(
    PROJECT_ROOT_PATH,
    PUBLIC_FOLDER_NAME
);

// {프로젝트 경로}/public/posts
export const POST_IMAGE_PATH = join(
    PUBLIC_FOLDER_PATH,
    POST_FOLDER_NAME
);

// 클라이언트에서 접근할때는 절대경로 X
// 예: /public/posts/xxx.jpg
export const POST_PUBLIC_IMAGE_PATH = join(
    PUBLIC_FOLDER_PATH,
    POST_FOLDER_NAME
)

// {프로젝트 경로}/temp
export const TEMP_FOLDER_PATH = join(
    PUBLIC_FOLDER_PATH,
    TEMP_FOLDER_NAME
);

댓글