냥냠
[React] S3으로 이미지 처리하기(1) 본문
쇼핑몰을 구현하면서
에디터랑 이미지 업로드하는 부분이 필요해서 에디터는 react-quill을 사용하고 이미지 업로드는 <input> 태그로 구현했다.
이미지를 업로드하고 처리하는 과정에서
에디터와 파일 업로더 둘 다 base24 코드로 저장하기 때문에 길이가 엄청 길다. 그래서 다들 서버를 통해서 url로 바꿔서 저장한다.
url로 바꿔주기 위해서 AWS S3을 사용하기로 했다.
그럴려면 버킷을 먼서 만들어주고 권한, 역할, 정책 관련으로 정해줘야 할 게 많은데
나는 아래의 블로그를 참고했다 지금이랑 조금 달라진 부분도 있어서
https://make-somthing.tistory.com/67
https://make-somthing.tistory.com/68
중간에 자격증명풀에서 조금 헤멜 수 있다.
자격 증명 풀을 다 생성하고도 나중에 편집할 수 있으니까 우선 어떻게든 생성을 하고 poolID 값을 만들어야 한다.
만들 때 제대로 만들었다면 오류가 나지 않지만 나는 중간에 S3 권한을 안줘서 오류가 났다.
여기서 역할 편집에 들어가서 IAM 역할 보기 -> 만들어져 있는 권한 정책 선택 -> 편집에 들어가서
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["cognito-sync:*", "cognito-identity:*", "s3:*"],
"Resource": ["*"]
}
]
}
이걸 넣으면 권한에 대한 오류는 해결이 된다.
<결과>
파일을 선택하고 저장하면 콘솔 창에 url이 뜬 것을 확인할 수 있다.
1. 파일 업로드 - 전체코드 ( 미리보기, S3 연결)
그리고 완성된 FileUpload.js 전체 코드이다. 따로 config.js를 만들어서 필요한 정보를 입력해놓아야 한다. (블로그 참고)
import { Alert, Button, IconButton } from '@mui/material';
import React, { useState, useRef } from 'react';
import AWS from 'aws-sdk';
import * as config from './../../config.js';
AWS.config.update({
region: config.awsRegion,
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: config.awsIdentityPoolId,
}),
});
const s3 = new AWS.S3();
const UploadFile = ({ maxImages }) => {
const [images, setImages] = useState([]);
const [error, setError] = useState('');
const inputRef = useRef(null);
const handleImageChange = (e) => {
const files = Array.from(e.target.files);
const currentImageCount = images.length;
if (currentImageCount + files.length > maxImages) {
setError(`최대 ${maxImages}개의 이미지만 업로드할 수 있습니다.`);
e.target.value = '';
return;
} else {
setError('');
}
const validImages = files.filter((file) => file.type.startsWith('image/')).slice(0, maxImages - currentImageCount);
validImages.forEach((file) => {
const reader = new FileReader();
reader.onloadend = () => {
setImages((prevImages) => [...prevImages, { file, preview: reader.result }]);
};
reader.readAsDataURL(file);
});
e.target.value = '';
};
const handleRemoveImage = (index) => {
setImages((prevImages) => prevImages.filter((_, i) => i !== index));
};
const handleButtonClick = () => {
if (inputRef.current) {
inputRef.current.click();
}
};
const saveEventHandler = async () => {
try {
const uploadedUrls = await Promise.all(
images.map(async ({ file }) => {
const params = {
Bucket: config.bucketName,
Key: `uploads/${Date.now()}-${file.name}`,
Body: file,
ContentType: file.type,
};
const { Location } = await s3.upload(params).promise();
return Location;
})
);
console.log('Uploaded URLs:', uploadedUrls);
} catch (err) {
console.error('S3 Upload Error:', err);
setError('이미지 업로드 중 오류가 발생했습니다.');
}
};
return (
<div>
<input
type="file"
accept="image/*"
multiple
onChange={handleImageChange}
ref={inputRef}
style={{ display: 'none' }}
/>
<Button
variant="outlined"
size="small"
color="primary"
onClick={handleButtonClick}
sx={{ margin: 1 }}
>
파일 선택
</Button>
{error && <Alert severity="error" variant="outlined">{error}</Alert>}
<div style={{ display: 'flex', flexWrap: 'wrap', width: '100%' }}>
{images.map(({ preview }, index) => (
<div key={index} style={{ position: 'relative', flexDirection: 'column', margin: '5px' }}>
<img
src={preview}
alt={`preview-${index}`}
style={{ width: '100px', height: '100px', objectFit: 'cover' }}
/>
<IconButton
onClick={() => handleRemoveImage(index)}
sx={{ position: 'absolute', top: '0px', right: '6px' }}
size="small"
>
×
</IconButton>
</div>
))}
</div>
<Button onClick={saveEventHandler} sx={{ marginLeft: '80%' }}>저장</Button>
</div>
);
};
export default UploadFile;
다음은 react-quill 에디터에서의 이미지처리도 같은 방법으로 해서 이미지를 url로 바꿔서 백엔드에 보내줄 수 있도록 해보겠다.
'React' 카테고리의 다른 글
[React] react-datepicker 라이브러리 적용 (0) | 2025.01.13 |
---|---|
[React] react-quil 이미지 s3로 처리하기 (2) (0) | 2024.11.08 |
[React] 회원가입 구현 ( stepper, 약관동의, 유효성 검사 ) (1) | 2024.10.28 |
[React] DOM 개념과 react-portal (0) | 2024.10.26 |
[React] 카테고리 관리 구현(추가, 수정, 삭제) (0) | 2024.10.25 |