์ด๋ฏธ์ง ์ ๋ก๋ ์ ์ฑ ๊ฒฐ์ ๊ณผ์
01. ๋ฐฐ๊ฒฝ
๋ ์ ์ต๊ด ๊ด๋ฆฌ ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ๋ ๋ฐฉ์์ ๊ณ ๋ฏผ์ด ๋ง์๋ค. ์ด๋ฏธ์ง๋ฅผ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ์ธ ๊ฐ์ง๊ฐ ์์๋ค. ์ด๋ค ๋ฐฉ์์ด ๋ ์ข์ ์ ํ์ธ์ง ํ๋จํ๊ธฐ๊ฐ ์ฝ์ง ์์๊ณ , ํนํ AWS S3๋ฅผ ์ถ์ฒ๋ฐ์์ง๋ง ์ค์ ๋ก ์ฌ์ฉํ๋ ค๋ฉด AWS ๊ณ์ ์์ ํค๋ฅผ ๋ณ๋๋ก ๋ฐ๊ธ๋ฐ์์ผ ํ๋ ๋ฒ๊ฑฐ๋ก์์ด ์์ด์ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ์ง ๊ณ ๋ฏผ์ด ๋ง์๋ค.
02. ์ด๋ฏธ์ง ์ ์ฅ ๋ฐฉ์ ๋น๊ต
๋ฐฉ์ 1. ์ธ๋ถ URL ๊ทธ๋๋ก ์ ์ฅ
์ธ๋ถ ์๋น์ค(์๋ผ๋ ๋ฑ)๊ฐ ์ ๊ณตํ๋ ์ด๋ฏธ์ง URL์ DB์ ๊ทธ๋๋ก ์ ์ฅํ๋ ๋ฐฉ์์ด๋ค.
.coverImageUrl(picked.cover()) // ์๋ผ๋ CDN URL ๊ทธ๋๋ก ์ ์ฅ
| ์ฅ์ | ๋จ์ |
|---|---|
| • ๊ตฌํ์ด ๋จ์ํ๊ณ ๋น ๋ฆ • ๋ณ๋ ์ธํ๋ผ ๋ถํ์ • S3 ๋น์ฉ ์์ |
• ์ธ๋ถ URL์ด ๋ง๋ฃ/๋ณ๊ฒฝ๋๋ฉด ์ด๋ฏธ์ง ๊นจ์ง • ์ธ๋ถ ๋๋ฉ์ธ์ ์์กด • ์ด๋ฏธ์ง ๊ฐ์ฉ์ฑ์ ์ธ๋ถ ์๋น์ค์ ์์กด |
๋ฐฉ์ 2. ์๋ฒ์์ ๋ค์ด๋ก๋ ํ S3 ์ฌ์ ๋ก๋
์ธ๋ถ URL์ ์ด๋ฏธ์ง๋ฅผ ์๋ฒ๊ฐ ๋ค์ด๋ก๋ํ ๋ค S3์ ์ ์ฅํ๊ณ , S3 URL์ DB์ ์ ์ฅํ๋ ๋ฐฉ์์ด๋ค.
public String uploadImageFromUrl(String imageUrl) {
URL url = new URL(imageUrl);
URLConnection connection = url.openConnection();
try (InputStream inputStream = connection.getInputStream()) {
byte[] imageBytes = inputStream.readAllBytes();
String fileName = UUID.randomUUID() + "_cover.jpg";
s3Client.putObject(
PutObjectRequest.builder()
.bucket(bucket)
.key(fileName)
.contentType("image/jpeg")
.contentLength((long) imageBytes.length)
.build(),
RequestBody.fromBytes(imageBytes)
);
return "https://" + bucket + ".s3." + region + ".amazonaws.com/" + fileName;
}
}
| ์ฅ์ | ๋จ์ |
|---|---|
| • ์ด๋ฏธ์ง ์์์ฑ ๋ณด์ฅ • ์ธ๋ถ ์์กด์ฑ ์ ๊ฑฐ • ์ด๋ฏธ์ง ๊ด๋ฆฌ ์ผ์ํ |
• AWS ํค ๋ฐ๊ธ ํ์ • S3 ๋น์ฉ ๋ฐ์ • ๊ตฌํ ๋ณต์ก๋ ์ฆ๊ฐ |
๋ฐฉ์ 3. ํด๋ผ์ด์ธํธ์์ ์ง์ S3 ์ ๋ก๋ (Presigned URL)
์๋ฒ๊ฐ S3 Presigned URL์ ๋ฐ๊ธํด์ฃผ๋ฉด, ํด๋ผ์ด์ธํธ๊ฐ ํด๋น URL๋ก ์ง์ S3์ ์ ๋ก๋ํ๋ ๋ฐฉ์์ด๋ค.
// ์๋ฒ: Presigned URL ๋ฐ๊ธ
public String generatePresignedUrl(String fileName) {
PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(10))
.putObjectRequest(r -> r.bucket(bucket).key(fileName))
.build();
return presigner.presignPutObject(presignRequest).url().toString();
}
// ํด๋ผ์ด์ธํธ: Presigned URL๋ก ์ง์ ์
๋ก๋
await axios.put(presignedUrl, file, {
headers: { 'Content-Type': file.type }
});
| ์ฅ์ | ๋จ์ |
|---|---|
| • ์๋ฒ ๋ถํ ์์ • ๋์ฉ๋ ํ์ผ์ ์ ๋ฆฌ • ๋คํธ์ํฌ ํจ์จ์ |
• AWS ํค ๋ฐ๊ธ ํ์ • ๊ตฌํ ๋ณต์ก๋ ๊ฐ์ฅ ๋์ • ํด๋ผ์ด์ธํธ-์๋ฒ ๊ฐ ์ถ๊ฐ ํต์ ํ์ |
03. ๊ฒฐ์ ๋ด์ฉ
ํ์ง ์ด๋ฏธ์ง (coverImageUrl)
์ด๊ธฐ์๋ ๋ฐฉ์ 2(์๋ฒ์์ S3 ์ฌ์ ๋ก๋)๋ฅผ ๊ณํํ๋ค. ๊ทธ๋ฌ๋ S3 ํค ๋ฐ๊ธ ์ ๊น์ง ๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ์์ ํ ์คํธ๊ฐ ๋ถ๊ฐ๋ฅํ ๋ฌธ์ ๊ฐ ์์๊ณ , ์๋ผ๋ CDN URL์ด ๋น์ฅ ๋ง๋ฃ๋๊ฑฐ๋ ๋ณ๊ฒฝ๋ ๊ฐ๋ฅ์ฑ์ด ๋ฎ๋ค๊ณ ํ๋จํด ๋ฐฉ์ 1๋ก ๋ณ๊ฒฝํ๋ค. Post ์ํฐํฐ์ coverImageUrl ํ๋๋ ๊ทธ๋๋ก ์ ์งํ๋ค.
// ๋ณ๊ฒฝ ์ (๊ณํ)
.coverImageUrl(s3Service.uploadImageFromUrl(picked.cover()))
// ๋ณ๊ฒฝ ํ (ํ์ฌ)
.coverImageUrl(picked.cover())
ํ๋กํ ์ด๋ฏธ์ง (profileImageUrl)
์ฌ์ฉ์๊ฐ ์ง์ ์ ๋ก๋ํ๋ ์ด๋ฏธ์ง์ด๋ฏ๋ก ์ธ๋ถ URL ์ ์ฅ ๋ฐฉ์์ ์ ์ฉํ ์ ์์ด ๋ฐฉ์ 2(S3 ์ ๋ก๋)๋ฅผ ๊ทธ๋๋ก ์ ์งํ๊ธฐ๋ก ํ๋ค. AWS ํค ๋ฐ๊ธ ๋ฐ ์ค์ ์ฐ๋์ D13 ๋ฐฐํฌ ํ๊ฒฝ ๊ตฌ์ฑ ๋จ๊ณ์์ ์งํํ๊ณ , ๊ทธ ์ ๊น์ง๋ ํ๋กํ ์ด๋ฏธ์ง ๊ด๋ จ API ํ ์คํธ๋ฅผ ์คํตํ๋ค. S3Config, S3Service, UserService์ ์ด๋ฏธ์ง ๊ด๋ จ ์ฝ๋๋ ๊ทธ๋๋ก ์ ์งํ๋ค.
// S3Service — ํ๋กํ ์ด๋ฏธ์ง ์
๋ก๋ (D13์์ ์ค์ ์ฐ๋)
public String uploadImage(MultipartFile image) {
String fileName = UUID.randomUUID() + "_" + image.getOriginalFilename();
s3Client.putObject(
PutObjectRequest.builder()
.bucket(bucket)
.key(fileName)
.contentType(image.getContentType())
.contentLength(image.getSize())
.build(),
RequestBody.fromInputStream(image.getInputStream(), image.getSize())
);
return "https://" + bucket + ".s3." + region + ".amazonaws.com/" + fileName;
}
04. ์ ๋ฆฌ
| ์ด๋ฏธ์ง ์ข ๋ฅ | ์ ์ฅ ๋ฐฉ์ | ๋น๊ณ |
|---|---|---|
| ํ์ง ์ด๋ฏธ์ง | ์ธ๋ถ URL ๊ทธ๋๋ก ์ ์ฅ | ์๋ผ๋ CDN URL |
| ํ๋กํ ์ด๋ฏธ์ง | S3 ์ ๋ก๋ | D13(๋ฐฐํฌ ์ค๋น ๋จ๊ณ)์์ ์ค์ ์ฐ๋ |
'๐ป PROJECT > [Spring Boot, React] ๋ ์ ์ต๊ด ๊ด๋ฆฌ ์๋น์ค' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [ํ๋ก์ ํธ] ๋ฆฌ๋ง์ธ๋ ์๋ฆผ ๊ตฌํ ๋ฐฉ์ ์ ํ ๊ณผ์ (0) | 2026.05.01 |
|---|---|
| [ํ๋ก์ ํธ] ํ์ด์ง๋ค์ด์ ๋ฐฉ์ ์ ํ ๊ณผ์ (0) | 2026.05.01 |
| [ํ๋ก์ ํธ] ๊ณตํต ์๋ต ํฌ๋งท ์ค๊ณ (0) | 2026.04.30 |
| [ํธ๋ฌ๋ธ์ํ ] Spring Boot์์ ๋์ ์ฟผ๋ฆฌ ๊ฐ์ ํ๊ธฐ: @Query์์ QueryDSL๋ก (0) | 2026.04.29 |
| [Spring Boot, React] ๋ ์ ์ต๊ด ๊ด๋ฆฌ ์๋น์ค(1์ฐจ ๊ฐ๋ฐ) (0) | 2026.01.04 |