Skip to content

Commit e2494db

Browse files
authored
RINGUS-44 refactor: 파일 로드 api 리팩토링 (#28)
* RINGUS-44 feat: 증명서 및 이미지 로직 관심사 분리 * RINGUS-44 feat: 프로필 이미지 조회 api 및 에러코드 작성 * RINGUS-44 fix: 조회 기능 삭제
1 parent 6ce9e23 commit e2494db

File tree

10 files changed

+178
-105
lines changed

10 files changed

+178
-105
lines changed

src/main/java/es/princip/ringus/domain/exception/MenteeErrorCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import org.springframework.http.HttpStatus;
55

66
public enum MenteeErrorCode implements ErrorCode {
7-
MENTEE_PROFILE_NOT_FOUND(HttpStatus.NOT_FOUND, "멘티 프로필을 등록한 적이 없음");
7+
MENTEE_PROFILE_NOT_FOUND(HttpStatus.NOT_FOUND, "멘티 프로필을 등록한 적이 없음"),
8+
MENTEE_NOT_FOUND(HttpStatus.NOT_FOUND, "멘티 정보를 찾을 수 없음");
89

910
MenteeErrorCode(HttpStatus status, String message) {
1011
this.status = status;

src/main/java/es/princip/ringus/domain/exception/MentorErrorCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import org.springframework.http.HttpStatus;
55

66
public enum MentorErrorCode implements ErrorCode {
7-
MENTOR_PROFILE_NOT_FOUND(HttpStatus.NOT_FOUND, "멘토 프로필을 등록한 적이 없음");
7+
MENTOR_PROFILE_NOT_FOUND(HttpStatus.NOT_FOUND, "멘토 프로필을 등록한 적이 없음"),
8+
MENTOR_NOT_FOUND(HttpStatus.NOT_FOUND, "멘토 정보를 찾을 수 없음");
89

910
MentorErrorCode(HttpStatus status, String message) {
1011
this.status = status;
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package es.princip.ringus.domain.exception;
2+
3+
import es.princip.ringus.global.exception.ErrorCode;
4+
import org.springframework.http.HttpStatus;
5+
6+
public enum ProfileErrorCode implements ErrorCode {
7+
PROFILE_NOT_FOUND(HttpStatus.NOT_FOUND,"프로필을 찾을 수 없음");
8+
9+
ProfileErrorCode(HttpStatus status,String message) {
10+
this.status = status;
11+
this.message = message;
12+
}
13+
14+
private final HttpStatus status;
15+
private final String message;
16+
17+
@Override
18+
public HttpStatus status() {
19+
return this.status;
20+
}
21+
22+
@Override
23+
public String message() {
24+
return this.message;
25+
}
26+
27+
@Override
28+
public String code() {
29+
return this.name();
30+
}
31+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package es.princip.ringus.global.util;
2+
3+
import es.princip.ringus.domain.member.MemberType;
4+
import es.princip.ringus.infra.storage.domain.CertificateType;
5+
6+
public class StoragePathUtil {
7+
8+
private StoragePathUtil() {} // 유틸리티 클래스이므로 인스턴스화 방지
9+
10+
/**
11+
* 증명서 폴더 경로 생성
12+
*/
13+
public static String buildCertificateFolderPath(CertificateType certificateType, Boolean isMentor) {
14+
String roleFolder = isMentor ? "mentor" : "mentee";
15+
return String.format("certificates/%s/%s", roleFolder, certificateType.name().toLowerCase());
16+
}
17+
18+
/**
19+
* 프로필 이미지 폴더 경로 생성
20+
*/
21+
public static String buildProfileFolderPath(MemberType userType) {
22+
return String.format("images/profile/%s", userType.name().toLowerCase());
23+
}
24+
}

src/main/java/es/princip/ringus/infra/storage/api/StorageController.java renamed to src/main/java/es/princip/ringus/infra/storage/api/CertificateController.java

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,42 @@
33
import es.princip.ringus.domain.exception.MemberErrorCode;
44
import es.princip.ringus.global.exception.CustomRuntimeException;
55
import es.princip.ringus.global.util.ApiResponseWrapper;
6-
import es.princip.ringus.infra.storage.application.StorageService;
6+
import es.princip.ringus.infra.storage.application.StorageCertificateService;
77
import es.princip.ringus.infra.storage.dto.CertificateUploadRequest;
8-
import es.princip.ringus.infra.storage.dto.ProfileUploadRequest;
98
import jakarta.servlet.http.HttpSession;
109
import lombok.RequiredArgsConstructor;
1110
import org.springframework.http.HttpStatus;
1211
import org.springframework.http.ResponseEntity;
13-
import org.springframework.web.bind.annotation.ModelAttribute;
14-
import org.springframework.web.bind.annotation.PostMapping;
15-
import org.springframework.web.bind.annotation.RequestMapping;
16-
import org.springframework.web.bind.annotation.RestController;
12+
import org.springframework.web.bind.annotation.*;
1713

1814
@RestController
19-
@RequestMapping("/storage")
15+
@RequestMapping("/storage/certificate")
2016
@RequiredArgsConstructor
21-
public class StorageController {
22-
23-
private final StorageService storageService;
17+
public class CertificateController {
2418

19+
private final StorageCertificateService storageCertificateService;
2520
/**
2621
* 멘티 증명서 업로드
2722
*/
28-
@PostMapping("/certificate/mentee")
23+
@PostMapping("/mentee")
2924
public ResponseEntity<ApiResponseWrapper<Void>> uploadMenteeCertificate(
3025
@ModelAttribute CertificateUploadRequest certificateUploadRequest,
3126
HttpSession session
32-
) {
27+
) {
3328

3429
Long memberId = (Long)session.getAttribute("memberId");
3530
if(memberId == null){
3631
throw new CustomRuntimeException(MemberErrorCode.SESSION_EXPIRED);
3732
}
3833

39-
String filePath = storageService.uploadMenteeCertificate(certificateUploadRequest,memberId);
34+
String filePath = storageCertificateService.uploadMenteeCertificate(certificateUploadRequest,memberId);
4035
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, filePath));
4136
}
4237

4338
/**
4439
* 멘토 증명서 업로드
4540
*/
46-
@PostMapping("/certificate/mentor")
41+
@PostMapping("/mentor")
4742
public ResponseEntity<ApiResponseWrapper<Void>> uploadMentorCertificate(
4843
@ModelAttribute CertificateUploadRequest certificateUploadRequest,
4944
HttpSession session
@@ -53,25 +48,8 @@ public ResponseEntity<ApiResponseWrapper<Void>> uploadMentorCertificate(
5348
throw new CustomRuntimeException(MemberErrorCode.SESSION_EXPIRED);
5449
}
5550

56-
String filePath = storageService.uploadMentorCertificate(certificateUploadRequest, memberId);
51+
String filePath = storageCertificateService.uploadMentorCertificate(certificateUploadRequest, memberId);
5752
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, filePath));
5853
}
5954

60-
/**
61-
* 프로필 이미지 업로드
62-
*/
63-
@PostMapping("/profile/image")
64-
public ResponseEntity<ApiResponseWrapper<Void>> uploadProfileImage(
65-
@ModelAttribute ProfileUploadRequest request,
66-
HttpSession session
67-
) {
68-
69-
Long memberId = (Long)session.getAttribute("memberId");
70-
if(memberId == null){
71-
throw new CustomRuntimeException(MemberErrorCode.SESSION_EXPIRED);
72-
}
73-
74-
String filePath = storageService.uploadProfileImage(request);
75-
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, filePath));
76-
}
7755
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package es.princip.ringus.infra.storage.api;
2+
3+
import es.princip.ringus.domain.exception.MemberErrorCode;
4+
import es.princip.ringus.global.exception.CustomRuntimeException;
5+
import es.princip.ringus.global.util.ApiResponseWrapper;
6+
import es.princip.ringus.infra.storage.application.StorageProfileImageService;
7+
import es.princip.ringus.infra.storage.dto.ProfileUploadRequest;
8+
import jakarta.servlet.http.HttpSession;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.http.HttpStatus;
11+
import org.springframework.http.ResponseEntity;
12+
import org.springframework.web.bind.annotation.*;
13+
14+
@RestController
15+
@RequestMapping("/storage/profile")
16+
@RequiredArgsConstructor
17+
public class ProfileImageController {
18+
19+
private final StorageProfileImageService storageProfileService;
20+
21+
/**
22+
* 프로필 이미지 업로드
23+
*/
24+
@PostMapping("/image")
25+
public ResponseEntity<ApiResponseWrapper<Void>> uploadProfileImage(
26+
@ModelAttribute ProfileUploadRequest request,
27+
HttpSession session
28+
) {
29+
30+
Long memberId = (Long)session.getAttribute("memberId");
31+
if(memberId == null){
32+
throw new CustomRuntimeException(MemberErrorCode.SESSION_EXPIRED);
33+
}
34+
35+
String filePath = storageProfileService.uploadProfileImage(request);
36+
return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, filePath));
37+
}
38+
39+
}

src/main/java/es/princip/ringus/infra/storage/application/S3Service.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public class S3Service {
2525
/**
2626
* S3에 파일 업로드
2727
* @param file 업로드할 파일
28-
* @param folderPath S3에 저장할 폴더 경로 (예: "profile-images/mentor", "certificates/mentee/ENROLLMENT" 등)
28+
* @param folderPath S3에 저장할 폴더 경로 (예: "images/profile/mentor", "certificates/mentee/ENROLLMENT" 등)
2929
* @return 업로드된 파일의 S3 URL
3030
*/
3131
public String uploadFile(MultipartFile file, String folderPath) {
@@ -53,7 +53,7 @@ public String uploadFile(MultipartFile file, String folderPath) {
5353
/**
5454
* S3에 저장된 파일의 URL 반환
5555
*/
56-
private String getFileUrl(String s3Key) {
56+
protected String getFileUrl(String s3Key) {
5757
return "https://" + bucketName + ".s3.amazonaws.com/" + s3Key;
5858
}
5959

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package es.princip.ringus.infra.storage.application;
2+
3+
import es.princip.ringus.global.util.StoragePathUtil;
4+
import es.princip.ringus.infra.storage.domain.FileMemberRepository;
5+
import es.princip.ringus.infra.storage.dto.CertificateUploadRequest;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.stereotype.Service;
8+
import org.springframework.transaction.annotation.Transactional;
9+
10+
@Service
11+
@Transactional(readOnly = true)
12+
@RequiredArgsConstructor
13+
public class StorageCertificateService {
14+
private final S3Service s3Service;
15+
private final FileMemberRepository fileMemberRepository;
16+
17+
/**
18+
* 멘티 증명서 업로드
19+
*/
20+
@Transactional
21+
public String uploadMenteeCertificate(CertificateUploadRequest request, Long memberId) {
22+
String folderPath = StoragePathUtil.buildCertificateFolderPath(request.certificateType(), false);
23+
String filePath = s3Service.uploadFile(request.file(), folderPath);
24+
25+
fileMemberRepository.save(request.toFileMemberEntity(filePath, memberId));
26+
27+
return filePath;
28+
}
29+
30+
/**
31+
* 멘토 증명서 업로드
32+
*/
33+
@Transactional
34+
public String uploadMentorCertificate(CertificateUploadRequest request, Long memberId) {
35+
String folderPath = StoragePathUtil.buildCertificateFolderPath(request.certificateType(), true);
36+
String filePath = s3Service.uploadFile(request.file(), folderPath);
37+
38+
fileMemberRepository.save(request.toFileMemberEntity(filePath, memberId));
39+
40+
return filePath;
41+
}
42+
43+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package es.princip.ringus.infra.storage.application;
2+
3+
import es.princip.ringus.global.util.StoragePathUtil;
4+
import es.princip.ringus.infra.storage.dto.ProfileUploadRequest;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.stereotype.Service;
7+
import org.springframework.transaction.annotation.Transactional;
8+
9+
@Service
10+
@Transactional(readOnly = true)
11+
@RequiredArgsConstructor
12+
public class StorageProfileImageService {
13+
14+
private final S3Service s3Service;
15+
16+
/**
17+
* 프로필 이미지 업로드
18+
*/
19+
@Transactional
20+
public String uploadProfileImage(ProfileUploadRequest request) {
21+
String folderPath = StoragePathUtil.buildProfileFolderPath(request.memberType());
22+
return s3Service.uploadFile(request.file(), folderPath);
23+
}
24+
25+
}

src/main/java/es/princip/ringus/infra/storage/application/StorageService.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

0 commit comments

Comments
 (0)