728x90
반응형
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개 선택하면 아래와 같이 표시된다.
저장버튼을 클릭하면, 파일이 업로드 되고 형식에 맞지 않는 파일인 경우 아래와 같이 에러 메시지를 표시한다.
728x90
반응형
'React' 카테고리의 다른 글
React] 배열 렌더링 How To Render Arrays in React (0) | 2020.10.08 |
---|---|
React 게시판 만들기 : 게시글 작성, 조회 (6) (1) | 2020.10.05 |
React 게시판 만들기 : React-Quill (4) (0) | 2020.09.29 |
React 게시판 만들기 : Pagination (3) (0) | 2020.09.28 |
React 게시판 만들기 : 리스트 (2) (2) | 2020.09.28 |
댓글