Java 415通过REST模板发送json文件时不支持的媒体类型

Java 415通过REST模板发送json文件时不支持的媒体类型,java,spring,rest,spring-mvc,resttemplate,Java,Spring,Rest,Spring Mvc,Resttemplate,我正在尝试通过REST模板发送json文件。当我通过PostMan将其作为多部分表单数据发送时,它运行良好。我应该给出的名称是特定的(比如aaa)。附上邮递员的截图。但当我尝试在另一个stackoverflow中指定的相同代码时,我得到415个不支持的媒体类型错误,如下所示 org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type at org.springframework.w

我正在尝试通过REST模板发送json文件。当我通过PostMan将其作为多部分表单数据发送时,它运行良好。我应该给出的名称是特定的(比如aaa)。附上邮递员的截图。但当我尝试在另一个stackoverflow中指定的相同代码时,我得到415个不支持的媒体类型错误,如下所示

org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
    at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:616) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:572) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:532) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:332) ~[spring-web-4.1.9.RELEASE.jar:4.1.9.RELEASE]
    at 
请不要将其标记为重复,因为指定的答案不适用于我。不与我的代码共享代码与我的代码完全相同,只是

requestParamerterMap.add("attachment", resource);
我的代码在哪里

requestParamerterMap.add("aaa", resource);
从服务器端对其进行调试后,看起来请求正在向服务器发出。我能够在服务器端看到以下错误:

[{error=Unsupported Media Type, exception=org.springframework.web.HttpMediaTypeNotSupportedException, message=Content type 'application/octet-stream' not supported, status=415, timestamp=1532557180124}] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@74d4827a]
因此,从服务器端日志来看,我不确定内容类型添加为应用程序/八位字节流的位置,因为我已将内容类型设置为

headers.setContentType(MediaType.MULTIPART_FORM_DATA);
下面是来自服务器控制器的代码。服务器端代码使用Spring引导

    @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE,consumes = {"multipart/form-data"})
        @ResponseBody
        public MyResponse uploadPhoto(@RequestPart(value = "aaa", required = false) Optional<MyRequest> myRequest,
                                    @RequestPart(value = "file", required = false) Optional<MultipartFile> file,
                                    HttpServletRequest request) {
//some logic
            return myResponse;
        }
并将其转换为字节数组,如下所示:

json.toString().getBytes("UTF-8")
那我就跟着。代码的不同之处在于,我将JSONObject作为字节流发送,因为我无法创建文件(性能问题)

而且我不能将JSONObject作为字符串发送,因为服务器需要文件和aaa的多部分表单数据

我已经创建了restTemplate作为

 public RestTemplate myRestTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setReadTimeout(HTTP_CLIENT_TIMEOUT);
        requestFactory.setConnectTimeout(HTTP_CLIENT_TIMEOUT);

        RestTemplate restTemplate = new RestTemplate(requestFactory);
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
        messageConverters.add(new FormHttpMessageConverter());
        messageConverters.add(new StringHttpMessageConverter());
        restTemplate.setMessageConverters(messageConverters);
        return restTemplate;
公共RestTemplate myRestTemplate(){ SimpleClientHttpRequestFactory requestFactory=新的SimpleClientHttpRequestFactory(); setReadTimeout(HTTP_客户端_超时); setConnectTimeout(HTTP_客户端_超时); RestTemplate RestTemplate=新的RestTemplate(requestFactory); 列表>(); 添加(新表单HttpMessageConverter()); 添加(新的StringHttpMessageConverter()); restemplate.setMessageConverters(messageConverters); 返回REST模板; 以下是调用服务的客户端代码:

public Optional<JSONObject> callService(byte[] multipartFile) {
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        InputStream stream = new ByteArrayInputStream(multipartFile);
        MultipartByteArrayResource resource = new MultipartByteArrayResource(multipartFile,fileName);


       body.add("aaa", resource);

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

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

        try {
            response =  restTemplate.postForObject(url, requestEntity , String.class);


        } catch (Exception exception) {
            LOG.error("Error", exception);
            return Optional.empty();
        }
    }

   public class MultipartInputStreamFileResource extends InputStreamResource {

        private final String filename;

        MultipartInputStreamFileResource(InputStream inputStream, String filename) {
            super(inputStream);
            this.filename = filename;
        }

        @Override
        public String getFilename() {
            return this.filename;
        }

        @Override
        public long contentLength() throws IOException {
            return -1; // we do not want to generally read the whole stream into memory ...
        }
}
公共可选呼叫服务(字节[]多部分文件){
MultiValueMap body=新链接的MultiValueMap();
InputStream=新的ByteArrayInputStream(多部分文件);
MultipartByteArrayResource resource=新的MultipartByteArrayResource(multipartFile,fileName);
正文。添加(“aaa”,资源);
HttpHeaders=新的HttpHeaders();
headers.setContentType(MediaType.MULTIPART\u FORM\u DATA);
HttpEntity requestEntity=新的HttpEntity(主体、标题);
试一试{
response=restTemplate.postForObject(url、requestEntity、String.class);
}捕获(异常){
LOG.error(“错误”,异常);
返回可选的.empty();
}
}
公共类MultipartInputStreamFileResource扩展InputStreamResource{
私有最终字符串文件名;
MultipartInputStreamFileResource(InputStream InputStream,字符串文件名){
超级(输入流);
this.filename=文件名;
}
@凌驾
公共字符串getFilename(){
返回此文件名;
}
@凌驾
public long contentLength()引发IOException{
return-1;//我们通常不希望将整个流读取到内存中。。。
}
}
当我发送文件时,同样的代码也会起作用(注意fileaaa是两件不同的事情,尽管它们在服务器端都是多部分/表单数据。file只是任何时候的文件(图像/文本/pdf)但是aaajson数据文件


在调试多一点之后,我观察到服务器端控制器希望文件内容是json,因为Jackson试图将该json反序列化为MyRequest对象。当我从POSTMAN发送帖子时,它的json内容如预期般工作,但从客户端代码来看,内容是byteArray,而且它没有反序列化到MyRequest对象。不确定如何修复此问题服务器端异常是由
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
生成的。Jackson是一个json库,Spring使用MessageConverter格式化请求和响应


当服务器有@products(application_JSON)注释时,客户端是否会发送一个“Accept:application/octet stream”呢?这意味着服务器会处理请求,只在发送响应时出现问题。您可以添加一些log.info()服务器中的语句来验证这一点。

最后我解决了这个问题。如前所述,在从邮递员和代码发送请求时,具有不同内容类型的多部分文件是我开始的地方。如果有人有任何问题,我将详细解释

    public Optional<JSONObject> save(byte[] multipartFile, String fileName) {
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        Resource content = new MultipartByteArrayResource(multipartFile , fileName);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Resource> requestEntityBody = new HttpEntity<Resource>(content, headers);
        body.add("aaa", requestEntityBody);
        String result = "";
        JSONParser parser = new JSONParser();
        JSONObject json = null;


        HttpHeaders requestHeaders = new HttpHeaders();
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, requestHeaders);
        ResponseEntity<String> response = null;
        try {
           RestTemplate restTemplate = customizeRestTemplate(); //I have defined this in different config file in my actual code
           response =  restTemplate.exchange(url , HttpMethod.POST , requestEntity , String.class);
           result = (response != null && response.getBody() != null) ? response.getBody().toString() : result;
           json = (JSONObject) parser.parse(result);
           LOG.info( "Response:", response );

        } catch (Exception exception) {
            LOG.error("Error , exception);
            return Optional.empty();
        }
        return Optional.ofNullable(json);
    }

   public class MultipartByteArrayResource extends ByteArrayResource{

       private String fileName;

        public MultipartByteArrayResource(byte[] byteArray , String filename) {
               super(byteArray);
               this.fileName = filename;
           }

        public String getFilename() { 
            return fileName; 
          }

        public void setFilename(String fileName) {
            this.fileName= fileName;
         }

     }

      public RestTemplate customizeRestTemplate() {

            SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            requestFactory.setReadTimeout(10000);
            requestFactory.setConnectTimeout(10000);

            RestTemplate restTemplate = new RestTemplate(requestFactory);
            List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
            messageConverters.add(new FormHttpMessageConverter());
            messageConverters.add(new StringHttpMessageConverter());
            restTemplate.setMessageConverters(messageConverters);
            return restTemplate;
        }

}
public可选保存(字节[]多部分文件,字符串文件名){
MultiValueMap body=新链接的MultiValueMap();
资源内容=新的MultipartByteArrayResource(multipartFile,文件名);
HttpHeaders=新的HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity requestEntityBody=新的HttpEntity(内容、标题);
添加(“aaa”,requestEntityBody);
字符串结果=”;
JSONParser=新的JSONParser();
JSONObject json=null;
HttpHeaders requestHeaders=新的HttpHeaders();
HttpEntity requestEntity=新的HttpEntity(主体,RequestHeader);
ResponseEntity response=null;
试一试{
RestTemplate RestTemplate=customizeRestTemplate();//我在实际代码中的不同配置文件中定义了它
response=restemplate.exchange(url,HttpMethod.POST,requestEntity,String.class);
结果=(response!=null&&response.getBody()!=null)?response.getBody().toString():结果;
json=(JSONObject)parser.parse(result);
登录
    public Optional<JSONObject> save(byte[] multipartFile, String fileName) {
        MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
        Resource content = new MultipartByteArrayResource(multipartFile , fileName);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<Resource> requestEntityBody = new HttpEntity<Resource>(content, headers);
        body.add("aaa", requestEntityBody);
        String result = "";
        JSONParser parser = new JSONParser();
        JSONObject json = null;


        HttpHeaders requestHeaders = new HttpHeaders();
        HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, requestHeaders);
        ResponseEntity<String> response = null;
        try {
           RestTemplate restTemplate = customizeRestTemplate(); //I have defined this in different config file in my actual code
           response =  restTemplate.exchange(url , HttpMethod.POST , requestEntity , String.class);
           result = (response != null && response.getBody() != null) ? response.getBody().toString() : result;
           json = (JSONObject) parser.parse(result);
           LOG.info( "Response:", response );

        } catch (Exception exception) {
            LOG.error("Error , exception);
            return Optional.empty();
        }
        return Optional.ofNullable(json);
    }

   public class MultipartByteArrayResource extends ByteArrayResource{

       private String fileName;

        public MultipartByteArrayResource(byte[] byteArray , String filename) {
               super(byteArray);
               this.fileName = filename;
           }

        public String getFilename() { 
            return fileName; 
          }

        public void setFilename(String fileName) {
            this.fileName= fileName;
         }

     }

      public RestTemplate customizeRestTemplate() {

            SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            requestFactory.setReadTimeout(10000);
            requestFactory.setConnectTimeout(10000);

            RestTemplate restTemplate = new RestTemplate(requestFactory);
            List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
            messageConverters.add(new FormHttpMessageConverter());
            messageConverters.add(new StringHttpMessageConverter());
            restTemplate.setMessageConverters(messageConverters);
            return restTemplate;
        }

}