15. multer를 이용한 이미지 업로드/서빙

유현준·2022년 8월 28일
0

hello! Nest

목록 보기
15/17

1. 준비물

  • @types/multer

2. 과정

1) 기능 module에 multerModule Import + 옵션 추가

cats.module.ts 
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Cat.name, schema: CatSchema }]),
    forwardRef(() => AuthModule),
    // 아래가 multerModule로 저장 위치를 설정
    MulterModule.register({
      dest: './upload', // 저장 위치
    }),
  ],

2) 이미지 관련 API에 FileInterceptor 등록. 이 때, multer가 옵션으로 활요됨

cats.controller.ts

@ApiOperation({ summary: '이미지 업로드' })

@UseInterceptors(FilesInterceptor('image', 10, multerOptions('cats')))
// filesInterceptor의 라이브러리로 Multer를 이용하는 것임.
// image라는 키에 들어온 파일을 + 최대 10개 제한으로 +  cats라는 폴더에 저장
//저장된 폴더/파일은 dist 폴더에서 확인 가능

@UseGuards(jwtGuard) // jwt guard를 실행
@Post('upload')
uploadCatImg(@UploadedFiles() files: Array<Express.Multer.File>, @User() cat: Cat) {
  console.log(files);
  return this.catsService.uploadImg(cat, files);
}

3) multerOptions 설정

  • common 폴더의 utiles라는 폴더 안에 설정하는 것이 가독성이 좋다.
  • 파일 구성을 요약하자면, 클라이언트에게서 받은 파일을 저장할 폴더의 이름과 위치, 파일의 이름을 일괄적으로 정하는 option을 생성하는 것이다.
  • multerOption은 커스텀이 가능하고, 아래 url을 참고하면 된다.
    https://github.com/expressjs/multer

import * as multer from 'multer';
import * as path from 'path';
import * as fs from 'fs';
import { MulterOptions } from '@nestjs/platform-express/multer/interfaces/multer-options.interface';

const createFolder = (folder: string) => {
  try {
    console.log('💾 Create a root uploads folder...');

    fs.mkdirSync(path.join(__dirname, '..', `uploads`));
  } catch (error) {
    console.log('The folder already exists...');
  }

  try {
    console.log(`💾 Create a ${folder} uploads folder...`);

    fs.mkdirSync(path.join(__dirname, '..', `uploads/${folder}`));
    // 폴더 생성하는 js 메소드 = 현재 폴더의 부모 폴더에서 uploads/folder 폴더 생성
  } catch (error) {
    console.log(`The ${folder} folder already exists...`);
  }
};

const storage = (folder: string): multer.StorageEngine => {
  createFolder(folder);

  return multer.diskStorage({
    // storage에 대한 옵션 정하는 메소드
    destination(req, file, cb) {
      //* 어디에 저장할 지 폴더에 대한 내용

      const folderName = path.join(__dirname, '..', `uploads/${folder}`);

      cb(null, folderName); // cb의 두번째 인자 저장 위치 설정
    },

    filename(req, file, cb) {
      //* 어떤 이름으로 올릴 지, 파일에 대한 내용

      const ext = path.extname(file.originalname); // path.extname => 파일에서 확장자 추출

      const fileName = `${path.basename(
        //저장할 파일의 이름을 설정
        file.originalname,
        ext,
      )} + ${Date.now()}${ext}`; //중복된 이미지를 허용하기 위해 date를 넣음

      cb(null, fileName);
    },
  });
};

export const multerOptions = (folder: string) => {
  // 매개변수 명의 폴더를 생성 + 파일을 storage 함수에 따라서 커스텀 하여 폴더에 저장
  const result: MulterOptions = {
    storage: storage(folder),
  };

  return result;
};

4) main.ts에서 정적파일 관리를 위한 미들웨어 설정(서버 내부에서 이미지 관리하는 경우)

app.useStaticAssets(path.join(__dirname, './common', 'uploads'), { prefix: '/media' });
  • bootstrap에 이를 저장할 경우, path.join에 기록된 서버 내부의 uri를 prefix에 할당된 값으로 치환함.

참고자료

profile
차가운에스프레소의 개발블로그입니다. (22.03. ~ 22.12.)

0개의 댓글