如何使用xhr2和FormData发送文件数组? (Java + Spring)

时间:2014-03-18 14:20:56

标签: java javascript html5 spring-mvc xmlhttprequest

我正在使用<input type="file" multiple />上传文件列表。这样可以正常工作,但我希望能够在上传之前删除单个文件,因此我将FileList存储在单独的对象中并通过xhr进行路由。但是,它不起作用。

表格如下:

<form:form commandName="documentsBean" enctype="multipart/form-data">
    <input type="hidden" name="submittedFormAction" value="attachDocumentSave"/>
    <input type="file" name="files" id="attachFiles" multiple/>
    <button type="submit" id="attachButton" onclick="return buildForm(this.form);">Attach</button>
</form:form>

这是处理它的功能(工作版本):

function buildForm(form){
    var formData = new FormData(form);
    formData.append('testString', "foobar");

    var xhr = new XMLHttpRequest();
    xhr.open('POST', form.action, true);
    xhr.send(formData);

    return false;
}

非工作版本,我尝试将文件手动粘贴到formData中:

function buildForm(form){
    var files = document.getElementById('attachFiles').files;

    // var tempfiles = [];
    // for(var i=0; i<files.length; i++){
    //     tempfiles[i]=files[i];
    // }

    var formData = new FormData();
    formData.append('submittedFormAction', "attachDocumentSave");
    formData.append('files', files);  // still broken with formData.append('files', tempfiles);
    formData.append('testString', "foobar");

    var xhr = new XMLHttpRequest();
    xhr.open('POST', form.action, true);
    xhr.send(formData);

    return false;
}

豆子:

public class DocumentsBean
{
    private List<MultipartFile> files = Arrays.asList();
    private String testString = "";

    public List<MultipartFile> getFiles(){
        return files;
    }
    public void setFiles(List<MultipartFile> files){
        this.files = files;
    }
    public String getTestString(){
        return testString;
    }
    public void setTestString(String testString){
        this.testString = testString;
    }
}

控制器:

@RequestMapping( method = RequestMethod.POST, params = { "submittedFormAction=attachDocumentSave" })
public ModelAndView attachDocumentSave(HttpServletRequest request, @ModelAttribute("documentsBean") DocumentsBean documentsBean, BindingResult errors) throws Exception
{
    // Drilling into documentsBean here with the working version shows:
    //
    //     files= LinkedList<E>  (id=78)
    //         first= LinkedList$Node<E>  (id=94)
    //         last= LinkedList$Node<E>  (id=96)
    //         modCount= 3
    //         size= 3
    //     testString= "foobar" (id=84)
    //
    // and it successfully uploads the 3 files.

    // Drilling into documentsBean here with the non-working version shows:
    //
    //     files= Arrays$ArrayList<E>  (id=116)
    //         a= MultipartFile[0]  (id=121)
    //         modCount= 0
    //     testString= "foobar" (id=119)
    //
    // and it does not upload the files.
}

如何让files正确附加到formData

1 个答案:

答案 0 :(得分:5)

为了让Spring将请求中的项目映射到列表,您需要在附加到表单数据时为每个项目提供相同的name(在FormData.append调用中)。这允许Spring有效地将请求视为name=value1&name=value2&name=value3(但显然是以表单数据的形式)。当Spring多次看到相同的键(&#34; name&#34;)时,它可以将值映射到集合中。继续你的例子,name&#34;文件&#34;是必需的,因为你的DocumentsBean已经这样命名了。这意味着您的JavaScript代码应该更改为:

function buildForm(form) {
    var files, formData, i, j, xhr;

    files = document.getElementById('attachFiles').files;
    formData = new FormData();

    formData.append('submittedFormAction', "attachDocumentSave");
    for (i = 0, j = files.length; i < j; i++) {
        formData.append('files', files[i]);
    }
    formData.append('testString', "foobar");

    xhr = new XMLHttpRequest();
    xhr.open('POST', form.action, true);
    xhr.send(formData);

    return false;
}