@RequestPart со смешанным многостраничным запросом, Spring MVC 3.2

Я разрабатываю службу RESTful на основе Spring 3.2. Я столкнулся с проблемой с контроллером, обрабатывающим смешанный многостраничный HTTP-запрос, со второй частью с форматированными данными XMLor JSON и второй частью с файлом изображения.

Я использую @RequestPart аннотацию для получения запроса

@RequestMapping(value = "/User/Image", method = RequestMethod.POST,  consumes = {"multipart/mixed"},produces="applcation/json")

public
ResponseEntity<List<Map<String, String>>> createUser(
        @RequestPart("file") MultipartFile file, @RequestPart(required=false) User user) {

    System.out.println("file" + file);

    System.out.println("user " + user);

    System.out.println("received file with original filename: "
            + file.getOriginalFilename());

    // List<MultipartFile> files = uploadForm.getFiles();
    List<Map<String, String>> response = new ArrayList<Map<String, String>>();
    Map<String, String> responseMap = new HashMap<String, String>();

    List<String> fileNames = new ArrayList<String>();

    if (null != file) {
        // for (MultipartFile multipartFile : files) {

        String fileName = file.getOriginalFilename();
        fileNames.add(fileName);

        try {
            file.transferTo(new File("C:/" + file.getOriginalFilename()));
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    responseMap.put("displayText", file.getOriginalFilename());
    responseMap.put("fileSize", "" + file.getSize());
    response.add(responseMap);

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add("Accept", "application/json");
    return new ResponseEntity<List<Map<String, String>>>(response,
            httpHeaders, HttpStatus.OK);

}

User.java будет выглядеть следующим образом:

@XmlRootElement(name = "User")


public class User implements Serializable { 
    private static final long serialVersionUID = 1L;

    private int userId;
    private String name;
    private String email;

    private String company;
    private String gender;

    //getter setter of the data members
}

Насколько я понимаю, используя аннотацию @RequestPart, я ожидал бы, что секция многопрофильного XML будет оцениваться в зависимости от ее Content-Type и, наконец, un-marshalled в мой класс User (я использую Jaxb2, marshaller/unmarhaller правильно настроенный в контексте приложения, и процедура работает нормально для всех других методов контроллера, когда я передаю данные XML как тело и использую аннотацию @RequestBody).

Но то, что на самом деле происходит, состоит в том, что, хотя файл правильно найден и проанализирован как MultipartFile, "пользовательская" часть никогда не видна, и запрос всегда терпит неудачу, а не соответствует сигнатуре метода контроллера.

Я воспроизвел проблему с несколькими типами клиентов, и я уверен, что формат многостраничного запроса в порядке.

Пожалуйста, помогите мне решить эту проблему. Возможно, какое-то обходное решение будет доступно для получения смешанного/многопрофильного запроса.

Спасибо и с уважением,

Рагвендра

Ответ 1

Не уверен, что вы исправили свою проблему, но у меня также была аналогичная проблема, когда мой JSON-объект не получал мой контроллер при смешивании @RequestPart и MultipartFile вместе.

Подпись метода для вашего вызова выглядит правильно:

public ResponseEntity<List<Map<String, String>>> createUser(
        @RequestPart("file") MultipartFile file, @RequestPart(required=false) User user) {

// ... CODE ... 
}

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

POST /createUser
Content-Type: multipart/mixed; boundary=B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E

--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="user";
Content-Type: application/xml; charset=UTF-8

<user><!-- your user xml --></user>
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E
Content-Disposition: form-data; name="file"; filename="A551A700-46D4-470A-86E7-52AD2B445847.dat"
Content-Type: application/octet-stream

/// FILE DATA
--B0EC8D07-EBF1-4EA7-966C-E492A9F2C36E--

Ответ 2

Мне удалось решить проблему

Пример конечной точки:

@PostMapping("/")
public Document create(@RequestPart Document document,
                       @RequestPart(required = false) MultipartFile file) {
    log.debug("#create: document({}), file({})", delegation, file);
    //custom logic
    return document;
}

Исключение:

"error_message": "Content type 'application/octet-stream' not supported"

Исключение выдается из следующего метода:

org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(HttpInputMessage,MethodParameter,Type)

Решение:

Мы должны создать собственный конвертер @Component, который реализует HttpMessageConverter или HttpMessageConverter и знает о MediaType.APPLICATION_OCTET_STREAM. Для простого обхода этого достаточно расширить AbstractJackson2HttpMessageConverter

@Component
public class MultipartJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {

/**
 * Converter for support http request with header Content-Type: multipart/form-data
 */
public MultipartJackson2HttpMessageConverter(ObjectMapper objectMapper) {
    super(objectMapper, MediaType.APPLICATION_OCTET_STREAM);
}

@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
    return false;
}

@Override
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
    return false;
}

@Override
protected boolean canWrite(MediaType mediaType) {
    return false;
}
}

Ответ 3

Вы можете использовать @RequestPart из org.springframework.web.bind.annotation.RequestPart; Он используется как сочетание @RequestBody и загрузки файла.

Используя @RequestParam как этот @RequestParam ("файл") MultipartFile файл, вы можете загрузить только файл и несколько отдельных данных (значение ключа), как

    @RequestMapping(value = "/uploadFile", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
    public void saveFile(
                         @RequestParam("userid") String userid,
                         @RequestParam("file") MultipartFile file) {

    }

вы можете публиковать данные объекта JSON и файл File, используя @RequestPart, как

    @RequestMapping(value = "/patientp", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<?> insertPatientInfo(
                                            @RequestPart PatientInfoDTO patientInfoDTO,
                                            @RequestPart("file") MultipartFile file) {
}

Вы не ограничены использованием загрузки нескольких файлов непосредственно в качестве параметров метода контроллера. Ваши объекты формы могут содержать поля Part или MultipartFile, и Spring автоматически знает, что он должен получить значения из файловых частей, и соответствующим образом преобразует их.

Вышеуказанный метод может отвечать на ранее продемонстрированный многочастный запрос, содержащий один файл. Это работает, потому что Spring имеет встроенный конвертер сообщений HTTP, который распознает части файла. В дополнение к типу javax.servlet.http.Part вы также можете преобразовать загружаемые файлы в org.springframework.web.multipart.MultipartFile. Если поле файла разрешает многократную загрузку файлов, как показано во втором многочастном запросе, просто используйте массив или набор частей или MultipartFiles.

        @RequestMapping(value = "/patientp", method = RequestMethod.POST,  consumes = { MediaType.MULTIPART_FORM_DATA_VALUE }, produces = { MediaType.APPLICATION_JSON_VALUE })
    public ResponseEntity<?> insertPatientInfo(
                                                @RequestPart PatientInfoDTO patientInfoDTO,
                                                @RequestPart("files") List<MultipartFile> files) {
    }

Рад помочь...

Ответ 4

Вы пробовали

ResponseEntity<List<Map<String, String>>> createUser(
        @RequestPart("file") MultipartFile file, @RequestBody(required=false) User user) {

или

ResponseEntity<List<Map<String, String>>> createUser(
        @RequestPart("file") MultipartFile file, @RequestParam(required=false) User user) {

Если это не сработает, вы можете показать нам mapping.xml