-
[JavaScript] SpringBoot 프로젝트 : 프로필 사진 기능 구현(5) - 이미지 Ajax전송(FormData, Ajax parameter)프로젝트/기능 정리 2023. 6. 11. 21:50
목적
- 회원제 웹사이트 개발시 거의 필수적으로 사용되는 프로필 사진 등록 및 수정 기능 구현
- 프로필 이미지 등록 관련 DB, Java, JS 처리 총 정리
- 일부 받아서 쓴 코드 리뷰
지난 글에서는 JS로 회원이 업로드한 이미지 미리보기 기능까지 알아봤다.
이번엔 업로드한 이미지를 Ajax 방식으로 컨트롤러에 전송하는 방법과 이미지 등록 취소시 코드를 보자.
데이터 흐름도는 다음과 같다.
[데이터 흐름도]
프로필이미지 데이터 흐름도 이전 글에 이어 JavaScript 코드를 보자.
먼저 기억해야할 태그들은 다음과 같았다.
<!--IMG TAG--> <img src = "${pageContext.request.contextPath}/mypage/photoView.do" class = "profile-photo"> <!--INPUT TAG--> <input type = "file" id = "upload" accept = "image/gif, image/png, image/jpeg"> <!--BUTTONS--> <button type="button" class="btn photo-reset" id = "photo_reset" data-bs-dismiss="modal">닫기</button> <button type="button" class="btn" id = "photo_submit">변경</button>
[JavaScript]
JS로는 총 세 가지 기능을 구현했다고 했다. 내용은 다음과 같다.
- 회원이 input 태그를 통해 이미지 파일을 선택했을 때, 파일 크기 확인 및 화면에 선택한 이미지 미리보기
- 이미지 파일 선택 후 변경 버튼을 클릭했을 때, Ajax 실행
- 닫기 버튼을 클릭했을 때, 미리보기 이미지가 보이는 상태라면 원래 이미지로 변경(모달 닫기는 dismiss가 해줌)
2번째 처리과정인 Ajax 부분 코드는 다음과 같다.
[JavaScript - Ajax처리]
//이전 글 코드 //데이터 전송 Ajax $('#photo_submit').click(function(){ //업로드한 이미지 여부 확인 if($('#upload').val() == ''){ alert('프로필 이미지를 선택해주세요.'); $('.profile-photo').attr('src',photo_path); return; } //파일 전송 let form_data = new FormData(); form_data.append('upload',my_photo);//회원이 업로드한 이미지 $.ajax({ url:'../mypage/updateProfileImg.do', data:form_data, type:'post', //전송 방식 dataType:'json', //전달 받을 데이터 형식 contentType:false, //전달 하는 데이터 형식 //enctype:'multipart/form-data', processData:false, //data String으로 변환여부 success:function(param){ if(param.result == 'logout'){ alert('로그인 후 변경 가능합니다.'); }else if(param.result == 'success'){ alert('프로필 사진이 수정되었습니다.'); $('#upload').val(''); //input 태그 value 초기화 $('#profile-change').modal('hide'); //모달창 닫기 }else{ alert('파일 전송 중 오류가 발생했습니다.'); } }, error:function(){ alert('네트워크 오류가 발생했습니다.'); } }); }); //이하 코드 생략
위 과정은 변경 버튼이 클릭됐을 때 실행되도록 했다.
가장 먼저 Input태그에 업로드한 파일이 있는지 확인 후, 없으면 원래 등록해뒀던 이미지로 돌린 뒤 리턴해줬다.
[FormData]
다음으로 JS단에서 form을 전송하기 위해 FormData 객체를 생성했다.
FormData에 대한 설명은 다음과 같다.
FormData 설명 더 궁금한 점이 있다면 다음 사이트를 참고하자.
참고 : https://developer.mozilla.org/ko/docs/Web/API/FormData
FormData 객체는 HTML의 form태그와 같은 역할을 하는데, 굳이 form태그를 사용하지 않고 복잡하게 JS에서 처리하는지 궁금할 수 있다.
이는 form태그를 사용해서 컨트롤러에 데이터를 넘길 경우 페이지 이동이 일어나기 때문이다.
페이지 이동 없이 현재 화면을 그대로 두고 프로필 이미지만 바꾸고 싶기 때문에 Ajax를 통해 비동기 처리를 하는 것이고, 이 Ajax에 담아줄 데이터를 JS단에서 처리하기 위해 FormData 객체를 사용한다고 생각하면 될 것 같다.
찾아보니 base64 인코딩, 이진데이터 등으로도 보낼 수 있다는데 FormData 쓰는게 가장 편해보인다..
돌아와서 FormData 객체를 생성한 뒤, append메소드를 이용해 upload라는 name에 회원이 업로드한 파일을 담아줬다(FormData.append(name, value)형태로 사용).
이걸 HTML form태그로 보면 다음과 같다고 할 수 있다.
<input type = "file" name = "upload" value = "회원이 업로드한 파일">
[Ajax 파라미터]
이제 Ajax 내부를 보자.
url:'../mypage/updateProfileImg.do', data:form_data, type:'post', dataType:'json', contentType:false, //enctype:'multipart/form-data', processData:false,
여러 파라미터들이 보이는데 하나씩 설명하면 다음과 같다.
- url: 컨트롤러에 매핑된 주소
- data: Ajax로 서버에 전송할 데이터
- type: 전송 방식
- dataType: 전달 받을 데이터 형식(서버 → ajax)
- contentType: 전송 하는 데이터 형식(기본: "application/x-www-form-urlencoded; charset=UTF-8")
- processData: data에 들어가 있는 데이터를 String으로 변환할 것인지 여부
보통 위 네 가지 정도를 설정해서 Ajax를 사용했는데 이미지 파일 전송을 위해서는 아래 두 가지 파라미터도 설정해야한다.
contentType은 request에 담아서 서버에 보내는 데이터의 타입을 적어주는 것이라 보면 된다.
기본 "application/x-www-form-urlencoded"가 설정되어 있다고 한다(쿼리문 형식인듯 하다. ex. name=kim&age=20).
암튼 나는 이미지 파일을 전송해야 하므로, multipart/form-data타입으로 보낸다고 써줘야 한다.
위 코드를 보면 enctype이라는 파라미터에 multipart/form-data를 써주고 있다.
어차피 인코딩 타입이나 데이터 타입이나 똑같은 것 같아서 contentType을 지우고 실행해봤더니 오류가 난다.
반대로 enctype을 지워봤더니 잘 실행됐다. 근데 false 대신 'multipart/form-data'를 써줬더니 안된다..
그래서 request header를 보니 차이가 좀 있었다(브라우저 우클릭- 검사 - Network - 호출 컨트롤러 찾아서 Headers).
contentType 삭제 contentType : multipart/form-data contentType : false contentType을 지우니 그냥 기본 설정 타입이 들어갔다. contentType은 필수로 들어가야 하나보다.
또 뒤에 붙은 저 boundary 어쩌고가 차이가 난다. 저 뒤에 붙은 바운더리가 무슨 기능을 하는 것 같은데..
추가: boundary는 서버가 수신하는 데이터를 나누는 방법을 알 수 있도록 하는 구분자역할 인듯 하다(참고).
나랑 똑같은 것을 해본 분의 포스트가 있어서 첨부한다. 나도 잘 이해가 안되므로.. 참고로 남겨 두겠다.
참고 : https://repacat.tistory.com/38
마지막으로 processData에 대한 설명은 다음과 같다.
jQuery ajax() 설명 더 많은 Ajax 파라미터 설명은 다음 사이트에서 확인할 수 있다(늦게 발견함).
참고 : https://api.jquery.com/jquery.ajax/
기본적으로 data 파라미터에 들어간 데이터들은 기본 타입인 "application/x-www-form-urlencoded"에 맞게 쿼리 문자열로 변환된다고 한다. 그래서 DOM 문서나 처리되지 않은 데이터를 보내려면 false로 해야한다고 써있다.
그니까 전송할 데이터를 이런 쿼리 문자열 형태로 변환하지 않고 원 데이터를 보내려면 false로 설정해야된다는 거다.
이렇게 모든 파라미터를 살펴봤고, 아래 success에서 처리는 간단하다.
성공적으로 수행이 되어 컨트롤러에서 success를 보내오면, input 태그에 들어 있던 데이터를 삭제하고 모달창을 닫아줬다.
[JavaScript - 취소처리]
JS에서 처리하는 마지막 단인 취소 처리를 보자.
//이전 글 코드 + 위 코드 $('.photo-reset').click(function(){ $('.profile-photo').attr('src',photo_path); $('#upload').val(''); }); });
취소 처리는 매우 간단하다.
닫기 버튼과 상단의 X버튼에 photo-reset이라는 클래스를 할당해 주고, 클릭 이벤트 발생 시 이미지를 기존 이미지로 변경 후 input 태그에 들어 있던 데이터를 삭제해줬다.
BootStrap의 모달창을 사용했는데 해당 태그들의 data-bs-dismiss="modal"가 모달창이 닫히도록 해준다.
이번 글에서는 JS에서 Ajax 방식으로 데이터를 전송하는 과정을 다뤘다.
다음 글에서는 Ajax가 호출한 컨트롤러가 어떤 처리를 거쳐 DB에 데이터를 전달하는지 알아보도록 하겠다.
'프로젝트 > 기능 정리' 카테고리의 다른 글