[26] 파일업로드 multer 설치, 세부설정, single(), array(), fields(), 일반폼 전송

minjeong·2024년 2월 5일
0
post-thumbnail

💡 body-parser 는 데이터를 쉽게 처리할 수 있게 도와주는 라이브러리였지만, 멀티파트 데이터를 처리하지 못한다는 단점이 있다. -> multer 이용

파일업로드(multer)

1-1. 파일업로드 - 프론트

  • 클라이언트에서 서버로 파일을 전송하는 방법
  • <input type = "file"> 로 지정
  • 일반 form 전송 or 동적 파일 업로드 선택
  • 파일 업로드 될때는 post방식으로 해야한다.
  • name 속성은 서버에서 파일을 인식할 이름이 됨(서버와 동일하게 설정해야함)!
  • input태그의 name과 서버에서 보내야할 파일과 동일하게 작성해야한다.

1-2. 클라이언트 준비 - 일반 폼 전송

  • form 태그의 enctype 속성으로 "multipart/form-data" 반드시 설정
 <form action="" method="" enctype="multipart/form-data"></form>

💡 Multer는 multipart/form-data 가 아닌 폼에서는 동작하지 않는다.

1-3. multer 미들웨어 - 서버

  • 파일 업로드를 위해 사용되는 미들웨어
  • express로 서버를 구축할 때 가장 많이 사용되는 미들웨어

multer 설치

(1) 터미널에서 multer설치

npm install multer

(2) 작성하고 있는 js파일에 multer 불러오기
✅ 이때 multer도 원하는 이름으로 생성!!

const multer = require('multer') 

(3) js파일에서 업로드 경로 설정
dest : 파일을 업로드하고 그 파일이 저장될 경로를 지정하는 속성
✅ 이때, uploads or upload는 원하는 파일명으로 지정

const upload = multer({
  dest : 'uploads/',
}); 

1-4. multer 세부설정

  • 경로 뿐만 아니라 파일명, 크기 등을 직접 지정 및 제어할 수 있다.
const uploadDetail = multer({
    //storage : 저장할 공간에 대한 정보
    //diskStorage : 파일을 저장하기 위한 모든 제어기능 제공(파일 저장관련 설정)
    storage: multer.diskStorage({
        //destination : 업로드할 파일을 저장할 폴더를 지정
        destination(req, file, done) {
            done(null, 'uploads/'); //에러처리 : null(설정하지 않음), done은 콜백함수
        },
        //filename : 파일이름 결정(요청객체, 업로드된 파일 객체, 콜백함수 순서)
        //여기서 file은 index.ejs에서 정의한 함수(본인이 설정한 이름으로 기재)
        filename(req, file, done) {
            //extname() : 확장자를 추출
            const ext = path.extname(file.originalname);
            //basename() : 파일이름을 추출(파일의 오리지널명, 확장자) => 확장자를 제외해서 파일이름만 추출
            const newName = path.basename(file.originalname, ext) + Date.now() + ext;
            done(null, newName); //콜백함수 호출
        },
    }),

    //limits : 파일저장, 용량제한
    limits: { filesize: 5 * 1024 * 1024 },
});
  • storage : 저장할 공간에 대한 정보
  • diskStorage : 파일을 디스크에 저장하기 위한 모든 제어 기능을 제공
  • destination : 저장할 경로
  • filename : 파일명
  • limits : 파일 제한
  • fileSize : 파일 사이즈 제한

1-5. 하나의 파일 업로드 - single()

  • 하나의 파일만 업로드 할 수 있게 한다.

예제코드

 <h1>FORM 싱글연습</h1>
        <!-- 파일업로드때는 post방식  -->
        <form action="/upload" method="post" enctype="multipart/form-data">
            <input type="file" name="userfile" /><br />
            <input type="text" name="title" /><br />
            <button type="submit">업로드</button>
        </form>

const multer = require('multer');
const path = require('path'); //폴더와 파일의 경로를 쉽게 조작하도록 제공

//multer 설정
const upload = multer({
    //dest : 업로드할 파일을 저장할 폴더를 지정
    //이렇게 하게되면 자동적으로 폴더가 생성이 됌
    dest: 'uploads/',
});

//router
app.get('/', (req, res) => {
    res.render('index');
});
//post.(multer설정이름.하나보내는거라 single.('보내야할 파일이름') ~~~)
//single()
app.post('/upload', uploadDetail.single('userfile'), (req, res) => {
    console.log('file', req.file); //req.file : 파일 업로드 성공 결과(파일 정보)
    console.log('title', req.body); // req.body : title 데이터 정보 확인 가능
});

실행결과

-> 터미널에서 req.file ,req.body 들의 객체 확인이 가능하다.
-> 실행을 하면 uploads/ 폴더가 새로 생기고, 세부설정을 했기 때문에 위에서 보여지는 것처럼 객체들의 파일명이 변경된 것을 확인할 수 있다.

1-6. 파일 여러개 업로드 ver1

  • array() : 여러 파일을 업로드할 때 사용, 하나의 요청 안에 여러 개의 파일이 존재

예제코드

ejs 파일

 <h1>FORM 멀티 연습(ver1)</h1>
        <form action="/upload/array" method="post" enctype="multipart/form-data">
            <input type="file" name="userfiles" multiple /><br />
            <input type="text" name="title" /><br />
            <button type="submit">업로드</button>
        </form>

js코드


const multer = require('multer');
const path = require('path'); //폴더와 파일의 경로를 쉽게 조작하도록 제공

//multer 설정
const upload = multer({
    //dest : 업로드할 파일을 저장할 폴더를 지정
    //이렇게 하게되면 자동적으로 폴더가 생성이 됌
    dest: 'uploads/',
});

app.post('/upload/array', uploadDetail.array('userfiles'), (req, res) => {
    console.log('file', req.files); //req.fules: [{},{},{},...] 배열 형태로 각 파일 정보를 가짐, 업로드 된 파일이 여러개이므로 복수형태로 작성!!!
    console.log('title', req.body); //req.body : title 데이터 정보 확인 가능
});

📝 req.files : 업로드 되는 파일이 여러개이고, 배열 형태로 가지기 때문에 files과 같이 복수형태로 작성

실행결과



+ 업로드 될때의 세부설정은 (1-4)에서 작성한 그대로이다.

1-7. 파일 여러개 업로드 ver2

  • fields() : 여러 파일을 업로드할 때 사용, 하나의 요청이 아닌 여러 개의 요청이 들어올 때 사용

예제코드

ejs 코드

<h1>FORM 멀티연습 (ver2)</h1>
        <!-- 하나의 요청이 아닌 여러 개의 요청이 들어올 때 -->
        <form action="/upload/fields/" method="post" enctype="multipart/form-data">
            <input type="file" name="userFile1" /><br />
            <input type="text" name="title1" /><br />
            <input type="file" name="userFile2" /><br />
            <input type="text" name="title2" /><br />
            <button type="submit">업로드</button>
        </form>

js코드

//multi ver2
app.post('/upload/fields', uploadDetail.fields([{ name: 'userFile1' }, { name: 'userFile2' }]), (req, res) => {
    console.log('file', req.files);
    console.log('title', req.body);
});

실행결과

🧡 multer 요약

  • single()
    : 하나의 파일 업로드
    : req.file - 파일 하나, 업로드 된 파일
    : req.body - 나머지 정보, 파일 외에 데이터 값들
  • array()
    : 여러 파일을 업로드할 때 사용, 하나의 요청 안에 여러 개의 파일이 존재할때
    :req.files - 파일 n개
    :req.body - 나머지 정보
  • fields()
    : 여러 파일을 업로드할 때 사용, 하나의 요청이 아닌 여러개의 요청이 들어올 때
    :req.files - 파일 n개
    :req.body - 나머지 정보

1-8. Axios 동적 파일 업로드

예제코드

ejs 코드

<h1>동적 파일 업로드</h1>
        <form>
            <input type="file" id="userfile" /><br />
            <input type="text" id="title" /><br />
            <button type="button" onclick="fileUpload()">업로드</button>
        </form>
        <br />
        <br />
        <div class="resultBox"></div>
        <script>
            const resultBox = document.querySelector('.resultBox');
            function fileUpload() {
                const file = document.querySelector('#userfile');
                //파일에 접근하기 위해서 file.files[0]을 사용
                //file.files는 배열을 반환하며 우리가 원하는 것은 첫번째 요소이기 때문에 [0]를 해줌
                console.log(file.files[0]);

                //FormData : 자바스크립트 내장 객체이고 폼 데이터를 생성해줌
                const formData = new FormData();
                formData.append('title', document.querySelector('#title').value);
                formData.append('file', file.files[0]); //file은 가장 마지막에 써야함. 위에다가 일반데이터를 써주고 파일은 마지막!!!!

                axios({
                    method: 'post',
                    url: '/upload/axios',
                    data: formData,
                    headers: {
                        'Content-Type': 'multipart/form-data', //동적업로드할때 비동기에는 form에 넣어줬지만 동적에선 꼭 여기에서 넣어줘야한다.
                    },
                }).then((res) => {
                    console.log('res', res);
                    resultBox.innerHTML = `<p> 이름은 ${res.data.title.title}</p><img src = ${res.data.file.path} width = "300px" height = "300px">`; //html에 바로 보여지게 지정하고 css도 설정할 수 있다.
                });
            }
        </script>

➡️ append 할 때, file은 가장 마지막에 작성할 것!
➡️ append(key, value) - key 자리에는 차피 백엔드로 보내는거니까 이름 상관없다.
➡️ FormData : 자바스크립트 내장 객체이고 폼 데이터를 생성해준다.

js코드

// 동적
//single('프론트에서 보내는 key로 했던 파일명') =>> formData.append('file', file.files[0]); 이부분
app.post('/upload/axios', uploadDetail.single('file'), (req, res) => {
  	console.log('file', req.file);
    res.send({ file: req.file, title: req.body });
});

실행결과



일반폼으로 업로드 후 결과 페이지에서 업로드 된 이미지 보여주기

예제코드

입력페이지(html)

<h1>프로필 - 일반폼 전송</h1>
        <form action="/upload" method="post" enctype="multipart/form-data">
            <fieldset>
                <legend>프로필 작성</legend>
                <input type="text" name="id" placeholder="아이디" /><br />
                <input type="password" name="pw" placeholder="비밀번호" /><br />
                <input type="text" name="name" placeholder="이름" /><br />
                <input type="number" name="age" placeholder="나이" /><br />
                <input type="file" name="userFile" /><br />
                <button type="submit">업로드</button>
            </fieldset>
        </form>

결과 페이지(html)

<h4>프로필</h4>
        <img src="<%= file%>" width="300px" height="300px" />
        <span><p><%= userInfo.id%>님 환영합니다!</p> </span><br />
        <span>비밀번호 : <%= userInfo.pw%></span><br />
        <span>이름 : <%= userInfo.name%></span><br />
        <span>나이 : <%= userInfo.age%></span>

➡️ <%= %> 여기에 백엔드에서 보내주는 파일을 받으면 되는 것!

js코드

const express = require('express');
const multer = require('multer');
const path = require('path');
const app = express();
const PORT = 8000;

app.set('view engine', 'ejs');

app.use(express.urlencoded({ extended: true }));
//정적파일설정
app.use('/uploads', express.static(__dirname + '/uploads'));

const upload = multer({
    //dest : 업로드할 파일을 저장할 폴더를 지정
    //이렇게 하게되면 자동적으로 폴더가 생성이 됌
    dest: 'uploads/',
});

const uploadDetail = multer({
    storage: multer.diskStorage({
        destination(req, file, done) {
            done(null, 'uploads/');
        },
        filename(req, file, done) {
            const ext = path.extname(file.originalname);
            const newName = req.body.id + ext; //확장자명 : id+확장자

            done(null, newName);
        },
    }),
    //limits : 파일저장, 용량제한

    limits: { fileSize: 5 * 1024 * 1024 },
});

app.get('/', (req, res) => {
    res.render('index');
});

app.post('/upload', uploadDetail.single('userFile'), (req, res) => {
    console.log('file', req.file);
    console.log('title', req.body);
    res.render('result', { title: '프로필', userInfo: req.body, file: req.file.path }); //여기서 파일도 같이 보내줘야함
});

app.listen(PORT, () => {
    console.log(`http://localhost:${PORT}`);
});

실행결과



마무리

다양한 방법으로 동일한 문제를 풀어보았다. 파일 업로드 방식은 매우 중요하니 활용해서 사용할 수 있게 한 문제를 다양하게 푸는 방법을 공부해야 할 것 같다.

profile
중요한 건 꺾여도 다시 일어서는 마음

0개의 댓글