-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: ExamImage Entity 작성 * feat: Exam Image 테이블 생성 sql 작성 * feat: servlet max file size * refactor: exam image의 id를 uuid로 변경 * feat: 시험 지문에 사용될 이미지 업로드 기능 구현 * feat: upload image 컨트롤러 응답 dto 구현 * feat: 시험 지문 이미지 업로드 기능 테스트 코드 작성 * feat: 시험 지문 이미지 업로드 기능 명세서 작성
- Loading branch information
Showing
12 changed files
with
209 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 4 additions & 0 deletions
4
server/src/main/java/com/fluffy/exam/api/response/UploadExamImageResponse.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package com.fluffy.exam.api.response; | ||
|
||
public record UploadExamImageResponse(String path) { | ||
} |
62 changes: 62 additions & 0 deletions
62
server/src/main/java/com/fluffy/exam/application/ExamImageService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.fluffy.exam.application; | ||
|
||
import com.fluffy.auth.domain.Member; | ||
import com.fluffy.auth.domain.MemberRepository; | ||
import com.fluffy.exam.domain.Exam; | ||
import com.fluffy.exam.domain.ExamImage; | ||
import com.fluffy.exam.domain.ExamImageRepository; | ||
import com.fluffy.exam.domain.ExamRepository; | ||
import com.fluffy.global.exception.ForbiddenException; | ||
import com.fluffy.global.web.Accessor; | ||
import com.fluffy.storage.application.StorageClient; | ||
import java.util.UUID; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class ExamImageService { | ||
|
||
private final StorageClient storageClient; | ||
private final ExamImageRepository examImageRepository; | ||
private final ExamRepository examRepository; | ||
private final MemberRepository memberRepository; | ||
|
||
@Transactional | ||
public String uploadImage(Long examId, MultipartFile image, Accessor accessor) { | ||
validateExamAuthor(examId, accessor); | ||
|
||
UUID imageId = UUID.randomUUID(); | ||
|
||
Long fileSize = image.getSize(); | ||
String filePath = generateUploadPath(imageId, accessor.id(), image.getOriginalFilename()); | ||
|
||
ExamImage examImage = new ExamImage(imageId, accessor.id(), examId, filePath, fileSize); | ||
examImageRepository.save(examImage); | ||
|
||
try { | ||
return storageClient.upload(image, filePath); | ||
} catch (Exception e) { | ||
examImageRepository.delete(examImage); | ||
throw e; | ||
} | ||
} | ||
|
||
private void validateExamAuthor(Long examId, Accessor accessor) { | ||
Exam exam = examRepository.findByIdOrThrow(examId); | ||
Member member = memberRepository.findByIdOrThrow(accessor.id()); | ||
|
||
if (exam.isNotWrittenBy(member.getId())) { | ||
throw new ForbiddenException("시험 작성자만 이미지를 업로드할 수 있습니다."); | ||
} | ||
} | ||
|
||
private String generateUploadPath(UUID imageId, Long memberId, String originalFilename) { | ||
int lastDotIndex = originalFilename.lastIndexOf("."); | ||
String extension = originalFilename.substring(lastDotIndex + 1); | ||
|
||
return "images/%d/exams/%s.%s".formatted(memberId, imageId, extension); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
server/src/main/java/com/fluffy/exam/domain/ExamImage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.fluffy.exam.domain; | ||
|
||
import com.fluffy.global.persistence.AuditableEntity; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import java.util.UUID; | ||
import lombok.AccessLevel; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
public class ExamImage extends AuditableEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.UUID) | ||
private UUID id; | ||
|
||
@Column(nullable = false) | ||
private Long memberId; | ||
|
||
@Column(nullable = false) | ||
private Long examId; | ||
|
||
@Column(nullable = false) | ||
private String path; | ||
|
||
@Column(nullable = false) | ||
private Long fileSize; | ||
|
||
public ExamImage(Long memberId, Long examId, String path, Long fileSize) { | ||
this(null, memberId, examId, path, fileSize); | ||
} | ||
|
||
public ExamImage(UUID id, Long memberId, Long examId, String path, Long fileSize) { | ||
this.id = id; | ||
this.memberId = memberId; | ||
this.examId = examId; | ||
this.path = path; | ||
this.fileSize = fileSize; | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
server/src/main/java/com/fluffy/exam/domain/ExamImageRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.fluffy.exam.domain; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface ExamImageRepository extends JpaRepository<ExamImage, Long> { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
server/src/main/resources/db/migration/V7__add_exam_image_table.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
CREATE TABLE exam_image | ||
( | ||
id UUID DEFAULT gen_random_uuid(), | ||
member_id BIGINT NOT NULL, | ||
exam_id BIGINT NOT NULL, | ||
path VARCHAR(255) NOT NULL, | ||
file_size BIGINT NOT NULL, | ||
created_at TIMESTAMP(6) NOT NULL, | ||
updated_at TIMESTAMP(6) NOT NULL, | ||
PRIMARY KEY (id) | ||
); | ||
|
||
ALTER TABLE exam_image | ||
ADD CONSTRAINT fk_member FOREIGN KEY (member_id) REFERENCES member (id); | ||
|
||
ALTER TABLE exam_image | ||
ADD CONSTRAINT fk_exam FOREIGN KEY (exam_id) REFERENCES exam (id); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters