2

Title might look common but none of them fit in my issue.

I have a rest service which accept normal parameters and file in form of multipart.

i want to use resttemplate to send data and file to above rest service.

till the time i was sending normal string data there was no issue. once i add code of sending bytes then i start getting 400 Bad request error.

if i comment code to send ByteArrayResource then it start working for normal parameters.

below is sample code

Rest service controller

@RestController
@RequestMapping(value="/ticket")
public class UserTicketController {

 @RequestMapping(value="/createTicket.do",method={RequestMethod.POST},
        consumes = {MediaType.MULTIPART_FORM_DATA_VALUE},headers={"content-type="+MediaType.MULTIPART_FORM_DATA_VALUE})
public void createTicket(@ModelAttribute ServiceDeskRequest serviceDeskRequest, HttpServletRequest request,HttpServletResponse response) throws Exception{

 }

 }

Servicedeskrequest model attribute is

 public class ServiceDeskRequest implements Serializable{


private String jsonData;
private MultipartFile attachment;
}

application-context.xml

 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean> 

Client Side code

RestTemplate restTemplate = new RestTemplate();
        MultiValueMap<String, Object> requestParamerterMap = new LinkedMultiValueMap<String, Object>();

        requestParamerterMap.add("jsonData", jsonData);
        MultipartFile attachment = userRequest.getAttachment();

        if(attachment!=null && attachment.getOriginalFilename()!=null) {
            ByteArrayResource byteArrayResource = new ByteArrayResource(attachment.getBytes(), attachment.getOriginalFilename());
            requestParamerterMap.add("attachment", byteArrayResource);
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(requestParamerterMap, headers);


        String response = restTemplate.postForObject(targetUrl, requestEntity, String.class);

2 Answers 2

2

I figured it out. There are two piece in this puzzle. No change in service code.

  1. Providing right converter to resttemplate. In list of default converts spring doesn't add FormHttpMessageConverter.

        FormHttpMessageConverter converter = new FormHttpMessageConverter();
    
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(converter);
    
  2. overriding bytearrayresource class. plz note you need to override getFilename method so that document name can be received at service side.

         public class MultipartByteArrayResource extends ByteArrayResource{
    
         private String fileName;
    
          public MultipartByteArrayResource(byte[] byteArray) {
                 super(byteArray);
             }
    
          public String getFilename() { 
              return fileName; 
            }
    
          public void setFilename(String fileName) {
              this.fileName= fileName;
           }
    
       }
    

After above changes client code will be

       FormHttpMessageConverter converter = new FormHttpMessageConverter();

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add(converter);

        MultiValueMap<String, Object> requestParamerterMap = new LinkedMultiValueMap<String, Object>();

        requestParamerterMap.add("jsonData", jsonData);

        MultipartFile attachment = userRequest.getAttachment();

        if(attachment!=null && attachment.getOriginalFilename()!=null) {
            //ByteArrayResource byteArrayResource = new ByteArrayResource(attachment.getBytes(), attachment.getOriginalFilename());

            MultipartByteArrayResource resource = new MultipartByteArrayResource(attachment.getBytes());

           //pass file name sepratly 
           resource.setFilename(attachment.getOriginalFilename());

            requestParamerterMap.add("attachment", resource);
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(requestParamerterMap, headers);

        String response = restTemplate.postForObject(targetUrls.get("sdCreateTicketsUrl"), requestEntity, String.class);
Sign up to request clarification or add additional context in comments.

3 Comments

Did this solution work for you? I did exactly what you said and I am getting 415 Unsupported exception. Only difference I have is requestParamerterMap.add("my_own_name_which_server_accepts", resource)
Yes, it is working fine for me, if you can share your code then i might help.
0

First, value="/createTicket.do" is way off the REST convention. Same goes for /ticket. Creation of a ticket should be done by POST to URL: .../tickets/

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.