ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [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에 데이터를 전달하는지 알아보도록 하겠다.

Designed by Tistory.