Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring mvc 使用RestTemplate请求将多部分文件作为POST参数发送_Spring Mvc_Multipartform Data_Resttemplate - Fatal编程技术网

Spring mvc 使用RestTemplate请求将多部分文件作为POST参数发送

Spring mvc 使用RestTemplate请求将多部分文件作为POST参数发送,spring-mvc,multipartform-data,resttemplate,Spring Mvc,Multipartform Data,Resttemplate,我正在使用Spring3和RestTemplate。我基本上有两个应用程序,其中一个必须将值发布到另一个应用程序。通过rest模板 当要发布的值是字符串时,它工作得很好,但是当我必须发布混合和复杂的参数(如MultipartFiles)时,我会得到一个转换器异常 举个例子,我有: App1-后置控制器: @RequestMapping(method = RequestMethod.POST) public String processSubmit(@ModelAttribute UploadDT

我正在使用Spring3和RestTemplate。我基本上有两个应用程序,其中一个必须将值发布到另一个应用程序。通过rest模板

当要发布的值是字符串时,它工作得很好,但是当我必须发布混合和复杂的参数(如MultipartFiles)时,我会得到一个转换器异常

举个例子,我有:

App1-后置控制器:

@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute UploadDTO pUploadDTO, 
        BindingResult pResult) throws URISyntaxException, IOException {
    URI uri = new URI("http://localhost:8080/app2/file/receiver");

    MultiValueMap<String, Object> mvm = new LinkedMultiValueMap<String, Object>();
    mvm.add("param1", "TestParameter");
    mvm.add("file", pUploadDTO.getFile()); // MultipartFile

    Map result = restTemplate.postForObject(uri, mvm, Map.class);
    return "redirect:postupload";
}
My application-context.xml:

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
            <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
            <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
            <bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
        </list>
    </property>
</bean>

<bean id="multipartResolver"  
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">  
    <property name="maxUploadSize">  
        <value>104857600</value>  
    </property>  
    <property name="maxInMemorySize">  
        <value>4096</value>  
    </property>      
</bean>  
因此,我的问题是:

  • 是否可以使用POST通过RestTemplate发送多部分文件
  • 是否有一些特定的转换器,我必须使用发送这种类型的对象?我的意思是,在我的配置中是否有一些MultipartFileHttpMessageConverter
  • MultiValueMap parts=新链接的MultiValueMap();
    增加(“名称1”、“价值1”);
    增加(“名称2”、“值2+1”);
    增加(“名称2”、“值2+2”);
    Resource logo=new ClassPathResource(“/org/springframework/http/converter/logo.jpg”);
    零件。添加(“徽标”,徽标);
    Source xml=新的StreamSource(新的StringReader(“”);
    添加(“xml”,xml);
    模板。postForLocation(“http://example.com/multipart“、零件);
    
    前几天我也遇到了同样的问题。谷歌搜索把我带到了这里和其他几个地方,但没有一个能解决这个问题。最后,我将上传的文件(MultiPartFile)保存为tmp文件,然后使用FileSystemResource通过RestTemplate上传它。这是我使用的代码

    String tempFileName = "/tmp/" + multiFile.getOriginalFileName();
    FileOutputStream fo = new FileOutputStream(tempFileName);
    
    fo.write(asset.getBytes());    
    fo.close();   
    
    parts.add("file", new FileSystemResource(tempFileName));    
    String response = restTemplate.postForObject(uploadUrl, parts, String.class, authToken, path);   
    
    
    //clean-up    
    File f = new File(tempFileName);    
    f.delete();
    

    我仍然在寻找一个更优雅的解决方案来解决这个问题。

    我们的一位同事对filesystemresource做了类似的事情。 试一试

    假设您的.getFile的输出是一个java文件对象,它的工作原理应该与我们的相同,即
    只有一个文件参数。

    解决这个问题的一种方法是使用ByteArrayResource,这样您就可以在post中发送字节数组(此代码适用于Spring 3.2.3):

    MultiValueMap=newlinkedMultivaluemap();
    最终字符串filename=“somefile.txt”;
    添加(“名称”,文件名);
    添加(“文件名”,文件名);
    ByteArrayResource contentsResource=新的ByteArrayResource(content.getBytes(“UTF-8”)){
    @凌驾
    公共字符串getFilename(){
    返回文件名;
    }
    };
    map.add(“文件”,contentsAsResource);
    String result=restemplate.postForObject(urlForFacade、map、String.class);
    

    我重写了ByteArrayResource的getFilename,因为如果我没有,我会得到一个空指针异常(显然这取决于java activation.jar是否在类路径上,如果在类路径上,它将使用文件名来尝试确定内容类型)

    我最近为这个问题挣扎了3天。客户端发送请求的方式可能不是原因,服务器可能未配置为处理多部分请求。我必须这样做才能让它工作:

    xml-添加了commons fileupload依赖项(如果不使用依赖项管理,如maven,请下载jar并将其添加到项目中)

    你的客户

    public static Boolean updateStationImage(StationImage stationImage) {
        if(stationImage == null) {
            Log.w(TAG + ":updateStationImage", "Station Image object is null, returning.");
            return null;
        }
    
        Log.d(TAG, "Uploading: " + stationImage.getImageUri());
        try {
            RestTemplate restTemplate = new RestTemplate();
            FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
            formConverter.setCharset(Charset.forName("UTF8"));
            restTemplate.getMessageConverters().add(formConverter);
            restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
    
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType("application/json")));
    
            MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
    
            parts.add(Constants.STATION_PROFILE_IMAGE_FILE, new FileSystemResource(stationImage.getImageFile()));
            parts.add(Constants.STATION_PROFILE_IMAGE_URI, stationImage.getImageUri());
            parts.add(Constants.STATION_PROFILE_IMAGE_TYPE, stationImage.getImageType());
            parts.add(Constants.FIELD_STATION_ID, stationImage.getStationId());
    
            return restTemplate.postForObject(Constants.REST_CLIENT_URL_ADD_IMAGE, parts, Boolean.class);
        } catch (Exception e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
    
            Log.e(TAG + ":addStationImage", sw.toString());
        }
    
        return false;
    }
    
    公共静态布尔更新StationImage(StationImage StationImage){
    如果(stationImage==null){
    w(TAG+“:updateStationImage”,“Station Image对象为空,返回“”);
    返回null;
    }
    Log.d(标签,“上传:”+stationImage.getImageUri());
    试一试{
    RestTemplate RestTemplate=新RestTemplate();
    FormHttpMessageConverter formConverter=新FormHttpMessageConverter();
    formConverter.setCharset(Charset.forName(“UTF8”);
    restemplate.getMessageConverters().add(formConverter);
    restemplate.getMessageConverters().add(新映射Jackson2HttpMessageConverter());
    setRequestFactory(新的HttpComponentsClientHttpRequestFactory());
    HttpHeaders HttpHeaders=新的HttpHeaders();
    httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType(“application/json”));
    MultiValueMap parts=新链接的MultiValueMap();
    添加(Constants.STATION\u PROFILE\u IMAGE\u文件,新文件系统资源(stationImage.getImageFile());
    添加(Constants.STATION\u PROFILE\u IMAGE\u URI,stationImage.getImageUri());
    添加(Constants.STATION\u PROFILE\u IMAGE\u TYPE,stationImage.getImageType());
    parts.add(Constants.FIELD\u STATION\u ID,stationImage.getStationId());
    返回restemplate.postForObject(Constants.REST\u CLIENT\u URL\u ADD\u IMAGE,parts,Boolean.class);
    }捕获(例外e){
    StringWriter sw=新的StringWriter();
    e、 printStackTrace(新PrintWriter(sw));
    Log.e(TAG+“:addStationImage”,sw.toString());
    }
    返回false;
    }
    

    这应该能奏效。我添加了尽可能多的信息,因为我花了几天的时间,拼凑了完整版本的各个部分,我希望这会有所帮助。

    如果您必须发送一个多部分文件,该文件由一个需要使用特定HttpMessageConverter转换的对象组成,并且您得到“没有合适的HttpMessageConverter”错误无论您尝试什么,您都可能希望尝试以下方法:

    RestTemplate restTemplate = new RestTemplate();
    FormHttpMessageConverter converter = new FormHttpMessageConverter();
    
    converter.addPartConverter(new TheRequiredHttpMessageConverter());
    //for example, in my case it was "new MappingJackson2HttpMessageConverter()"
    
    restTemplate.getMessageConverters().add(converter);
    
    这为我解决了一个自定义对象的问题,该对象与一个文件(在我的例子中是instanceof FileSystemResource)一起,是我需要发送的多部分文件的一部分。
    我尝试使用的解决方案(以及在web上找到的许多其他解决方案)没有效果,然后我查看了FormHttpMessageConverter的源代码并尝试了这个方法。

    您必须将FormHttpMessageConverter添加到applicationContext.xml才能发布多部分文件

    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
                <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
            </list>
        </property>
    </bean>
    
    
    

    有关示例,请参见。

    您可以简单地使用
    multipartttpServletRequest

    例如:

     @RequestMapping(value={"/upload"}, method = RequestMethod.POST,produces = "text/html; charset=utf-8")
     @ResponseBody
     public String upload(MultipartHttpServletRequest request /*@RequestBody MultipartFile file*/){
        String responseMessage = "OK";
        MultipartFile file = request.getFile("file");
        String param = request.getParameter("param");
        try {
            System.out.println(file.getOriginalFilename());
            System.out.println("some param = "+param);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8));
            // read file
        }
        catch(Exception ex){
            ex.printStackTrace();
            responseMessage = "fail";
        }
         return responseMessage;
    }
    
    其中,
    request.getParameter()
    中的参数名称必须与相应的前端名称相同

    注意,该文件是通过MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>(); final String filename="somefile.txt"; map.add("name", filename); map.add("filename", filename); ByteArrayResource contentsAsResource = new ByteArrayResource(content.getBytes("UTF-8")){ @Override public String getFilename(){ return filename; } }; map.add("file", contentsAsResource); String result = restTemplate.postForObject(urlForFacade, map, String.class);
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>${commons-version}</version>
    </dependency>
    
    <filter>
      <filter-name>multipartFilter</filter-name>
      <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    </filter>
    <filter-mapping>
      <filter-name>multipartFilter</filter-name>
      <url-pattern>/springrest/*</url-pattern>
    </filter-mapping>
    
    <beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <beans:property name="maxUploadSize">
            <beans:value>10000000</beans:value>
        </beans:property>
    </beans:bean>
    
    @RequestMapping(value=Constants.REQUEST_MAPPING_ADD_IMAGE, method = RequestMethod.POST, produces = { "application/json"})
    public @ResponseBody boolean saveStationImage(
            @RequestParam(value = Constants.MONGO_STATION_PROFILE_IMAGE_FILE) MultipartFile file,
            @RequestParam(value = Constants.MONGO_STATION_PROFILE_IMAGE_URI) String imageUri, 
            @RequestParam(value = Constants.MONGO_STATION_PROFILE_IMAGE_TYPE) String imageType, 
            @RequestParam(value = Constants.MONGO_FIELD_STATION_ID) String stationId) {
        // Do something with file
        // Return results
    }
    
    public static Boolean updateStationImage(StationImage stationImage) {
        if(stationImage == null) {
            Log.w(TAG + ":updateStationImage", "Station Image object is null, returning.");
            return null;
        }
    
        Log.d(TAG, "Uploading: " + stationImage.getImageUri());
        try {
            RestTemplate restTemplate = new RestTemplate();
            FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
            formConverter.setCharset(Charset.forName("UTF8"));
            restTemplate.getMessageConverters().add(formConverter);
            restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
    
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
    
            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setAccept(Collections.singletonList(MediaType.parseMediaType("application/json")));
    
            MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
    
            parts.add(Constants.STATION_PROFILE_IMAGE_FILE, new FileSystemResource(stationImage.getImageFile()));
            parts.add(Constants.STATION_PROFILE_IMAGE_URI, stationImage.getImageUri());
            parts.add(Constants.STATION_PROFILE_IMAGE_TYPE, stationImage.getImageType());
            parts.add(Constants.FIELD_STATION_ID, stationImage.getStationId());
    
            return restTemplate.postForObject(Constants.REST_CLIENT_URL_ADD_IMAGE, parts, Boolean.class);
        } catch (Exception e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
    
            Log.e(TAG + ":addStationImage", sw.toString());
        }
    
        return false;
    }
    
    RestTemplate restTemplate = new RestTemplate();
    FormHttpMessageConverter converter = new FormHttpMessageConverter();
    
    converter.addPartConverter(new TheRequiredHttpMessageConverter());
    //for example, in my case it was "new MappingJackson2HttpMessageConverter()"
    
    restTemplate.getMessageConverters().add(converter);
    
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.StringHttpMessageConverter" />
                <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
            </list>
        </property>
    </bean>
    
     @RequestMapping(value={"/upload"}, method = RequestMethod.POST,produces = "text/html; charset=utf-8")
     @ResponseBody
     public String upload(MultipartHttpServletRequest request /*@RequestBody MultipartFile file*/){
        String responseMessage = "OK";
        MultipartFile file = request.getFile("file");
        String param = request.getParameter("param");
        try {
            System.out.println(file.getOriginalFilename());
            System.out.println("some param = "+param);
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8));
            // read file
        }
        catch(Exception ex){
            ex.printStackTrace();
            responseMessage = "fail";
        }
         return responseMessage;
    }
    
    ByteArrayResource contentsAsResource = new ByteArrayResource(byteArr){
                @Override
                public String getFilename(){
                    return filename;
                }
            };
    
    public void loadInvoices(MultipartFile invoices, String channel) throws IOException {
    
        init();
    
        Resource invoicesResource = invoices.getResource();
    
        LinkedMultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
        parts.add("file", invoicesResource);
    
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
        httpHeaders.set("channel", channel);
    
        HttpEntity<LinkedMultiValueMap<String, Object>> httpEntity = new HttpEntity<>(parts, httpHeaders);
    
        String url = String.format("%s/rest/inbound/invoices/upload", baseUrl);
    
        restTemplate.postForEntity(url, httpEntity, JobData.class);
    }