Ważne: To pytanie jest całkowicie bezużyteczne dla każdej wiosennej wersji wyższej niż 3.0.4 jako kwestii omawianej w tym wątku było fixed w tej wersji dawno temu i nie można go już odtworzyć w kolejnych wersjach Springa.Przesyłanie wielu plików przy użyciu MVC wiosny 3.0.2 po HiddenHttpMethodFilter została włączona
Używam wersji Spring 3.0.2. Muszę przesłać kilka plików za pomocą atrybutu przeglądarkę plików multiple="multiple"
takich jak
<input type="file" id="myFile" name="myFile" multiple="multiple"/>
(a nie za pomocą wielu przeglądarek plików coś jak ten podany przez this answer, to rzeczywiście działa próbowałem).
Mimo że żadna wersja Internet Explorera nie obsługuje tego podejścia, chyba że użyto odpowiedniej wtyczki/widgetu jQuery, nie obchodzi mnie to teraz (ponieważ większość innych przeglądarek obsługuje tę funkcję).
To działa prawidłowo z commons fileupload ale oprócz korzystania RequestMethod.POST
i RequestMethod.GET
metody, ja też chce skorzystać z innych metod żądania obsługiwane i sugerowane przez wiosnę jak RequestMethod.PUT
i RequestMethod.DELETE
w swoich właściwych miejscach. Aby tak się stało, skonfigurowałem Spring pod numerem HiddenHttpMethodFilter
, który jest zgodny z this question.
ale może przesłać tylko jeden plik na raz, mimo że wybrano wiele plików w przeglądarce plików. W klasie kontrolera Spring metoda jest mapowana w następujący sposób.
@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());
}
}
Nawet z parametrem żądania @RequestParam("myFile") List<MultipartFile> files
który jest List
typu MultipartFile
(zawsze może mieć tylko jeden plik na raz).
Mogę znaleźć strategię, która prawdopodobnie będzie działać z wieloma plikami on this blog. Przeszedłem przez to ostrożnie.
Rozwiązanie poniżej, sekcja ROZWIĄZANIE 2 - stosowanie surowego REQUEST mówi
Jeśli jednak klient nalega na użyciu tej samej nazwy pól formularza takich jako „akt []” lub "files", a następnie zapełnianie tej nazwy wieloma plikami , potrzebny jest mały hack w następujący sposób:. Jak wspomniano powyżej, Spring 2.5 zgłasza wyjątek, jeśli wykryje tę samą formę wprowadzania nazwy pliku typu więcej niż jeden raz. CommonsFileUploadSupport - klasa, która wyrzuca ten wyjątek nie jest ostateczny i method który wyrzuca wyjątek jest zabezpieczone, przy użyciu cuda dziedziczenia i podklasy jednego może łatwo ustalić/zmienić logikę trochę następująco. Zmieniona przeze mnie zmiana jest dosłownie jednym słowem reprezentującym jedno wywołanie metody , które pozwala nam mieć wiele plików przychodzących pod tą samą nazwą wejściową .
Próbuje zastąpić metodę
protected MultipartParsingResult parseFileItems(List fileItems, String encoding){}
z klasy abstrakcyjnej CommonsFileUploadSupport
poprzez rozszerzenie klasy CommonsMultipartResolver
takich jak
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);
}
}
Co się dzieje, że ostatni wiersz w metodzie parseFileItems()
(oświadczenie zwrotne), tj.
return new MultipartParsingResult(multipartFiles, multipartParameters);
powoduje błąd kompilacji, ponieważ pierwszy parametr multipartFiles
jest rodzajem Map
realizowane przez HashMap
ale w rzeczywistości, to wymaga parametru typuMultiValueMap<String, MultipartFile>
Jest to konstruktor klasy statycznej wewnątrz abstrakcyjny Klasa CommonsFileUploadSupport
,
public abstract class CommonsFileUploadSupport {
protected static class MultipartParsingResult {
public MultipartParsingResult(MultiValueMap<String, MultipartFile> mpFiles, Map<String, String[]> mpParams) {}
}
}
powodem może być - to rozwiązanie jest o wiosennej wersji 2.5 i używam wersji 3.0.2 wiosnę, które mogą być nieodpowiednie dla tej wersji.
ja jednak starał się zastąpić Map
z MultiValueMap
w różnych sposobów, takich jak ten pokazany na poniższym segmencie kodu
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);
ale bez powodzenia. Nie jestem pewien, jak zastąpić Map
z MultiValueMap
i nawet może to działać. Po wykonaniu tej czynności, przeglądarka pokazuje odpowiedź HTTP
HTTP status 400 -
typ raportu Stan
wiadomość
opis Żądanie wysłane przez klienta było składniowo niepoprawny ().
Apache Tomcat/6.0.26
próbowałem skrócić pytanie, jak to możliwe, jak tylko mogłem i nie obejmowały zbędnego kodu.
Jak można umożliwić przesyłanie wielu plików po skonfigurowaniu Spring pod numerem HiddenHttpMethodFilter
?
Ten blog wskazuje, że jest to długotrwały błąd o wysokim priorytecie.
Jeśli nie ma rozwiązania dotyczącego wersji 3.0.2 (3 lub wyższej), to muszę wyłączyć wsparcie Spring na zawsze i nadal używać commons-fileupolad, jak sugeruje trzecie rozwiązanie na tym blogu, pomijając PUT, DELETE i inne żądanie metody na zawsze.
Bardzo małe zmiany kodu w metodzie wewnątrz klasy MultiCommonsMultipartResolver
parseFileItems()
może uczynić go przesłać kilka plików, ale nie może się udać w moich próbach (znów z wiosennej wersji 3.0.2 (lub wyższej) 3).
Naprawiono problem [problem Jira] (https://jira.springsource.org/browse/SPR-2784?page=com.atlassian.jira.plugin.system.issuetabpanels%25253Aall-tabpanel) w poście na blogu od wersji 3.0.4, czy możesz spróbować uaktualnić? –
@RC - Dzięki za ten link. Mam dużą aplikację, która jest więcej niż w połowie ukończona. Zmiana struktury może wymagać zmiany kodu w wielu miejscach, więc mogę wymyślić wyższą wersję tylko dla przyszłych projektów (powinienem był to wiedzieć zanim zacząłem). Dziękuję Ci. – Tiny
3.0.2 do 3.0.4 to niewielkie ulepszenie (głównie poprawki błędów, jeśli spojrzę na numer wersji), więc powinno być bezbolesne. Powinieneś go wypróbować i uruchomić, jeśli działa –