JS/Nest.js

[Nest] 이미지 업로드 구현 V1

Mini_96 2024. 9. 22. 16:42
  • post 컬럼추가
@Column({
  nullable:true,
})
image?: string;
  • 이미지 저장할 절대경로, 상대경로 추가
import {join} from 'path';

//서버 프로젝트의 루트폴더 절대경로
export const PROJECT_ROOT_PATH = process.cwd();

export const PUBLIC_FOLDER_NAME = 'public';

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

//공개폴더의 절대경로
// /{}/public
export const PUBLIC_FOLDER_PATH = join(
  PROJECT_ROOT_PATH,
  PUBLIC_FOLDER_NAME
)

//포스트 이미지를 저장할 폴더
/// /{}/public/posts
export const POST_IMAGE_PATH = join(
  PUBLIC_FOLDER_PATH,
  POSTS_FOLDER_NAME
)

// 상대경로
// /public/posts/xxx.jpg
// FE에서 요청시 localhost붙여서 요청하면됨.
export const POST_PUBLIC_IMAGE_PATH = join(
  PUBLIC_FOLDER_NAME,
  POSTS_FOLDER_NAME,
)
  • multer 모듈 추가
@Module({
  imports:[
    TypeOrmModule.forFeature([
      PostsModel
    ]),
    AuthModule,
    UsersModule,
    CommonModule,
    MulterModule.register({
      limits:{
        fileSize: 10000000, //10MB 제한
      },
      fileFilter : (req, file, cb) =>  {
        /**
         * cb(error, bool)
         *
         * 에러가 있을경우 에러정보
         * 파일을 받을지 말지 bool
         */
        const ext=extname(file.originalname); //확장자 가져오기
        if(ext !== '.jpg' && ext !== '.png' && ext !== '.jpeg'){
          return cb(
            new BadRequestException('Only jpg or png support'),
            false, //파일안받음
          );
        }

        return cb(null,true); //올바른확장자인경우, 파일받음
      },
      storage: multer.diskStorage({
        destination: function(req, file, cb){
          cb(null,POST_IMAGE_PATH) //에러없음, 이미지업로드할 경로
        },
        filename: (req, file, cb) => {
          // 파일이름 : uuid.png
          cb(null, `${uuid()}${extname(file.originalname)}`);
        }
      })
    }),
  ],
  • 컨트롤러 수정
    • image라는 key를 받을수있음.
@Post()
@UseGuards(AccessTokenGuard)
@UseInterceptors(FileInterceptor('image')) //req에 image키값에 대해 우리가 등록한 multer 검증실행
postPost(
  @User('id') userId : number,
  @Body() body : CreatePostDto,
  @UploadedFile() file?
  ){
  return this.postsService.createPost(userId ,body, file?.filename, );
}
  • 서비스 수정
async createPost(authorId: number, postDto : CreatePostDto, image? :string){

  const post = this.postsRepository.create({
    author: {
      id: authorId,
    },
    ...postDto,
    image,
    likeCount:0,
    commentCount:0,
  });

결과

 

* 만든 정적파일 제공하기

yarn add @nestjs/serve-static
  • 제공폴더 추가
@Module({
  imports: [
    UsersModule,
    PostsModule,
    ServeStaticModule.forRoot({
      //이 경로에 있는 이미지들을 제공해줄것임.
      rootPath: PUBLIC_FOLDER_PATH, //public 폴더의 절대경로 : D:nest/insta/public
      //문제 : root인 public폴더는 제외된채로 외부에 전달됨 -> 기존의 컨트롤러 url과 겹침 (/posts/4022.jpg)
      //해결 : serveRoot 추가(/public/posts/4022.jpg)

      serveRoot: '/public',
    }),

결과