2015-12-05 3 views
9

私のユーザーは、食べ物の写真と食べ物の投稿を自分のサーバーに投稿できます。春のRestTemplate:画像とオブジェクトの両方を同時に投稿する

たとえば、誰かが美味しいものを見て、その写真をスナップして、「おいしい!」と書いてみましょう。写真の下に。写真はサーバーに送信され、「おいしい!」というメッセージが送信されます。ユーザー名、日付、場所などを含むメッセージが、1つのAPIコールを使用して「Post」というオブジェクトでサーバーに送信されます。

私は私のアンドロイド側に次のコードを書かれている:

final String url = Constants.POST_PICS; 
    RestTemplate restTemplate = RestClientConfig.getRestTemplate(context, true); 
    //adding StringHttpMessageConverter, formHttpMessageConverter and MappingJackson2HttpMessageConverter to restTemplate 
    restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); 
    FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); 
    restTemplate.getMessageConverters().add(formHttpMessageConverter); 
    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); 
    //putting both objects into a map 
    MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>(); 
    map.add("image", new FileSystemResource(file)); 
    map.add("post", post); 
    HttpHeaders imageHeaders = new HttpHeaders(); 
    //setting content type to multipart as the image is a multipart file 
    imageHeaders.setContentType(MediaType.MULTIPART_FORM_DATA); 
    HttpEntity<MultiValueMap<String, Object>> imageEntity = new HttpEntity<MultiValueMap<String, Object>>(map, imageHeaders); 
    ResponseEntity<Post> response = restTemplate.exchange(url, HttpMethod.POST, imageEntity, Post.class); 
    return response.getBody(); 

これは春の側のコードです:

 @RequestMapping(value = "/uploadpostpic", method = RequestMethod.POST) 
public Post uploadPostWithPic(@RequestParam("image") MultipartFile srcFile, 
            @RequestParam("post") Post post) { 
    return serviceGateway.uploadPostWithPic(srcFile, post); 
} 

私はエラーを取得しています:

An exception occurred during request network execution :Could not write request: no suitable HttpMessageConverter found for request type [Model.Post]

org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [Model.Post]

コンテンツタイプがMULTIPART_FORM_DATAに設定されていると思われますが、トランスフォームする必要があるため、これを設定する必要があります画像をサーバーに転送します。

restTemplateを使用してマルチパートファイルと別のオブジェクトを同時にアップストリームで転送することは可能ですか?

EDIT:

私はこれらの記事を見てきました:

Resttemplate form/multipart: image + JSON in POST

Sending Multipart File as POST parameters with RestTemplate requests

そして、彼らのガイダンスに従って、このコードを試してみました:他に

final String url = Constants.POST_PIC; 
    RestTemplate restTemplate = new RestTemplate(); 
    restTemplate.getMessageConverters().add(new StringHttpMessageConverter()); 
    restTemplate.getMessageConverters().add(new ByteArrayHttpMessageConverter()); 
    restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); 
    restTemplate.getMessageConverters().add(new ResourceHttpMessageConverter()); 

    FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); 
    formHttpMessageConverter.addPartConverter(new MappingJackson2HttpMessageConverter()); 
    formHttpMessageConverter.addPartConverter(new ResourceHttpMessageConverter()); // This is hope driven programming 
    formHttpMessageConverter.addPartConverter(new ByteArrayHttpMessageConverter()); 

    restTemplate.getMessageConverters().add(formHttpMessageConverter); 

    MultiValueMap<String, Object> multipartRequest = new LinkedMultiValueMap<>(); 

    byte[] bFile = new byte[(int) imageFile.length()]; 
    FileInputStream fileInputStream; 

    //convert file into array of bytes 
    fileInputStream = new FileInputStream(imageFile); 
    fileInputStream.read(bFile); 
    fileInputStream.close(); 

    ByteArrayResource bytes = new ByteArrayResource(bFile) { 
     @Override 
     public String getFilename() { 
      return "file.jpg"; 
     } 
    }; 

    //post portion of the multipartRequest 
    HttpHeaders xHeader = new HttpHeaders(); 
    xHeader.setContentType(MediaType.APPLICATION_JSON); 
    HttpEntity<Post> xPart = new HttpEntity<>(post, xHeader); 
    multipartRequest.add("post", xPart); 

    //picture portion of the multipartRequest 
    HttpHeaders pictureHeader = new HttpHeaders(); 
    pictureHeader.setContentType(MediaType.IMAGE_JPEG); 
    HttpEntity<ByteArrayResource> picturePart = new HttpEntity<>(bytes, pictureHeader); 
    multipartRequest.add("srcFile", picturePart); 

    //adding both the post and picture portion to one httpentity for transmitting to server 
    HttpHeaders header = new HttpHeaders(); 
    header.setContentType(MediaType.MULTIPART_FORM_DATA); 
    HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity(multipartRequest, header); 
    return restTemplate.postForObject(url, requestEntity, Post.class); 

を側、ポスト= nullと私はなぜそれがnullであるか分からない。

これは、私は、サーバー側でやろうとしているすべてである:

public Post uploadPostPic(MultipartFile srcFile, Post post) { 
    Post savedPost = repo.save(post); 
} 

私は私のリポジトリとエラーにそれを保存しています:私は見ていない

java.lang.IllegalArgumentException: Entity must not be null! 

答えて

1

はこのような何かを試してみてください。

@RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST) 
    public @ResponseBody 
    String uploadMultipleFileHandler(@RequestParam("name") String[] names, 
      @RequestParam("file") MultipartFile[] files) { 

     if (files.length != names.length) 
      return "Mandatory information missing"; 

     String message = ""; 
     for (int i = 0; i < files.length; i++) { 
      MultipartFile file = files[i]; 
      String name = names[i]; 
      try { 
       byte[] bytes = file.getBytes(); 

       // Creating the directory to store file 
       String rootPath = System.getProperty("catalina.home"); 
       File dir = new File(rootPath + File.separator + "tmpFiles"); 
       if (!dir.exists()) 
        dir.mkdirs(); 

       // Create the file on server 
       File serverFile = new File(dir.getAbsolutePath() 
         + File.separator + name); 
       BufferedOutputStream stream = new BufferedOutputStream(
         new FileOutputStream(serverFile)); 
       stream.write(bytes); 
       stream.close(); 

       logger.info("Server File Location=" 
         + serverFile.getAbsolutePath()); 

       message = message + "You successfully uploaded file=" + name 
         + "<br />"; 
      } catch (Exception e) { 
       return "You failed to upload " + name + " => " + e.getMessage(); 
      } 
     } 
     return message; 
    } 
} 

EDITED:

は最終的に、私は私の問題を解決するためにjsonStringの使用をしなければなりませんでした。 URLが非常に長くなるので理想的ではありませんが、問題を解決するための最速の方法です:

あなたのオブジェクトをjsonStringに変換し、それらを再変換する方法についてはmykongのアドバイスをご覧くださいオブジェクト:

ObjectMapper mapper = new ObjectMapper(); 
Staff obj = new Staff(); 

//Object to JSON in String 
String jsonInString = mapper.writeValueAsString(obj); 

//JSON from String to Object 
Staff obj = mapper.readValue(jsonInString, Staff.class); 

http://www.mkyong.com/java/jackson-2-convert-java-object-to-from-json/

+0

Springにこの機能が自動的に組み込まれている場合、私はこれをしたくない/ – Simon

+0

結局のところ、あなたの方法を使って私の問題を解決しました。 – Simon

0

あなたのPostクラスの登録済みHttpMessageConverter。おそらく、MultiValueMapにHttpMessageConverterを登録する必要があります。

+0

はMappingJackson2HttpMessageConverterは()JSONオブジェクトにそれを正しくマッピングすることができませんか? – Simon

+0

あなたのポストがジャクソンの注釈を持っているならば、正に、私はそう思います。あなたの '@RequestParam( "post")ポストポストのためのSpring ConversionServiceにConverterを登録したと仮定します。あなたのPostクラスをStringに置き換えて、それが動作するかどうかを調べようとします。 – Alexander

0

oookay、私は数週間前に同じ問題に直面しました。簡単な言葉で

A "multipart/form-data" message contains a series of parts, each representing a successful control.

A successful control is "valid" for submission. Every successful control has its control name paired with its current value as part of the submitted form data set

を、マルチパートフォームデータをサーバーへのデータの異なるコンテンツ・タイプを送ることができます:multipart/form-dataコンテンツタイプが何を意味するのか、すべての最初には、明確にすること。ここで、サンプルである:ここで

POST/HTTP/1.1 
Host: localhost:8000 
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:29.0) Gecko/20100101 Firefox/29.0 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-US,en;q=0.5 
Accept-Encoding: gzip, deflate 
Cookie: __atuvc=34%7C7; permanent=0; _gitlab_session=226ad8a0be43681acf38c2fab9497240; __profilin=p%3Dt; request_method=GET 
Connection: keep-alive 
Content-Type: multipart/form-data; boundary=---------------------------9051914041544843365972754266 
Content-Length: 554 

-----------------------------9051914041544843365972754266 
Content-Disposition: form-data; name="text" 

text default 
-----------------------------9051914041544843365972754266 
Content-Disposition: form-data; name="file1"; filename="a.txt" 
Content-Type: text/plain 

Content of a.txt. 

-----------------------------9051914041544843365972754266 
Content-Disposition: form-data; name="file2"; filename="a.html" 
Content-Type: text/html 

<!DOCTYPE html><title>Content of a.html.</title> 

-----------------------------9051914041544843365972754266-- 

は、3つの異なるセットを送信する試料である - 最初のものは、第二の一方はplain textであり、第3つhtmlであり、それらは境界によって分離されているbinary dataあります。

現在作業中Spring's RestTemplate?もしmultipart/form-dataに要求ヘッダーを設定する際

、resttemplateはmultipart/form-dataためFormHttpMessageConverterはDOC hereを見るであろう登録メッセージコンバータから適切なHttpMessageConverterをピックアップします。

しかしFormHttpMessageConverterpartConvertersのプロパティを持ち、FormHttpMessageConverterのために登録されたコンバータであり、デフォルトでは(文字列、bytearrayおよびリソース)です。ここでコンストラクタのソースコードは、単に言葉で)

public FormHttpMessageConverter() { 
    this.supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); 
    this.supportedMediaTypes.add(MediaType.MULTIPART_FORM_DATA); 

    this.partConverters.add(new ByteArrayHttpMessageConverter()); 
    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); 
    stringHttpMessageConverter.setWriteAcceptCharset(false); 
    this.partConverters.add(stringHttpMessageConverter); 
    this.partConverters.add(new ResourceHttpMessageConverter()); 
} 

FormHttpMessageConverterオブジェクトPostを書き込むための適切なメッセージ変換を見つけることができません。 PostをJSONとして記述したい場合は、にMappingJackson2HttpMessageConverterを追加する必要があります。

@Produces 
    public RestTemplate getRestTemplate() { 
     RestTemplate template = new RestTemplate(); 
     template.getMessageConverters().add(0,createFormHttpConverter()); 
     return template; 
    } 
private static HttpMessageConverter<?> createFormHttpConverter(){ 

     FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); 
     formHttpMessageConverter.setPartConverters(getPartConverters()); 
     return formHttpMessageConverter; 
    } 

private static List<HttpMessageConverter<?>> getPartConverters(){ 
    RestTemplate template = new RestTemplate(); 
    MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); 
    List<HttpMessageConverter<?>> messageConverters = template.getMessageConverters(); 
    messageConverters.add(0,converter); 
    return messageConverters; 
} 
+0

この回答をありがとう - 私はちょうどそれを試み、resttemplateはサーバーに送信することができましたが、サーバーに到達したとき、イメージオブジェクトは正常に送信されましたが、POSTオブジェクトはサーバー側でnullを返しました。あなたはあなたのコードがサーバー側でどのように見えるかを見せてもらえますか?私はあなたがRequestMappings、RequestParamsなどの点で何をしたかを見ることができます。 – Simon

0

リクエストパラメータをオブジェクトにマップする方法をSpringに伝える必要があります。あなたはアレクサンダーによって提案されたように、カスタムHttpMessageConterterを実装することにより、これを行うことができますが、私はもっと簡単な方法があります:コマンド・オブジェクト(とも呼ばれるフォームのバッキングオブジェクト)を使用してください:

public class PostWithPicCommand() { 
    public PostWithPic() {}; //Default constructor is required 

    //name the variables like the request parameters! 
    private Post post; 
    private MultipartFile image; 

    Getter and Setter! 
} 

@RequestMapping(value = "/uploadpostpic", method = RequestMethod.POST) 
public Post uploadPostWithPic(PostWithPicCommand postWithPicCommand 
     /*no @Param attribte for postWithPicCommand*/) {  
    .... 
} 

をそして、あなたが設定する必要があります/レジスタはマルチパートリゾルバを起動し、マルチパートリクエストとしてリクエストを送信する必要があります。

0

私はこれを使用して似たような作られた: ここjsonStringを送信し、後であなたがより多くの説明が必要なら、私が知っているobjectwriter.Let使用してオブジェクトに変換:

HttpHeaders headers = new HttpHeaders(); 
    headers.add("Accept","application/json");  
    headers.setContentType(MediaType.MULTIPART_FORM_DATA); 
    MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>(); 
    map.add("image", new FileSystemResource(file)); 
    map.add("post", post); 
    HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(map, headers); 
    RestTemplate restTemplate = RestClientConfig.getRestTemplate(context, true); 
    restTemplate.getMessageConverters().add(new FormHttpMessageConverter()); 
    ResponseEntity<Post> response = restTemplate.postForObject(url, requestEntity, Post.class); 
+0

私はまだエンティティをnullにしてはいけません!私のサーバー側でエラーが発生しました。あなたはあなたのサーバーのサイドコードを教えていただけますか? – Simon

+0

あなたはどんな種類のサーバーを持っていますか? PHP、Groovyなど? –

+0

スプリングブートJava。 – Simon

関連する問題