Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Springboot - unable to get multiple file uploads working in @RequestParam("image") MultipartFile[] image

I am using Java Spring boot for an application and I am struggling to get multiple files to hit the endpoint.

"Required request part 'image' is not present" enter image description here Im the formData -- its coming back as image[0], image1

my code looks like this

@CrossOrigin
@RequestMapping(value = "/api/register", method = RequestMethod.POST)
//@PostMapping("/api/register")
@ResponseBody
public ResponseEntity<BaseResponse> register(@RequestParam("email") String email, @RequestParam("image") MultipartFile[] image) throws IOException {
    System.out.println("email " + email);
    System.out.println("image " + image);
    return null;
}

I've followed various links - that indicate the code is correct

https://www.baeldung.com/spring-file-upload https://www.oodlestechnologies.com/blogs/upload-a-file-using-multipartfile-in-spring-mvc/ https://www.bezkoder.com/spring-boot-file-upload/

--- this may work - but this looks really clumsy and not the right approach

@RequestParam("image[0]") MultipartFile image)

is it the way I am making the formData? -- I've done a conversion from json using these functions

export function buildFormData(formData, data, parentKey) {
  if (data && typeof data === 'object' && !(data instanceof Date) && !(data instanceof File)) {
    Object.keys(data).forEach(key => {
      buildFormData(formData, data[key], parentKey ? `${parentKey}[${key}]` : key);
    });
  } else {
    const value = data == null ? '' : data;

    formData.append(parentKey, value);
  }
}

export function jsonToFormData(data) {
  const formData = new FormData();
  
  buildFormData(formData, data);
  
  return formData;
}

I've tried a different method - used here -- https://dev.to/bawa_geek/how-to-convert-json-to-formdata-for-better-file-uploading-using-ajax-2ahf

it returns as a single entity now - but I still get the same error - "Required request part 'image' is not present"

enter image description here

Also tried

@PostMapping(value = "/api/register", consumes = MediaType.MULTIPART_FORM_DATA_VALUE )

*** 09/03/2023 - Working solution. but need a programmatically way of replacing the old jsonToFromData to ensure it works properly/expected -- not sure why the other versions weren't working or how to make them similar to this hardcoded example.

frontend

I've had to rejig the jsonToFromData function

export function jsonToFormData(data) {
      const formData = new FormData();
        formData.append("email", data.email);
    
        // Retrieve FileList boject
        const files = data.image;
    
        // Loop through files
        for (let i = 0; i < files.length; i++) {
          let file = files.item(i)
          formData.append("image", file);
        }
      return formData;
    }

enter image description here

^ this lists the "image" multiple times in the FormData payload without any square brackets.

the backend -- I've got it working on MultipartFile[]

public ResponseEntity<BaseResponse> register(@RequestParam("email") String email, @RequestParam("image") MultipartFile[] image) throws IOException {

enter image description here

then I've been able to loop through it like this

System.out.println("email " + email);
System.out.println("image " + image);

for (int i = 0; i < image.length; i++){
    System.out.println("each img = "+ image[i]);
}

-=-- also wanting to make adding images optional - but this seems to be an issue too

@RequestParam("image") Optional<MultipartFile[]> image)

fails with a same error - "image Optional.empty" value looks like this

how can I make a RequestParam optional for multipartfiles?

this does not work @RequestParam(value = "image", required=false) MultipartFile[] image

like image 618
The Old County Avatar asked Aug 06 '26 21:08

The Old County


1 Answers

This works for me:

@RestController
@RequestMapping("/multifileupload")
public class MultiFileUploadController {

    @PostMapping(path = "/requestparam", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public String postWithRequestParam(
                       @RequestParam String email,

                       @RequestParam(required = false) List<MultipartFile> files
    ) {
        return "email: " + email + ", number of files: " + Optional.ofNullable(files).map(List::size).orElse(0);
    }
@WebMvcTest(controllers = MultiFileUploadController.class)
class MultiFileUploadControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void postWithRequestParam() throws Exception {
        String email = "[email protected]";
        byte[] emailBytes = email.getBytes();

        MockPart emailMockPart = new MockPart("email", emailBytes);

        MockMultipartFile file1 = new MockMultipartFileToStringable("files", "file1", APPLICATION_OCTET_STREAM_VALUE, "File 1 content".getBytes());
        MockMultipartFile file2 = new MockMultipartFileToStringable("files", "file2", APPLICATION_OCTET_STREAM_VALUE, "File 2 content".getBytes());


        mockMvc.perform(multipart("/multifileupload/requestparam")
                                .part(emailMockPart)
                                .file(file1)
                                .file(file2)
                                .contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
                )
                .andExpect(status().isOk())
                .andExpect(content().string("email: [email protected], number of files: 2"));
    }


    @Test
    void postWithRequestParam_noFiles() throws Exception {
        String email = "[email protected]";
        byte[] emailBytes = email.getBytes();

        MockPart emailMockPart = new MockPart("email", emailBytes);

        mockMvc.perform(multipart("/multifileupload/requestparam")
                        .part(emailMockPart)
                        .contentType(MediaType.MULTIPART_FORM_DATA_VALUE)
                )
                .andExpect(status().isOk())
                .andExpect(content().string("email: [email protected], number of files: 0"));
    }
    
}

Tests passed. Hope, this helps.

like image 67
ILya Cyclone Avatar answered Aug 09 '26 10:08

ILya Cyclone