<form enctype="multipart/form-data">
input 태그 ...
</form>
<script>
function example() {
let data = {
inputTextA: $('#inputTextA').val(),
inputTextB: $('#inputTextB').val(),
}
let fileImg = $('#file')[0].files[0];
let form = new FormData();
form.append("keyA", new Blob([JSON.stringify(data)], {type: "application/json"}))
form.append("keyB", fileImg);
$.ajax({
type: "POST",
url: "/example",
contentType: false,
processData: false,
data: form,
success: function (response) {
alert("SUCCESS!");
}
});
}
</script>
[의문점] 여기서 잠깐!
기존에 JSON 포맷을 ajax를 사용해 서버로 전송했는데 이때는Content-Type
이application/json
으로 보내면 됐다. 하지만 파일까지 같이 보내면Content-Type
이multipart/form-data
이다.
ajax로 두 가지 타입을 보낼 수 있나?? 그렇다고 파일을 JSON 안에 넣을 수는 없을테고...
의문점 해결
FormData를 만들고 FormData 객체에 JSON과 file을 append한다. 그리고 FormData 객체를 서버로 전송한다.
ajax로 두 가지 Content-Type을 보낼 수 없다. 그래서 Blob을 사용하여 Content-Type을 지정해서 FormData에 추가한다. 이는 여러 Content-Type으로 보낼 수 있게 한다.
data 파라미터로 전달된 데이터를 jQuery 내부적으로 쿼리 스트링
으로 만드는데, 파일 전송의 경우에는 쿼리 스트링이 사용되지 않는다. 이를 설정하는 것이 processData: false
다.
contentType
은 default
값이 "application/x-www-form-urlencoded; charset=UTF-8"
인데, "multipart/form-data"
로 전송 되게 false
로 넣어준다.
알쓸신잡
IE 브라우저에서 ajax를 사용하다보면 데이터가 갱신이 안 되고 이전 데이터가 그대로 남아있는 경우가 있다. 이는 IE 브라우저에서 ajax 통신을 할 때 url을 새로 호출하지 않고, 가지고 있는 캐시 값을 그대로 노출시킨다. 따라서cache: false
를 사용하여 캐싱을 막는다.
서버에서 FormData 받는 방법
@PostMapping("/example")
public Example example(@RequestPart(name = "keyA") ExampleDto exampleDto, @RequestPart(name = "keyB") MultipartFile multipartFile) throws IOException {
return exampleService.postExample(exampleDto, multipartFile);
}
보통 Controller로 요청이 온 JSON을 DTO로 바인딩 할 때는 @RequestBody
를 주로 사용한다.
그리고 File을 받을 때는 MultipartFile 객체를 사용하고 @RequestParam
을 사용한다.
하지만 File과 Dto를 같이 받기 위해서는 @RequestPart
라는 어노테이션을 사용한다.
비즈니스 로직은 Service 계층에서 처리한다.
참고
https://repacat.tistory.com/38
https://medium.com/jaehoon-techblog/simpleblog-%EA%B0%9C%EB%B0%9C-%EC%9D%BC%EC%A7%80-4-55a8d2a8604