JSON के साथ स्प्रिंग MVC मल्टीपार्ट अनुरोध


84

मैं स्प्रिंग जेवीसी का उपयोग करके कुछ JSON डेटा के साथ एक फ़ाइल पोस्ट करना चाहता हूं। इसलिए मैंने एक रेस्ट सर्विस विकसित की है

@RequestMapping(value = "/servicegenerator/wsdl", method = RequestMethod.POST,consumes = { "multipart/mixed", "multipart/form-data" })
@ResponseBody
public String generateWSDLService(@RequestPart("meta-data") WSDLInfo wsdlInfo,@RequestPart("file") MultipartFile file) throws WSDLException, IOException,
        JAXBException, ParserConfigurationException, SAXException, TransformerException {
    return handleWSDL(wsdlInfo,file);
}

जब मैं बाकी क्लाइंट से अनुरोध भेजता हूं content-Type = multipart/form-data or multipart/mixed, तो मुझे अगला अपवाद मिलता है: org.springframework.web.multipart.support.MissingServletRequestPartException

किसी को भी इस मुद्दे को हल करने में मेरी मदद कर सकते हैं?

क्या मैं @RequestPartमल्टीपार्ट और JSON दोनों को एक सर्वर पर भेजने के लिए उपयोग कर सकता हूं ?


क्या आपने org.springframework.web.multipart.commons.CommonsMultipartResolverअपने सर्वलेट संदर्भ में निर्दिष्ट किया है ?
विल किलिंग

हाँ, यह मेरे स्प्रिंग में जोड़ा गया है। xml। <bean id = "multipartResolver" class = "org.springframework.web.multipart.commons.CommonsMultipartResolver"> <संपत्ति का नाम = "maxUploadShow" मान = "300000000" /> </ bean>
सुनील कुमार

जवाबों:


200

इस तरह मैंने JSON डेटा के साथ स्प्रिंग MVC मल्टीपार्ट अनुरोध लागू किया।

JSON डेटा के साथ मल्टीपार्ट अनुरोध (जिसे मिश्रित मल्टीपार्ट भी कहा जाता है):

स्प्रिंग 4.0.2 रिलीज़ में रेस्टफुल सेवा के आधार पर, XML या JSON के डेटा के रूप में पहले भाग के साथ HTTP अनुरोध और एक फ़ाइल के रूप में दूसरा भाग @RequestPart के साथ प्राप्त किया जा सकता है। नीचे नमूना कार्यान्वयन है।

जावा स्निपेट:

कंट्रोलर की बाकी सेवा में ऐसे मल्टीपार्ट + JSON अनुरोध की सेवा के लिए @RequestPart और MultipartFile मिश्रित होंगे।

@RequestMapping(value = "/executesampleservice", method = RequestMethod.POST,
    consumes = {"multipart/form-data"})
@ResponseBody
public boolean executeSampleService(
        @RequestPart("properties") @Valid ConnectionProperties properties,
        @RequestPart("file") @Valid @NotNull @NotBlank MultipartFile file) {
    return projectService.executeSampleService(properties, file);
}

फ्रंट एंड (जावास्क्रिप्ट) स्निपेट:

  1. एक FormData ऑब्जेक्ट बनाएँ।

  2. नीचे दिए गए चरणों में से एक का उपयोग करके फ़ाइल को फॉर्मडेटा ऑब्जेक्ट में जोड़ें।

    1. यदि फ़ाइल को "फ़ाइल" प्रकार के इनपुट तत्व का उपयोग करके अपलोड किया गया है, तो इसे फॉर्मडेटा ऑब्जेक्ट पर जोड़ें। formData.append("file", document.forms[formName].file.files[0]);
    2. सीधे फ़ाइल को फॉर्मडेटा ऑब्जेक्ट में जोड़ें। formData.append("file", myFile, "myfile.txt");याformData.append("file", myBob, "myfile.txt");
  3. कड़े JSON डेटा के साथ एक बूँद बनाएँ और इसे FormData ऑब्जेक्ट में जोड़ें। यह मल्टीपार्ट अनुरोध में दूसरे भाग के कंटेंट-प्रकार को फ़ाइल प्रकार के बजाय "एप्लिकेशन / जोंस" होने का कारण बनता है।

  4. सर्वर को अनुरोध भेजें।

  5. का अनुरोध करें विवरण:
    Content-Type: undefined। यह ब्राउज़र को कंटेंट-टाइप को मल्टीपार्ट / फॉर्म-डेटा सेट करने और सीमा को सही ढंग से भरने का कारण बनता है। मल्टीपार्ट / फॉर्म-डेटा के लिए सामग्री-प्रकार को मैन्युअल रूप से सेट करना अनुरोध के सीमा पैरामीटर को भरने में विफल होगा।

जावास्क्रिप्ट कोड:

formData = new FormData();

formData.append("file", document.forms[formName].file.files[0]);
formData.append('properties', new Blob([JSON.stringify({
                "name": "root",
                "password": "root"                    
            })], {
                type: "application/json"
            }));

अनुरोध विवरण:

method: "POST",
headers: {
         "Content-Type": undefined
  },
data: formData

अनुरोध पेलोड:

Accept:application/json, text/plain, */*
Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryEBoJzS3HQ4PgE1QB

------WebKitFormBoundaryvijcWI2ZrZQ8xEBN
Content-Disposition: form-data; name="file"; filename="myfile.txt"
Content-Type: application/txt


------WebKitFormBoundaryvijcWI2ZrZQ8xEBN
Content-Disposition: form-data; name="properties"; filename="blob"
Content-Type: application/json


------WebKitFormBoundaryvijcWI2ZrZQ8xEBN--

1
अच्छी तरह से किया। मैं का इस्तेमाल किया था processData: false, contentType: falseके साथJQuery $ajax()
sura2k

1
@ सुनीलकुमार, अगर मुझे वैकल्पिक रूप में फ़ाइल अपलोड देने की आवश्यकता है .. तो फॉर्म डेटा के साथ। मैं यह कैसे कर सकता हूं? क्योंकि अगर छवि का चयन नहीं हो रहा हैRequired request part file is not present
हेमा

1
मेरे लिए "नया ब्लॉब ([JSON.stringify (...)]" भाग ने किया .. मेरे पास जगह में सब कुछ था। Thx।
ओस्टाटी

4
@SunilKumar क्या आपको ConnectionProperties के लिए कनवर्टर निर्दिष्ट करना था? अगर मैं ऊपर दिए गए कनेक्शनप्रोपरेटीज के लिए ऊपर दिखाए गए एक पोजो का उपयोग करता हूं तो मुझे ... HttpMediaTypeNotSupportedException: सामग्री प्रकार 'एप्लिकेशन / ऑक्टेट-स्ट्रीम' समर्थित नहीं है अगर मैं POJO को स्ट्रिंग में बदल देता हूं तो यह काम करता है। तो यह स्पष्ट नहीं है कि POJO में रूपांतरण कैसे हो रहा है?
user2412398

1
बस यह स्पष्ट करने के लिए: @NotBlankफ़ाइल खाली है, तो MultipartFile विधि पैरामीटर पर एनोटेशन वास्तव में जाँच नहीं करेगा। अभी भी 0 बाइट्स के साथ दस्तावेज़ अपलोड करना संभव है।
sn42

14

यह काम करना होगा!

ग्राहक (कोणीय):

$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 JSON!
      var req = {
        url: '/upload',
        method: 'POST',
        headers: {'Content-Type': undefined},
        data: formData,
        transformRequest: function (data, headersGetterFunction) {
          return data;
        }
      };

बैकएंड-स्प्रिंग बूट:

@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

1

जैसा कि प्रलेखन कहता है:

अपने नाम से पहचाने गए "मल्टीपार्ट / फॉर्म-डेटा" अनुरोध का हिस्सा नहीं मिलने पर उठाया।

ऐसा इसलिए हो सकता है क्योंकि अनुरोध मल्टीपार्ट / फॉर्म-डेटा नहीं है क्योंकि या तो हिस्सा अनुरोध में मौजूद नहीं है, या क्योंकि मल्टीपार्ट अनुरोधों को संसाधित करने के लिए वेब एप्लिकेशन को सही तरीके से कॉन्फ़िगर नहीं किया गया है - जैसे कोई मल्टीपार्ट।


0

हमने अपनी परियोजनाओं में देखा है कि JSON और फ़ाइलों के साथ पोस्ट अनुरोध फ्रंटएंड और बैकेंड डेवलपर्स के बीच बहुत अधिक भ्रम पैदा कर रहा है, जिससे समय की अनावश्यक बर्बादी हो रही है।

यहां एक बेहतर तरीका है: फ़ाइल बाइट्स सरणी को बेस 64 स्ट्रिंग में कनवर्ट करें और इसे JSON में भेजें।

public Class UserDTO {
    private String firstName;
    private String lastName;
    private FileDTO profilePic; 
}

public class FileDTO {
    private String base64;
    // just base64 string is enough. If you want, send additional details
    private String name;
    private String type;
    private String lastModified;
}

@PostMapping("/user")
public String saveUser(@RequestBody UserDTO user) {
    byte[] fileBytes = Base64Utils.decodeFromString(user.getProfilePic().getBase64());
    ....
}

फ़ाइल को बेस 64 स्ट्रिंग में बदलने के लिए JS कोड:

var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {

  const userDTO = {
    firstName: "John",
    lastName: "Wick",
    profilePic: {
      base64: reader.result,
      name: file.name,
      lastModified: file.lastModified,
      type: file.type
    }
  }
  
  // post userDTO
};
reader.onerror = function (error) {
  console.log('Error: ', error);
};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.