web-dev-qa-db-fra.com

REST demande mixte multipartite (fichier + json) avec Spring

Je dois envoyer un fichier avec un JSON à ma manette Spring. J'ai la classe de contrôleur suivante: 

@Controller
@RequestMapping("/perform")
public class PerformController {

    ...

    @RequestMapping(path = "gopdf", method = RequestMethod.POST, consumes = { "multipart/mixed" })
    @ResponseStatus(HttpStatus.CREATED)
    public void handleFileUpload(@RequestPart("file") MultipartFile file, @RequestPart("map") String map,   HttpServletResponse response) throws Exception {
        ...
    }

}

Mais quand je tourne sur mon serveur avec la commande suivante:

 curl -H "Content-Type: multipart/form-data" -F "[email protected]; type=application/json" -F "[email protected]" -X POST localhost:9000/perform/gopdf-i -v

Je reçois 415 types de support non pris en charge!

Un indice?

6
ElArbi

La chose consomme dans les autres réponses n'a pas fait la merde pour moi. La clé consistait à obtenir les types multipart/* spécifiques que je voulais prendre en charge sur certaines clés d'en-tête du RequestMapping. C'était vraiment difficile à comprendre, surtout deviner le travail et regarder le code source de Spring. Je suis un peu déçu du support de Spring pour cela, mais j'ai réussi à le faire fonctionner dans notre application Spring Boot, mais uniquement avec Tomcat?!? Quelque chose qui s'appelle le MultipartResolver étrangle lorsque vous configurez votre application de démarrage pour utiliser Jetty ... si longtemps Jetty. Mais je m'égare ...

Dans mon contrôleur, je configure les données multipart/mixtes ou multipart/form comme ...

@RequestMapping(value = "/user/{userId}/scouting_activities", method = RequestMethod.POST,
        headers = {"content-type=multipart/mixed","content-type=multipart/form-data"})
public ResponseEntity<String> POST_v1_scouting_activities(
        @RequestHeader HttpHeaders headers,
        @PathVariable String userId,
        @RequestPart(value = "image", required = false) MultipartFile image,
        @RequestPart(value = "scouting_activity", required = true) String scouting_activity_json) {
  LOG.info("POST_v1_scouting_activities: headers.getContentType(): {}", headers.getContentType());
  LOG.info("POST_v1_scouting_activities: userId: {}", userId);
  LOG.info("POST_v1_scouting_activities: image.originalFilename: {}, image: {}",
          (image!=null) ? image.getOriginalFilename() : null, image);
  LOG.info("POST_v1_scouting_activities: scouting_activity_json.getType().getName(): {}, scouting_activity: {}",
          scouting_activity_json.getClass().getName(), scouting_activity_json);
  return new ResponseEntity<String>("POST_v1_scouting_activities\n", HttpStatus.OK);
}

Cet en-tête lui a permis d'identifier de manière unique les types de contenu en plusieurs parties qu'il était prêt à essayer. Cela permet des boucles comme ...

curl -i -X POST 'http://localhost:8080/robert/v1/140218/scouting_activities' \
-H 'Content-type:multipart/mixed' \
-F 'image=@Smile_128x128.png;type=image/png' \
-F 'scouting_activity={
  "field": 14006513,
  "longitude": -93.2038253,
  "latitude": 38.5203231,
  "note": "This is the center of Dino Head.",
  "scouting_date": "2017-01-19T22:56:04.836Z"
};type=application/json'

...ou...

curl -i -X POST 'http://localhost:8080/robert/v1/140218/scouting_activities' \
-H 'Content-type:multipart/form-data' \
-F 'image=@Smile_128x128.png;type=image/png' \
-F '[email protected];type=application/json'

travail.

4
Bob Kuhar

J'ai trouvé la solution: Je dois utiliser @RequestParam au lieu de @RequestPart

@RequestMapping(path = "gopdf", method = RequestMethod.POST, consumes = { "multipart/form-data" })
@ResponseStatus(HttpStatus.OK)
public void handleFileUpload2(@RequestParam("file") MultipartFile file, @RequestParam("map") String jsonMap,
        HttpServletResponse response) throws Exceptio
2
ElArbi

Le multipart/mix pour le printemps webflux (2.1.0) ne fonctionnait pas pour moi. Voici une approche alternative qui a fonctionné

  • Travailler - spring-boot-starter-web/Multipart [] - télécharger des fichiers oùone est la charge utile, un autre est un fichier lui-même. Dans mon cas, puisque la charge utile était constante, cela a fonctionné.
  • Ne fonctionne pas - printemps-boot-starter-webflux/Flux. Le flux est vide. J'ai essayé ceci https://github.com/spring-projects/spring-boot/issues/13268 , mais cela n'a pas fonctionné
1
Aravind

C'est peut-être lié à votre annotation de mappage de demande. Je pense que la valeur accept est manquante pour déterminer quel service peut accepter:

Exemple :

@RequestMapping(path = "gopdf", method = RequestMethod.POST, consumes = { "multipart/mixed" }, accept = MediaType.MULTIPART_FORM_DATA_VALUE)

Importer:

import org.springframework.http.MediaType;

Documentation/API:http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/MediaType.html

0
Mickael