web-dev-qa-db-ger.com

Wie benutze ich PrimeFaces p: fileUpload? Die Listener-Methode wird niemals aufgerufen, oder UploadedFile ist null oder führt zu einem Fehler/ist nicht verwendbar

Ich versuche, eine Datei mit PrimeFaces hochzuladen, aber die fileUploadListener-Methode wird nach dem Hochladen nicht aufgerufen.

Hier ist die Ansicht:

<h:form>
    <p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload}"
        mode="advanced" 
        update="messages"
        sizeLimit="100000" 
        allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>

    <p:growl id="messages" showDetail="true"/>
</h:form>

Und die Bohne:

@ManagedBean
@RequestScoped
public class FileUploadController {

    public void handleFileUpload(FileUploadEvent event) {
        FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
        FacesContext.getCurrentInstance().addMessage(null, msg);
    }

}

Ich habe einen Haltepunkt für die Methode festgelegt, der jedoch nie aufgerufen wird. Bei Verwendung von mode="simple" und ajax="false" wurde es aufgerufen, aber ich möchte, dass es im erweiterten Modus arbeitet. Ich verwende Netbeans und Glassfish 3.1.

93

Wie Sie <p:fileUpload> konfigurieren und Fehler beheben, hängt von der PrimeFaces-Version ab.

Alle PrimeFaces-Versionen

Die folgenden Anforderungen gelten für alle PrimeFaces-Versionen:

  1. Das Attribut enctype des <h:form> muss auf multipart/form-data gesetzt werden. Ist dies nicht der Fall, funktioniert der Ajax-Upload möglicherweise nur, das allgemeine Browserverhalten ist jedoch nicht festgelegt und von der Formularkomposition und der Marke/Version des Webbrowsers abhängig. Einfach immer angeben, um auf der sicheren Seite zu sein.

  2. Wenn Sie mode="advanced" verwenden (d. H. Ajax-Upload, dies ist die Standardeinstellung), stellen Sie sicher, dass in der (Master-) Vorlage ein <h:head> vorhanden ist. Dadurch wird sichergestellt, dass die erforderlichen JavaScript-Dateien ordnungsgemäß enthalten sind. Dies ist für mode="simple" (kein Ajax-Upload) nicht erforderlich, würde jedoch das Erscheinungsbild und die Funktionalität aller anderen PrimeFaces-Komponenten beeinträchtigen, sodass Sie dies sowieso nicht verpassen möchten.

  3. Bei Verwendung von mode="simple" (d. H. Hochladen ohne Ajax) muss Ajax für alle PrimeFaces-Befehlsschaltflächen/-links von ajax="false" deaktiviert werden, und Sie müssen <p:fileUpload value> mit <p:commandButton action> anstelle von <p:fileUpload fileUploadListener> verwenden.

Wenn Sie also einen (automatischen) Dateiupload mit Ajax-Unterstützung wünschen (beachten Sie den <h:head>!):

<h:form enctype="multipart/form-data">
    <p:fileUpload fileUploadListener="#{bean.upload}" auto="true" />
</h:form>
public void upload(FileUploadEvent event) {
    UploadedFile uploadedFile = event.getFile();
    String fileName = uploadedFile.getFileName();
    String contentType = uploadedFile.getContentType();
    byte[] contents = uploadedFile.getContents(); // Or getInputStream()
    // ... Save it, now!
}

Oder wenn Sie keine Ajax-Datei hochladen möchten:

<h:form enctype="multipart/form-data">
    <p:fileUpload mode="simple" value="#{bean.uploadedFile}" />
    <p:commandButton value="Upload" action="#{bean.upload}" ajax="false" />
</h:form>
private UploadedFile uploadedFile; // +getter+setter

public void upload() {
    String fileName = uploadedFile.getFileName();
    String contentType = uploadedFile.getContentType();
    byte[] contents = uploadedFile.getContents(); // Or getInputStream()
    // ... Save it, now!
}

Beachten Sie, dass Ajax-bezogene Attribute wie auto, allowTypes, update, onstart, oncomplete usw. in mode="simple"ignoriert ​​sind. Daher ist es in einem solchen Fall unnötig, sie anzugeben.

Beachten Sie auch, dass Sie den Dateiinhalt sofort lesen innerhalb der oben genannten Methoden und nicht in einer anderen Bean-Methode, die von einer späteren HTTP-Anforderung aufgerufen wird. Dies liegt daran, dass der Inhalt der hochgeladenen Datei anforderungsspezifisch ist und daher in einer späteren/anderen HTTP-Anforderung nicht verfügbar ist. Jeder Versuch, es in einer späteren Anforderung zu lesen, führt höchstwahrscheinlich zu Java.io.FileNotFoundException in der temporären Datei.


PrimeFaces 5.x

Dies erfordert keine zusätzliche Konfiguration, wenn Sie JSF 2.2 verwenden und Ihr faces-config.xml auch als JSF 2.2-konform deklariert ist. Sie benötigen den PrimeFaces-Datei-Upload-Filter überhaupt nicht. Wenn Sie nicht wissen, wie Sie JSF in Abhängigkeit vom verwendeten Zielserver richtig installieren und konfigurieren, lesen Sie Wie Sie JSF-Bibliotheken über Maven richtig installieren und konfigurieren? Und Abschnitt "JSF installieren" unserer JSF-Wiki-Seite .

Wenn Sie JSF 2.2 jedoch noch nicht verwenden und es nicht aktualisieren können (sollte problemlos möglich sein, wenn Sie sich bereits in einem Servlet 3.0-kompatiblen Container befinden), müssen Sie den folgenden PrimeFaces-Datei-Upload-Filter in web.xml manuell registrieren (das wird analysiert) mehrteilige Anfrage und füllen Sie die reguläre Anfrageparameterkarte aus, damit FacesServlet wie gewohnt weiterarbeiten kann):

<filter>
    <filter-name>primeFacesFileUploadFilter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>primeFacesFileUploadFilter</filter-name>
    <servlet-name>facesServlet</servlet-name>
</filter-mapping>

Der <servlet-name>-Wert von facesServlet muss genau mit dem Wert im <servlet>-Eintrag des javax.faces.webapp.FacesServlet im selben web.xml übereinstimmen. Wenn es also z.B. Faces Servlet, dann müssen Sie es entsprechend anpassen.


PrimeFaces 4.x

Dieselbe Geschichte wie bei PrimeFaces 5.x gilt auch für 4.x.

Es gibt nur ein potenzielles Problem beim Abrufen des Inhalts der hochgeladenen Datei durch UploadedFile#getContents(). Dies gibt null zurück, wenn die native API anstelle von Apache Commons FileUpload verwendet wird. Sie müssen stattdessen UploadedFile#getInputStream() verwenden. Siehe auch Wie füge ich ein hochgeladenes Bild aus p: fileUpload als BLOB in MySQL ein?

Ein weiteres mögliches Problem mit der nativen API tritt auf, wenn die Upload-Komponente in einer Form vorliegt, in der eine andere "reguläre" Ajax-Anforderung ausgelöst wird, die die Upload-Komponente nicht verarbeitet. Siehe auch Das Hochladen von Dateien funktioniert nicht mit AJAX in PrimeFaces 4.0/JSF 2.2.x - javax.servlet.ServletException: Der Anforderungsinhaltstyp ist kein mehrteiliges Datenformat .

Beide Probleme können auch durch Umstieg auf Apache Commons FileUpload behoben werden. Weitere Informationen finden Sie im Abschnitt PrimeFaces 3.x.


PrimeFaces 3.x

Diese Version unterstützt das native Hochladen von Dateien mit JSF 2.2/Servlet 3.0 nicht. Sie müssen Apache Commons FileUpload manuell installieren und den Datei-Upload-Filter explizit in web.xml registrieren.

Sie benötigen folgende Bibliotheken:

Diese müssen im Laufzeitklassenpfad der Webapp vorhanden sein. Stellen Sie bei der Verwendung von Maven sicher, dass sie mindestens über den Laufzeitbereich verfügen (der Standardumfang der Kompilierung ist ebenfalls gut). Stellen Sie beim manuellen Mitführen von JARs sicher, dass sie im Ordner /WEB-INF/lib landen.

Die Details zur Registrierung des Datei-Upload-Filters finden Sie oben im Abschnitt PrimeFaces 5.x. Wenn Sie PrimeFaces 4+ verwenden und Apache Commons FileUpload explizit anstelle von nativem JSF 2.2/Servlet 3.0-Dateiupload verwenden möchten, müssen Sie neben den genannten Bibliotheken auch den folgenden Kontextparameter in web.xml filtern:

<context-param>
    <param-name>primefaces.UPLOADER</param-name>
    <param-value>commons</param-value><!-- Allowed values: auto, native and commons. -->
</context-param>

Fehlerbehebung

Falls es immer noch nicht funktioniert, gibt es noch weitere mögliche Ursachen, die nichts mit der PrimeFaces-Konfiguration zu tun haben:

  1. Nur wenn Sie den PrimeFaces-Datei-Upload-Filter verwenden: In Ihrer Webanwendung befindet sich ein weiteres Filter, dasvordem PrimeFaces-Datei-Upload-Filter ausführt und den Anfragetext bereits von z. Aufruf von getParameter(), getParameterMap(), getReader() usw. Ein Anfragetext kann nur einmal analysiert werden. Wenn Sie eine dieser Methoden aufrufen, bevor der Datei-Upload-Filter seine Aufgabe erfüllt, erhält der Datei-Upload-Filter einen leeren Anforderungshauptteil.

    Um dies zu beheben, müssen Sie den <filter-mapping> des Datei-Upload-Filtersvorden anderen Filter in web.xml einfügen. Wenn die Anforderung keine multipart/form-data-Anforderung ist, wird der Datei-Upload-Filter so fortgesetzt, als ob nichts passiert wäre. Wenn Sie Filter verwenden, die automatisch hinzugefügt werden, weil sie Anmerkungen verwenden (z. B. PrettyFaces), müssen Sie möglicherweise eine explizite Reihenfolge über web.xml hinzufügen. Siehe Definieren der Ausführungsreihenfolge von Servlet-Filtern mithilfe von Anmerkungen in WAR

  2. Nur wenn Sie den PrimeFaces-Datei-Upload-Filter verwenden: In Ihrer Webanwendung befindet sich ein weiteres Filter, dasvordem PrimeFaces-Datei-Upload-Filter ausführt und einen ausgeführt hat. RequestDispatcher#forward() call. Normalerweise tun URL-Umschreibefilter wie PrettyFaces dies. Dies löst den Dispatcher FORWARD aus, filtert jedoch standardmäßig nur den Dispatcher REQUEST.

    Um dies zu beheben, müssen Sie entweder den PrimeFaces-Datei-Upload-Filtervorden Weiterleitungsfilter setzen oder den PrimeFaces-Datei-Upload-Filter neu konfigurieren, um auch den FORWARD-Dispatcher abzuhören:

    <filter-mapping>
        <filter-name>primeFacesFileUploadFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    
  3. Es gibt einen verschachtelten <h:form>. Dies ist in HTML unzulässig und das Browserverhalten ist nicht spezifiziert. In den meisten Fällen sendet der Browser beim Senden nicht die erwarteten Daten. Stellen Sie sicher, dass Sie <h:form> nicht verschachteln. Dies ist völlig unabhängig von der enctype des Formulars. Schachteln Sie einfach überhaupt keine Formulare.

Wenn Sie weiterhin Probleme haben, debuggen Sie den HTTP-Verkehr. Öffnen Sie das Developer Toolset des Webbrowsers (drücken Sie F12 in Chrome/Firebug23 +/IE9 +) und überprüfen Sie den Abschnitt Net/Network. Wenn der HTTP-Teil gut aussieht, debuggen Sie den JSF-Code. Setzen Sie einen Haltepunkt auf FileUploadRenderer#decode() und fahren Sie von dort fort.


Hochgeladene Datei wird gespeichert

Nachdem Sie es endlich zum Laufen gebracht haben, lautet Ihre nächste Frage wahrscheinlich "Wie/wo speichere ich die hochgeladene Datei?". Fahren Sie hier fort: Wie Sie die hochgeladene Datei in JSF speichern.

211
BalusC

Sie benutzen auch hübsche Gesichter? Dann setzen Sie den Dispatcher auf FORWARD:

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>
30
Reinaldo Gil

Ein Punkt, den ich bei Primefaces 3.4 und Netbeans 7.2 festgestellt habe:

Entfernen Sie die automatisch ausgefüllten Parameter von Netbeans für die Funktion handleFileUpload, d. H. (Event), andernfalls könnte event null sein.

<h:form>
    <p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload(event)}"
        mode="advanced" 
        update="messages"
        sizeLimit="100000" 
        allowTypes="/(\.|\/)(gif|jpe?g|png)$/"/>

    <p:growl id="messages" showDetail="true"/>
</h:form>
6
user1791617

Sieht aus wie javax.faces.SEPARATOR_CHAR darf nicht gleich _ sein

2
HazeHorizon

Ich hatte das gleiche Problem mit Primefaces 5.3 und habe alle von BalusC beschriebenen Punkte ohne Ergebnis durchlaufen. Ich folgte seinem Rat zum Debuggen von FileUploadRenderer # decode () und stellte fest, dass meine web.xml-Datei nicht ordnungsgemäß eingestellt war

<context-param>
  <param-name>primefaces.UPLOADER</param-name>
  <param-value>auto|native|commons</param-value>
</context-param>

Der Parameterwert muss 1 dieser 3 Werte sein, aber nicht alle !! Der gesamte context-param-Abschnitt kann entfernt werden. Die Standardeinstellung lautetauto

0
eric A

Keiner der Vorschläge hier war für mich hilfreich. Also musste ich Primefaces debuggen und stellte fest, dass das Problem so war:

Java.lang.IllegalStateException: No multipart config for servlet fileUpload

Dann habe ich meinem Webservice in web.xml einen Abschnitt hinzugefügt. Das hat also das Problem behoben: 

<servlet>
    <servlet-name>main</servlet-name>

        <servlet-class>org.Apache.myfaces.webapp.MyFacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <multipart-config>
            <location>/tmp</location>
            <max-file-size>20848820</max-file-size>
            <max-request-size>418018841</max-request-size>
            <file-size-threshold>1048576</file-size-threshold>
        </multipart-config>
    </servlet>
0
engilyin

Ich hatte das gleiche Problem, weil ich die gesamte Konfiguration hatte, die in diesem Beitrag beschrieben wird. In meinem Fall war es jedoch, dass ich zwei Jquery-Importe hatte (einer davon war die Anfrage der Primefaces), wodurch Konflikte beim Hochladen von Dateien verursacht wurden.

Siehe Primefaces Jquery-Konflikt

bean.xhtml

    <h:form enctype="multipart/form-data">    
<p:outputLabel value="Choose your file" for="submissionFile" />
                <p:fileUpload id="submissionFile"
                    value="#{bean.file}"
                    fileUploadListener="#{bean.uploadFile}" mode="advanced"
                    auto="true" dragDropSupport="false" update="messages"
                    sizeLimit="100000" fileLimit="1" allowTypes="/(\.|\/)(pdf)$/" />

</h:form>

Bean.Java

@ManagedBean

@ViewScoped Public-Klasse Übermittlung implementiert Serializable {

private UploadedFile file;

//Gets
//Sets

public void uploadFasta(FileUploadEvent event) throws FileNotFoundException, IOException, InterruptedException {

    String content = IOUtils.toString(event.getFile().getInputstream(), "UTF-8");

    String filePath = PATH + "resources/submissions/" + nameOfMyFile + ".pdf";

    MyFileWriter.writeFile(filePath, content);

    FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
            event.getFile().getFileName() + " is uploaded.", null);
    FacesContext.getCurrentInstance().addMessage(null, message);

}

}

web.xml

    <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<filter>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>PrimeFaces FileUpload Filter</filter-name>
    <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

Für Benutzer von Tomee oder Tomcat, die nicht funktionieren können, versuchen Sie, context.xml in META-INF zu erstellen und allowCasualMultipartParsing = "true" hinzuzufügen.

<?xml version="1.0" encoding="UTF-8"?>
<Context allowCasualMultipartParsing="true">
  <!-- empty or not depending your project -->
</Context>
0
Xavier Lambros