Resttemplate form/multipart: image + JSON in POST

匿名 (未验证) 提交于 2019-12-03 08:48:34

问题:

I'm trying to call a rest ws (using resttemplate), that accepts an image and some JSON. However, I don't seem to be able to get it running.

The relevant code is as follows:

    HttpHeaders header = new HttpHeaders();     header.setContentType(MediaType.MULTIPART_FORM_DATA);      MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();     ByteArrayResource bytes = new ByteArrayResource(pictureData) {         @Override         public String getFilename() {             return pictureName;         }     };     map.add("x", x);     map.add("file", bytes);      HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity(map, header);     String response =  restTemplate.postForObject(UPLOAD_URL, requestEntity, String.class); 

Where x is some POJO with all the required JSON annotations (I receive it from another web service, that part works ok).

This thing, however, tells me: HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for x.

If I change ByteArrayResource to byte[] then I get a 400 Bad Request. If I change the content type to JSON, then ByteArrayResource cannot be serialized into JSON:

Caused by: org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.util.LinkedMultiValueMap["file"]->java.util.LinkedList[0]->a.b.c.["inputStream"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.util.LinkedMultiValueMap["file"]->java.util.LinkedList[0]->a.b.c.["inputStream"]) 

I have the following converters configured:

StringHttpMessageConverter, MappingJackson2HttpMessageConverter FormHttpMessageConverter 

Any ideas, please? Thanks in advance.

UPDATE

So this is what I currently have after the instructions: I register the converters like this:

    RestTemplate restTemplate = new RestTemplate();     restTemplate.getMessageConverters().add(new StringHttpMessageConverter());     restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());      FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();         formHttpMessageConverter.addPartConverter(new MappingJackson2HttpMessageConverter());         formHttpMessageConverter.addPartConverter(new ResourceHttpMessageConverter()); // This is hope driven programming      restTemplate.getMessageConverters().add(new ResourceHttpMessageConverter());     restTemplate.getMessageConverters().add(formHttpMessageConverter); 

Then in the ws call I have:

    HttpHeaders header = new HttpHeaders();     header.setContentType(MediaType.APPLICATION_JSON); //Also tried with multipart...      MultiValueMap<String, Object> multipartRequest = new LinkedMultiValueMap<>();      ByteArrayResource bytes = new ByteArrayResource(pictureData) {         @Override         public String getFilename() {             return pictureName;         }     };      HttpHeaders xHeader = new HttpHeaders();     xHeader.setContentType(MediaType.APPLICATION_JSON);     HttpEntity<X> xPart = new HttpEntity<>(x, xHeader);     multipartRequest.add("x", xPart);      HttpHeaders pictureHeader = new HttpHeaders();     pictureHeader.setContentType(MediaType.IMAGE_PNG);     HttpEntity<ByteArrayResource> picturePart = new HttpEntity<>(bytes, pictureHeader);     multipartRequest.add("file", picturePart);      HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity(multipartRequest, header);     return restTemplate.postForObject(UPLOAD_URL, requestEntity, String.class); 

回答1:

If you want to use ByteArrayResource, simply register a ResourceHttpMessageConverter.

If you want to use a byte[], simply register a ByteArrayHttpMessageConverter.

The content type of the image part should be an image type, like image/png, not application/json.

You can set each individual part's data type with

HttpHeaders partHeaders = new HttpHeaders(); partHeaders.setContentType(MediaType.IMAGE_PNG); HttpEntity<ByteArrayResource> bytesPart = new HttpEntity<ByteArrayResource>(bytes, partHeaders);  map.add("file", bytesPart); 

Create your RestTemplate by providing your collection of HttpMessageConverters

HttpMessageConverter<Object> jackson = new MappingJackson2HttpMessageConverter(); HttpMessageConverter<Resource> resource = new ResourceHttpMessageConverter(); FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); formHttpMessageConverter.addPartConverter(jackson); formHttpMessageConverter.addPartConverter(resource); // This is hope driven programming  RestTemplate restTemplate = new RestTemplate(Arrays.asList(jackson, resource, formHttpMessageConverter)); 

and your outermost HttpEntity should have a multipart content type

header.setContentType(MediaType.MULTIPART_FORM_DATA); 


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!