Chcę opublikować plik z danymi JSON przy użyciu Spring MVC. Więc opracowałem usługę odpoczynku jako
@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);
}
Kiedy wysyłam żądanie od pozostałego klienta
content-Type = multipart/form-data or multipart/mixed
, otrzymuję następny wyjątek:
org.springframework.web.multipart.support.MissingServletRequestPartException
Czy ktoś może mi pomóc w rozwiązaniu tego problemu?
Czy mogę użyć @RequestPart
do wysłania zarówno Multipart, jak i JSON na serwer?
json
spring
spring-mvc
Sunil Kumar
źródło
źródło
org.springframework.web.multipart.commons.CommonsMultipartResolver
w kontekście swojego serwletu?Odpowiedzi:
W ten sposób zaimplementowałem Spring MVC Multipart Request z danymi JSON.
Żądanie wieloczęściowe z danymi JSON (nazywane również Wieloczęściowym mieszanym):
Opierając się na usłudze RESTful w wydaniu Spring 4.0.2, żądanie HTTP z pierwszą częścią jako dane w formacie XML lub JSON, a drugą częścią jako plik można uzyskać za pomocą @RequestPart. Poniżej znajduje się przykładowa realizacja.
Fragment Java:
Usługa Rest w kontrolerze będzie miała mieszane @RequestPart i MultipartFile do obsługi takiego żądania Multipart + JSON.
@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); }
Fragment interfejsu (JavaScript):
Utwórz obiekt FormData.
Dołącz plik do obiektu FormData, wykonując jeden z poniższych kroków.
formData.append("file", document.forms[formName].file.files[0]);
formData.append("file", myFile, "myfile.txt");
LUBformData.append("file", myBob, "myfile.txt");
Utwórz obiekt BLOB ze zdefiniowanymi danymi JSON i dołącz go do obiektu FormData. Powoduje to, że typ zawartości drugiej części w żądaniu wieloczęściowym to „application / json” zamiast typu pliku.
Wyślij żądanie do serwera.
Poproś o szczegóły:
Content-Type: undefined
. Powoduje to, że przeglądarka ustawia Content-Type na multipart / form-data i prawidłowo wypełnia granice. Ręczne ustawienie Content-Type na multipart / form-data nie spowoduje wypełnienia parametru brzegowego żądania.Kod JavaScript:
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" }));
Szczegóły prośby:
method: "POST", headers: { "Content-Type": undefined }, data: formData
Poproś o ładunek:
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--
źródło
processData: false, contentType: false
zJQuery $ajax()
Required request part file is not present
@NotBlank
adnotacja w parametrze metody MultipartFile nie sprawdza, czy plik jest pusty. Nadal możliwe jest przesyłanie dokumentów zawierających 0 bajtów.To musi działać!
klient (kątowy):
$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; } };
Backend-Spring Boot:
@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
źródło
Jak mówi dokumentacja:
źródło
W naszych projektach widzieliśmy, że żądanie postu z JSON i plikami powoduje wiele zamieszania między programistami frontendu i backendu, co prowadzi do niepotrzebnego marnowania czasu.
Oto lepsze podejście: przekonwertuj tablicę bajtów pliku na ciąg Base64 i wyślij ją w formacie 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()); .... }
Kod JS do konwersji pliku na ciąg base64:
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); };
źródło