Spring Контроллер @RequestBody с возможностью загрузки файлов возможен?

У меня есть такой контроллер, и я хочу отправить форму с загрузкой файла, а также некоторые данные формы, такие как метка, как показано ниже. Кроме того, я хочу сделать это с помощью @RequestBody, чтобы я мог использовать аннотацию @Valid для оболочки, так как будет добавлено больше переменных.

public @ResponseBody WebResponse<Boolean> updateEUSettings(
    final Locale locale,
    @Validated @ModelAttribute final EUPSettingsWrapper endUserPortalSettingsWrapper) {
}

И моя обертка это:

public class EUPSettingsWrapper {

    private String label;
    private MultipartFile logo;
// getter , setters..etc...
}

Но я хотел бы преобразовать его в @RequestBody из ModelAttributes.

Я пытаюсь разделить загрузку файла как параметр запроса, например так:

public @ResponseBody WebResponse<Boolean> updateEUSettings(
    final Locale locale,
    @Validated @RequestBody final EUPSettingsWrapper endUserPortalSettingsWrapper, 
    @RequestParam(value = "file1", required = true) final MultipartFile logo) {

    endUserPortalSettingsWrapper.setLogo(logo);

    // ...
}

В моем макете MVC я устанавливаю:

getMockMvc().perform(fileUpload(uri).file(logo)
                        .accept(MediaType.APPLICATION_JSON)
                        .content(JSONUtils.toJSON(wrapper))
                        .contentType(MediaType.MULTIPART_FORM_DATA))
                        .andExpect(status().isOk());

Но я получаю такую ошибку, которая говорит:

org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data' not supported

У кого-нибудь есть хорошее представление о том, как многокомпонентные загрузки файлов можно использовать с @RequestBody? Что-то я не так делаю выше?

Ответы

Ответ 1

Вы можете действительно упростить свою жизнь здесь, так как все, что вы делаете, это отправляете форму, которая содержит некоторые поля и файл. Вам не нужен @RequestBody для того, что вы пытаетесь сделать. Вы можете использовать обычные функции Spring MVC, поэтому ваш метод контроллера будет выглядеть так:

@ResponseBody
public WebResponse<Boolean> updateEUSettings(
     Locale locale, 
     @Valid EUPSettingsWrapper endUserPortalSettingsWrapper, 
     @RequestParam(value = "file1", required = true) MultipartFile logo
) {


}

Клиент, который отправляет запрос этому контроллеру, должен иметь форму с enctype="multipart/form-data".

В своем тесте Spring MVC вы бы написали что-то вроде этого:

getMockMvc().perform(fileUpload(uri).file("file1", "some-content".getBytes()) 
                        .param("someEuSettingsProperty", "someValue")
                        .param("someOtherEuSettingsProperty", "someOtherValue")
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.MULTIPART_FORM_DATA))
                        .andExpect(status().isOk());

Ответ 2

Добавьте дополнительный bean в свой spring -servlet.xml, чтобы добавить поддержку для многостраничного запроса.

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

Также не забудьте добавить зависимость для commons-fileupload jar

Ответ 3

Я не мог найти способ использовать @RequestBody.

Однако вы можете сделать что-то вроде этого:

@RequestMapping(value = "/uploadStuff", method = RequestMethod.POST)
public MyViewDto doStuff(@RequestPart("json") @Valid MyDto dto,
                         @RequestPart("file") MultipartFile file) { ... }

Вы можете проверить это следующим образом:

MockMultipartFile jsonFile = new MockMultipartFile("json", "",
            "application/json", "{}".getBytes());
MockMultipartFile dataFile = new MockMultipartFile("file", "foo.zip", "application/octet-stream", bytes);

mockMvc.perform(fileUpload("/uploadStuff")
            .file(dataFile)
            .file(jsonFile))
            .andExpect(status().isOk());

Ответ 4

Для Spring 4 и более поздних версий вы можете сделать следующее, чтобы получить полный объект:

public ResponseEntity<Object> upload(@Payload EUPSettingsWrapper wrapper) {

}

Примечание: также должен работать без тега

public ResponseEntity<Object> upload(EUPSettingsWrapper wrapper) {

}

Ответ 5

Спасибо @JasonGlez, ответ, который работал для меня: публичная загрузка ResponseEntity (оболочка EUPSettingsWrapper) {

}

Ответ 6

Я немного потрудился с этим и закончил прохождение как простые параметры. Отлично, если у вас нет лота, чтобы передать ваш запрос:

myMethod(@RequestParam("file") MultipartFile myFile,
        @RequestParam("param1") Float param1, @RequestParam("param2") String param2 {}