Prateek
Prateek

Reputation: 11

How to consume Request Body (JSON) along with multiple files (multipart/form-data) via REST API in Spring Boot?

I want to consume both JSON & files in an API for my spring boot application (using Spring WebFlux). I tried multiple ways as was recommended over the internet (Article1, Article2, Article3), but it's not working for me. The API is not being hit and getting status 415 (Unsupported Media Type) from Postman.

Spring-Boot version : 2.5.3

Spring-Web/Webflux version : 5.3.9

Employee :

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
    
    private String name;
    private int age;
    private int mobileNo;
    private List<MultipartFile> files;

}

Controller :

@PostMapping(path = "employee", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public Mono<Response> processEmployeeDocs(@RequestPart Employee request, @RequestPart List<MultipartFile> files) {
    Employee employee = new Employee(request.getName(), request.getAge(), request.getMobileNo(), files);
    return employeeService.processDocs(employee);
}

Upvotes: 1

Views: 8790

Answers (2)

theseventhsense
theseventhsense

Reputation: 137

We can achieve this by using RESTEasy's @MultipartForm annotation along with a custom wrapper object:

I've provided the steps that were followed to make this scenario work.

Step 1: Add RESTEasy Multipart Dependency

Make sure you have the RESTEasy multipart provider dependency in your pom.xml:

<dependency>
  <groupId>org.jboss.resteasy</groupId>
  <artifactId>resteasy-multipart-provider</artifactId>
</dependency>

Step 2: Create the DTO for the JSON Part

Define the class for your JSON object:

public class FirstObject {
private String field1;
private int field2;

// Add Getters and Setters
}

Step 3: Create the Multipart Form Wrapper

Create a class that will hold the multipart form data:

import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
import org.jboss.resteasy.annotations.providers.multipart.PartType;
import javax.ws.rs.FormParam;
import org.springframework.web.multipart.MultipartFile;
public class MultipleRequestBody {

 @FormParam("firstObject")
 @PartType("application/json")
 private FirstObject firstObject;

 @FormParam("file")
 @PartType("application/octet-stream")
 private byte[] file;

 // Add Getters and Setters
}

Note that MultipartFile is a Spring-specific class. Instead, use byte[] / InputStream to handle file uploads in RESTEasy.

Step 4: Create the Controller

Use the @MultipartForm annotation in your controller to handle the multipart request:

import org.jboss.resteasy.annotations.providers.multipart.MultipartForm;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class MyController {
@PostMapping("/multiple-body")
public ResponseEntity<String> handleMultipleBodies(@MultipartForm MultipleRequestBody request) {
    // Process the firstObject (JSON part)
    FirstObject firstObject = request.getFirstObject();
    String field1 = firstObject.getField1();
    int field2 = firstObject.getField2();

    // Process the file (file part)
    byte[] fileContent = request.getFile();
    String fileName = "uploaded_file"; // You can extract the filename if needed

    // Perform any necessary processing
    // ...

    return ResponseEntity.ok("Processed JSON and file successfully");
}
}

Upvotes: 0

rajat behl
rajat behl

Reputation: 181

Instead of using MultipartFile use FilePart to consume multipart content as per the spring docs

Below is the working code snippet

@PostMapping(path = "employees", consumes = {MediaType.APPLICATION_JSON_VALUE, MediaType.MULTIPART_FORM_DATA_VALUE})
public Mono<ResponseEntity<Response>> processEmployeeDocs(@RequestPart Employee request, @RequestPart Flux<FilePart> files) {
    log.info("processing request {}", request);
    return files.flatMap(part -> part.transferTo(Paths.get("temp", File.separator, part.filename())))
            .then(employeeService.processDocs(request))
            .then(Mono.just(ResponseEntity.ok().build()));
}

The above code will save the files in "temp" directory. You can use those files for processing your logic.

Postman Request enter image description here

Upvotes: 3

Related Questions