From 3349a211502eae0fafb1e096e29fcebf9910036b Mon Sep 17 00:00:00 2001 From: MiN <81948815+leesumin0526@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:44:03 +1000 Subject: [PATCH 1/2] =?UTF-8?q?[FEAT/#128]=20-=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=95=84=20=EC=82=AC=EC=A7=84=20=EC=A1=B0=ED=9A=8C=20API=20?= =?UTF-8?q?=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inquiry/controller/InquiryController.java | 14 ++++++++++++ .../inquiry/service/ProfileImageService.java | 1 + .../service/ProfileImageServiceImpl.java | 22 +++++++++++++++++++ .../assu/server/infra/s3/AmazonS3Manager.java | 4 ++-- 4 files changed, 39 insertions(+), 2 deletions(-) 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..a8a6807 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)](/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(); From e1bec634ae4e7dc894e62816f962c620141b7f43 Mon Sep 17 00:00:00 2001 From: MiN <81948815+leesumin0526@users.noreply.github.com> Date: Thu, 18 Sep 2025 00:56:21 +1000 Subject: [PATCH 2/2] =?UTF-8?q?[FEAT/#128]=20-=20=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../server/domain/inquiry/controller/InquiryController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a8a6807..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 @@ -126,7 +126,7 @@ public BaseResponse uploadOrReplaceProfileImage( @Operation( summary = "프로필 이미지 조회 API", - description = "# [v1.0 (2025-09-18)](/2711197c19ed8039bbe2c48380c9f4c8?source=copy_link)\n" + + description = "# [v1.0 (2025-09-18)](https://clumsy-seeder-416.notion.site/2711197c19ed8039bbe2c48380c9f4c8?source=copy_link)\n" + "- 로그인한 사용자의 프로필 이미지 presigned URL을 반환합니다.\n" + "- URL은 일정 시간 동안만 유효합니다." )