포시코딩

[multer] 업로드 기능 class로 모듈화 시키기 본문

Node.js

[multer] 업로드 기능 class로 모듈화 시키기

포시 2023. 1. 4. 18:17
728x90

개요

orders.routes.js

// ...생략
const multer = require('multer');
const moment = require('moment');
const fs = require('fs');
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const path = './src/public/uploads/orders';
    fs.mkdirSync(path, { recursive: true });
    cb(null, path);
  },
  filename: (req, file, cb) => {
    file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8');
    cb(null, moment().format('YYYYMMDDHHmmss') + '_' + file.originalname);
  },
});

const OrdersController = require('../controllers/orders.controller');
const ordersController = new OrdersController();
const authMiddleware = require('../config/authMiddleware');

router.post('/', authMiddleware, multer({ storage: storage }).array('files'), ordersController.createOrder);
// ...생략

module.exports = router;

service도 아닌 라우터 파일의 코드가 multer의 이미지 저장 기능 하나 때문에 

상당히 더러워져 있었다.

 

그렇다고 controller나 service로 빼기에는 여기서만 작동하는 기능이라 난감한 상황이었는데

 

class로 따로 만들어 불러오는 방식을 써볼까 해서 밑져야 본전으로 작업을 시작했다.

 

어떻게?

처음에 class로 모듈화가 가능하겠다고 생각이 든 이유가 있었는데

위에 뚱뚱한 부분은 모두 multer의 파일 저장 및 세팅에 대한 부분이고 

정작 가져다가 사용하는 부분은 

router.post('/', authMiddleware, multer({ storage: storage }).array('files'), ordersController.createOrder);

여기서 multer와 storage뿐이었다.

 

multer는 require로 불러온 multer가 되고, 

storage는 그 밑에서 multer.diskStorage()를 통해 선언되고 있었는데

 

이 두가지를 class의 멤버 변수로 할당하여

class.multer, class.storage처럼 불러와 사용할 수 있지 않을까 하는 것에 가능성을 두었다.

 

결과

 

UploadManager.js

'use strict';

const multer = require('multer');
const moment = require('moment');
const fs = require('fs');

class UploadManager {
  constructor(path) {
    this.path = path;
    this.multer = multer;
  }

  storage = multer.diskStorage({
    destination: (req, file, cb) => {
      const upload_path = this.path;
      fs.mkdirSync(upload_path, { recursive: true });
      cb(null, upload_path);
    },
    filename: (req, file, cb) => {
      file.originalname = Buffer.from(file.originalname, 'latin1').toString('utf8');
      cb(null, moment().format('YYYYMMDDHHmmss') + '_' + file.originalname);
    },
  });
}

module.exports = UploadManager;

orders.routes.js

'use strict';

const express = require('express');
const router = express.Router();
require('dotenv').config();

const OrdersController = require('../controllers/orders.controller');
const ordersController = new OrdersController();
const UploadManager = require('../config/UploadManager');
const uploadManager = new UploadManager(process.env.MULTER_PATH_UPLOADS_ORDERS);

const authMiddleware = require('../config/authMiddleware');

router.post(
  '/',
  authMiddleware,
  uploadManager.multer({ storage: uploadManager.storage }).array('files'),
  ordersController.createOrder
);
// ...생략

module.exports = router;

 

결론부터 말하자면 대성공이었다.

 

UploadManager라는 class를 만들어 모든 코드를 옮겼고

결과적으로 orders.routes.js에는 class를 호출하는 부분 말고는 원하는 정보만 남길 수 있게 되었다.

 

계획했던대로 multer는 멤버 변수로, storage는 멤버 변수가 아닌 메소드로 정의했다.

 

만들다가 추가된게 하나 있는데

해당 class가 다른 기능에 대해 쓰일 것도 대비해

orders가 아닌 다른 곳에도 저장이 가능하게 path를 생성자로 받게끔 하여

env 파일에서 세팅해서 건내주게끔 만들었다.

 

 

솔직히 이미지 저장 기능을 이번 프로젝트를 하며 처음 구현해봤는데

multer라는 패키지 덕분에 매우 쉽게 구현하기도 했고

 

예전과 달리 어떤것이든 class로 따로 빼서 객체 지향적인 코딩을 할 수 있게 된 것 같아 기쁘다 :)

728x90