Come utilizzare PrimeFaces p: fileUpload? Il metodo listener non viene mai richiamato o UploadedFile è null / genera un errore / non è utilizzabile


101

Sto cercando di caricare un file utilizzando PrimeFaces, ma il fileUploadListenermetodo non viene richiamato al termine del caricamento.

Ecco la vista:

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

E il fagiolo:

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

}

Ho inserito un punto di interruzione nel metodo, ma non viene mai chiamato. Quando si usa mode="simple"e ajax="false", è stato richiamato, ma voglio che funzioni in modalità avanzata. Sto usando Netbeans e Glassfish 3.1.

Risposte:


224

La modalità di configurazione e risoluzione dei problemi <p:fileUpload>dipende dalla versione di PrimeFaces.

Tutte le versioni di PrimeFaces

I seguenti requisiti si applicano a tutte le versioni di PrimeFaces:

  1. L' enctypeattributo di <h:form>deve essere impostato su multipart/form-data. Quando questo è assente, il caricamento ajax potrebbe funzionare, ma il comportamento generale del browser non è specificato e dipende dalla composizione del modulo e dalla marca / versione del browser web. Basta sempre specificarlo per essere al sicuro.

  2. Quando usi mode="advanced"(es. Caricamento ajax, questo è il valore predefinito), assicurati di avere un <h:head>nel modello (principale). Ciò garantirà che i file JavaScript necessari siano inclusi correttamente. Questo non è richiesto per mode="simple"(caricamento non ajax), ma ciò interromperebbe l'aspetto e la funzionalità di tutti gli altri componenti PrimeFaces, quindi non vorrai perderlo comunque.

  3. Quando si utilizza mode="simple"(ad es. Caricamento non ajax), l'ajax deve essere disabilitato su qualsiasi pulsante / collegamento di comando PrimeFaces da ajax="false"e è necessario utilizzare <p:fileUpload value>con <p:commandButton action>invece di <p:fileUpload fileUploadListener>(per PrimeFaces <= 7.x) o <p:fileUpload listener>(per PrimeFaces> = 8.x)

Quindi, se vuoi il caricamento (automatico) del file con il supporto ajax (attenzione <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!
}

Oppure, se desideri caricare file non ajax:

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

Fare nota che gli attributi Ajax-correlati, come auto, allowTypes, update, onstart, oncomplete, ecc sono ignorati in mode="simple". Quindi è inutile specificarli in questo caso.

Notare inoltre che è necessario leggere il contenuto del file immediatamente all'interno dei metodi sopra menzionati e non in un metodo bean diverso richiamato da una successiva richiesta HTTP. Questo perché il contenuto del file caricato ha un ambito di richiesta e quindi non è disponibile in una richiesta HTTP successiva / diversa. Qualsiasi tentativo di leggerlo in una richiesta successiva molto probabilmente finirà java.io.FileNotFoundExceptionnel file temporaneo.


PrimeFaces 8.x

La configurazione è identica alle informazioni sulla versione 5.x di seguito, ma se il tuo ascoltatore non viene chiamato, controlla se l'attributo è chiamato listenere non (come con le versioni precedenti alla 8.x)fileUploadListener

PrimeFaces 5.x

Questo non richiede alcuna configurazione aggiuntiva se stai usando JSF 2.2 e la tua versione faces-config.xmlè anche dichiarata conforme JSF 2.2. Non hai affatto bisogno del filtro di caricamento file PrimeFaces. Nel caso in cui non ti sia chiaro come installare e configurare correttamente JSF a seconda del server di destinazione utilizzato, vai a Come installare e configurare correttamente le librerie JSF tramite Maven? e la sezione "Installazione di JSF" della nostra pagina wiki JSF .

Se tuttavia non stai ancora utilizzando JSF 2.2 e non puoi aggiornarlo (dovrebbe essere facile quando sei già su un contenitore compatibile con Servlet 3.0), allora devi registrare manualmente il filtro di caricamento file PrimeFaces sotto web.xml(analizzerà il multi richiesta di parte e riempire la mappa dei parametri della richiesta regolare in modo che FacesServletpossa continuare a funzionare come al solito):

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

Il <servlet-name>valore di facesServletdeve corrispondere esattamente al valore <servlet>nell'entrata dello javax.faces.webapp.FacesServletstesso web.xml. Quindi, se è ad esempio Faces Servlet, devi modificarlo di conseguenza in modo che corrisponda.


PrimeFaces 4.x

La stessa storia di PrimeFaces 5.x vale anche per 4.x.

C'è solo un potenziale problema nell'ottenere il contenuto del file caricato da UploadedFile#getContents(). Questo verrà restituito nullquando viene utilizzata l'API nativa al posto di Apache Commons FileUpload. Devi usare UploadedFile#getInputStream()invece. Vedi anche Come inserire un'immagine caricata da p: fileUpload come BLOB in MySQL?

Un altro potenziale problema con l'API nativa si manifesterà quando il componente di caricamento è presente in un modulo in cui viene attivata una richiesta ajax "normale" diversa che non elabora il componente di caricamento. Vedi anche Il caricamento di file non funziona con AJAX in PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: il tipo di contenuto della richiesta non è un multipart / form-data .

Entrambi i problemi possono essere risolti anche passando ad Apache Commons FileUpload. Vedere la sezione PrimeFaces 3.x per i dettagli.


PrimeFaces 3.x

Questa versione non supporta il caricamento di file nativi JSF 2.2 / Servlet 3.0. È necessario installare manualmente Apache Commons FileUpload e registrare esplicitamente il filtro di caricamento dei file in formatoweb.xml .

Hai bisogno delle seguenti librerie:

Devono essere presenti nel classpath di runtime della webapp. Quando si utilizza Maven, assicurarsi che abbiano almeno l'ambito di runtime (anche l'ambito di compilazione predefinito è buono). Quando si trasportano manualmente i JAR, assicurarsi che finiscano in/WEB-INF/lib cartella.

I dettagli di registrazione del filtro di caricamento file possono essere trovati nella sezione PrimeFaces 5.x qui sopra. Nel caso in cui si utilizzi PrimeFaces 4+ e si desideri utilizzare esplicitamente Apache Commons FileUpload invece del caricamento di file nativo JSF 2.2 / Servlet 3.0, è necessario accanto alle librerie menzionate e filtrare anche il parametro di contesto sottostante in web.xml:

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

Risoluzione dei problemi

Nel caso in cui ancora non funzioni, ecco altre possibili cause non correlate alla configurazione di PrimeFaces:

  1. Solo se si sta utilizzando il filtro di caricamento di file primefaces: C'è un altro Filternel vostro webapp che corre prima che il filtro di upload di file primefaces e ha già consumato il corpo della richiesta da parte ad esempio di chiamata getParameter(), getParameterMap(), getReader(), eccetera. Il corpo di una richiesta può essere analizzato solo una volta. Quando chiami uno di questi metodi prima che il filtro di caricamento del file faccia il suo lavoro, il filtro di caricamento del file avrà un corpo della richiesta vuoto.

    Per risolvere questo problema, è necessario inserire il <filter-mapping>filtro di caricamento file prima dell'altro filtro in web.xml. Se la richiesta non è una multipart/form-datarichiesta, il filtro di caricamento del file continuerà semplicemente come se non fosse successo nulla. Se utilizzi filtri che vengono aggiunti automaticamente perché utilizzano annotazioni (ad esempio PrettyFaces), potresti dover aggiungere un ordine esplicito tramite web.xml. Vedere Come definire l'ordine di esecuzione del filtro servlet utilizzando le annotazioni in WAR

  2. Solo se stai utilizzando il filtro di caricamento file PrimeFaces: ce Filtern'è un altro nella tua webapp che viene eseguito prima del filtro di caricamento file PrimeFaces e ha eseguito una RequestDispatcher#forward()chiamata. Di solito, i filtri di riscrittura degli URL come PrettyFaces lo fanno. Questo attiva il FORWARDdispatcher, ma i filtri ascoltano per impostazione predefinita REQUESTsolo sul dispatcher.

    Per risolvere questo problema, è necessario inserire il filtro di caricamento dei file PrimeFaces prima del filtro di inoltro o riconfigurare il filtro di caricamento dei file PrimeFaces per ascoltare anche il FORWARDdispatcher:

    <filter-mapping>
        <filter-name>primeFacesFileUploadFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
  3. C'è un annidato <h:form>. Ciò è illegale in HTML e il comportamento del browser non è specificato. Il più delle volte, il browser non invierà i dati previsti al momento dell'invio. Assicurati di non fare il nido <h:form>. Questo è completamente indipendentemente dal modulo enctype. Basta non annidare affatto le forme.

Se hai ancora problemi, beh, esegui il debug del traffico HTTP. Apri il set di strumenti per sviluppatori del browser web (premi F12 in Chrome / Firebug23 + / IE9 +) e controlla la sezione Rete / Rete. Se la parte HTTP sembra a posto, esegui il debug del codice JSF. Metti un punto di interruzione FileUploadRenderer#decode()e avanza da lì.


Salvataggio del file caricato

Dopo averlo finalmente fatto funzionare, la tua prossima domanda sarà probabilmente "Come / dove salvo il file caricato?". Bene, continua qui: Come salvare il file caricato in JSF .


2
Un'altra causa potrebbe essere che non hai registrato il filtro di caricamento PrimeFaces web.xmlsecondo la Guida per gli utenti di PrimeFaces. L'hai letto comunque? Ciò tuttavia non spiegherebbe perché mode="simple"funziona per te.
BalusC

1
Sì, l'ho letto e ho registrato il filtro, ma ho appena notato che mi dà un errore all'avvio del server "SEVERE: WebModule [/ EventsCalendary] PWC1270: Eccezione durante l'avvio del filtro PrimeFaces FileUpload Filter" Mi sento così stupido per non notandolo prima. Qualche consiglio su come risolvere questo errore?
Rodrigo Cavalcante

2
Forse la mappatura del filtro non è corretta. Deve essere mappato sul <servlet-name>della FacesServletcome hai definied in web.xml. Di default è impostato dalla maggior parte degli IDE / generatori di codice Faces Servlet, ma può essere altrettanto buono facesServleto qualcosa che è più confermare le convenzioni di denominazione.
BalusC

2
Nevermind l'ha risolto aggiungendo commons-fileupload al classpath e commons-io, c'è da qualche parte che dice che queste librerie sono necessarie? Ad ogni modo, sembra che tutto funzioni adesso, il metodo viene chiamato come avrebbe dovuto, grazie.
Rodrigo Cavalcante

1
Quindi è venuto fuori tutto con la situazione in cui ho avuto la stessa configurazione in TomEE e JBoss .. forum.primefaces.org/viewtopic.php?f=3&t=43798
Dmitry Alexandrov

30

Stai usando anche dei bei volti? Quindi imposta il dispatcher su FORWARD:

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

Questo è ancora un problema se utilizzato con OCP Rewrite. Ti devo una birra :)
Babl

7

Un punto che ho notato con Primefaces 3.4 e Netbeans 7.2:

Rimuovere i parametri Netbeans compilati automaticamente per la funzione handleFileUpload ie (evento) altrimenti l'evento potrebbe essere nullo.

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


0

Ho avuto lo stesso problema con primefaces 5.3 e ho esaminato tutti i punti descritti da BalusC senza risultato. Ho seguito il suo consiglio di eseguire il debug di FileUploadRenderer # decode () e ho scoperto che il mio web.xml non era impostato correttamente

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

Il valore param deve essere 1 di questi 3 valori ma non tutti !! L'intera sezione context-param può essere rimossa e l'impostazione predefinita sarà auto


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

Puoi spiegare perché questa è una risposta? È solo un codice, non una spiegazione o altro
Kukeltje,

"# {bean.uploadFile}" vs "# {bean.uploadFasta}", rimuovi update = "messages" e funzionerà (solo) per me!
romsky

0

Nessuno dei suggerimenti qui è stato utile per me. Quindi ho dovuto eseguire il debug delle prime facce e ho scoperto che il motivo del problema era:

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

Quindi ho aggiunto una sezione nel mio servlet volti in web.xml. Quindi questo ha risolto il problema:

<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

Ho avuto lo stesso problema, a causa del fatto che avevo tutta la configurazione descritta in questo post, ma nel mio caso era perché avevo due importazioni jquery (una di queste era la query di primefaces) che causava conflitti per caricare i file.

Vedi Primefaces Jquery conflitto


Allora non hai ricevuto un errore specifico nella console per sviluppatori del browser?
Kukeltje

@Kukeltje questo è ciò che la console ha mostrato: Uncaught TypeError: Object [object Object] non ha il metodo "fileupload"
Christian Altamirano Ayala

0

Per le persone che utilizzano Tomee o Tomcat e non riescono a farlo funzionare, provare a creare context.xml in META-INF e aggiungere allowCasualMultipartParsing = "true"

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

Questa è una soluzione per una configurazione / ordinamento del filtro errato.
BalusC

Ciao @BalusC, puoi darci altre spiegazioni? C'è un modo migliore di questo lavoro in giro?
Xavier Lambros

Vedi la mia risposta in questa domanda.
BalusC

0

Con JBoss 7.2 (Undertow) e PrimeFaces 6.0 org.primefaces.webapp.filter.FileUploadFilter dovrebbe essere rimosso da web.xml e il file uploader dei parametri di contesto dovrebbe essere impostato su native:

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

Dovrebbero? Ottieni errori specifici se non lo fai?
Kukeltje

Sì, il mio FileUploadEvent non si richiama senza queste modifiche.
Alex D

Non è un errore esplicito, è un comportamento inaspettato
Kukeltje
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.