소개
파일 업로드에 대한 예제를 적어놓은 문서다.
더미 형식으로 만들었기 떄문에 커스터마이징 필요
파일 업로드
- FormData를 이용하여 업로드한다.
- MultiPart(RequestPart)방식을 사용하며,
FormData 에 데이터 및 파일을 모두 넣는다
Controller
java@RestController @RequestMapping("/api/files/") @RequiredArgsConstructor public class FileUploadController { private final FileUploadService fileUploadService; // Client에서 multipart/form-data로 보내야한다. // Object, String[] 의 경우 formData.append("data", new Blob([JSON.stringify(object)], {type: "application/json"}); 으로 json형식이 명시되어있는지 확인 @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public String uploadFile( @RequestPart(value = "data", required = false) Object data, @RequestPart(value = "files", required = false) MultipartFile[] files, @RequestPart(value = "deleted", required = false) String[] deleted, HttpServletRequest httpRequest, HttpServletResponse httpResponse) { return fileUploadService.uploadFileAndSave(data, files, deleted); } }
Service
java@Slf4j @Service public class FileUploadService { public List<String> uploadFile(MultipartFile[] files) { List<String> result = new ArrayList<>(); for (MultipartFile file : files) { try { // 파일 원래 이름 String originalFilename = file.getOriginalFilename(); // 파일 업로드 로직 result.add(uploadLocal(file, "")); } catch (Exception e) { log.error(e.getMessage()); } } // 파일 업로드 로직 return result; } public String uploadFileAndSave(Object data, MultipartFile[] files, String[] deleted) { if (data != null) { // 1. data 저장 로직 } if (files != null && files.length > 0) { // 2-1. 파일 업로드 List<String> filePaths = uploadFile(files); // 2-2. 파일 업로드 경로 저장 로직 } if (deleted != null && deleted.length > 0) { // 3. 파일 저장 DB 삭제 로직 } return "true"; } private String uploadLocal(MultipartFile file, String filePath) { // 로컬 업로드 try { UUID uuid = UUID.randomUUID(); String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); String saveFileName = uuid + extension; String saveUrl = filePath + "/" + saveFileName; File result = new File(saveUrl); file.transferTo(result); // 파일 데이터를 지정한 file로 저장 return saveFileName; } catch (Exception e) { log.error(e.getMessage()); } return null; } private String uploadS3(MultipartFile file) { // AWS S3 return "true"; } }
Client에서 FormData로 전향하기
typescriptconst formData = new FormData(); formData.append("data", JSON.stringify(data)); if (files.length > 0) { files.forEach((file) => { formData.append("files", file); }); }
Tip
- Filter에서 Logging을 위해 RequestWrapper를 사용하고 있다면, Content-Type이 multipart/ 일 때 제외시킨다.
- MultiRead 또는 Caching 방식으로 RequestWrapper를 사용하더라도 MultiPart(RequestPart)의 경우 사라진다.