2015-12-05 6 views
9

Meine Benutzer können ein Foto von einem Essen und einem Post von dem, was das Essen ist, auf meinem Server posten.Spring RestTemplate: posten Sie gleichzeitig ein Bild und ein Objekt

Zum Beispiel, sagen wir, jemand sieht etwas Leckeres, macht ein Bild davon und schreibt dann "Tasty!" unter dem Bild. Das Foto wird an den Server gesendet und die Nachricht "Tasty!" einschließlich des Benutzernamens, des Datums, des Ortes usw. wird in einem Objekt, das "Post" genannt wird, unter Verwendung eines API-Anrufs an meinen Server gesendet.

ich den folgenden Code auf meinem Android-Seite geschrieben haben:

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(); 

Dies ist der Code auf der Federseite ist:

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

Ich erhalte eine Fehlermeldung:

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]

Ich vermute, es ist damit zu tun, dass der Content-Typ auf MULTIPART_FORM_DATA gesetzt ist, aber ich muss es so einstellen, wie ich es übertragen muss er das Bild bis zum Server.

Ist es sogar möglich, eine mehrteilige Datei und ein weiteres Objekt gleichzeitig mit restTemplate zu übertragen?

EDIT:

Resttemplate form/multipart: image + JSON in POST

Sending Multipart File as POST parameters with RestTemplate requests

und versuchte, nach ihrer Führung diesen Code:

ich an diesen Stellen ausgesehen haben

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); 

Auf der anderen Seite, der Beitrag = null und ich bin mir nicht sicher, warum es null ist.

Das ist alles, was ich bin versucht, auf der Server-Seite zu tun:

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

ich es in meinen Repository bin Speicher und der Fehler ist:

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

Antwort

1

Versuchen: Senden jsonString hier und es später konvertieren Objekt mit objectwriter.Let Sie mich wissen, wenn Sie mehr Erklärung benötigen.

@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:

Schließlich hatte ich die Verwendung des jsonString zu machen, mein Problem zu lösen. Es ist nicht ideal, da die URL am Ende sehr lang wird, aber es ist der schnellste Weg, um mein Problem zu lösen:

Bitte werfen Sie einen Blick auf den Rat von Mykong, wie Sie Ihr Objekt zu jsonString transformieren und sie zurück in Objekte:

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

Ich möchte dies nicht tun, wenn Spring diese Funktion automatisch eingebaut hat/ – Simon

+0

Am Ende habe ich Ihre Methode verwendet, um mein Problem zu lösen. – Simon

0

Ich sehe nicht, ein registrierter HttpMessageConverter für Ihre Post-Klasse. Sie müssen wahrscheinlich einen HttpMessageConverter für MultiValueMap registrieren.

+0

Kann die MappingJackson2HttpMessageConverter() nicht richtig an ein jSON-Objekt abbilden? – Simon

+0

Ehrlich gesagt, würde ich es erwarten, wenn Ihr Post die Jackson Annotationen hat. Ich nehme an, Sie haben einen Converter in Spring ConversionService für Ihren Posteingang "@RequestParam (" post ") registriert. Ich würde versuchen, Ihre Post-Klasse durch String zu ersetzen und zu sehen, ob es funktioniert. – Alexander

0

oookay, ich hatte vor ein paar Wochen das selbe Problem. Zunächst einmal klar sein, was multipart/form-data Content-Typ bedeutet:

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

in einfachen Worten, mit mehrteiliger Form-Daten können Sie verschiedene Content-Typen von Daten an den Server senden. Hier ist ein Beispiel:

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-- 

Hier ist ein Beispiel drei verschiedene Sätze von Senden - der erste ist binary data die zweite ist plain text und die dritte ist html und sie werden durch Grenze getrennt.

jetzt wie funktioniert Spring's RestTemplate?

, wenn Sie den Request-Header auf multipart/form-data gesetzt ist, wird resttemplate entsprechende HttpMessageConverter von registrierten Nachrichtenwandler aufzunehmen, die für multipart/form-data wird FormHttpMessageConverterhere doc zu sehen sein.

Aber FormHttpMessageConverter haben eine Eigenschaft von partConverters und sie sind Konverter für die FormHttpMessageConverter registriert und standardmäßig sind sie (string, bytearray und Ressourcen). hier ist ein Quellcode des Konstruktor;)

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()); 
} 

mit nur Worte, FormHttpMessageConverter nicht korrekt Nachrichtenumformer schreiben Post Objekt finden. Wenn Sie möchten, dass Post als JSON geschrieben wird, sollten Sie MappingJackson2HttpMessageConverter zu partConverters hinzufügen.

+0

Danke für diese Antwort - Ich habe es gerade ausprobiert und restemplate war in der Lage, es an den Server zu senden, aber als es den Server erreichte, wurde das Bildobjekt erfolgreich gesendet, aber das Post-Objekt gab null auf der Serverseite zurück. Können Sie mir zeigen, wie Ihr Code auf der Serverseite aussieht, damit ich sehen kann, was Sie in Bezug auf RequestMappings, RequestParams usw. getan haben. – Simon

0

Sie müssen Spring mitteilen, wie die Anforderungsparameter Ihren Objekten zugeordnet werden. Sie können dies tun, indem Sie eine benutzerdefinierte Implementierung HttpMessageConterter wie von Alexander vorgeschlagen, aber ich gibt es eine viel einfachere Möglichkeit: Verwenden Sie einen Befehl-Objekt (manchmal formTrägerObjekt genannt):

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*/) {  
    .... 
} 

Und Sie müssen konfigurieren/Registrieren Sie Federn Multipart Resolver, und müssen die Anfrage als eine mehrteilige Anfrage senden.

0

machte ich etwas ähnliches dies mit:

so etwas wie dieses
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

Ich bekomme immer noch die Entität muss nicht null sein! Fehler auf meiner Serverseite. Können Sie mir bitte Ihren Server-Side-Code zeigen? – Simon

+0

Welche Art von Server haben Sie? PHP, Groovy usw.? –

+0

Spring Boot Java. – Simon

Verwandte Themen