Spring: données JSON et fichier dans la même demande

Je sais comment créer des points de terminaison traitant des fichiers à l’aide de MediaType.MULTIPART_FORM_DATA et de @FormDataParam("file") FormDataBodyPart bodyPart , mais je me demandais si je pouvais également avoir des données JSON avec cette demande? Quelque chose comme:

  @POST @Path("somepath") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFileAndJSON(@RequestBody SomeModel someModel, @FormDataParam("file") FormDataBodyPart bodyPart) { return null; } 

À l’heure actuelle, si j’ajoute des données JSON dans l’onglet “raw” de la requête suivante, @RequestBody HTTP 415 Unsupported Media Type probablement parce que j’ai indiqué que je consum MULTIPART_FORM_DATA mais j’utilise également @RequestBody qui recherche JSON. contenu qui est APPLICATION_JSON . Alors, comment puis-je avoir des données JSON et un fichier traité dans la même demande? Je sais qu’il est possible de faire cela en deux demandes, je veux juste le faire en une si possible?

entrez la description de l'image ici

Pourquoi utilisez-vous les annotations Spring et Jersey? Vous devez vous en tenir aux annotations destinées au framework. Puisque vous utilisez Jersey, vous devriez vous en tenir à ses annotations.

Voici donc les éléments à prendre en compte concernant votre code et votre environnement actuels.

  1. Il ne peut y avoir deux corps séparés. Avec votre code, c’est ce que vous attendez, semble-t-il.
  2. Vous pouvez cependant placer le JSON dans le corps en plusieurs parties. Pour cela, vous devez également annoter le SomeModel avec le Jersey @FormDataParam

     @POST @Path("somepath") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFileAndJSON( @FormDataParam("model") SomeModel someModel, @FormDataParam("file") FormDataBodyPart bodyPart) { } 
  3. Dans la configuration de Jersey, vous devez vous assurer d’enregistrer MultiPartFeature . Si vous ne le faites pas, le corps ne pourra pas être désérialisé et vous obtiendrez des exceptions et des réponses d’erreur.

  4. Maintenant, le problème de Postman. Vous pouvez voir un problème similaire ici . Le problème était que le type de Content-Type n’était pas défini pour la partie de corps JSON. Par exemple, le corps pourrait ressembler à quelque chose comme

     --AaB03x Content-Disposition: form-data; name="model" {"some":"model", "data":"blah"} --AaB03x Content-Disposition: form-data; name="file"; filename="file1.txt" Content-Type: text/plain ... contents of file1.txt ... --AaB03x-- 

    Vous pouvez réellement voir le corps si vous cliquez sur le bouton Aperçu dans Postman. Le problème est qu’il n’y a pas de type de Content-Type pour la partie "model" , comme vous pouvez le voir dans la partie "file" . Cela est dû au fait que vous ne pouvez pas définir le type de Content-Type des pièces individuelles dans Postman. Celui que vous verrez sera découvert à partir de l’extension de fichier. Par exemple, un fichier .txt Postman à définir Content-Type sur text/plain et un fichier .png à image/png .

    Si vous regardez dans le lien ci-dessus, j’ai proposé que vous puissiez utiliser un fichier .json au lieu de taper les données. Bien sûr, ce n’était qu’une théorie. Je ne l’ai pas réellement testé.

    Dans tous les cas, le type de Content-Type doit être défini pour que Jersey puisse savoir le désérialiser au format JSON. Si la théorie de l’extension de fichier .json ne fonctionne pas, vous pouvez utiliser un client différent, tel que cURL, dont j’ai montré un exemple dans le lien, ou vous pouvez utiliser le client Jersey pour tester, comme indiqué ici .

  5. Ne définissez pas l’en Content-Type tête Content-Type sur multipart/form-data dans Postman. Il le configure pour vous lorsque vous utilisez les données de formulaire . Je viens de voir un message où quelqu’un a dit qu’il y avait un bug lorsque vous définissez l’en-tête. Impossible de trouver le message pour l’instant, et ce n’est pas quelque chose que j’ai confirmé, mais je le laisserais simplement de côté.


METTRE À JOUR

Le PO a donc été en mesure de trouver un moyen de définir le type de Content-Type: application/json sur la partie “modèle”. Mais il arrive parfois qu’avec un client Javascript, vous ne puissiez pas le définir. Donc, il n’y aura pas de type de Content-Type . Si tel est le cas, Jersey ne sera pas en mesure de désérialiser le JSON, car il n’a aucune idée qu’il est effectivement envoyé au format JSON. Si vous ne pouvez absolument pas ou ne savez absolument pas comment définir le type de Content-Type pour des pièces individuelles, procédez comme suit.

 @POST @Path("somepath") @Consumes(MediaType.MULTIPART_FORM_DATA) public Response uploadFileAndJSON(@FormDataParam("model") FormDataBodyPart jsonPart, @FormDataParam("file") FormDataBodyPart bodyPart) { jsonPart.setMediaType(MediaType.APPLICATION_JSON_TYPE); SomeModel model = jsonPart.getValueAs(SomeModel.class); } 

Oui, vous pouvez obtenir cela en tant que données de formulaire en plusieurs parties.

vous obtenez comme ça dans angularjs:

 $scope.uploadFile = function () { var file = $scope.selectedFile[0]; $scope.upload = $upload.upload({ url: 'api/upload', method: 'POST', data: angular.toJson($scope.model), file: file }).progress(function (evt) { $scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10); }).success(function (data) { //do something }); }; $scope.onFileSelect = function ($files) { $scope.uploadProgress = 0; $scope.selectedFile = $files; }; public Response uploadFileAndJSON(@RequestParam("data") Ssortingng data, @MultiPartFile("file")File file) { you can data as form data and convert it like you want to your object using Gson jar. return null; } 

Consultez le code angularjs: Angularjs comment télécharger des données de formulaire en plusieurs parties et un fichier?

https://puspendu.wordpress.com/2012/08/23/restful-webservice-file-upload-with-jersey/