diff --git a/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java b/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java index b5c173e..93d7f58 100644 --- a/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java +++ b/src/main/java/com/assu/server/domain/inquiry/controller/InquiryController.java @@ -123,4 +123,18 @@ public BaseResponse uploadOrReplaceProfileImage( String key = profileImageService.updateProfileImage(pd.getMemberId(), image); return BaseResponse.onSuccess(SuccessStatus._OK, new ProfileImageResponse(key)); } + + @Operation( + summary = "프로필 이미지 조회 API", + description = "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2711197c19ed8039bbe2c48380c9f4c8?source=copy_link)\n" + + "- 로그인한 사용자의 프로필 이미지 presigned URL을 반환합니다.\n" + + "- URL은 일정 시간 동안만 유효합니다." + ) + @GetMapping("/profile/image") + public BaseResponse getProfileImage( + @AuthenticationPrincipal PrincipalDetails pd + ) { + String url = profileImageService.getProfileImageUrl(pd.getMemberId()); + return BaseResponse.onSuccess(SuccessStatus._OK, new ProfileImageResponse(url)); + } } \ No newline at end of file diff --git a/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageService.java b/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageService.java index d19a5db..09a2282 100644 --- a/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageService.java +++ b/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageService.java @@ -4,4 +4,5 @@ public interface ProfileImageService { String updateProfileImage(Long memberId, MultipartFile image); + String getProfileImageUrl(Long memberId); } diff --git a/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageServiceImpl.java b/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageServiceImpl.java index 3f79788..79fee6f 100644 --- a/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageServiceImpl.java +++ b/src/main/java/com/assu/server/domain/inquiry/service/ProfileImageServiceImpl.java @@ -51,5 +51,27 @@ public String updateProfileImage(Long memberId, MultipartFile image) { // 5) 호출자에 key 반환 (FE는 필요 시 presigned URL 생성해 사용) return uploadedKey; } + + @Override + @Transactional(readOnly = true) + public String getProfileImageUrl(Long memberId) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new CustomAuthException(ErrorStatus.NO_SUCH_MEMBER)); + + String keyOrUrl = member.getProfileUrl(); + if (keyOrUrl == null || keyOrUrl.isBlank()) { + throw new CustomAuthException(ErrorStatus.PROFILE_IMAGE_NOT_FOUND); + } + + if (keyOrUrl.startsWith("http://") || keyOrUrl.startsWith("https://")) { + return keyOrUrl; + } + + String presigned = amazonS3Manager.generatePresignedUrl(keyOrUrl); + if (presigned == null) { + throw new CustomAuthException(ErrorStatus.PROFILE_IMAGE_NOT_FOUND); + } + return presigned; + } } diff --git a/src/main/java/com/assu/server/infra/s3/AmazonS3Manager.java b/src/main/java/com/assu/server/infra/s3/AmazonS3Manager.java index 8ec2f5d..6c875a4 100644 --- a/src/main/java/com/assu/server/infra/s3/AmazonS3Manager.java +++ b/src/main/java/com/assu/server/infra/s3/AmazonS3Manager.java @@ -71,7 +71,7 @@ public String uploadFile(String keyName, byte[] fileBytes, String contentType) { } - // FE로 url을 보내기 위해 사용하는 메서드 + // 그대로 사용 public String generatePresignedUrl(String keyName) { if (keyName == null || keyName.isBlank()) return null; @@ -81,7 +81,7 @@ public String generatePresignedUrl(String keyName) { .build(); GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() - .signatureDuration(Duration.ofMinutes(10)) + .signatureDuration(Duration.ofMinutes(10)) // 유효기간 10분 .getObjectRequest(getObjectRequest) .build();