Comment traiter une requête multi-part composée d'un fichier et D'un objet JSON dans le service Spring restful?

j'ai la ressource suivante (implémentée au printemps 4.05.RELEASE) qui accepte un fichier et un objet JSON:

(P.S. activityTemplate est une classe d'entity sérialisable)

...
@RequestMapping(value="/create", method=RequestMethod.POST)
public @ResponseBody ActivityTemplate createActivityTemplate(
        @RequestPart ActivityTemplate activityTemplate, @RequestPart MultipartFile jarFile)
{
   //process the file and JSON
}
...

et c'est la forme que je suis en train de tester:

<form method="POST" enctype="multipart/form-data"
    action="http://localhost:8080/activityTemplates/create">
    JSON: <input type="text" name="activityTemplate" value='/* the JSON object*/'><br />

    File to upload: <input type="file" name="file">
    <input type="submit" value="Upload">
</form>

et c'est l'erreur que j'obtiens:

 There was an unexpected error (type=Unsupported Media Type, status=415).
 Content type 'application/octet-stream' not supported

alors comment dois-je faire pour que la ressource accepte l'objet JSON dans le cadre de la requête multipart, ou dois-je envoyer le formulaire d'une manière différente?

18
demandé sur Sami 2014-12-04 16:06:35

7 réponses

cela m'a pris deux jours pour travailler pour moi!

client (angulaire):

$scope.saveForm = function () {
      var formData = new FormData();
      var file = $scope.myFile;
      var json = $scope.myJson;
      formData.append("file", file);
      formData.append("ad",JSON.stringify(json));//important: convert to string JSON!
      var req = {
        url: '/upload',
        method: 'POST',
        headers: {'Content-Type': undefined},
        data: formData,
        transformRequest: function (data, headersGetterFunction) {
          return data;
        }
      };

Printemps (De Démarrage):

@RequestMapping(value = "/upload", method = RequestMethod.POST)
    public @ResponseBody
    Advertisement storeAd(@RequestPart("ad") String adString, @RequestPart("file") MultipartFile file) throws IOException {

        Advertisement jsonAd = new ObjectMapper().readValue(adString, Advertisement.class);
//do whatever you want with your file and jsonAd
24
répondu mohi 2015-05-09 19:26:31

Espérons que cela devrait vous aider. Vous devez définir la limite de votre requête pour informer la requête HTTP. est simple; une brève introduction à la multipart format peut être trouvé dans le lien ci-dessous

HTML 4.01 spécification pour multipart

L'exemple suivant illustre "multipart / form-data" encodage. Si le Objet Json" MyJsonObj", et le fichier qui doit être envoyé est " myfile.txt", l'agent utilisateur peut envoyer les données suivantes:

Content-Type: multipart/form-data; boundary=MyBoundary

--MyBoundary
Content-Disposition: form-data; name="myJsonString"
Content-Type: application/json

MyJsonObj //Your Json Object goes here
--MyBoundary
Content-Disposition: form-data; name="files"; filename="myfile.txt"
Content-Type: text/plain

... contents of myfile.txt ...
--MyBoundary--

ou si vos fichiers de type image avec le nom " image.gif" alors,

--MyBoundary
Content-Disposition: file; filename="image.gif"
Content-Type: image/gif
Content-Transfer-Encoding: binary

...contents of image.gif...
--MyBoundary--

Vous spécifiez boundary dans le Content-Type header pour que le serveur sache comment diviser les données envoyées.

ainsi, vous avez essentiellement besoin de sélectionner une valeur limite à:

  • utilisez une valeur qui n'apparaîtra pas dans les données HTTP envoyées au serveur comme 'AaB03x'.
  • être cohérent et utiliser la même valeur sur toute la requête.
2
répondu Sridhar DD 2015-01-05 11:43:09

Vous n'avez pas donné les noms de param à votre @RequestPart s ?

public @ResponseBody ActivityTemplate createActivityTemplate(
    @RequestPart("activityTemplate") ActivityTemplate activityTemplate, @RequestPart("file") MultipartFile jarFile)
{
   //process the file and JSON
}

Note: n'oubliez pas d'inclure le jackson mapper .jar ( mapping your Json to ActivityTemplate fichier dans votre classpath.

1
répondu codeMan 2015-01-12 10:36:02

ne Pouvais pas changer votre

@RequestMapping(value="/create", method=RequestMethod.POST)

@RequestMapping(value="/create",
                method=RequestMethod.POST, consumes ={"multipart/form-data"})
1
répondu Vogel 2015-10-09 18:27:27

le type de contenu par défaut est 'application/octet-stream'. Puisque vous téléchargez le fichier jar et JSON, le type de contenu doit être défini dans le @RequestMapping annotation comme suit:

@RequestMapping(value="/create", method=RequestMethod.POST, headers="content-type=application/json,application/java-archive")
0
répondu Mithun 2015-01-06 11:12:32

le message d'erreur indique qu'il n'y a pas de HttpMessageConverter enregistré pour une partie multi-part/MIME du type de contenu: application/octet-stream. Encore, votre jarFile le paramètre est très probablement correctement identifié comme application / octet-stream, donc je suppose qu'il y a une inadéquation dans la cartographie des paramètres.

alors, essayez d'abord de définir le même nom pour le paramètre et l'élément d'entrée du formulaire.

un autre problème est que le JSON est chargé en tant que valeur (régulière) d'une entrée de texte dans la forme, pas comme une partie séparée dans le multi-partie/MIME. Donc, il n'y a pas d'en-tête content-type associé à cela pour découvrir que Spring devrait utiliser le deserializer JSON. Vous pouvez utiliser @RequestParam à la place et enregistrez un convertisseur spécifique comme dans cette réponse: paramètre JSON dans le contrôleur MVC du printemps

0
répondu miw 2017-05-23 10:31:33

cela peut vous aider, pendant que vous recevez MultipartFile vous devriez mettre l'en-tête de la requête content-type à "multipart/form-data" , puis dans votre controller use consumes="multipart / form-data" , consommes également utilisés pour mapper notre requête à notre méthode dans le controller.

si vous voulez recevoir des données JSON, mieux vaut envoyer une requête sous la forme de JSONString , il suffit de recevoir ce jsonstring, plus tard convertir en JSON Object format alors, utilisez cet objet pour vos opérations.

vérifier ci-dessous le code :

@RequestMapping(value="/savingImg", method=RequestMethod.POST, 
        consumes="multipart/form-data", produces="application/json")
public ResponseEntity<?> savingAppIMgDtlss(
        @RequestParam(value="f1", required = false) MultipartFile f1 , 
        @RequestParam(value="f2", required = false) MultipartFile f2 ,
        @RequestParam(value="f3", required = false) MultipartFile f3 ,
        @RequestParam(value="f4", required = false) MultipartFile f4 ,
        @RequestParam(value="f5", required = false) MultipartFile f5 ,
        @RequestParam(value="f6", required = false) MultipartFile f6 ,
        @RequestParam(value="f7", required = false) MultipartFile f7 ,
        @RequestParam(value="f8", required = false) MultipartFile f8 ,@RequestParam("data") String jsonString) 
                throws Exception , ParseException {
    try{
        JSONObject gstcTranObj = new JSONObject();
                //converting JSONString to JSON
        net.sf.json.JSONObject jsonDtls = net.sf.json.JSONObject.fromObject(jsonString);
        System.out.println("f1::"+f1.getOriginalFilename());
        System.out.println("f2::"+f2.getOriginalFilename());
        System.out.println("f3::"+f3.getOriginalFilename());
        System.out.println("f4::"+f4.getOriginalFilename());
        System.out.println("f5::"+f5.getOriginalFilename());
        System.out.println("f6::"+f6.getOriginalFilename());
        System.out.println("f7::"+f7.getOriginalFilename());
        System.out.println("f8::"+f8.getOriginalFilename());
} catch (Exception e) {
        e.printStackTrace();

        return new ResponseEntity<>("Failed",HttpStatus.NOT_FOUND);
    }finally{

    }
return new ResponseEntity<>("Success", HttpStatus.OK);

  }
}
0
répondu kishorekumar reddy 2018-05-14 12:52:47