Spring Boot · 2026-03-01

Spring Boot과 AWS S3로 파일 업로드/다운로드 구현

Spring Boot 애플리케이션에서 AWS S3를 연동해 파일 업로드와 다운로드를 단계별 예제 코드로 설명하며 설정, 권한, 성능 고려사항까지 포함한 설명

작성일 : 2026-03-01 ㆍ 작성자 : 관리자
post
목차

개요

이 글에서는 Spring Boot에서 AWS S3를 연동해 파일을 업로드하고 다운로드하는 실무적 구성과 코드를 다룬다. 처음 접하는 개발자도 이해할 수 있도록 의존성 추가부터 권한 설정, 업로드/다운로드 구현, 성능 및 보안 고려사항까지 순서대로 정리한다. 주요 키워드는 spring boot s3 업로드 예제, aws s3 spring boot 연동, spring boot upload s3 이다.

사전 준비

다음 항목이 준비되어야 한다.

  • AWS 계정 및 S3 버킷 생성
  • AWS IAM 사용자(또는 역할)와 S3 접근 권한 부여
  • Spring Boot 프로젝트 생성(Maven/Gradle)

의존성

Spring Boot에서 AWS SDK v2를 사용하거나 SDK v1을 선택할 수 있다. 여기서는 비교적 간단한 AWS SDK for Java v1 예제를 사용한다.

com.amazonaws:aws-java-sdk-s3:1.12.XXX
org.springframework.boot:spring-boot-starter-web

설정(application.properties)

자격증명은 환경변수나 EC2 IAM 역할을 권장한다. 간단한 로컬 개발 예시는 properties에 넣을 수 있다.

cloud.aws.credentials.access-key=YOUR_ACCESS_KEY
cloud.aws.credentials.secret-key=YOUR_SECRET_KEY
cloud.aws.region.static=ap-northeast-2
app.s3.bucket=your-bucket-name

S3 클라이언트 설정

AmazonS3 빈을 생성해 재사용한다. Java 코드에서는 빈을 통해 업로드/다운로드를 처리한다.

package com.example.config;

import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class S3Config {

    @Value("${cloud.aws.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.credentials.secret-key}")
    private String secretKey;

    @Value("${cloud.aws.region.static}")
    private String region;

    @Bean
    public AmazonS3 amazonS3() {
        BasicAWSCredentials creds = new BasicAWSCredentials(accessKey, secretKey);
        return AmazonS3ClientBuilder.standard()
                .withRegion(region)
                .withCredentials(new AWSStaticCredentialsProvider(creds))
                .build();
    }
}

파일 업로드 서비스

MultipartFile을 받아 S3에 저장하고 URL이나 키를 반환한다. 스트리밍 업로드로 큰 파일도 안정적으로 처리한다.

package com.example.service;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ObjectMetadata;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.UUID;

@Service
public class S3Service {

    private final AmazonS3 amazonS3;

    @Value("${app.s3.bucket}")
    private String bucket;

    public S3Service(AmazonS3 amazonS3) {
        this.amazonS3 = amazonS3;
    }

    public String upload(MultipartFile file) throws IOException {
        String key = UUID.randomUUID().toString() + "_" + file.getOriginalFilename();
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentLength(file.getSize());
        metadata.setContentType(file.getContentType());
        amazonS3.putObject(bucket, key, file.getInputStream(), metadata);
        return key;
    }

    public byte[] download(String key) {
        try (var s3is = amazonS3.getObject(bucket, key).getObjectContent()) {
            return s3is.readAllBytes();
        } catch (IOException e) {
            throw new RuntimeException("S3 다운로드 실패", e);
        }
    }
}

컨트롤러

간단한 REST API로 업로드와 다운로드 엔드포인트를 제공한다. 다운로드는 스트리밍 응답으로 구현한다.

package com.example.controller;

import com.example.service.S3Service;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/files")
public class FileController {

    private final S3Service s3Service;

    public FileController(S3Service s3Service) {
        this.s3Service = s3Service;
    }

    @PostMapping("/upload")
    public ResponseEntity<String> upload(@RequestParam("file") MultipartFile file) throws Exception {
        String key = s3Service.upload(file);
        return ResponseEntity.ok(key);
    }

    @GetMapping("/download/{key}")
    public ResponseEntity<byte[]> download(@PathVariable String key) {
        byte[] data = s3Service.download(key);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + key + "\"")
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(data);
    }
}

권한과 보안

IAM 정책은 최소 권한으로 설정한다. 일반적으로 다음 권한만 허용한다.

  • s3:PutObject
  • s3:GetObject
  • s3:ListBucket(필요 시)

자격증명은 코드에 하드코딩하지 않고 환경변수, 프로파일, 또는 AWS IAM 역할을 활용한다. 공개 버킷 사용은 피한다.

성능 및 비용 고려사항

  • 큰 파일은 멀티파트 업로드를 사용하면 안정성과 속도를 개선할 수 있다.
  • 빈번한 작은 파일 업로드는 비용 상승 요인이므로 합치기 전략 고려.
  • 프리사인드 URL을 활용하면 서버 부하를 줄이고 직접 S3로 업로드 가능.

프리사인드 URL 예시

public String generatePresignedUrl(String key) {
    java.util.Date expiration = new java.util.Date();
    long expTimeMillis = expiration.getTime();
    expTimeMillis += 1000 * 60 * 60; // 1 hour
    expiration.setTime(expTimeMillis);

    com.amazonaws.services.s3.model.GeneratePresignedUrlRequest generatePresignedUrlRequest =
            new com.amazonaws.services.s3.model.GeneratePresignedUrlRequest(bucket, key)
                    .withMethod(com.amazonaws.HttpMethod.PUT)
                    .withExpiration(expiration);
    return amazonS3.generatePresignedUrl(generatePresignedUrlRequest).toString();
}

요약 및 권장 흐름

핵심 흐름은 다음과 같다.

  • 의존성 추가 및 AmazonS3 빈 등록
  • IAM 권한 최소화
  • MultipartFile로 업로드, 스트리밍으로 다운로드
  • 대용량은 멀티파트/프리사인드 사용

위 구현을 바탕으로 테스트와 로깅을 추가하면 운영 환경에서도 안정적으로 S3 연동을 유지할 수 있다. spring boot s3 업로드 예제와 aws s3 spring boot 연동, spring boot upload s3 관련 요구사항을 충족하도록 설계되어 있다.

spring boot s3 업로드 예제 aws s3 spring boot 연동 spring boot upload s3 aws s3 spring boot 파일 업로드 amazon s3 s3 다운로드 s3 프리사인드 URL