Sending file over spring rest service via resttemp

2020-03-30 01:53发布

问题:

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

回答1:

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


回答2:

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/