java 使用 RestTemplate 时如何在分段上传中为文件设置内容类型(来自休息客户端)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28373130/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set content-type for the file in multipart upload when using RestTemplate (from a rest client)
提问by RGR
The file i'm trying to upload will always be a xml file. I want to set the content-type as application/xml Here is my code:
我尝试上传的文件将始终是一个 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'
the raw request looks like this:
原始请求如下所示:
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 ..
The content-type of the file is being generated as 'application/octet-stream' where as i want it to be 'application/xml' How can i set the content type for the file?
文件的内容类型正在生成为“应用程序/八位字节流”,而我希望它是“应用程序/xml” 如何设置文件的内容类型?
回答by RGR
I figured out the solution after taking hint from this link:
我从这个链接中得到提示后找到了解决方案:
Making a multipart post request with compressed jpeg byte array with spring for android
使用 spring for android 使用压缩的 jpeg 字节数组制作多部分发布请求
Solution is to put the ByteArrayResource in a HttpEntity with required header and add the HttpEntity to Multivaluemap (Instead of adding ByteArrayResource itself.)
解决方案是将 ByteArrayResource 放在具有所需标头的 HttpEntity 中,并将 HttpEntity 添加到 Multivaluemap (而不是添加 ByteArrayResource 本身。)
Code:
代码:
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);
回答by Pankaj
I've not used RestTemplate but i've used HttpClient in past - This is how i pass the body part -
我没有使用过 RestTemplate,但我过去使用过 HttpClient - 这就是我传递正文部分的方式 -
MultipartEntityBuilder eb = MultipartEntityBuilder.create().setBoundary(MULTIPART_BOUNDARY)
.addTextBody(BODYPART_ENTITY, key, ContentType.create("application/xml", Charset.forName("UTF-8")));
You will have to look at for API in RestTemplate which can take content-type
您将不得不在 RestTemplate 中寻找可以采用内容类型的 API
回答by Clemens Eberwein
As i can not comment the answer of @RGR I'm posting this as new answer although RGR's answer is absolutely correct.
由于我无法评论@RGR 的答案,我将此作为新答案发布,尽管 RGR 的答案是绝对正确的。
The problem is, that the Sprint RestTemplates uses FormHttpMessageConverter to send the multi part request. This converter detects everything that inherits from Resource and uses this as the request's "file" part. e.g. If you use a MultiValueMap every property you add will be send in it's own part as soon as you add a "Resource"...--> Setting filename, Mime-Type, length,.. will not be part of the "file part".
问题是,Sprint RestTemplates 使用 FormHttpMessageConverter 发送多部分请求。此转换器检测从 Resource 继承的所有内容,并将其用作请求的“文件”部分。例如,如果您使用 MultiValueMap,则您添加的每个属性都将在您添加“资源”后立即发送到它自己的部分...--> 设置文件名、Mime-Type、长度……将不会成为“的一部分”文件部分”。
Not an answer, but it's the explanation why ByteArrayResource must be extended to return the filename and be send as the only part of the request. Sending multiple files will work with a MultiValueMap
不是答案,而是解释为什么必须扩展 ByteArrayResource 以返回文件名并作为请求的唯一部分发送。发送多个文件将与 MultiValueMap 一起使用
It looks like this behaviour was fixed in Spring 4.3 by SPR-13571
看起来此行为已在 Spring 4.3 中由SPR-13571修复
回答by Kent Munthe Caspersen
This is how I handle file upload and receiving an uploaded file:
这是我处理文件上传和接收上传文件的方式:
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();
}
And I consume it like this with the service listening at port 8000:
我像这样使用侦听端口 8000 的服务来使用它:
@Controller
@RequestMapping("upload")
public class FileUploadController {
@PostMapping("")
public ResponseEntity uploadFile(@RequestParam("file") MultipartFile file) {
handleUploadedFile(
file.getSize(),
file.getBytes(),
file.getContentType(),
file.getOriginalFilename()
);
}
}