2012-12-03 8 views
7

Wichtig aktiviert: Diese Frage ist völlig nutzlos gewesen für jeden Frühling Version höher als 3.0.4 als das Thema in diesem Thread diskutiert fixed in dieser Version vor langer Zeit und ist nicht reproduzierbar in späteren Versionen von Spring.Upload mehrerer Dateien mit Spring MVC 3.0.2 nach HiddenHttpMethodFilter wurde


Ich verwende Spring Version 3.0.2. Ich brauche, um mehrere Dateien laden mit dem multiple="multiple" Attribut eines Dateibrowser wie

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

(und nicht mehrere Dateibrowser so etwas wie die von this answer erklärte man verwenden, ist es in der Tat funktioniert habe ich versucht).

Obwohl keine Versionen von Internet Explorer diesen Ansatz unterstützen, es sei denn, ein passendes jQuery-Plugin/Widget wird verwendet, ist mir im Moment egal (da die meisten anderen Browser dies unterstützen).

Dies funktioniert gut mit commons fileupload aber zusätzlich zur Verwendung RequestMethod.POST und RequestMethod.GET Methoden, mag ich auch wie RequestMethod.PUT und RequestMethod.DELETE in ihren eigenen entsprechenden Stellen andere Anforderungsmethoden unterstützt und schlugen vor, bis zum Frühjahr verwenden. Um dies zu tun, habe ich Spring mit HiddenHttpMethodFilter konfiguriert, die gut geht, wie this question angibt.

aber es kann nur eine Datei auf einmal hochladen, obwohl mehrere Dateien im Dateibrowser ausgewählt sind. In der Spring-Controller-Klasse wird eine Methode wie folgt zugeordnet.

@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()); 
    } 
} 

Auch mit dem Anforderungsparameter @RequestParam("myFile") List<MultipartFile> files, die ein List vom Typ MultipartFile (es kann immer nur eine Datei auf einmal hat).


Ich könnte eine Strategie finden, die mit mehreren Dateien arbeiten on this blog wahrscheinlich ist. Ich habe es sorgfältig durchgegangen.

Die Lösung unter der Abschnitt SOLUTION 2 - Verwenden Sie die RAW REQUEST sagt

Wenn jedoch der Kunde darauf besteht, die gleiche Form Eingabe Namen auf unter Verwendung eines solchen als 'Dateien []' oder "Dateien" und dann diesen Namen mit mehreren Dateien bevölkern dann ist ein kleiner Hack wie folgt erforderlich. Wie oben erwähnt, gibt Spring 2.5 eine Exception aus, wenn es den gleichen Formular-Eingabe-Namen des Dateityps mehr als einmal erkennt. CommonsFileUploadSupport - die Klasse, die diese Ausnahme wirft, ist nicht endgültig und die method, die diese Ausnahme wirft so geschützt ist, die Wunder der Vererbung und Subklassen einer einfach beheben/ändern die Logik ein wenig wie folgt. Die Änderung , die ich gemacht habe, ist buchstäblich ein Wort, das einen Methodenaufruf darstellt, der uns ermöglicht, mehrere Dateien zu haben, die unter dem gleichen Formular eingabename eingehen.

Es versucht, das Verfahren zu überschreiben

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

der abstrakten Klasse CommonsFileUploadSupport durch die Erweiterung der Klasse CommonsMultipartResolver wie

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); 
    } 
} 

Was geschieht, ist, dass die letzte Zeile in dem Verfahren parseFileItems() (die Rückkehranweisung) dh

return new MultipartParsingResult(multipartFiles, multipartParameters); 

verursacht einen Fehler bei der Kompilierung, da der erste Parameter multipartFiles eine Art von Map von HashMapaber in Wirklichkeit umgesetzt ist, erfordert es einen Parameter vom TypMultiValueMap<String, MultipartFile>

Es ist ein Konstruktor einer statischen Klasse innerhalb der abstrakten CommonsFileUploadSupport Klasse,

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

der Grund könnte sein - diese Lösung ist über die Feder Version 2.5 und ich bin mit dem Frühling Version 3.0.2, die für diese Version ungeeignet sein könnte.


I jedoch versucht, die mit MapMultiValueMap auf verschiedene Weise wie das in dem folgenden Codesegment,

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); 

aber keinen Erfolg gezeigt, zu ersetzen. Ich bin mir nicht sicher, wie man Map durch MultiValueMap ersetzen kann und sogar so tun könnte, entweder. Nachdem Sie das getan, zeigt der Browser die HTTP-Antwort,

HTTP-Status 400-

Art Statusbericht

Nachricht

Beschreibung Die Anfrage vom Client gesendet wurde syntaktisch falsch ().

Apache Tomcat/6.0.26


Ich habe versucht, die Frage wie möglich zu verkürzen, wie ich kann, und ich habe keinen unnötigen Code enthalten.

Wie könnte es möglich gemacht werden, mehrere Dateien hochzuladen, nachdem Spring mit HiddenHttpMethodFilter konfiguriert wurde?

Dieser Blog zeigt an, dass es eine lange, hohe Priorität Bug ist.

Wenn es keine Lösung bezüglich der Version 3.0.2 (3 oder höher) gibt, muss ich die Spring-Unterstützung für immer deaktivieren und weiterhin commons-fileupolad verwenden, wie von der dritten Lösung in diesem Blog vorgeschlagen, PUT, DELETE und andere Anfrage auslassen Methoden für immer.


Sehr kleine Änderungen an den Code in der parseFileItems() Methode innerhalb der Klasse MultiCommonsMultipartResolver könnten es mehrere Dateien machen hochladen, aber ich konnte nicht in meinen Versuchen (wieder mit der Spring-Version 3.0.2 (3 oder höher erfolgreich)).

+0

Das [Jira-Problem] (https://jira.springsource.org/browse/SPR-2784?page=com.atlassian.jira.plugin.system.issuetabpanels%25253Aall-tabpanel), das im Blogpost erwähnt wird, ist behoben seit Version 3.0.4, können Sie versuchen, zu aktualisieren? –

+0

@RC - Danke für diesen Link. Ich habe eine große Anwendung, die mehr als halb fertig ist. Das Ändern des Frameworks kann erfordern, dass der Code an vielen Stellen geändert wird, so dass ich mir nur eine höhere Version für die zukünftigen Projekte vorstellen kann (ich hätte es schon wissen müssen, bevor ich angefangen habe). Vielen Dank. – Tiny

+2

3.0.2 bis 3.0.4 ist ein kleines Upgrade (hauptsächlich Bugfixes, wenn ich die Versionsnummer anschaue), so sollte es schmerzlos sein. Sie sollten es versuchen und es gehen, wenn es funktioniert –

Antwort

1

Das Problem, wie in der Frage erwähnt, war fixed ab Frühjahr 3.0.4. Wenn Sie also diese Version oder höher verwenden (ja, es ist jetzt 4.x.x), müssten Sie diese Frage/Antwort nicht mehr lesen.

3

für das Hochladen von mehreren Dateien in einer Anfrage ich diesen Code verwendet:

<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" /> 

Datei-Upload-Klasse Bean:

ich solche jsp haben

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:

@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"; 
    } 
} 

Dieser Code ermöglicht es, mehrere Dateien in einer Anfrage, und möglich sein, zu erhalten Instanz CommonsMultipartFile für jede Datei zu.

+0

Ja, es ist der Weg, mehrere Dateien hochzuladen, und die Technik, die ich zum Hochladen mehrerer Dateien verwendet habe, unterscheidet sich nicht mehr von der, die du gezeigt hast, aber die Sache funktioniert nicht mit ** dem Spring Framework 3.0.2 (oder niedriger) * * was ich früher benutzt habe. In dem, es ist eine Datei hochgeladen (in der Regel die erste aus der Liste der Dateien aus der Datei Durchsuchen ausgewählt). Sprechen Sie über diese Version? Hat es in dieser Version für dich funktioniert? Ich bin sicher, es hätte mit dieser Version von Spring nicht passieren dürfen, oder? Die Antwort ist sehr zu begrüßen. Vielen Dank. – Tiny

Verwandte Themen