Skip to content

Commit 7e0a491

Browse files
authored
refactor: 파일 업로드 로직 수정 (#73)
* refactor: 파일 업로드 로직 수정 * chore: log debug 변경 * chore: 발표자료 수정 로직 변경 * chore: S3 이동 실패시 예외처리 추가
1 parent 9779537 commit 7e0a491

File tree

6 files changed

+97
-9
lines changed

6 files changed

+97
-9
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.oronaminc.join.document.event;
2+
3+
public record DocumentCreateEvent(String objectKey, String fileName) { }
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.oronaminc.join.document.event;
2+
3+
4+
import com.oronaminc.join.global.exception.ErrorCode;
5+
import com.oronaminc.join.global.exception.ErrorException;
6+
import com.oronaminc.join.infra.service.S3Service;
7+
import lombok.RequiredArgsConstructor;
8+
import lombok.extern.slf4j.Slf4j;
9+
import org.springframework.stereotype.Component;
10+
import org.springframework.transaction.event.TransactionPhase;
11+
import org.springframework.transaction.event.TransactionalEventListener;
12+
13+
14+
@Slf4j
15+
@Component
16+
@RequiredArgsConstructor
17+
public class DocumentEventHandler {
18+
19+
private final S3Service s3Service;
20+
21+
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
22+
public void handleDocumentEvent(DocumentCreateEvent event) {
23+
String newKey = "documents/" + event.fileName();
24+
25+
try {
26+
s3Service.moveObject(event.objectKey(), newKey);
27+
28+
log.debug("✅ S3 파일 이동 성공: {} → {}", event.objectKey(), newKey);
29+
} catch (Exception e) {
30+
log.error("❌ S3 파일 이동 실패: {} → {}, 이유: {}", event.objectKey(), newKey, e.getMessage(), e);
31+
throw new ErrorException(ErrorCode.MOVEMENT_FILE_FAILED);
32+
}
33+
}
34+
}

src/main/java/com/oronaminc/join/document/service/DocumentService.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.oronaminc.join.document.service;
22

3+
4+
import com.oronaminc.join.document.domain.Document;
5+
import com.oronaminc.join.document.event.DocumentCreateEvent;
6+
import org.springframework.context.ApplicationEventPublisher;
7+
38
import java.util.UUID;
49

510
import org.springframework.stereotype.Service;
@@ -17,12 +22,15 @@
1722

1823
import lombok.RequiredArgsConstructor;
1924

25+
2026
@Service
2127
@RequiredArgsConstructor
2228
public class DocumentService {
2329

2430
private final DocumentRepository documentRepository;
2531
private final S3Service s3Service;
32+
private final ApplicationEventPublisher publisher;
33+
private final DocumentReader documentReader;
2634

2735
@Transactional
2836
public void deleteByRoomId(Long roomId) {
@@ -34,8 +42,16 @@ public DocumentResponse generatePresignedUrl(DocumentRequest request, String mem
3442
throw new ErrorException(ErrorCode.UNAUTHORIZED_MEMBER);
3543
}
3644

45+
String OriginalFileName = request.fileName();
46+
String extension = "";
47+
48+
int dotIndex = OriginalFileName.lastIndexOf('.');
49+
if (dotIndex != -1) {
50+
extension = OriginalFileName.substring(dotIndex);
51+
}
52+
3753
String uuid = UUID.randomUUID().toString();
38-
String objectKey = "documents/" + uuid + "_" + request.fileName();
54+
String objectKey = "temp/" + uuid + extension;
3955
String presignedUrl = s3Service.generatePresignedUrl(objectKey);
4056

4157
return new DocumentResponse(presignedUrl, objectKey);
@@ -45,7 +61,24 @@ public DocumentResponse generatePresignedUrl(DocumentRequest request, String mem
4561
public void saveDocument(String objectKey, Room room) {
4662
String fileName = objectKey.replaceAll("^.*/","");
4763

48-
documentRepository.save(DocumentMapper.toDocument(objectKey, fileName, room));
64+
String newKey = "documents/" + fileName;
65+
66+
documentRepository.save(DocumentMapper.toDocument(newKey, fileName, room));
67+
publisher.publishEvent(new DocumentCreateEvent(objectKey, fileName));
68+
}
69+
70+
@Transactional
71+
public void updateDocument(String objectKey, Long roomId) {
72+
Document document = documentReader.getByRoomId(roomId);
73+
String fileName = objectKey.replaceAll("^.*/","");
74+
75+
String oldKey = document.getFileUrl();
76+
String newKey = "documents/" + fileName;
77+
78+
document.update(newKey);
79+
80+
s3Service.deleteFile(oldKey);
81+
publisher.publishEvent(new DocumentCreateEvent(objectKey, fileName));
4982
}
5083

5184
}

src/main/java/com/oronaminc/join/global/exception/ErrorCode.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public enum ErrorCode {
3434

3535
FILE_UPLOAD_FAILED("FILE-001", "파일 업로드에 실패하였습니다.", INTERNAL_SERVER_ERROR),
3636
NOT_FOUND_FILE("FILE-002", "존재하지 않는 파일입니다.", NOT_FOUND),
37+
MOVEMENT_FILE_FAILED("FILE-003", "파일 이동이 실패하였습니다.", INTERNAL_SERVER_ERROR),
38+
DELETE_FILE_FAILED("FILE-004", "파일 삭제에 실패하였습니다.", INTERNAL_SERVER_ERROR),
39+
3740

3841
NOT_FOUND_ROOM_QUESTION("QUESTION-001", "질문을 해당 방에서 찾을 수 없습니다.", NOT_FOUND),
3942
NOT_FOUND_QUESTION("QUESTION-002", "질문을 찾을 수 없습니다.", NOT_FOUND),

src/main/java/com/oronaminc/join/infra/service/S3Service.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
package com.oronaminc.join.infra.service;
22

3+
import com.oronaminc.join.global.exception.ErrorCode;
34
import com.oronaminc.join.global.exception.ErrorException;
45
import lombok.RequiredArgsConstructor;
56
import lombok.extern.slf4j.Slf4j;
67
import org.springframework.beans.factory.annotation.Value;
78
import org.springframework.stereotype.Service;
89
import software.amazon.awssdk.services.s3.S3Client;
9-
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
10-
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
11-
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
12-
import software.amazon.awssdk.services.s3.model.S3Exception;
10+
import software.amazon.awssdk.services.s3.model.*;
1311
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
1412
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
1513
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;
@@ -53,6 +51,7 @@ public void deleteFile(String key) {
5351
}
5452
} catch (S3Exception e) {
5553
log.error("S3Exception: {}", e.getMessage(), e);
54+
throw new ErrorException(ErrorCode.DELETE_FILE_FAILED);
5655
}
5756
}
5857

@@ -68,4 +67,21 @@ public Boolean isFileExist(String key) {
6867
return false;
6968
}
7069
}
70+
71+
public void moveObject(String objectKey, String destinationKey) {
72+
CopyObjectRequest copyRequest = CopyObjectRequest.builder()
73+
.sourceBucket(bucket)
74+
.sourceKey(objectKey)
75+
.destinationBucket(bucket)
76+
.destinationKey(destinationKey)
77+
.build();
78+
s3Client.copyObject(copyRequest);
79+
80+
DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder()
81+
.bucket(bucket)
82+
.key(objectKey)
83+
.build();
84+
85+
s3Client.deleteObject(deleteRequest);
86+
}
7187
}

src/main/java/com/oronaminc/join/room/service/RoomService.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,8 @@ public CreateRoomResponse createRoom(CreateRoomRequest createRoomRequest,
7070
Room room = RoomMapper.toRoom(createRoomRequest, code);
7171
roomRepository.save(room);
7272

73-
documentService.saveDocument(createRoomRequest.documentUrl(), room);
7473
participantService.savePresenterAndTeam(presenterEmail, createRoomRequest.teamEmail(), room);
74+
documentService.saveDocument(createRoomRequest.documentUrl(), room);
7575

7676
return RoomMapper.toCreateRoomResponse(room);
7777
}
@@ -105,15 +105,14 @@ public void updateRoom(Long memberId, Long roomId, RoomUpdateRequest updateRoomR
105105
participantService.validatePresenter(roomId, memberId);
106106

107107
Room room = roomReader.getById(roomId);
108-
Document document = documentReader.getByRoomId(roomId);
109108

110109
if (room.getRoomStatus().equals(RoomStatus.STARTED)) {
111110
throw new ErrorException(BAD_REQUEST_ROOM_STARTED);
112111
}
113112

114-
document.update(updateRoomRequest.documentUrl());
115113
room.update(updateRoomRequest);
116114
participantService.updateTeam(room, updateRoomRequest.teamEmail());
115+
documentService.updateDocument(updateRoomRequest.documentUrl(), roomId);
117116
}
118117

119118
@Transactional

0 commit comments

Comments
 (0)