1. Multer ์ธํ
Multer๋ฅผ ์ฌ์ฉํด ํ์ผ ์ ๋ก๋๋ฅผ ๊ตฌํํ ๊ฒ์ด๋ค.
1yarn add multer @types/multer uuid @types/uuid
posts ์ํฐํฐ์ ์ด๋ฏธ์ง ํ๋กํผํฐ๋ฅผ ์ถ๊ฐํ๋ค.
posts.entity.ts
1// ์๋ต23@Entity()4export class PostsModel extends BaseModel {5// ์๋ต67@Column({8nullable: true,9})10image?: string1112// ์๋ต13}
common/const/path.const.ts ํ์ผ์ ๋ง๋ ๋ค.
common/const/path.const.ts
1import { join } from 'path'2import * as process from 'process'34// ์๋ฒ ํ๋ก์ ํธ์ ๋ฃจํธ ํด๋5export const PROJECT_ROOT_PATH = process.cwd()6// ์ธ๋ถ์์ ์ ๊ทผ ๊ฐ๋ฅํ ํ์ผ๋ค์ ๋ชจ์๋ ํด๋ ์ด๋ฆ7export const PUBLIC_FOLDER_NAME = 'public'8// ํฌ์คํธ ์ด๋ฏธ์ง๋ค์ ์ ์ฅํ ํด๋ ์ด๋ฆ9export const POSTS_FOLDER_NAME = 'posts'1011// ์ค์ ๊ณต๊ฐํด๋์ ์ ๋ ๊ฒฝ๋ก12// /{ํ๋ก์ ํธ์ ์์น}/public13export const PUBLIC_FOLDER_PATH = join(PROJECT_ROOT_PATH, PUBLIC_FOLDER_NAME)1415// ํฌ์คํธ ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ ํด๋16// /{ํ๋ก์ ํธ์ ์์น}/public/posts17export const POST_IMAGE_PATH = join(PUBLIC_FOLDER_PATH, POSTS_FOLDER_NAME)1819// ์ ๋๊ฒฝ๋ก x20// public/posts/xxx.jpg21export const POST_PUBLIC_IMAGE_PATH = join(PUBLIC_FOLDER_NAME, POSTS_FOLDER_NAME)
- ์ถ๊ฐ์ ์ผ๋ก ํ๋ก์ ํธ์ ๋ฃจํธ ๊ฒฝ๋ก์
public/postsํด๋๋ฅผ ๋ง๋ ๋ค.
posts ๋ชจ๋์์ Multer ๋ชจ๋์ ์ ๋ถ importํ๋ค.
posts.module.ts
1import * as multer from 'multer'2import { v4 as uuid } from 'uuid'3// ์๋ต45@Module({6imports: [7/*** ๋ชจ๋ธ์ ํด๋นํ๋ repostory๋ฅผ ์ฃผ์ ==> forFeature8* repository : ํด๋น ๋ชจ๋ธ์ ๋ค๋ฃฐ ์ ์๊ฒ ํด์ฃผ๋ ํด๋์ค9*/10TypeOrmModule.forFeature([11PostsModel, //12]),13AuthModule,14UsersModule,15CommonModule,16MulterModule.register({17limits: {18// byte ๋จ์๋ก ์ ๋ ฅ (10000000byte -> 10MB๊ฐ ๋๋ ํ์ผ์ ์๋ฌ)19fieldSize: 10000000,20},21/*** cb(์๋ฌ, boolean)22* ์ฒซ๋ฒ์จฐ ํ๋ผ๋ฏธํฐ์๋ ์๋ฌ๊ฐ ์์ ๊ฒฝ์ฐ ์๋ฌ ์ ๋ณด๋ฅผ ๋ฃ์ด์ค๋ค.23* ๋๋ฒ์จฐ ํ๋ผ๋ฏธํฐ๋ ํ์ผ์ ๋ฐ์์ง ๋ง์ง boolean์ ๋ฃ์ด์ค๋ค.24*/25fileFilter: (req, file, cb) => {26// xxx.jpg -> .jpg๊ฐ์ด ํ์ฅ์๋ง ๊ฐ์ ธ์์ค27const ext = extname(file.originalname)2829if (ext !== '.jpg' && ext !== '.jpeg' && ext !== '.png') {30return cb(31new BadRequestException('jpg/jpeg/png ํ์ผ๋ง ์ ๋ก๋ ๊ฐ๋ฅํฉ๋๋ค!'), //32false,33)34}35return cb(null, true)36},37storage: multer.diskStorage({38// ํ์ผ์ ์ด๋์ ๋ณด๋ผ์ง39destination: function (req, res, cb) {40cb(null, POST_IMAGE_PATH)41},42filename: function (req, file, cb) {43cb(null, `${uuid()}${extname(file.originalname)}`)44},45}),46}),47],48// ์๋ต49})50export class PostsModule {}
2. FileInterceptor ์ ์ฉ
posts ์ปจํธ๋กค๋ฌ์ ์ด๋ฏธ์ง๋ฅผ ๋ฐ์ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ฐ์์ ๋๊ฒจ์ค๋ค.
posts.controller.ts
1// posts.controller.ts ์๋ต2@Post()3@UseGuards(AccessTokenGuard)4@UseInterceptors(FileInterceptor('image'))5postPosts(6@User('id') userId: number,7@Body() body: CreatePostDto,8@UploadedFile() file?: Express.Multer.File,9// @Body('title') title: string,10// @Body('content') content: string,11// ๊ธฐ๋ณธ๊ฐ์ true๋ก ์ค์ ํ๋ ํ์ดํ12// @Body('isPublic', new DefaultValuePipe(true)) isPublic: boolean,13) {14return this.postsService.createPost(userId, body, file?.filename)15}
posts ์๋น์ค์์ ๋ฐ์ ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ๋ค.
posts.service.ts
1// posts.service.ts ์๋ต2async createPost(authorId: number, postDto: CreatePostDto, image?: string) {3const post = this.postsRepository.create({4author: {5id: authorId,6},7...postDto,8image,9likeCount: 0,10commentCount: 0,11})12const newPost = await this.postsRepository.save(post)13return newPost14}