Spring 3.0 FileUpload только с POST? - PullRequest
7 голосов
/ 02 ноября 2011

Я пытаюсь загрузить файл с одним параметром, используя пружину 3.

Это мой метод контроллера, который должен включить эту услугу:

@RequestMapping(value="/{id}", method = RequestMethod.PUT, headers="content-type=multipart/form-data")
public ResponseEntity<String> uploadImageWithJsonParamater(@PathVariable("id") Long id, @RequestParam String json, @RequestParam MultipartFile customerSignFile) {
    //...
}

Проблема в том, что сервер не может выполнить этот метод: MissingServletRequestParameterException: обязательный параметр String 'json' отсутствует

Если я изменю RequestMethod с PUT на POST, все в порядке. Так кто-нибудь знает проблему?

Кажется, что нельзя передавать данные формы через PUT.

Я немного отладил, и следующий метод возвращает false в случае PUT, но true в случае POST:

public boolean isMultipart(HttpServletRequest request) {
    return (request != null && ServletFileUpload.isMultipartContent(request));
}

Буду признателен за любую помощь!

Заранее спасибо!

Ответы [ 4 ]

5 голосов
/ 09 июля 2012

Вы можете сделать это, используя HiddenHttpMethodFilter , но вам нужно убедиться, что вы вставили Spring MultipartFilter перед фильтром HiddenHttpMethodFilter в цепочке фильтров web.xml.

Например: в вашем web.xml

<filter>
    <filter-name>MultipartFilter</filter-name>
    <filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
    <init-param>
        <param-name>multipartResolverBeanName</param-name>
        <param-value>filterMultipartResolver</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>MultipartFilter</filter-name>
    <servlet-name>/*</servlet-name>
</filter-mapping>
<filter>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>HiddenHttpMethodFilter</filter-name>
    <servlet-name>/*</servlet-name>
</filter-mapping>

Затем в вашем spring-config.xml добавьте ссылку на CommonsMultipartResolver:

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

Обратите внимание, что если вы не добавите запись spring-config.xml, ваш MultipartFilter по умолчанию будет использовать MultipartResolver, который использует реализацию сервлета spec 3.0 и выдаст ошибку, подобную: NoSuchMethodError HttpServletRequest.getParts () если вы не используете 3.0.

4 голосов
/ 06 апреля 2012

Я столкнулся с той же проблемой.Мое решение заключалось в реализации ExtendedMultipartResolver, который также принимает множественные числа, отправленные через метод PUT httpПросто скопируйте код CommonsMultipartResolver, переименуйте класс и измените реализацию функции isMultipart() в соответствии с вашими потребностями:

private boolean isMultipartContent(HttpServletRequest request) {
  String httpMethod = request.getMethod().toLowerCase();
  // test for allowed methods here...
  String contentType = request.getContentType();
  return (contentType != null && contentType.toLowerCase().startsWith("multipart"));
}


public boolean isMultipart(HttpServletRequest request) {
      return (request != null && isMultipartContent(request));
}

Вы можете проверить POST, PUT или другой HTTPметоды здесь.В моем случае все методы будут приняты, поскольку аннотации моего контроллера будут фильтроваться по разрешенным методам.

Не забудьте настроить bean-компонент в весеннем веб-контексте:

<bean id="multipartResolver" class="sample.package.ExtendedMultipartResolver"/>

надеюсь, чтопомогает.

ура Крис

2 голосов
/ 02 ноября 2011

Вы не можете отправлять данные формы через PUT согласно стандарту HTML.Вы можете отправлять файлы только через PUT, и в этом случае они отправляются более эффективно, чем через POST (потому что у вас больше нет всех накладных расходов из нескольких частей), но для того, чтобы ваш компонент на стороне сервера PUT прослушивания мог фактически получить файлчерез PUT вы должны убедиться, что вы действительно отправляете ему команду PUT (например, через javascript).Вот пример, который использует JQuery:

$('#file_upload').fileUpload({
    namespace: 'file_upload',
    url: '/path',
    method: 'PUT'
});
1 голос
/ 11 ноября 2015

Я реализовал немного другое решение, вдохновленное http://rugal.ga/development/2015/10/03/uploading-file-other-than-post/, и близкое к предыдущему посту:

public class ExtendedMultipartResolver extends CommonsMultipartResolver {

@Override
public boolean isMultipart(HttpServletRequest request) {
    return (request != null && isMultipartContent(request));
}

/**
 * Extends ServletFileUpload.isMultipartContent() behavior to allow PUT requests as multipart.
 * 
 * @param request
 *            The servlet request to be evaluated. Must be non-null.
 *
 * @return <code>true</code> if the request is multipart; <code>false</code> otherwise.
 * @see org.apache.commons.fileupload.servlet.ServletFileUpload#isMultipartContent
 */
public static final boolean isMultipartContent(HttpServletRequest request) {
    HttpMethod httpMethod = HttpMethod.valueOf(request.getMethod());
    if (HttpMethod.POST != httpMethod && HttpMethod.PUT != httpMethod) {
        return false;
    }
    return FileUploadBase.isMultipartContent(new ServletRequestContext(request));
}

}

Ничего нового здесь, кроме того, что мой код полагаетсяна org.apache.commons.fileupload.FileUploadBase.isMultipartContent (RequestContext) вместо дублирования его содержимого.

Теперь, если вам когда-либо понадобилось реализовать модульные тесты служб загрузки файлов, вы могли бы использовать org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload () следующим образом:

@Test
public void testUploadFilePost() throws Exception {
    MockMultipartFile multipartFile = new MockMultipartFile(...);
    String url = ...;
    mockMvc.perform(fileUpload(url).file(multipartFile)).andExpect(status().isOk());
}

Приведенный выше код может выдавать только POST-запросы из-за способа org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder реализован.Чтобы выполнить модульное тестирование загрузки файла PUT, вас может заинтересовать следующий код:

private static final RequestPostProcessor PUT_REQUEST_POST_PROCESSOR = new RequestPostProcessor() {

    @Override
    public MockHttpServletRequest postProcessRequest(MockHttpServletRequest request) {
        request.setMethod(HttpMethod.PUT.name());
        return request;
    }

};

private static MockHttpServletRequestBuilder putFileUpload(String url, MockMultipartFile multipartFile,
        Object... urlVariables) {
    return fileUpload(url, urlVariables).file(multipartFile).with(PUT_REQUEST_POST_PROCESSOR);
}

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

@Test
public void testUploadFilePut() throws Exception {
    MockMultipartFile multipartFile = new MockMultipartFile(...);
    String url = ...;
    mockMvc.perform(putFileUpload(url, multipartFile)).andExpect(status().isOk());
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...