Как установить тип содержимого для файла в многостраничной загрузке при использовании RestTemplate (от клиента отдыха)
Файл, который я пытаюсь загрузить, всегда будет xml файлом. Я хочу установить тип содержимого как application/xml Вот мой код:
MultiValueMap<String, Object parts = new LinkedMultiValueMap<String,
Object(); parts.add("subject", "some info");
ByteArrayResource xmlFile = new ByteArrayResource(stringWithXMLcontent.getBytes("UTF-8")){
@Override
public String getFilename(){
return documentName;
}
};
parts.add("attachment", xmlFile);
//sending the request using RestTemplate template;, the request is successfull
String result = template.postForObject(getRestURI(), httpEntity,String.class);
//but the content-type of file is 'application/octet-stream'
необработанный запрос выглядит следующим образом:
Content-Type:
multipart/form-data;boundary=gbTw7ZJbcdbHIeCRqdX81DVTFfA-oteHHEqgmlz
User-Agent: Java/1.7.0_67 Host: some.host Connection: keep-alive
Content-Length: 202866
--gbTw7ZJbcdbHIeCRqdX81DVTFfA-oteHHEqgmlz Content-Disposition: form-data; name="subject" Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 19
some info
--gbTw7ZJbcdbHIeCRqdX81DVTFfA-oteHHEqgmlz Content-Disposition: form-data; name="attachment"; filename="filename.xml" Content-Type:
application/octet-stream Content-Length: 201402
....xml file contents here ..
Тип содержимого файла генерируется как "application/octet-stream", где, поскольку я хочу, чтобы оно было "application/xml",
Как установить тип содержимого для файла?
Ответы
Ответ 1
Я понял решение после того, как понял из этой ссылки:
Создание многостраничного почтового запроса со сжатым массивом байтов jpeg с spring для андроида
Решение состоит в том, чтобы поместить ByteArrayResource в HttpEntity с требуемым заголовком и добавить HttpEntity в Multivaluemap (вместо добавления самого ByteArrayResource.)
код:
Resource xmlFile = new ByteArrayResource(stringWithXMLcontent.getBytes("UTF-8")){
@Override
public String getFilename(){
return documentName;
}
};
HttpHeaders xmlHeaders = new HttpHeaders();
xmlHeaders.setContentType(MediaType.APPLICATION_XML);
HttpEntity<Resource> xmlEntity = new HttpEntity<Resource>(xmlFile, xmlHeaders);
parts.add("attachment", xmlEntity);
Ответ 2
Я не использовал RestTemplate, но использовал HttpClient в прошлом - вот как я передаю часть тела -
MultipartEntityBuilder eb = MultipartEntityBuilder.create().setBoundary(MULTIPART_BOUNDARY)
.addTextBody(BODYPART_ENTITY, key, ContentType.create("application/xml", Charset.forName("UTF-8")));
Вам нужно будет искать API в RestTemplate, который может использовать тип содержимого
Ответ 3
Поскольку я не могу прокомментировать ответ @RGR, я публикую это как новый ответ, хотя ответ RGR является абсолютно правильным.
Проблема заключается в том, что Sprint RestTemplates использует FormHttpMessageConverter для отправки многокомпонентного запроса. Этот конвертер обнаруживает все, что унаследовано от Resource, и использует его как часть "файла" запроса.
например Если вы используете MultiValueMap, каждое добавляемое свойство будет отправлено в отдельной части, как только вы добавите "Resource"...--> Установка имени файла, Mime-Type, length,.. не будет частью "файла" часть".
Не ответ, но объяснение, почему ByteArrayResource должен быть расширен для возврата имени файла и отправки в качестве единственной части запроса. Отправка нескольких файлов будет работать с MultiValueMap
Похоже, это поведение было исправлено в Spring 4.3 с помощью SPR-13571
Ответ 4
Вот как я обрабатываю загрузку и получение загруженного файла:
public String uploadFile(byte[] fileContent, String contentType, String filename) {
String url = "https://localhost:8000/upload";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, String> fileMap = new LinkedMultiValueMap<>();
ContentDisposition contentDisposition = ContentDisposition.builder("form-data")
.name("file")
.filename(filename)
.build();
fileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());
fileMap.add(HttpHeaders.CONTENT_TYPE, contentType);
HttpEntity<byte[]> entity = new HttpEntity<>(fileContent, fileMap);
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("file", entity);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
ResponseEntity<String> response = template.exchange(url, HttpMethod.POST, requestEntity, String.class);
return response.getBody();
}
И я использую его так, когда служба прослушивает порт 8000:
@Controller
@RequestMapping("upload")
public class FileUploadController {
@PostMapping("")
public ResponseEntity uploadFile(@RequestParam("file") MultipartFile file) {
handleUploadedFile(
file.getSize(),
file.getBytes(),
file.getContentType(),
file.getOriginalFilename()
);
}
}