form-data 형식으로
MultipartFile
타입의 file과String
타입의 description으로파일 저장을 요청한 후,
파일 저장이 완료된면 저장된 파일에 대한 정보를 FileDTO 객체로 응답하려고 함
@Setter
@AllArgsConstructor
public class FileDTO {
private String originalFileName;
private String savedName;
private String filePath;
private String description;
}
@RestController
@RequestMapping("/api")
public class FileUploadController {
private final FileUploadService fileUploadService;
public FileUploadController(FileUploadService fileUploadService) {
this.fileUploadService = fileUploadService;
}
@PostMapping("/files")
public ResponseEntity<List<FileDTO>> uploadFiles(
@RequestParam("files") List<MultipartFile> files,
@RequestParam("description") String description) throws FileUploadException {
List<FileDTO> uploadFiles = fileUploadService.uploadFiles(files, description);
return new ResponseEntity<>(uploadFiles, HttpStatus.OK);
}
}
@Service
public class FileUploadService {
@Value("${file.upload-dir}")
private String uploadDir;
/*
1. 파일 업로드
*/
public List<FileDTO> uploadFiles(List<MultipartFile> files, String description) throws FileUploadException {
if (!files.isEmpty()) {
List<FileDTO> fileList = new ArrayList<>();
for (MultipartFile file : files) {
FileDTO responseDTO = saveFile(file, description);
fileList.add(responseDTO);
}
return fileList;
} else {
throw new FileUploadException("파일이 비어있습니다.");
}
}
/*
컴퓨터에 파일 저장
*/
private FileDTO saveFile(MultipartFile file, String description) throws FileUploadException {
//파일 저장 경로 설정
String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
Path path = Paths.get(uploadDir + fileName);
try {
Files.createDirectories(path.getParent());
Files.write(path, file.getBytes());
return new FileDTO(file.getOriginalFilename(), fileName, path.toString(), description);
} catch (IOException e) {
throw new FileUploadException("파일 저장에 실패했습니다.");
}
}
}
"파일은 정상적으로 저장되는데, Response가 아래처럼 빈 객체로 오는 상황 발생"
[
{},
{}
]
200 OK
를 받음fileList
도 정상적으로 생성되고, 각 파일이 반환될 때마다 fileDTO
도 정상적으로 생성된 후에 fileList에 저장됨uploadFiles
도 정상적으로 넘어옴디버깅을 통해 "ResponseEntity"에 "uploadFiles"를 담아서 응답하는 과정에서 문제가 있다는 사실을 알아냄
객체를 return할 때, 해당 원본 클래스이 멤버변수에는 반드시 "Getter"가 존재해야 한다
아... 나는 FileDTO 에 Setter는 만들어두었지만, Getter는 만들어 두지 않았음 😩
내가 너무 싫어지는 순간..~
@Getter
@Setter
@AllArgsConstructor
public class FileDTO {
private String originalFileName;
private String savedName;
private String filePath;
private String description;
}
기존 FileDTO 코드에 Lombok으로 Getter
를 추가하니 무슨 일 있었냐는 듯 너무나 깔끔한 응답이 옴
[
{
"originalFileName": "증명1.jpg",
"savedName": "ed278095-dba7-4f85-ab3b-65142d681ac5_증명1.jpg",
"filePath": "./files/ed278095-dba7-4f85-ab3b-65142d681ac5_증명1.jpg",
"description": "사진에대한 설명입니다"
},
{
"originalFileName": "증명2.jpg",
"savedName": "0224f9e5-3e28-4ffe-94b5-40b597e88b34_증명2.jpg",
"filePath": "./files/0224f9e5-3e28-4ffe-94b5-40b597e88b34_증명2.jpg",
"description": "사진에대한 설명입니다"
}
]
다들 나같은 이런 바보같은 실수 하지 말기..~