Загрузка нескольких файлов с помощью Spring MVC 3.0.2 после включения HiddenHttpMethodFilter

важно : этот вопрос совершенно бесполезен для любой весенней версии выше 3.0.4 как обсуждаемый в этой теме было!--36-->основные в этой версии давно и больше не воспроизводится в последующих версиях Spring.


я использую весеннюю версию 3.0.2. Мне нужно загрузить несколько файлов с помощью multiple="multiple" атрибут файлового браузера, например,

<input type="file" id="myFile" name="myFile" multiple="multiple"/>

(и не используя несколько файловых браузеров что-то вроде того, что указано ответ, это действительно работает, я пробовал).

хотя ни одна версия Internet Explorer не поддерживает этот подход, если не используется соответствующий плагин/виджет jQuery, я не забочусь об этом прямо сейчас (так как большинство других браузеров поддерживают это).

это отлично работает с commons fileupload но в дополнение к использованию RequestMethod.POST и RequestMethod.GET методы, я также хочу использовать другие методы запроса поддерживается и предлагается весной, как RequestMethod.PUT и RequestMethod.DELETE в своих соответствующих местах. Чтобы это было так, я настроил Spring с HiddenHttpMethodFilter который идет отлично, как этот вопрос указывает.

но он может загрузить только один файл за раз даже если выбрано несколько файлов в файл-браузер. В классе Spring controller метод отображается следующим образом.

@RequestMapping(method={RequestMethod.POST}, value={"admin_side/Temp"})
public String onSubmit(@RequestParam("myFile") List<MultipartFile> files, @ModelAttribute("tempBean") TempBean tempBean, BindingResult error, Map model, HttpServletRequest request, HttpServletResponse response) throws IOException, FileUploadException {
    for (MultipartFile file : files) {
        System.out.println(file.getOriginalFilename());
    }
}

даже с параметром запроса @RequestParam("myFile") List<MultipartFile> files что это List типа MultipartFile (он всегда может иметь только один файл за раз).


я мог бы найти стратегию, которая может работать с несколькими файлами этот блог. Я тщательно все просмотрел.

решение ниже раздел РЕШЕНИЕ 2-ИСПОЛЬЗУЙТЕ НЕОБРАБОТАННЫЙ ЗАПРОС говорит,

Если же клиент настаивает на использовании то же имя ввода формы, например как "файлы []" или " файлы’ , а затем заполнить это имя несколькими файлы, то небольшой хак необходимо следующим образом. Как отмечалось выше, Весна 2.5 создает исключение, если оно обнаруживает одно и то же имя ввода формы типа file более одного раза. CommonsFileUploadSupportкласс, который бросает это исключение не является окончательным и метод, который бросает это исключение защищен таким образом, используя чудеса наследования и подкласс один можно просто исправить / изменить логику немного следующим образом. Изменение Я сделал буквально одно слово, представляющее один вызов метода что позволяет нам иметь несколько файлов, входящих в одной форме имя Входа.

он пытается переопределить метод

protected MultipartParsingResult parseFileItems(List fileItems, String encoding){}

абстрактный класс CommonsFileUploadSupport расширяя класс CommonsMultipartResolver, например,

package multipartResolver;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.apache.commons.fileupload.FileItem;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

public final class MultiCommonsMultipartResolver extends CommonsMultipartResolver {

    public MultiCommonsMultipartResolver() {}

    public MultiCommonsMultipartResolver(ServletContext servletContext) {
        super(servletContext);
    }

    @Override
    @SuppressWarnings("unchecked")
    protected MultipartParsingResult parseFileItems(List fileItems, String encoding) {
        Map<String, MultipartFile> multipartFiles = new HashMap<String, MultipartFile>();
        Map multipartParameters = new HashMap();

        // Extract multipart files and multipart parameters.
        for (Iterator it = fileItems.iterator(); it.hasNext();) {
            FileItem fileItem = (FileItem) it.next();

            if (fileItem.isFormField()) {
                String value = null;

                if (encoding != null) {
                    try {
                        value = fileItem.getString(encoding);
                    } catch (UnsupportedEncodingException ex) {
                        if (logger.isWarnEnabled()) {
                            logger.warn("Could not decode multipart item '" + fileItem.getFieldName()
                                    + "' with encoding '" + encoding + "': using platform default");
                        }

                        value = fileItem.getString();
                    }
                } else {
                    value = fileItem.getString();
                }

                String[] curParam = (String[]) multipartParameters.get(fileItem.getFieldName());

                if (curParam == null) {
                    // simple form field
                    multipartParameters.put(fileItem.getFieldName(), new String[]{value});
                } else {
                    // array of simple form fields
                    String[] newParam = StringUtils.addStringToArray(curParam, value);
                    multipartParameters.put(fileItem.getFieldName(), newParam);
                }
            } else {
                // multipart file field
                CommonsMultipartFile file = new CommonsMultipartFile(fileItem);
                if (multipartFiles.put(fileItem.getName(), file) != null) {
                    throw new MultipartException("Multiple files for field name [" + file.getName()
                            + "] found - not supported by MultipartResolver");
                }

                if (logger.isDebugEnabled()) {
                    logger.debug("Found multipart file [" + file.getName() + "] of size " + file.getSize()
                            + " bytes with original filename [" + file.getOriginalFilename() + "], stored "
                            + file.getStorageDescription());
                }
            }
        }

        return new MultipartParsingResult(multipartFiles, multipartParameters);
    }
}

что происходит что последняя строка в методе parseFileItems() (возвращение заявления), т. е.

return new MultipartParsingResult(multipartFiles, multipartParameters);

вызывает ошибку времени компиляции, потому что первый параметр multipartFiles тип Map осуществлен HashMap но на самом деле для этого требуется параметр типа MultiValueMap<String, MultipartFile>

это конструктор статического класса внутри абстрактного класса CommonsFileUploadSupport,

public abstract class CommonsFileUploadSupport {
    protected static class MultipartParsingResult {
        public MultipartParsingResult(MultiValueMap<String, MultipartFile> mpFiles, Map<String, String[]> mpParams) {}
    }
}

причина может быть - это решение касается весенней версии 2.5, и я использую весеннюю версию 3.0.2, которая может быть неуместной для этой версии.


я, однако, попытался заменить Map С MultiValueMap различными способами, как показано в следующем сегменте кода

MultiValueMap<String, MultipartFile>mul=new LinkedMultiValueMap<String, MultipartFile>();   

for(Entry<String, MultipartFile>entry:multipartFiles.entrySet()) {
    mul.add(entry.getKey(), entry.getValue());
}

return new MultipartParsingResult(mul, multipartParameters);

но без успеха. Я не уверен, как заменить Map С MultiValueMap и даже это может работать. После этого, браузер показывает HTTP-ответ,

статус HTTP 400 -

отчет о состоянии типа

описание запроса, отправленного клиентом был синтаксически некорректный ().

Apache Tomcat / 6.0.26


я попытался максимально сократить вопрос, и я не включил ненужный код.

как можно было бы загрузить несколько файлов после того, как Spring был настроен с HiddenHttpMethodFilter?

этот блог указывает, что это давняя, высокоприоритетная ошибка.

если нет решения относительно версии 3.0.2 (3 или выше), то я должен отключить поддержку Spring навсегда и продолжать использовать commons-fileupolad как предложено третьим решением в этом блоге, опуская PUT, DELETE и другие методы запроса навсегда.


очень мало изменений в коде в parseFileItems() метод внутри класса MultiCommonsMultipartResolver может заставить его загружать несколько файлов, но я не смог добиться успеха в своих попытках (снова с весенней версией 3.0.2 (3 или выше)).

2 ответов


для загрузки нескольких файлов в одном запросе я использовал этот код:

у меня такой jsp:

<p>Select files to upload. Press Add button to add more file inputs.</p>
<table>
    <tr>
        <td><input name="files" type="file" multiple="true"/></td>
    </tr>
    <tr>
        <td><input name="files" type="file" multiple="true"/></td>
    </tr>
</table>
<br/><input type="submit" value="Upload" />

загрузка файла класса bean:

import org.springframework.web.multipart.commons.CommonsMultipartFile;

public class FileUploadForm {

    private CommonsMultipartFile [] files;

    public CommonsMultipartFile[] getFiles() {
        return files;
    }

    public void setFiles( CommonsMultipartFile[] files ) {
        this.files = files;
    }
}

:

@Controller
@RequestMapping("/upload")
public class FileUploadController {

    @RequestMapping(method = RequestMethod.GET)
    public String displayForm(ModelMap modelMap) {
        modelMap.addAttribute( new FileUploadForm() );
        return "uploadForm.jsp";
    }

    @RequestMapping(method = RequestMethod.POST)
    public String save(FileUploadForm uploadForm) {
        CommonsMultipartFile[] files = uploadForm.getFiles();
        if(files != null && files.length != 0) {
            for(MultipartFile file : files) {
                System.out.println( file.getOriginalFilename() );
            }
        }
        return "success.jsp";
    }
}

этот код позволяет загружать несколько файлов в одном запросе, и можно получить экземпляр CommonsMultipartFile для каждого файла.


проблема, упомянутая в вопросе, была основные по состоянию на весну 3.0.4. Таким образом, если вы случайно использовать эту версию или выше (да, это 4.X. x now), вам больше не нужно будет читать этот вопрос/ответ(ы).