-
Notifications
You must be signed in to change notification settings - Fork 0
[Feature] S3 이미지 업로드 기능 구현 #60
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
Conversation
Summary of ChangesHello @hyobin-yang, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 Pull Request는 애플리케이션의 이미지 저장 방식을 AWS S3 기반으로 전환하여, 기존의 단순 URL 저장 방식의 한계를 극복하고 이미지 관리의 안정성과 확장성을 확보합니다. 사용자 프로필 및 게시물 이미지 업로드를 위한 전용 API를 제공하며, 파일 크기 및 형식 검증, 고유 파일명 생성 등 견고한 이미지 처리 로직을 포함합니다. 이를 통해 사용자 경험을 개선하고, 향후 이미지 관련 기능 확장을 위한 기반을 마련합니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
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.
Code Review
This pull request introduces AWS S3 image upload functionality. Key changes include adding the AWS SDK v2 BOM to build.gradle, configuring S3 credentials and bucket details in application.yml files, and setting multipart file size limits. A new S3ImageService was created to handle image uploads, including validation for file type, size, and emptiness, and generating unique filenames. A new ImageController provides an endpoint for uploading multiple images to S3, returning their URLs. The AuthService and AuthController were modified to integrate this new image upload capability into the user signup process, allowing users to upload a profile image as a MultipartFile instead of providing a URL, and removing the profileImage field from SignupRequestDto. Error handling in GlobalExceptionHandler was enhanced to better manage BusinessExceptions wrapped within other exceptions. Review comments suggest improving the S3Client configuration to use DefaultCredentialsProvider for more flexible credential management, changing ALLOWED_CONTENT_TYPES to a Set for better performance, refactoring the uploadImages method to use Java Streams, and enhancing the filename generation logic for robustness. Additionally, it was suggested to include the user ID in S3 object keys for better organization and access control.
| public S3Client s3Client() { | ||
| AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(accessKey, secretKey); | ||
| return S3Client.builder() | ||
| .region(Region.of(region)) | ||
| .credentialsProvider(StaticCredentialsProvider.create(awsCredentials)) | ||
| .build(); | ||
| } |
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.
StaticCredentialsProvider를 사용하여 자격 증명을 명시적으로 설정하는 것보다 DefaultCredentialsProvider.create()를 사용하는 것이 더 유연하고 안전합니다. DefaultCredentialsProvider는 환경 변수, 시스템 속성, 자격 증명 파일, EC2/ECS 인스턴스 프로필 등 표준적인 위치에서 자동으로 자격 증명을 찾아 사용합니다. 이렇게 하면 로컬 개발 환경과 실제 배포 환경(e.g., EC2)에서 코드를 변경하지 않고도 각 환경에 맞는 자격 증명을 사용할 수 있습니다. 이 변경을 적용하면 accessKey, secretKey 필드와 관련 @Value 어노테이션, 그리고 AwsBasicCredentials, StaticCredentialsProvider import를 제거할 수 있습니다.
| public S3Client s3Client() { | |
| AwsBasicCredentials awsCredentials = AwsBasicCredentials.create(accessKey, secretKey); | |
| return S3Client.builder() | |
| .region(Region.of(region)) | |
| .credentialsProvider(StaticCredentialsProvider.create(awsCredentials)) | |
| .build(); | |
| } | |
| @Bean | |
| public S3Client s3Client() { | |
| return S3Client.builder() | |
| .region(Region.of(region)) | |
| .credentialsProvider(software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider.create()) | |
| .build(); | |
| } |
| private static final List<String> ALLOWED_CONTENT_TYPES = Arrays.asList( | ||
| "image/jpeg", "image/jpg", "image/png", "image/gif" | ||
| ); |
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.
ALLOWED_CONTENT_TYPES를 List 대신 Set으로 관리하면 contains 연산의 시간 복잡도가 O(N)에서 O(1)로 개선되어 성능상 이점이 있습니다. 상수의 경우 Set.of()를 사용하여 불변 Set으로 선언하는 것을 권장합니다. 이 변경과 함께 java.util.Set을 import하고, java.util.Arrays import는 제거해주세요.
| private static final List<String> ALLOWED_CONTENT_TYPES = Arrays.asList( | |
| "image/jpeg", "image/jpg", "image/png", "image/gif" | |
| ); | |
| private static final java.util.Set<String> ALLOWED_CONTENT_TYPES = java.util.Set.of( | |
| "image/jpeg", "image/jpg", "image/png", "image/gif" | |
| ); |
| public List<String> uploadImages(List<MultipartFile> images) { | ||
| List<String> uploadedUrls = new ArrayList<>(); | ||
|
|
||
| for (MultipartFile image : images) { | ||
| String url = uploadImage(image); | ||
| uploadedUrls.add(url); | ||
| } | ||
|
|
||
| return uploadedUrls; |
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.
|
|
||
| try { | ||
| String fileName = generateFileName(file.getOriginalFilename()); | ||
| String key = "images/" + fileName; |
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.
| private String generateFileName(String originalFilename) { | ||
| String extension = ""; | ||
| if (originalFilename != null && originalFilename.contains(".")) { | ||
| extension = originalFilename.substring(originalFilename.lastIndexOf(".")); | ||
| } | ||
| return UUID.randomUUID() + extension; | ||
| } |
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.
현재 확장자 추출 로직은 .bashrc와 같이 점으로 시작하는 파일의 경우 .bashrc 전체를 확장자로 인식하고, myfile.와 같이 점으로 끝나는 파일의 경우 .을 확장자로 인식하는 등 예외적인 케이스에 취약할 수 있습니다. 보다 안전하게 확장자를 추출하도록 로직을 개선하는 것을 제안합니다.
private String generateFileName(String originalFilename) {
String extension = "";
if (originalFilename != null) {
int dotIndex = originalFilename.lastIndexOf('.');
if (dotIndex > 0 && dotIndex < originalFilename.length() - 1) {
extension = originalFilename.substring(dotIndex);
}
}
return UUID.randomUUID().toString() + extension;
}
S3 이미지 업로드 기능 구현
개요
기존의 이미지 URL을 String으로 직접 저장하는 방식에서, 실제 이미지 파일을 AWS S3에 업로드하고 업로드된 이미지 URL을 저장하는 방식으로 변경했습니다. 프로필 이미지와 포스트 이미지 업로드를 지원합니다.
구현 내용
1. API 엔드포인트
POST
/images/uploadmultipart/form-dataimage(MultipartFile){ "imageUrl": "https://bucket-name.s3.ap-northeast-2.amazonaws.com/images/uuid.jpg" }2. 파일 크기 제한: 10MB
이미지 파일 크기를 10MB로 제한한 이유:
서버 메모리(RAM) 보호
충분한 크기
네트워크 및 처리 시간 최적화
3. S3Client 사용 이유
S3Template대신 AWS SDK v2의S3Client를 직접 사용한 이유:영구적인 이미지 URL 제공
S3Template의getObjectUrl()메서드는 기본적으로 Presigned URL을 생성합니다https://버킷명.s3.리전.amazonaws.com/키형태의 문자열을 생성하는 방식이 영구적인 이미지 제공에 더 적합합니다명시적인 URL 생성
더 세밀한 제어
4. S3 URL 생성 규칙
S3 이미지 URL은 다음 규칙으로 생성됩니다:
구성 요소:
bucketName:application.yml에서 설정한 S3 버킷 이름region: AWS 리전 (기본값:ap-northeast-2)key:images/{UUID}.{확장자}형식예시:
파일명 생성 규칙:
images/디렉토리 하위에 저장하여 구조화UUID 사용 이유:
파일명 충돌 방지
보안 강화
고유성 보장
확장성
5. 허용하는 파일 형식
다음 이미지 형식만 업로드 가능합니다:
image/jpeg,image/jpg)image/png)image/gif)검증 방식:
MultipartFile.getContentType()을 사용하여 MIME 타입 검증6. 예외 처리
다음과 같은 예외 상황을 처리합니다:
IMAGE_400IMAGE_401IMAGE_402IMAGE_5007. 파일 업로드 프로세스
파일 검증
파일명 생성
S3 업로드
URL 생성 및 반환
8. 컨트롤러 구현
@RequestPart사용: multipart/form-data 요청에서 특정 파트를 명확하게 지정consumes = MediaType.MULTIPART_FORM_DATA_VALUE: Content-Type 명시image(클라이언트에서image필드로 전송)9. 설정
application.yml에서max-file-size: 10MB설정application-secret.yml또는application-prod.yml에서 버킷명, 자격 증명, 리전 설정AppConfig에서 AWS 자격 증명을 사용하여 S3Client Bean 생성10. 보안 고려사항
12. 향후 개선 사항