Programing/jQuery

동적 파일업로드를 위한 ajaxForm 정리

리커니 2019. 3. 27.
반응형

동적 파일업로드를 위한 ajaxForm 정리

 

이번 포스팅에서는 브라우져별 파일요소(File Element)에 대해 알아보고

이를 ajaxForm을 사용하여 어떻게 파일 객체가 전달되는지를 알아보도록 하겠습니다.

 

이전 ajaxForm을 이용한 동적파일 업로드에 대한 정리로 생각하시면 될 것 같습니다.

 

Link : javascript spring 멀티파일선택 업로드 ajaxForm multipart/form-data  MultipartHttpServletRequest

 

Link : Java Spring File Upload MultipartHttpServletRequest 멀티파일 업로드 방법

 

Link : javascript 동적 멀티파일 업로드, 동적으로 선택된 파일 전달, ajaxForm 활용 fileList 컨트롤,  dynamic file upload

 

기본적으로 각 브라우져에서는 보안상의 문제로 File Element (Input type="file") 에 대한 접근만을 허용하고 있습니다.

수정을 할 수 없죠. 그렇기 때문에 대부분의 사이트에서는 File Element와는 별도로 업로드한 파일을 보여주고,

그 내에서 수정, 삭제를 하고 있습니다.

 

Ex)

 

위의 이미지에서 보시는 것과 같이 파일객체의 내용을 별도의 요소로 보여주고, 백단에서 따로 실제 업로드할 파일을 관리하는 것이죠.

 

이제 실제로 form 태그 내에 복수의 file Element 가 있을 경우 실제 저장되는 파일을 관리하는 프론트앤드 단의 로직을 보도록 하겠습니다.

 

 

위는 적용했을 경우의 예시 화면입니다. 첫번째 대표이미지의 경우 단일 파일만 선택 가능, 서브이미지의 경우 복수의 이미지가 선택가능합니다. 코드를 보도록 하죠.

 

<form action='Request URL' id='frm' name='frm' enctype="multipart/form-data">
    <article class="tbl tbl-view">
        <table>
            <tbody>
                <tr class="req">
                    <th>제목</th>
                        <td><input type="text" name="subject"></td>
                </tr>
                <tr class="req">
                    <th>대표이미지</th>
                    <td class="file" id="mFile">
                        <label for="mainFiles">파일선택</label>
                        <input type="file" id="mainFile" name="mainFile">
                        <ul></ul>
                        <span>업로드 완료: <i>0</i>/1개 업로드 가능</span>
                    </td>
                </tr>
                <tr>
                    <th>서브이미지</th>
                    <td class="file" id="sFile">
                        <label for="subFiles">파일선택</label>
                        <input type="file" id="subFiles" name="subFiles[]" multiple="multiple">
                        <ul></ul>
                        <span>업로드 완료: <i>0</i>/ 3개 업로드 가능</span>
                    </td>
                </tr>
            </tbody>
        </table>
    </article>
</form>

 

※아래의 코드들 부터는 실제로 파일에 대한 코드만을 제공하겠습니다.

 

코드를 보시면 mainFile 의 경우 단일 업로드기 때문에 multiple 옵션이 없고,

subFiles의 경우 복수 업로드기 때문에 multiple 옵션이 있고 name에서 배열과 같이 선언을 하여 구분하였습니다.

파일이 추가가 되면 각 File Element 다음 ul 의 li Element로 파일의 명칭이 추가되게 됩니다.

실제 파일은 File Element 내에 있지만 이를 추가 삭제하기 위해 li로 표현을 하는 것이죠.

 

그리고 앞에서 설명 했듯이 브라우져에서 File Element에 대한 접근만을 허용(수정, 삭제 불가)하기 때문에

실제로 저장 할 최종 파일이 있는 객체가 필요합니다.

이를 위해 전역변수 하나는 추가하겠습니다.

 

var FILE_BUFFER;

 

여기에 최종으로 전달될 파일 객체를 담을 변수 입니다.

이 FILE_BUFFUR 변수는 동적으로 페이지 내의 파일 객체를 읽어 다차원 배열의 형태로 관리가 됩니다.

페이지 로드 시 페이지 내의 File Element의 수 만큼 배열을 만들어서 세팅을 합니다.

 

$(function(){
    FILE_BUFFER = settingFileBuffer();
});

 

 - settingFileBuffer함수

 

settingFileBuffer : function(){
    var filebuffer = [];
    var fileEleCnt = $("input[type=file]").length;
    for(var i=0; i<fileEleCnt; i++){
        var eleArray = [];
        var fileArray = [];
        eleArray.push(i);
        eleArray.push(fileArray);
        filebuffer.push(eleArray);
    }
    return filebuffer;
},

 

위의 페이지에서는 File Element가 2개이기 때문에 아래와 같이 세팅이 될 것 입니다.

 

[   [   요소인덱스 , [  파일어레이  ]   ], [  요소인덱스 ,  [  파일어레이  ]  ]   ]

 

그럼 File Element가 변경되었을 경우와 li 를 삭제 하였을 경우의 코드를 보도록 하겠습니다.

 

$('#mainFile,#subFiles').change(function(){
    var fileIndex = $('input[type=file]').index(this);
    var fileSize = $(this)[0].files.length;
    for(var i=0; i<fileSize; i++){
        FILEBUFFER[fileIndex][1].push($(this).files[i]);
    }
    if ((navigator.appName == 'Netscape' && navigator.userAgent.search('Trident') != -1) || (agent.indexOf("msie") != -1) ){
        $(this).replaceWith( $(this).clone(true));
    }else{
        $(this).val("");
    }
}

 

파일이 선택되게 되면 위의 함수가 실행됩니다.

fileIndex 변수는 파일객체의 index (main이 0, sub가 1이 됩니다.) 그리고 그 다음 인덱스는 선택된 파일 배열이 됩니다.

그리고나서 파일 객체는 초기화를 해줍니다. if 조건을 준 이유는 브라우져 마다 초기화 방식이 다르기 때문입니다.

그럼 위의 change 함수 마지막에 FILE_BUFFER와 mainFile 에 대한 console.log 를 추가하고

메인파일을 변경하여 해당 값을 확인해 보도록 하겠습니다.

 

IE에서 확인한 결과입니다.

- FILE_BUFFER

 

 

- File Element

 

 

 

FILE_BUFFER 객체의 첫번째 파일요소(mainFile) 에는 추가된 값이 있지만, File element는 초기화 된 것을 보실 수 있습니다.

이렇게 하는 이유는 같은 이름의 파일을 업로드 했을 경우 Change 함수가 실행되지 않기 때문입니다.

(같은 이름의 파일을 업로드 허용)

 

그럼 이 FILE_BUFFER를 ajaxForm을 활용하여 서블릿으로 넘기기 전의 형태를 보도록 하겠습니다.

 

ajaxForm('frm', FILE_BUFFER, function(returnData){
    if(returnData.resultCode==200){
        //성공로직
    }else{                                    
        //실패로직
    }
});

 

 

ajaxForm : function (id, file, func){
    $('#'+id).ajaxForm({
        contentType : false,
        processData: false,
        enctype: "multipart/form-data",
        method : "POST",
        dataType : 'json',
        beforeSubmit: function(data, form, option) {
            console.log(data);
        },
        success: function(returnData) {
            console.log("returnData : "+returnData);
            func(returnData);
        },
        error: function(x,e){
            console.log("[AF]ajax status : "+x.status);
            console.log(e);
        },
});
 

 

beforeSubmit 함수에서 data를 확인해보도록 하겠습니다. 좌측이 IE, 우측이 크롬입니다.

 

 

 

 

폼 내의 객체의 값은 위의 change 함수에서 초기화 해주었기 때문에 value가 "" 가 되죠.

이제 저 곳에 FILE_BUFFER의 값을 추가해 주시면 됩니다.

beforeSubmit 함수에 아래의 로직을 추가 합니다.

 

for(var i in file){
    for(var j in file[i][1]){
        var obj = {
            name : $('input[type=file]:eq('+file[i][0]+')').prop('name'),
            value : file[i][1][j],
            type : "file"
        };
        data.push(obj);
    }
}

 

전달한 FILE_BUFFER의 데이터로 오브젝트를 생성하고 서블릿으로 전달할 data 배열에 추가해 주었습니다.

다시 콘솔을 확인해 보도록 하죠.

main에 1개, sub에 3개의 파일을 선택한 후 확인해보겠습니다.

 

 

 

결과를 보시면 서블릿으로 전달될 데이터에 파일 정보가 추가된 것을 보실 수 있습니다.

여기서 명칭이 같은 것을 배열로 묶어서 전달하거나 하면 값을 받을 수 없습니다. 위와 같이 같은 이름 명칭으로 전달해 주셔야 합니다.

그리고 value=""인 파일 요소를 제거해 주셔도 값이 전달이 되지 않습니다.

기존에 데이터에 file 객체만 추가해주세요. 대신 실제 파일 객체의 값은 초기화를 해주셔야 원하는 데이터가 전달됩니다.

반응형

댓글

💲 추천 글