27

I have the POST request api call to accept the json body request parameters and multipart file from client side(postman or java client).

I want to pass both the json data and multipart file in single request.

I have written the code like below.

@RequestMapping(value = "/sendData", method = RequestMethod.POST, consumes = "multipart/form-data")
public ResponseEntity<MailResponse> sendMail(@RequestPart MailRequestWrapper request) throws IOException

But, i could not accomplish it using postman rest client.

I'm using spring boot on server side.

Could anyone suggest me on this question.

Thanks in advance,

2

5 Answers 5

41

You cat use @RequestParam and Converter for JSON objects
simple example :

@SpringBootApplication
public class ExampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(ExampleApplication.class, args);
    }

    @Data
    public static class User {
        private String name;
        private String lastName;
    }

    @Component
    public static class StringToUserConverter implements Converter<String, User> {

        @Autowired
        private ObjectMapper objectMapper;

        @Override
        @SneakyThrows
        public User convert(String source) {
            return objectMapper.readValue(source, User.class);
        }
    }

    @RestController
    public static class MyController {

        @PostMapping("/upload")
        public String upload(@RequestParam("file") MultipartFile file, 
                             @RequestParam("user") User user) {
            return user + "\n" + file.getOriginalFilename() + "\n" + file.getSize();
        }

    }

}

and postman: enter image description here

UPDATE apache httpclient 4.5.6 example:

pom.xml dependency:

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.6</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpmime</artifactId>
        <version>4.5.6</version>
    </dependency>

   <!--dependency for IO utils-->
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>

service will be run after application fully startup, change File path for your file

@Service
public class ApacheHttpClientExample implements ApplicationRunner {

    private final ObjectMapper mapper;

    public ApacheHttpClientExample(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    @Override
    public void run(ApplicationArguments args) {
        try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
            File file = new File("yourFilePath/src/main/resources/foo.json");
            HttpPost httpPost = new HttpPost("http://localhost:8080/upload");

            ExampleApplication.User user = new ExampleApplication.User();
            user.setName("foo");
            user.setLastName("bar");
            StringBody userBody = new StringBody(mapper.writeValueAsString(user), MULTIPART_FORM_DATA);
            FileBody fileBody = new FileBody(file, DEFAULT_BINARY);

            MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
            entityBuilder.addPart("user", userBody);
            entityBuilder.addPart("file", fileBody);
            HttpEntity entity = entityBuilder.build();
            httpPost.setEntity(entity);

            HttpResponse response = client.execute(httpPost);
            HttpEntity responseEntity = response.getEntity();

            // print response
            System.out.println(IOUtils.toString(responseEntity.getContent(), UTF_8));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

console output will look like below:

ExampleApplication.User(name=foo, lastName=bar)
foo.json
41
Sign up to request clarification or add additional context in comments.

4 Comments

So, after using the converter. I could receive the both multipart file and form data into spring boot api through postman rest client. Thanks for your time and help. Do you have any idea to use this using java application apache http
you are welcome, I updated the answer and added an apache HttpClient example
Sending json in a request param wouldn't be good idea and implementation.I down vote it.
How's the data secure if we are using request param to send json data instead of POST body?
19

You can use both of them.

@RequestPart : This annotation associates a part of a multipart request with the method argument, which is useful for sending complex multi-attribute data as payload, e.g., JSON or XML.

In other words Request Part parse your json string object from request to your class object. On the other hand, Request Param just obtain the string value from your json string value.

For example, using Request Part:

@RestController
@CrossOrigin(origins = "*", methods= {RequestMethod.POST, RequestMethod.GET,
RequestMethod.PUT})
@RequestMapping("/api/api-example")
public class ExampleController{    
@PostMapping("/endpoint-example")
public ResponseEntity<Object> methodExample(
    @RequestPart("test_file") MultipartFile file,
    @RequestPart("test_json") ClassExample class_example) { 
      /* do something */ 
 }
}

and postman would be configured like: enter image description here

@RequestParam : Another way of sending multipart data is to use @RequestParam. This is especially useful for simple data, which is sent as key/value pairs along with the file, as I said, just key/value. Also is used to get value from query params, I think that is its main goal.

3 Comments

The screenshot of postman helped. I had to add the content-type manually like you mentioned. This does not work in my swagger though. Any idea how to achieve this through swagger? I'm using spring boot.
@jhonatan_yachi, The postman image description may be broken. Could you please upload another one?
This was driving my crazy until I notice I hadn't set hte content type for my json, thanks for pointing this out!
2

I was stuck with this problem for past few hours

So I came across this question.

Summary:
Use @ModelAttribute instead of @RequestBody. @ModelAttriute will work just like other normal(without multipart property in entity) Entity mapping.

Comments

1

You have two options -

Send a MultipartFile along with json data

public void uploadFile(@RequestParam("identifier") String identifier, @RequestParam("file") MultipartFile file){
}

OR

Send Json data inside a MultipartFile and then parse Multipart file as mentioned below and thats it.

public void uploadFile(@RequestParam("file") MultipartFile file){
    POJO p = new ObjectMapper().readValue(file.getBytes(), POJO.class);
}

Comments

1

simply add following spring configuration

 @Configuration
 public class JacksonConfig implements WebMvcConfigurer {

/**
 * This method is needed to allow sending multipart requests. For example, when an item is
 * created together with an image. If this is not set the request will return an exception with:
 * <p>
 * Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type
 * 'application/octet-stream' is not supported]
 */
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    messageConverters.stream()
            .filter(MappingJackson2HttpMessageConverter.class::isInstance)
            .map(MappingJackson2HttpMessageConverter.class::cast)
            .forEach(conv -> {
                List<MediaType> supportedMediaTypes = new ArrayList<>(conv.getSupportedMediaTypes());
                supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
                conv.setSupportedMediaTypes(supportedMediaTypes);
            });
}

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.