MultipartFile
를 간단히 사용해 보려고 합니다[front-end]
1) 파일 전송 요청
- 뷰 페이지
- "/upload"
[back-end]
2) 요청 받아서 파일을 서버에 저장
- Post로 파일전송받음
- "api/v1/file"
- 성공시 success페이지로 이동
- 실패시 예외발생, 에러리턴
[front-end]
3) 전송 성공 확인페이지
- 뷰 페이지
- "/success"
@Controller
@RequiredArgsConstructor
public class FileController {
private final FileService fileService;
@GetMapping("/upload")
public String upload() {
return "upload";
}
@GetMapping("/success")
public String success() {
return "success";
}
@PostMapping("/api/v1/file")
public String uploadFile(@RequestParam("file") MultipartFile file) {
fileService.fileUpload(file);
return "redirect:/success";
}
}
@Service
public class FileService {
Logger log = LoggerFactory.getLogger(getClass());
@Value("${user.home}")
private String uploadDir;
public void fileUpload(MultipartFile multipartFile) {
Path serverPath = Paths.get(
uploadDir +
File.separator +
StringUtils.cleanPath(multipartFile.getOriginalFilename()));
try {
Files.copy(multipartFile.getInputStream(), serverPath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
log.error("fail to store file : name={}, exception={}",
multipartFile.getOriginalFilename(),
e.getMessage());
throw new FileStorageException("fail to store file");
}
}
}
FileSystem이 OS 별로 다른 이유로 File.seperator
또한 다른데
/
문자인 반면, 윈도우에서는 \
구분자이므로 StringUtils.cleanPath
를 사용해 OS 종속성 제거 했습니다MultipartFile 이라는 인터페이스를 사용하는거 빼면 Local 개발컴퓨터에서 그냥 File 입출력이랑 다를게 없습니다
페이지의 form 요소의 코드 중 아래와 같은 부분이 있는데
.... enctype="multipart/form-data">
<input type="file" name="file" ...
enctype이 "multipart/form-data" 인 경우 파일로 인식해서 SpringBoot 에서 알아서 MultipartFile
객체로 변환해주기 때문
Content-type 타입을 명시하고(예를 들어 text이면 text/plain, xml이면 text/xml, jpg이미지는 image/jpeg 등등)
Body의 해석 방식을 지정하는 타입으로 enctype 을 사용하는데, 대부분의 HTTP message가 ASCI 기반 인데
Filed의 경우 ASCI 방식의 인코딩이 아닌, Binary 방식의 인코딩을(사진, 음악, 암호화된 문서 등등)꼭 사용해야하며 그렇지 않는경우 파일이 깨질 수 있다
multipart 타입을 지정하면 HTTP Request에서 multipart의 Body를 전송하는 규약대로 서버-클라간 통신한다
자세한 사항은 RFC 7231, section 4.3.3: POST 표준을 참고해주세요
아무튼 결론은 HTTP 표준의 multipart
규약을 이용하여 파일 업로드를 구현하는 것!