S3 버켓을 사용한 Image관리 구현해보자
1. npm init
2. 라이브러리 다운받기
npm i aws-sdk dotenv express express-async-handler multer util
3. dev에 필요한 라이브러리 다운받기
npm i -D concurrently nodemon
4. 루트 디렉터리에 npx create-react-app frontend 추가.
5. 루트 디렉토리에 backend라는 폴더 추가.
6. 그 안에 server.js라는 파일을 추가.
const express = require('express');
require('dotenv').config(); //.env라는 파일을 불러오기 위해 설치했음.
const app = express();
app.use(express.json({ limit: '50mb' })); //디렉토리에 왔다갔다하는 양을 지정.
// x-www-form-urlencoded를 사용하면 다음이 필요
/** Decode Form URL Encoded data */
app.use(express.urlencoded({ limit: '50mb', extended: false }));
app.use('/api/gallery', require('./routes/galleryRoutes'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));
7. 다음으로는 라우트 만들기 위해 routes라는 폴더를 만들고
galleryRoutes.js를 만들었다.
const express = require('express');
const multer = require('multer');
const router = express.Router();
const {
getGallery,
createGallery
} = require('../controllers/galleryController');
//getGallery는 사진을 읽을 때 불러오는 것이고
//createGallery는 사진을 저장할 때 쓰는 함수이다.
// multer를 사용해서 업로드 하겠다.
const upload = multer({ dest: 'uploads/' });
// router.route
router.route('/').get(getGallery);
router.route('/').post(upload.single('imageFile'), createGallery);
module.exports = router;
8. 이제 위에서 쓰인 getGallery, createGallery함수를 만들어 보겠다.
controllers 폴더를 만들고 galleryController.js를 만든다.
const asyncHandler = require('express-async-handler');
const { upload } = require('./awsController');
//post로 왔을 때 실행할 함수명.
const createGallery = asyncHandler(async (req, res) => {
const image = req.file; // image 파일은 리액트에서 온 파일이다.
const result = await upload(image);// 이미지를 AWS S3에 올림
res.status(201).json({ location: result.Location });// aws에 제대로 올라갓으면 Location이라는 리턴을 해준다.
});
const getGallery = asyncHandler(async (req, res) => {
res.status(200).json({ message: 'get photos ' });
});
module.exports = {
createGallery,
getGallery,
};
9. 이 다음에는 사진을 aws저장할 때 쓰는 awsController.js를 만들어 보겠다.
여기는 aws에서 시키는 대로 작성이 거의 되었다.
require('dotenv').config();
const fs = require('fs');
const S3 = require('aws-sdk/clients/s3');
//aws가 정해놓은 파라미터.
const bucketName = process.env.AWS_BUCKET_NAME;
const region = process.env.AWS_REGION;
const accessKeyId = process.env.AWS_ACCESS_KEY;
const secretAccessKey = process.env.AWS_SECRET_KEY;
const s3 = new S3({
region,
accessKeyId,
secretAccessKey,
});
// uploads a file to s3
function upload(file) {
const uploadParams = {
Bucket: bucketName,
Body: fs.createReadStream(file.path), //createReadStream은 fs모듈로 파일을 읽기 위함이다.
Key: file.filename,
};
return s3.upload(uploadParams).promise();
}
module.exports = { upload };
---여기 까지가 백앤드 끝이다.
이제 프론트앤드를 시작해보자.
10. npm axios
11. npm -D tailwindcss postcss autoprefixer 를 설치!
12. npx tailwindcss init -p => tailwind.conf.js라는 파일이 생긴다.
module.exports = {
content: ['./src/**/*.{js, jsx, ts, tsx}'],
theme: {
extend: {},
},
plugins: [],
};
이렇게 써 넣었다.
13. index.css에 아래를 써넣었다.
@tailwind base;
@tailwind components;
@tailwind utilities;
14. 그 다음에 App.js에 아래와 같이 쓴다.
import React from 'react';
import NewGallery from './pages/NewGallery';
function App() {
return (
<>
<NewGallery />
</>
);
}
export default App;
이제 NewGallery를 만들어보자.
15. 일단 useState변수와 리턴 부분은 아래와 같다.
import React, { useState, useEffect } from 'react';
import createFormData from '../gallery/createFormData';
const NewGallery = () => {
const [picturename, setPicturename] = useState('');
const [imageFile, setImageFile] = useState(null);
const [s3Location, setS3Location] = useState('');
return (
<>
<h1 className='bg-indigo-500 text-center p-4 text-4xl text-white'>
AWS S3에서 사진 불러오기
</h1>
<form onSubmit={handleSubmit} className='flex justify-center mt-8 '>
<label>
이미지 이름:
</label>
<input
className='text-2xl border-2 bg-indigo-200 mr-1 md:mr-5'
name='picturename'
type='text'
id='picturename'
value={picturename}
onChange={(e) => setPicturename(e.target.value)}
/>
{/* 밑에는 파일을 넣는 input
파일을 넣으면은 handleFileChange함수가 작동되어
*/}
<input
type='file'
name='imageFile'
accept='image/jpeg, image/jp, image/png'
onChange={handleFileChange}
/>
<button>
제출
</button>
</form>
<img
src={s3Location}
alt=''
className='text-center mt-10 mx-auto w-80 h-70'
/>
</>
);
};
export default NewGallery;
여기서 handleFileChange가 작동되면 어떤게 나타날까?
import React, { useState, useEffect } from 'react';
import createFormData from '../gallery/createFormData';
const NewGallery = () => {
const [picturename, setPicturename] = useState('');
const [imageFile, setImageFile] = useState(null);
const [s3Location, setS3Location] = useState('');
const handleFileChange = (e) => {
console.log(e.target.files[0])
setImageFile(e.target.files[0]);
};
return (
<>
<h1 className='bg-indigo-500 text-center p-4 text-4xl text-white'>
AWS S3에서 사진 불러오기
</h1>
<form onSubmit={handleSubmit} className='flex justify-center mt-8 '>
<label>
이미지 이름:
</label>
<input
className='text-2xl border-2 bg-indigo-200 mr-1 md:mr-5'
name='picturename'
type='text'
id='picturename'
value={picturename}
onChange={(e) => setPicturename(e.target.value)}
/>
{/* 밑에는 파일을 넣는 input
파일을 넣으면은 handleFileChange함수가 작동되어
*/}
<input
type='file'
name='imageFile'
accept='image/jpeg, image/jp, image/png'
onChange={handleFileChange}
/>
<button>
제출
</button>
</form>
<img
src={s3Location}
alt=''
className='text-center mt-10 mx-auto w-80 h-70'
/>
</>
);
};
export default NewGallery;
콘솔로 e.target.files[0]를 찍어보니
이게 나온다.
마지막으로 handleSubmit함수를 보자.
16. 아래에서 formData를 사용해 사진 이름과 파일을 넣어 createFormData라는 함수에 보냈다.
import React, { useState, useEffect } from 'react';
import createFormData from '../gallery/createFormData';
const NewGallery = () => {
const [picturename, setPicturename] = useState('');
const [imageFile, setImageFile] = useState(null);
const [s3Location, setS3Location] = useState('');
const handleFileChange = (e) => {
console.log(e.target.files[0])
setImageFile(e.target.files[0]);
};
const handleSubmit = async (e) => { //제출버튼을 눌렀을 때 작동됨.
e.preventDefault();
const formData = new FormData();// ajax로 form data 전송을 가능하게 해주는 객체
//HTML5의 <form> 태그이용해 input값을 서버에 전송하지만, formdata를 이용해 스크립트로도 전송을 할수 있다
formData.append('picturename', picturename); //이미지 이름input에서넣은 이미지 이름
formData.append('imageFile', imageFile); //파일선택버튼으로 넣은 파일
const location = await createFormData(formData);
setS3Location(location.data.location);
};
return (
<>
<h1 className='bg-indigo-500 text-center p-4 text-4xl text-white'>
AWS S3에서 사진 불러오기
</h1>
<form onSubmit={handleSubmit} className='flex justify-center mt-8 '>
<label>
이미지 이름:
</label>
{/* 밑에는 이미지 이름 넣는 input */}
<input
className='text-2xl border-2 bg-indigo-200 mr-1 md:mr-5'
name='picturename'
type='text'
id='picturename'
value={picturename}
onChange={(e) => setPicturename(e.target.value)}
/>
{/* 밑에는 파일을 넣는 input
파일을 넣으면은 handleFileChange함수가 작동되어 imageFile이름을 지정.*/}
<input
type='file'
name='imageFile'
accept='image/jpeg, image/jp, image/png'
onChange={handleFileChange}
/>
<button>
제출
</button>
</form>
<img
src={s3Location}
alt=''
className='text-center mt-10 mx-auto w-80 h-70'
/>
</>
);
};
export default NewGallery;
다음으로 createFormData함수를 보자.
createFormData.js
import axios from 'axios';
const createFormData = async (formData) => {
const config = {
headers: {
'Content-Type': 'multipart/form-data',
},
};
const location = await axios.post('/api/gallery', formData, config);
console.log('location from createFormData', location);
return location;
};
export default createFormData;
이제 흐름을 한번 정리를 해보면,
1. NewGallery.js
이미지 파일을 선택하면 handleFileChange라는 함수가 작동되어 이미지 파일을 imageFile변수에 저장하고
이미지 이름을 써넣고, 이미지를 파일선택한 뒤 제출을 누르면 formData라는 변수에 담겨 createFormData 함수가 실행.
2. createFormData.js
/api/gallery경로로 post요청이 간다. formData, config도 같이 보낸다.
3. 서버 폴더의 galleryRoutes.js
post요청이 실행되어, uploads폴더에 올라간 파일과 함께 createGallery 함수가 실행된다.
4. galleryController.js
createGallery함수에 image라는 변수에 파일이 저장되고,
aws에 이미지를 올리는 함수가 작동된다. 이 upload함수는 awsController.js에 짜여있다.
5. awsController.js
aws에서 시킨대로 코딩이 된 파일이다.
bucket이름, 파일, 파일이름이 aws로 업로드 된다.
6. galleryController.js
aws에 제대로 올라갓으면 Location이라는 리턴을 해준다.
7. createFormData.js
location값을 받아서 리턴해준다.
8. NewGallery.js
location이라는 변수에 aws에 저장된 경로를 지정해줌으로써 바로 볼수있게 해준다.