-
Notifications
You must be signed in to change notification settings - Fork 1
feat: S3 이미지 업로드 API 추가 #147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
이 PR은 사용자가 이미지 파일을 S3에 업로드할 수 있는 기능을 추가합니다. POST /upload/image 엔드포인트를 통해 png, jpg, webp 형식의 이미지를 업로드하며, AWS S3에 저장된 후 CloudFront URL을 반환합니다.
Changes:
- S3 이미지 업로드 API 엔드포인트 추가 (인증 필요)
- AWS SDK v2 의존성 및 S3 클라이언트 설정 추가
- 파일 타입 및 크기 검증 로직 구현
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| build.gradle | AWS SDK v2 BOM 및 S3 클라이언트 의존성 추가 |
| S3StorageProperties.java | S3 버킷, 리전, 키 프리픽스, 최대 업로드 크기 설정을 위한 configuration properties |
| StorageCdnProperties.java | CloudFront CDN base URL 설정을 위한 configuration properties |
| S3ClientConfig.java | AWS S3 클라이언트 빈 설정 (lazy initialization) |
| ApiResponseCode.java | 파일 업로드 관련 에러 코드 추가 (INVALID_FILE_CONTENT_TYPE, INVALID_FILE_SIZE, FAILED_UPLOAD_FILE) |
| UploadService.java | S3 업로드 비즈니스 로직, 파일 검증, 키 생성 구현 |
| ImageUploadResponse.java | S3 object key와 CDN URL을 포함한 응답 DTO |
| UploadApi.java | 이미지 업로드 API 인터페이스 정의 (Swagger 문서 포함) |
| UploadController.java | UploadApi 구현체, 인증된 사용자만 접근 가능 |
src/main/java/gg/agit/konect/domain/upload/service/UploadService.java
Outdated
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/upload/service/UploadService.java
Outdated
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/upload/dto/ImageUploadResponse.java
Outdated
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/upload/controller/UploadController.java
Show resolved
Hide resolved
src/main/java/gg/agit/konect/domain/upload/service/UploadService.java
Outdated
Show resolved
Hide resolved
|
8708da8 to
81ab8a2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 8 out of 9 changed files in this pull request and generated 6 comments.
| private void validateS3Configuration() { | ||
| if (s3StorageProperties.bucket() == null || s3StorageProperties.bucket().isBlank()) { | ||
| throw CustomException.of(ApiResponseCode.ILLEGAL_STATE, "storage.s3.bucket 설정이 필요합니다."); | ||
| } | ||
|
|
||
| if (s3StorageProperties.region() == null || s3StorageProperties.region().isBlank()) { | ||
| throw CustomException.of(ApiResponseCode.ILLEGAL_STATE, "storage.s3.region 설정이 필요합니다."); | ||
| } | ||
| } |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
설정 검증(validateS3Configuration)이 매 요청마다 실행됩니다. 이 설정 값들은 애플리케이션 시작 시 한 번만 검증하면 되는 불변 값입니다. 설정 검증을 @PostConstruct 메서드로 이동하여 서비스 빈이 생성될 때 한 번만 실행되도록 하면 성능이 개선되고, 잘못된 설정으로 인한 문제를 더 빨리 발견할 수 있습니다. 또한, 애플리케이션 시작 시 설정 오류를 즉시 감지할 수 있어 운영상 안전합니다.
| private String trimTrailingSlash(String baseUrl) { | ||
| if (baseUrl == null || baseUrl.isBlank()) { | ||
| throw CustomException.of(ApiResponseCode.ILLEGAL_STATE, "storage.cdn.base-url 설정이 필요합니다."); | ||
| } |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trimTrailingSlash 메서드에서 baseUrl 검증이 매 요청마다 실행됩니다. 이 검증은 validateS3Configuration과 함께 @PostConstruct 메서드로 이동하여 애플리케이션 시작 시 한 번만 실행되도록 하는 것이 좋습니다. 이렇게 하면 잘못된 설정을 더 빨리 발견하고 런타임 오버헤드를 줄일 수 있습니다.
| String fileUrl = trimTrailingSlash(storageCdnProperties.baseUrl()) + "/" + key; | ||
| return new ImageUploadResponse(key, fileUrl); |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trimTrailingSlash와 normalizePrefix 메서드가 매 요청마다 동일한 문자열 변환을 수행합니다. 이 값들은 설정으로부터 가져온 불변 값이므로, @PostConstruct 메서드에서 한 번만 처리하여 필드 변수에 저장해 두는 것이 효율적입니다. 이렇게 하면 매 업로드 요청마다 불필요한 문자열 처리를 피할 수 있습니다.
| @Bean | ||
| @Lazy | ||
| public S3Client s3Client(S3StorageProperties s3StorageProperties) { | ||
| return S3Client.builder() | ||
| .region(Region.of(s3StorageProperties.region())) | ||
| .credentialsProvider(DefaultCredentialsProvider.builder().build()) | ||
| .build(); | ||
| } |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
S3Client 빈이 @Lazy로 표시되어 있어 첫 번째 사용 시점에만 생성됩니다. 이는 S3 설정이 잘못되어도 애플리케이션이 시작될 수 있게 하지만, 운영 환경에서 첫 번째 파일 업로드 시도 시 실패할 위험이 있습니다. S3가 필수 기능이라면 @Lazy를 제거하여 애플리케이션 시작 시 설정 오류를 즉시 감지하는 것을 고려해야 합니다. 또는 현재대로 유지하려면 헬스체크 엔드포인트에서 S3 연결을 확인하는 것을 고려해야 합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
🔍 개요
🚀 주요 변경 내용
POST /upload/image엔드포인트를 추가했습니다.확장자가
png,jpg,webp인 이미지에 대해서만 업로드를 허용합니다.업로드된 파일은
kap-test버킷의konect폴더로 저장됩니다.💬 참고 사항
✅ Checklist (완료 조건)