最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Issue with sending 2 dimensional array of files - Stack Overflow

programmeradmin4浏览0评论

I am sending multiple files with formData like this

In my Spring MVC Controller

@PostMapping(value = "/marches")
public Integer saveMarches(
        @RequestPart("formJson") FooBean formJson, 
        @RequestPart("attachOs") MultipartFile[][] attachOs
        ) throws IOException {
    ...
}

My conf :

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(30000000);
    return multipartResolver;
}

But i got a 400 Bad Request in the browser

And in the IDE I got :

Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException:
Required request part 'attachOs' is not present]

and if i try @RequestPart("attachOs[][]") MultipartFile[][] attachOs i got always a bad request with Required request part 'attachOs[][]' is not present

The problem is obvious : spring is searching just for attachOs part (@RequestPart("attachOs")) but i am sending attachOs[0][0], attachOs[0][1] ...

When i send just the formJson part without files or if i send just a single file @RequestPart("attachOs") MultipartFile attachOs or one dimension array of files @RequestPart("attachOs") MultipartFile[] attachOs everything works fine.

Javascript code :

const formData = new FormData();

for (const [i, os] of formJson.os.entries()) {
    if(os.attachment) {
        for (const [j, file] of [...os.attachment].entries()) {
            formData.append(`attachOs[${i}][${j}]`, file );
        }
    }
}
...
formData.append('formJson', 
           new Blob([JSON.stringify(formJson)], {type:'application/json'}));
...
axios({
    url: ...,
    method: 'POST',
    data: formData,
})
...

My formJson structure is

{
    // form fields
    ...
    os: [
        {
            // os form fields
            ...
            attachment: [{ /* File type */ }, ...], // multiple files per os
        },
        ...
    ]
}

I know that files cannot be sent along with JSON that's why i am constructing the formData above and after that i will delete the attachment property from JSON structure

So my questions :

1. How to fix the bad request issue ?

2. is there another approach or design pattern to handle this use case ?

I am sending multiple files with formData like this

In my Spring MVC Controller

@PostMapping(value = "/marches")
public Integer saveMarches(
        @RequestPart("formJson") FooBean formJson, 
        @RequestPart("attachOs") MultipartFile[][] attachOs
        ) throws IOException {
    ...
}

My conf :

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    multipartResolver.setMaxUploadSize(30000000);
    return multipartResolver;
}

But i got a 400 Bad Request in the browser

And in the IDE I got :

Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException:
Required request part 'attachOs' is not present]

and if i try @RequestPart("attachOs[][]") MultipartFile[][] attachOs i got always a bad request with Required request part 'attachOs[][]' is not present

The problem is obvious : spring is searching just for attachOs part (@RequestPart("attachOs")) but i am sending attachOs[0][0], attachOs[0][1] ...

When i send just the formJson part without files or if i send just a single file @RequestPart("attachOs") MultipartFile attachOs or one dimension array of files @RequestPart("attachOs") MultipartFile[] attachOs everything works fine.

Javascript code :

const formData = new FormData();

for (const [i, os] of formJson.os.entries()) {
    if(os.attachment) {
        for (const [j, file] of [...os.attachment].entries()) {
            formData.append(`attachOs[${i}][${j}]`, file );
        }
    }
}
...
formData.append('formJson', 
           new Blob([JSON.stringify(formJson)], {type:'application/json'}));
...
axios({
    url: ...,
    method: 'POST',
    data: formData,
})
...

My formJson structure is

{
    // form fields
    ...
    os: [
        {
            // os form fields
            ...
            attachment: [{ /* File type */ }, ...], // multiple files per os
        },
        ...
    ]
}

I know that files cannot be sent along with JSON that's why i am constructing the formData above and after that i will delete the attachment property from JSON structure

So my questions :

1. How to fix the bad request issue ?

2. is there another approach or design pattern to handle this use case ?

Share Improve this question edited Oct 6, 2019 at 12:26 Hayi asked Sep 25, 2019 at 16:12 HayiHayi 6,32630 gold badges84 silver badges154 bronze badges 15
  • Can you first try @RequestPart(name="attachOs", required=false) and test that your controller can accept only formJson portion? Also add consumes = "multipart/form-data" in your @PostMapping annotation – buræquete Commented Oct 3, 2019 at 9:26
  • I think the problem is that spring is looking for a part named attachOs but your form data shows part named attachOs[0][0], etc. Don't know if spring could make a research by dynamic names. But maybe the solution is that you use attachOs as entry nam for each entry? Like: formData.append(attachOs, file ); – Mohicane Commented Oct 3, 2019 at 9:26
  • try @RequestPart("attachOs[][]") MultipartFile[][] attachOs notice the square brackets in the annotation value. – Mustafa Commented Oct 3, 2019 at 9:31
  • How about trying with a single object, make it a MultipartFile attachOs with only one input from front-end with formData.append('attachOs', file ); only once, and try to see that you can essentially get multiple request parts correctly. – buræquete Commented Oct 3, 2019 at 9:36
  • @Mustafa @RequestPart("attachOs[][]") MultipartFile[][] attach already try it but with no success – Hayi Commented Oct 3, 2019 at 9:42
 |  Show 10 more ments

4 Answers 4

Reset to default 2

Spring supports binding all multivalue map and single value map of multipart and part files in SPR-17405

Adding Map<String, MultipartFile> will map the multipart value to key.

Something like attachOs[0][0], attachs[0][1]

@PostMapping(value = "/marches")
public Integer saveMarches(
        @RequestPart("formJson") FooBean formJson, 
        @RequestParam Map<String, MultipartFile> attachOs
        ) throws IOException {
    ...
}

Another variation would be send multiple multipart values per row. For that you could use MultiValueMap<String, MultipartFile>. For this variation you have to update your angular code.

Something like attachOs[0], attachs[1]

 @PostMapping(value = "/marches")
    public Integer saveMarches(
            @RequestPart("formJson") FooBean formJson, 
            @RequestParam MultiValueMap<String, MultipartFile> attachOs
            ) throws IOException {
        ...
    }

If you would like to use second variant you can give unique name per os and append files. There is no need to make it appear like array. You can call data.append multiple append with same name and it will add them as array of files.

for (const [i, os] of formJson.os.entries()) {
    if(os.attachment) {
        for (const [j, file] of [...os.attachment].entries()) {
            formData.append(os.name, file);
        }
    }
}

If you want to send multiple file attachments per OS you can use a List instead of a 2-dimensional array in the spring controller.

@PostMapping(value = "/marches")
public Integer saveMarches(
        @RequestPart("formJson") FooBean formJson, 
        @RequestPart("attachOs") List<MultipartFile> files
        ) throws IOException {

    // Associate files with their os using the index in their name.
}

and in your angular code append the os index in the name of the file.

for (const [i, os] of formJson.os.entries()) {
    if (os.attachment) {
        for (const [j, file] of [...os.attachment].entries()) {
            formData.append(`attachOs`, file, file.name + ":" + i );
        }
    }
}

I found a solution by utilizing a @ModelAttribute (from here);

First create a model class like;

public class MyRequest {
    private FooBean formJson;
    private MultipartFile[][] attachOs = new MultipartFile[2][2];

    // getters/setters
}

Then add it to your controller like;

@PostMapping(value = "/marches", consumes = "multipart/form-data")
public Integer saveMarches(@ModelAttribute MyRequest request) throws IOException {
    // some code
}

The important part was the initialization of the MultipartFile[][] attachOs, otherwise it does not work with multidimensional arrays due to some internal initialization issue.


Or you can use the following type in the model class;

private List<MultipartFile>[] attachOs;

which works without an initialization.

You need to create custom converter @Component, which implements HttpMessageConverter

发布评论

评论列表(0)

  1. 暂无评论