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"
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"

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;
}

^ 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 {

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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With