-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
파일 업로드 기능 구현 완료 #97
파일 업로드 기능 구현 완료 #97
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package balancetalk.module.file.application; | ||
|
||
import balancetalk.global.exception.BalanceTalkException; | ||
import balancetalk.module.file.domain.File; | ||
import balancetalk.module.file.domain.FileRepository; | ||
import balancetalk.module.file.domain.FileType; | ||
import balancetalk.module.file.dto.FileDto; | ||
import jakarta.servlet.ServletContext; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.core.io.UrlResource; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.Paths; | ||
import java.nio.file.StandardCopyOption; | ||
import java.util.Arrays; | ||
import java.util.UUID; | ||
|
||
import static balancetalk.global.exception.ErrorCode.NOT_FOUND_DIRECTORY; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class FileService { | ||
private final FileRepository fileRepository; | ||
private final ServletContext servletContext; | ||
|
||
// 파일 업로드 | ||
@Transactional | ||
public File uploadFile(MultipartFile file) throws IOException { | ||
String uploadDir = "C:\\Users\\King\\Desktop"; // TODO : 경로 configuration 파일로 빼기 | ||
String originalFileName = file.getOriginalFilename(); | ||
String storedFileName = UUID.randomUUID().toString().replace("-", "") + "_" + originalFileName; | ||
String path = Paths.get(uploadDir, storedFileName).toString(); | ||
String contentType = file.getContentType(); | ||
FileType fileType = convertMimeTypeToFileType(contentType); | ||
|
||
FileDto fileDto = FileDto.of(file, storedFileName, path, fileType); | ||
File saveFile = fileDto.toEntity(); | ||
|
||
Files.copy(file.getInputStream(), Paths.get(path), StandardCopyOption.REPLACE_EXISTING); | ||
return fileRepository.save(saveFile); | ||
} | ||
|
||
private FileType convertMimeTypeToFileType(String mimeType) { | ||
if (mimeType == null) { | ||
throw new IllegalArgumentException("MIME 타입은 NULL이 될 수 없습니다."); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exception들을 ErrorCode에 추가해서 사용하는건 어떨까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PR 단위를 나누기 위해서 임시 구현한 단계입니다! 추후 예외 처리 이슈에서 구현하겠습니다~! |
||
} | ||
|
||
return Arrays.stream(FileType.values()) | ||
.filter(type -> type.getMimeType().equalsIgnoreCase(mimeType)) | ||
.findFirst() | ||
.orElseThrow(() -> new IllegalArgumentException("지원하지 않는 파일 타입 : " + mimeType)); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package balancetalk.module.file.domain; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface FileRepository extends JpaRepository<File, Long> { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,19 @@ | |
import balancetalk.module.file.domain.FileType; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import lombok.*; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
@Data | ||
@Builder | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@AllArgsConstructor | ||
public class FileDto { | ||
@Schema(description = "파일 id", example = "1") | ||
private Long id; | ||
@Schema(description = "사용자가 업로드한 파일명", example = "사진1") | ||
private String uploadName; | ||
@Schema(description = "서버에 저장되는 파일명", example = "d23d2dqwt1251asbds사진1") | ||
private String storedName; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 필드만 스웨거 설정을 안하신 이유가 있을까요?.? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 발견 못한 필드네요! 감사합니다!! |
||
@Schema(description = "업로드한 파일의 경로", example = "/...") | ||
private String path; | ||
@Schema(description = "업로드한 파일 확장자", example = "JPEG") | ||
|
@@ -35,4 +41,14 @@ public static FileDto fromEntity(File file) { | |
.size(file.getSize()) | ||
.build(); | ||
} | ||
|
||
public static FileDto of(MultipartFile file, String storedFileName, String path, FileType fileType) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정적 팩토리 메서드 말고 고려하신 다른 방법이 있으신가요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정적 팩터리 메서드 말고는 따로 생각나는 방법이 없었습니다..! |
||
return FileDto.builder() | ||
.uploadName(file.getOriginalFilename()) | ||
.storedName(storedFileName) | ||
.path(path) | ||
.type(fileType) | ||
.size(file.getSize()) | ||
.build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package balancetalk.module.file.presentation; | ||
|
||
import balancetalk.module.file.application.FileService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.core.io.Resource; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import org.springframework.web.multipart.MultipartFile; | ||
|
||
import java.io.IOException; | ||
|
||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/files") | ||
public class FileController { | ||
private final FileService fileService; | ||
|
||
@ResponseStatus(HttpStatus.CREATED) | ||
@PostMapping("/upload") | ||
public String uploadFile(@RequestParam("file") MultipartFile file) throws IOException { | ||
fileService.uploadFile(file); | ||
return "파일이 업로드되었습니다."; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try / catch를 통해서 IoException을 처리해준다면 컨트롤러에서 익셉션을 throw하지 않아도 되지 않을까 싶어서 의견 여쭤봅니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이 부분도 예외 처리 단계에서 개선할 예정입니다! 감사합니다!!