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": "사진에대한 설명입니다"
}
]
다들 나같은 이런 바보같은 실수 하지 말기..~