리액트 사진 게시판 - liaegteu sajin gesipan

Multer Installation

Multer는 multipart/form-data를 이용하여 파일을 업로드 할 수 있게 해주는 middleware이다. 

npm install multer

package.json에 아래와 같이 설치가 된다. 

"multer": "^1.4.2",

Multer Usage

uploadRouter.js

const express = require('express'); const router = express.Router(); const multer = require("multer"); const path = require("path"); //diskStorage 엔진으로 파일저장경로와 파일명을 세팅한다. let storage = multer.diskStorage({ //multer disk storage settings destination: function(req, file, callback) { callback(null, "uploads/") }, filename: function(req, file, callback) { let extension = path.extname(file.originalname); let basename = path.basename(file.originalname, extension); callback(null, basename + "-" + Date.now() + extension); } }); //특정 파일형식만 저장하기 위해서는 fileFilter함수를 사용한다. const upload = multer({ //multer settings storage: storage, fileFilter: function(req, file, callback) { var ext = path.extname(file.originalname); if (ext !== '.xlsx' && ext !== '.pdf' && ext !== '.png' && ext !== '.jpg' && ext !== '.gif' && ext !== '.jpeg') { return callback(new Error('Only .xlsx .pdf .png, .jpg .gif and .jpeg format allowed!')) } callback(null, true) }, }).any(); //.any()는 전달받는 모든 파일을 받는다. 파일배열은 req.files에 저장되어 있다. router.post('/files', (req, res, next) => { const reqFiles = []; try { upload(req, res, function(err) { if (err) { return res.status(400).send({ //에러발생하면, 에러 메시지와 빈 파일명 array를 return한다. message: err.message, files: reqFiles }); } for (var i = 0; i < req.files.length; i++) { //저장된 파일명을 차례로 push한다. reqFiles.push(req.files[i].filename) } res.status(200).send({ //저장 성공 시, 저장성공 메시지와 저장된 파일명 array를 return한다. message: "Uploaded the file successfully", files: reqFiles }); }) } catch (err) { console.log(err); res.status(500).send({ message: `Could not upload the file: ${err}`, files: reqFiles }); } }); module.exports = router;

fileUploadService.js

import axios from 'axios'; const upload = (file) => { let formData = new FormData(); for (const key of Object.keys(file)) { formData.append('file', file[key]); } //formData.append("file", file); return axios.post("/api/upload/files", formData, { headers: { "Content-Type": "multipart/form-data", } }); }; export default { upload };

UploadFiles.js

부모 컴포넌트(NoticeComponentWrite.js)에서 자식컴포넌트(UploadFiles.js)의 메서드 호출할 수 있도록 하기 위해 

useImperativeHandle()을 사용하며, forwardRef()와 함께 사용한다. 

import React, { useState, useRef, useImperativeHandle, forwardRef } from "react"; import FileUploadService from "../utils/fileUploadService"; const UploadFiles = forwardRef((props, ref) => { const [selectedFiles, setSelectedFiles] = useState(undefined); const [message, setMessage] = useState(""); const selectFile = (event) => { setSelectedFiles(event.target.files); }; //NoticeWriteComponent에서 저장버튼을 클릭 시, 파일 업로드를 실행하기 위해서 //useImperativeHandle이라는 hook을 사용한다. useImperativeHandle(ref, () => ({ upload: () => { return new Promise((resolve, reject) => { if (selectedFiles) { let result = FileUploadService.upload(selectedFiles) .then((response) => { setMessage(response.data.message); resolve(response.data.files); //return UploadService.getFiles(); }) .catch((err) => { fileInput.current.value = ''; setSelectedFiles(undefined); if (err.response.data.message) { setMessage(err.response.data.message); } else { setMessage("Could not upload the file!"); } reject(); }); } else { resolve([]); } }) } })); const fileInput = useRef(); return ( <div className="form-group"> <label className="btn btn-default"> //여러개 파일을 한번에 업로드 하기 위해 multiple 속성을 추가한다. //파일 정보를 배열로 받을 수 있다. <input type="file" onChange={selectFile} ref={fileInput} multiple /> </label> //업로드 완료 시, 성공이나 실패 메시지를 붉은 색으로 표기해준다. <div className="alert alert-light" role="alert" style={{color:'red'}}> {message} </div> </div> ) }); export default UploadFiles;

이제 UploadFiles 컴포넌트를 아무 곳에서나 import하여 사용이 가능하다. 

NoticeWriteComponent.js

import UploadFiles from '../UploadFiles'; const NoticeWriteComponent = () => { const uploadReferenece = React.createRef(); async function onClickSearch() { await uploadReferenece.current.upload().then(function (result) { const files = result; alert('저장 완료'); }).catch(function (err) { }); } return ( <div> <UploadFiles ref={uploadReferenece} /> <div className="text-center pd12"> <button className="lf-button primary" onClick={onClickSearch}>저장</button> </div> </div> ) }; export default NoticeWriteComponent;

파일을 2개 선택하면 아래와 같이 표시된다. 

저장버튼을 클릭하면, 파일이 업로드 되고 형식에 맞지 않는 파일인 경우 아래와 같이 에러 메시지를 표시한다. 

Toplist

최신 우편물

태그