问题
I'm using <input type="file" multiple />
to upload a list of files. This works fine as is, but I want the ability to remove individual files before upload, so I'm storing the FileList
in a separate object and routing it through xhr. However, it doesn't work.
The form looks like this:
<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>
Here's the function that handles it (working version):
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;
}
And the non-working version, where I try to stick the files into the formData manually:
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;
}
The bean:
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;
}
}
And the controller:
@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.
}
How can I make files
correctly append to formData
?
回答1:
In order for Spring to map items in a request to a list, you need to provide the same name
(in the FormData.append
calls) for each item when appending to the form data. This allows Spring to effectively see the request as name=value1&name=value2&name=value3
(but obviously in the form of form data). When Spring sees the same key ("name") multiple times, it can map the values into a collection. Going with your example, the name
"files" is needed because your DocumentsBean
has named it that way. That means your JavaScript code should change to be something like this:
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;
}
来源:https://stackoverflow.com/questions/22482170/how-do-i-send-an-array-of-files-using-xhr2-and-formdata-java-spring