Wie verwende ich PrimeFaces p: fileUpload? Die Listener-Methode wird niemals aufgerufen oder UploadedFile ist null / löst einen Fehler aus / kann nicht verwendet werden

101

Ich versuche, eine Datei mit PrimeFaces hochzuladen, aber die fileUploadListenerMethode wird nach Abschluss des Uploads 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 der Methode einen Haltepunkt gesetzt, 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 funktioniert. Ich benutze Netbeans und Glassfish 3.1.

Rodrigo Cavalcante
quelle

Antworten:

223

Die Konfiguration und Fehlerbehebung <p:fileUpload>hängt von der PrimeFaces-Version ab.

Alle PrimeFaces-Versionen

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

  1. Das enctypeAttribut von <h:form>muss auf gesetzt werden multipart/form-data. Wenn dies nicht vorhanden ist, funktioniert der Ajax-Upload möglicherweise nur, aber das allgemeine Verhalten des Browsers ist nicht spezifiziert und hängt von der Zusammensetzung des Formulars und der Marke / Version des Webbrowsers ab. Geben Sie es einfach immer an, um auf der sicheren Seite zu sein.

  2. Wenn Sie mode="advanced"(dh Ajax-Upload, dies ist die Standardeinstellung) verwenden, stellen Sie sicher, dass Sie eine <h:head>in der (Master-) Vorlage haben. Dadurch wird sichergestellt, dass die erforderlichen JavaScript-Dateien ordnungsgemäß enthalten sind. Dies ist für mode="simple"(Nicht-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 der Verwendung von mode="simple"(dh nicht-Ajax - Upload), dann muss Ajax deaktiviert werden auf alle PrimeFaces durch Tasten / Links - Befehl ajax="false", und Sie müssen verwenden <p:fileUpload value>mit <p:commandButton action>statt <p:fileUpload fileUploadListener>(für PrimeFaces <= 7.x) oder <p:fileUpload listener>(für PrimeFaces> = 8.x)

Wenn Sie also (automatisch) Dateien mit Ajax-Unterstützung hochladen möchten (beachten Sie die <h:head>!):

<h:form enctype="multipart/form-data">
    <p:fileUpload fileUploadListener="#{bean.upload}" auto="true" /> // for PrimeFaces >= 8.x this should be listener instead of fileUploadListener 
</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 eine Nicht-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!
}

Zu beachten ist, dass Ajax-bezogene Attribute wie auto, allowTypes,update , onstart, oncomplete, etc. werden ignoriert in mode="simple". In diesem Fall müssen sie nicht angegeben werden.

Beachten Sie auch, dass Sie sollten den Dateiinhalt sofort in den oben genannten Methoden lesen 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 einen Anforderungsbereich hat und daher in einer späteren / anderen HTTP-Anforderung nicht verfügbar ist. Jeder Versuch, es in einer späteren Anfrage zu lesen, endet höchstwahrscheinlich java.io.FileNotFoundExceptionin der temporären Datei.


PrimeFaces 8.x.

Die Konfiguration ist identisch mit den unten stehenden 5.x-Versionsinformationen. Wenn Ihr Listener jedoch nicht aufgerufen wird, überprüfen Sie, ob der attriubute aufgerufen wird listenerund nicht (wie bei Versionen vor 8.x).fileUploadListener

PrimeFaces 5.x.

Dies erfordert keine zusätzliche Konfiguration, wenn Sie JSF 2.2 verwenden und Ihre faces-config.xmlVersion auch als konform JSF 2.2 deklariert ist. Sie benötigen den Filter zum Hochladen von PrimeFaces-Dateien überhaupt nicht. Falls Ihnen nicht klar ist, wie Sie JSF abhängig vom verwendeten Zielserver ordnungsgemäß installieren und konfigurieren können, lesen Sie Wie Sie JSF-Bibliotheken über Maven ordnungsgemäß installieren und konfigurieren. und "Installieren von JSF" auf unserer JSF-Wiki-Seite .

Wenn Sie JSF 2.2 jedoch noch nicht verwenden und es nicht aktualisieren können (sollte mühelos sein, wenn Sie bereits einen Servlet 3.0-kompatiblen Container verwenden), müssen Sie den folgenden Filter zum Hochladen von PrimeFaces-Dateien manuell registrieren web.xml(er analysiert das Multi Teileanforderung und füllen Sie die reguläre Anforderungsparameterzuordnung aus, damit Sie FacesServletwie gewohnt weiterarbeiten können):

<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 facesServletmuss genau mit dem Wert im <servlet>Eintrag des javax.faces.webapp.FacesServletin demselben übereinstimmen web.xml. Wenn es also z Faces Servlet.


PrimeFaces 4.x.

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

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

Ein weiteres potenzielles Problem mit der nativen API besteht darin, dass 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 Datei-Upload funktioniert nicht mit AJAX in PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: Der Anforderungsinhaltstyp ist kein Multipart / Formulardaten .

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


PrimeFaces 3.x.

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

Sie benötigen folgende Bibliotheken:

Diese müssen im Laufzeitklassenpfad der Webanwendung vorhanden sein. Stellen Sie bei der Verwendung von Maven sicher, dass sie mindestens einen Laufzeitbereich haben (der Standardbereich für die Kompilierung ist ebenfalls gut). Stellen Sie beim manuellen Mitführen von JARs sicher, dass sie im /WEB-INF/libOrdner landen .

Die Registrierungsdetails für den Filter zum Hochladen von Dateien finden Sie oben im Abschnitt PrimeFaces 5.x. Wenn Sie PrimeFaces 4+ verwenden und Apache Commons FileUpload anstelle des nativen Hochladens von JSF 2.2 / Servlet 3.0-Dateien explizit verwenden möchten, müssen Sie neben den genannten Bibliotheken auch den folgenden Kontextparameter filtern in web.xml:

<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 nicht mit der PrimeFaces-Konfiguration zusammenhängen:

  1. Nur wenn Sie die PrimeFaces Datei - Upload - Filter verwenden: Es gibt ein anderes Filterin Ihrem Webapp , die ausgeführt wird, bevor die Filter PrimeFaces Datei - Upload und hat bereits den Wunsch Körper zB durch Berufung verbraucht getParameter(), getParameterMap(),getReader() , und so weiter. Ein Anforderungshauptteil kann nur einmal analysiert werden. Wenn Sie eine dieser Methoden aufrufen, bevor der Filter zum Hochladen von Dateien seine Aufgabe erfüllt, erhält der Filter zum Hochladen von Dateien einen leeren Anforderungshauptteil.

    Um dies zu beheben, müssen Sie <filter-mapping>den Filter zum Hochladen von Dateien vor den anderen Filter setzen web.xml. Wenn es sich bei der Anforderung nicht um eine multipart/form-dataAnforderung handelt, wird der Filter zum Hochladen von Dateien so fortgesetzt, als wäre nichts passiert. 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 Filter zum Hochladen von PrimeFaces-Dateien verwenden: FilterIn Ihrer Webanwendung befindet sich ein weiterer Filter, der vor dem Filter zum Hochladen von PrimeFaces-Dateien ausgeführt wird und einen RequestDispatcher#forward()Aufruf ausgeführt hat. Normalerweise tun dies URL-Umschreibungsfilter wie PrettyFaces . Dies löst den FORWARDDispatcher aus, aber Filter überwachen standardmäßig REQUESTnur den Dispatcher.

    Um dies zu beheben, müssen Sie entweder den PrimeFaces-Filter zum Hochladen von Dateien vor den Weiterleitungsfilter stellen oder den PrimeFaces-Filter zum Hochladen von Dateien neu konfigurieren, um auch den FORWARDDispatcher 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 eine verschachtelte <h:form>. Dies ist in HTML illegal und das Browserverhalten ist nicht angegeben. Mehr als oft sendet der Browser beim Senden nicht die erwarteten Daten. Stellen Sie sicher, dass Sie nicht verschachteln <h:form>. Dies ist völlig unabhängig von der Form enctype. Verschachteln Sie Formen überhaupt nicht.

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


Hochgeladene Datei speichern

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: So speichern Sie hochgeladene Dateien in JSF .

BalusC
quelle
2
Eine andere Ursache könnte sein, dass Sie den PrimeFaces-Upload-Filter nicht web.xmlgemäß dem PrimeFaces-Benutzerhandbuch registriert haben . Hast du es trotzdem gelesen? Das würde jedoch nicht erklären, warum mode="simple"für Sie funktioniert.
BalusC
1
Ja, ich habe es gelesen und den Filter registriert, aber ich habe gerade bemerkt, dass es mir beim Starten des Servers einen Fehler gibt. "SEVERE: WebModule [/ EventsCalendary] PWC1270: Ausnahme beim Starten des Filters PrimeFaces FileUpload Filter" Ich fühle mich so dumm, nicht vorher bemerkt. Irgendwelche Tipps zur Behebung dieses Fehlers?
Rodrigo Cavalcante
2
Möglicherweise ist die Filterzuordnung falsch. Es muss auf dem <servlet-name>von FacesServletIhnen definierten abgebildet werden web.xml. Die meisten IDEs / Codegeneratoren verwenden standardmäßig die Option Faces Servlet, aber es kann genauso gut sein facesServletoder etwas, das die Namenskonventionen besser bestätigt.
BalusC
2
Nevermind hat es gelöst, indem commons-fileupload zum Klassenpfad und commons-io hinzugefügt wurde. Gibt es irgendwo einen Hinweis darauf, dass diese Bibliotheken benötigt werden? Wie auch immer, im Moment scheint alles zu funktionieren, die Methode wird so aufgerufen, wie sie sollte, danke.
Rodrigo Cavalcante
1
Also kam alles auf die Situation, dass ich die gleiche Konfiguration in TomEE und JBoss habe .. forum.primefaces.org/viewtopic.php?f=3&t=43798
Dmitry Alexandrov
30

Du benutzt auch hübsche Gesichter? Stellen Sie dann den Dispatcher auf FORWARD:

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>
Reinaldo Gil
quelle
Dies ist immer noch ein Problem, wenn es mit OCP Rewrite verwendet wird. Ich schulde dir ein Bier :)
Babl
7

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

Entfernen Sie die automatisch ausgefüllten Netbeans-Parameter für die Funktion handleFileUpload, dh (Ereignis), da sonst das Ereignis null sein könnte.

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

quelle
2

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

HazeHorizon
quelle
2
Könnten Sie bitte näher darauf eingehen?!
Karl Richter
0

Ich hatte das gleiche Problem mit Primefaces 5.3 und habe alle von BalusC beschriebenen Punkte ohne Ergebnis durchgearbeitet. Ich folgte seinem Rat, FileUploadRenderer # decode () zu debuggen, und stellte fest, dass meine web.xml nicht richtig 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 Kontextparameterabschnitt kann entfernt werden und die Standardeinstellung ist automatisch

Eric A.
quelle
0

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 class Submission 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>
Waldeyr Mendes da Silva
quelle
Können Sie erklären, warum dies eine Antwort ist? Es ist nur Code, keine Erklärung oder was auch immer
Kukeltje
"# {bean.uploadFile}" vs "# {bean.uploadFasta}", entferne update = "messages" und es wird (nur) das für mich funktionieren!
Romsky
0

Keiner der Vorschläge hier war für mich hilfreich. Also musste ich Primefaces debuggen und fand den Grund für das Problem:

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

Dann habe ich einen Abschnitt in mein Gesichtsservlet in der web.xml eingefügt. Damit ist 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>
engilyin
quelle
0

Ich hatte das gleiche Problem aufgrund der Tatsache, dass ich alle in diesem Beitrag beschriebenen Konfigurationen hatte, aber in meinem Fall, weil ich zwei JQuery-Importe hatte (einer davon war die Abfrage von Primefaces), die Konflikte beim Hochladen von Dateien verursachten.

Siehe Primefaces Jquery-Konflikt

Christian Altamirano Ayala
quelle
Haben Sie damals keinen bestimmten Fehler in der Browser-Entwicklerkonsole erhalten?
Kukeltje
@Kukeltje dies ist, was die Konsole zeigte: Uncaught TypeError: Object [Objekt Object] hat keine Methode 'fileupload'
Christian Altamirano Ayala
0

Wenn Sie Tomee oder Tomcat verwenden und es nicht zum Laufen bringen 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>
Xavier Lambros
quelle
Dies ist eine Problemumgehung für eine falsche Filterkonfiguration / -reihenfolge.
BalusC
Hallo @BalusC, kannst du uns mehr erklären? Gibt es einen besseren Weg als diese Problemumgehung?
Xavier Lambros
Siehe meine Antwort in dieser Frage.
BalusC
0

Mit JBoss 7.2 (Undertow) und PrimeFaces 6.0 sollte org.primefaces.webapp.filter.FileUploadFilter aus web.xml entfernt und der Uploader der Kontextparameterdatei auf native gesetzt werden:

<context-param>
    <param-name>primefaces.UPLOADER</param-name>
    <param-value>native</param-value>
</context-param>
Alex D.
quelle
Sollte? Erhalten Sie bestimmte Fehler, wenn Sie dies nicht tun?
Kukeltje
Ja, mein FileUploadEvent wird ohne diese Änderungen nicht aufgerufen.
Alex D
Das ist kein expliziter Fehler, das ist unerwartetes Verhalten
Kukeltje