Bagaimana cara menggunakan PrimeFaces p: fileUpload? Metode pendengar tidak pernah dipanggil atau UploadedFile null / memunculkan kesalahan / tidak dapat digunakan

101

Saya mencoba mengupload file menggunakan PrimeFaces, tetapi fileUploadListenermetode ini tidak dipanggil setelah upload selesai.

Ini dia viewnya:

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

Dan kacang:

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

}

Saya telah menempatkan titik putus pada metode, tetapi tidak pernah dipanggil. Saat menggunakan mode="simple"dan ajax="false", ini telah dipanggil, tetapi saya ingin berfungsi dalam mode lanjutan. Saya menggunakan Netbeans dan Glassfish 3.1.

Rodrigo Cavalcante
sumber

Jawaban:

225

Cara mengkonfigurasi dan memecahkan masalah <p:fileUpload>tergantung pada versi PrimeFaces.

Semua versi PrimeFaces

Persyaratan di bawah ini berlaku untuk semua versi PrimeFaces:

  1. The enctypeatribut dari <h:form>kebutuhan harus ditetapkan untuk multipart/form-data. Jika ini tidak ada, unggahan ajax mungkin hanya berfungsi, tetapi perilaku browser umum tidak ditentukan dan bergantung pada komposisi formulir dan merek / versi browser web. Selalu tentukan agar aman.

  2. Saat menggunakan mode="advanced"(mis. Ajax upload, ini defaultnya), lalu pastikan Anda sudah memiliki <h:head>template (master). Ini akan memastikan bahwa file JavaScript yang diperlukan disertakan dengan benar. Ini tidak diperlukan untuk mode="simple"(unggahan non-ajax), tetapi ini akan merusak tampilan dan fungsionalitas semua komponen PrimeFaces lainnya, jadi Anda tetap tidak ingin melewatkannya.

  3. Saat menggunakan mode="simple"(misalnya, unggahan non-ajax), maka ajax harus dinonaktifkan pada setiap tombol / tautan perintah PrimeFaces oleh ajax="false", dan Anda harus menggunakan <p:fileUpload value>dengan <p:commandButton action>alih - alih <p:fileUpload fileUploadListener>(untuk PrimeFaces <= 7.x) atau <p:fileUpload listener>(untuk PrimeFaces> = 8.x)

Jadi, jika Anda ingin mengunggah file (otomatis) dengan dukungan ajax (ingatlah <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!
}

Atau jika Anda ingin mengunggah 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!
}

Apakah dicatat bahwa atribut yang berhubungan dengan ajax seperti auto, allowTypes, update, onstart, oncomplete, dll diabaikan dalam mode="simple". Jadi tidak perlu menentukannya dalam kasus seperti itu.

Perhatikan juga bahwa Anda harus membaca konten file segera di dalam metode yang disebutkan di atas dan bukan dalam metode kacang berbeda yang dipanggil oleh permintaan HTTP nanti. Ini karena konten file yang diunggah adalah permintaan yang tercakup dan dengan demikian tidak tersedia di permintaan HTTP nanti / berbeda. Upaya apa pun untuk membacanya di permintaan nanti kemungkinan besar akan berakhir java.io.FileNotFoundExceptiondi file sementara.


PrimeFaces 8.x

Konfigurasi identik dengan info versi 5.x di bawah, tetapi jika pendengar Anda tidak dipanggil, periksa apakah attriubute dipanggil listenerdan tidak (seperti dengan versi 8.x sebelumnya)fileUploadListener

PrimeFaces 5.x

Ini tidak memerlukan konfigurasi tambahan jika Anda menggunakan JSF 2.2 dan Anda faces-config.xmljuga dinyatakan sesuai dengan versi JSF 2.2. Anda tidak memerlukan filter unggah file PrimeFaces sama sekali. Jika tidak jelas bagi Anda bagaimana cara menginstal dan mengkonfigurasi JSF dengan benar tergantung pada server target yang digunakan, buka Bagaimana cara menginstal dan mengkonfigurasi pustaka JSF dengan benar melalui Maven? dan bagian "Menginstal JSF" di halaman wiki JSF kami .

Namun, jika Anda belum menggunakan JSF 2.2 dan Anda tidak dapat memutakhirkannya (semestinya mudah ketika sudah menggunakan wadah yang kompatibel dengan Servlet 3.0), maka Anda perlu mendaftar secara manual filter unggah file PrimeFaces di bawah web.xml(ini akan mengurai multi bagian permintaan dan isi peta parameter permintaan biasa sehingga FacesServletdapat terus bekerja seperti biasa):

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

The <servlet-name>nilai facesServletharus sama persis nilai dalam <servlet>masuknya javax.faces.webapp.FacesServletdi sama web.xml. Jadi jika itu misalnya Faces Servlet, maka Anda perlu mengeditnya agar cocok.


PrimeFaces 4.x

Kisah yang sama seperti PrimeFaces 5.x berlaku di 4.x juga.

Hanya ada kemungkinan masalah dalam mendapatkan konten file yang diunggah dengan UploadedFile#getContents(). Ini akan kembali nullketika API asli digunakan sebagai ganti Apache Commons FileUpload. Anda perlu menggunakan UploadedFile#getInputStream()sebagai gantinya. Lihat juga Bagaimana cara memasukkan gambar yang diupload dari p: fileUpload sebagai BLOB di MySQL?

Masalah potensial lainnya dengan API asli akan terlihat adalah ketika komponen unggahan ada dalam bentuk di mana permintaan ajax "biasa" yang berbeda diaktifkan yang tidak memproses komponen unggahan. Lihat juga Unggahan file tidak berfungsi dengan AJAX di PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: Jenis konten permintaan bukan data multipart / formulir .

Kedua masalah ini juga dapat diatasi dengan beralih ke FileUpload Apache Commons. Lihat bagian PrimeFaces 3.x untuk detailnya.


PrimeFaces 3.x

Versi ini tidak mendukung unggahan file asli JSF 2.2 / Servlet 3.0. Anda perlu menginstal FileUpload Apache Commons secara manual dan secara eksplisit mendaftarkan filter upload file web.xml.

Anda membutuhkan perpustakaan berikut:

Mereka harus ada di classpath waktu proses aplikasi web. Saat menggunakan Maven, pastikan mereka setidaknya memiliki cakupan waktu proses (cakupan default kompilasi juga bagus). Saat membawa-bawa JAR secara manual, pastikan semuanya dimasukkan ke dalam /WEB-INF/libfolder.

Detail pendaftaran filter unggah file dapat ditemukan di bagian PrimeFaces 5.x di sini di atas. Jika Anda menggunakan PrimeFaces 4+ dan Anda ingin secara eksplisit menggunakan FileUpload Apache Commons alih-alih mengunggah file asli JSF 2.2 / Servlet 3.0, maka Anda perlu di sebelah pustaka yang disebutkan dan memfilter juga parameter konteks di bawah ini di web.xml:

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

Penyelesaian masalah

Jika masih tidak berfungsi, berikut adalah kemungkinan penyebab lain yang tidak terkait dengan konfigurasi PrimeFaces:

  1. Hanya jika Anda menggunakan PrimeFaces upload file filter: Ada satu lagi Filterdi webapp Anda yang berjalan sebelum para PrimeFaces upload file filter dan telah dikonsumsi tubuh permintaan misalnya panggilan getParameter(), getParameterMap(), getReader(), dan sebagainya. Badan permintaan hanya dapat diurai sekali. Jika Anda memanggil salah satu metode tersebut sebelum filter upload file melakukan tugasnya, filter upload file akan mendapatkan isi permintaan kosong.

    Untuk memperbaikinya, Anda harus menempatkan <filter-mapping>filter unggahan file sebelum filter lainnya masuk web.xml. Jika permintaan tersebut bukan multipart/form-datapermintaan, maka filter unggah file akan terus berlanjut seolah-olah tidak ada yang terjadi. Jika Anda menggunakan filter yang ditambahkan secara otomatis karena menggunakan anotasi (mis. PrettyFaces), Anda mungkin perlu menambahkan pengurutan eksplisit melalui web.xml. Lihat Bagaimana menentukan urutan eksekusi filter servlet menggunakan anotasi dalam WAR

  2. Hanya jika Anda menggunakan filter unggah file PrimeFaces: Ada lagi Filterdi aplikasi web Anda yang berjalan sebelum filter unggah file PrimeFaces dan telah melakukan RequestDispatcher#forward()panggilan. Biasanya, filter penulisan ulang URL seperti PrettyFaces melakukan ini. Ini memicu FORWARDpetugas operator, tetapi filter mendengarkan secara default REQUESThanya di petugas operator.

    Untuk memperbaikinya, Anda harus meletakkan filter unggah file PrimeFaces sebelum filter penerusan, atau untuk mengkonfigurasi ulang filter unggahan file PrimeFaces untuk mendengarkan di FORWARDoperator juga:

    <filter-mapping>
        <filter-name>primeFacesFileUploadFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    
  3. Ada yang bersarang <h:form>. Ini ilegal di HTML dan perilaku browser tidak ditentukan. Seringkali, browser tidak mengirimkan data yang diharapkan saat dikirim. Pastikan Anda tidak bersarang <h:form>. Ini sepenuhnya terlepas dari bentuknya enctype. Hanya saja, jangan bentuk sarang sama sekali.

Jika Anda masih mengalami masalah, lakukan debug pada lalu lintas HTTP. Buka toolset pengembang webbrowser (tekan F12 di Chrome / Firebug23 + / IE9 +) dan periksa bagian Net / Network. Jika bagian HTTP terlihat baik-baik saja, maka debug kode JSF. Letakkan breakpoint FileUploadRenderer#decode()dan maju dari sana.


Menyimpan file yang diunggah

Setelah Anda akhirnya berhasil, pertanyaan Anda berikutnya mungkin seperti "Bagaimana / di mana saya menyimpan file yang diunggah?". Nah, lanjutkan di sini: Cara menyimpan file yang diupload di JSF .

BalusC
sumber
2
Penyebab lain mungkin karena Anda tidak mendaftarkan filter unggahan PrimeFaces web.xmlsesuai Panduan Pengguna PrimeFaces. Apakah Anda tetap membacanya? Namun itu tidak akan menjelaskan mengapa mode="simple"berhasil untuk Anda.
BalusC
1
Ya, saya telah membacanya dan saya telah mendaftarkan filternya, tetapi saya baru menyadari bahwa itu memberi saya kesalahan saat memulai server "SEVERE: WebModule [/ EventsCalendary] PWC1270: Pengecualian memulai filter PrimeFaces FileUpload Filter" Saya merasa sangat bodoh karena tidak memperhatikannya sebelumnya. Adakah tips untuk mengatasi kesalahan ini?
Rodrigo Cavalcante
2
Mungkin pemetaan filter salah. Ini harus dipetakan pada salah <servlet-name>satu FacesServletseperti yang telah Anda definisikan web.xml. Ini secara default oleh sebagian besar IDE / generator kode Faces Servlet, tetapi bisa juga bagus facesServletatau sesuatu yang lebih mengkonfirmasi konvensi penamaan.
BalusC
2
Nevermind menyelesaikannya dengan menambahkan commons-fileupload ke classpath dan commons-io, apakah ada tempat yang mengatakan bahwa library ini diperlukan? Bagaimanapun, semuanya tampaknya berfungsi sekarang, metode ini dipanggil seperti yang seharusnya, terima kasih.
Rodrigo Cavalcante
1
Jadi semuanya muncul dengan situasi di mana saya menggunakan konfigurasi yang sama di TomEE dan JBoss .. forum.primefaces.org/viewtopic.php?f=3&t=43798
Dmitry Alexandrov
30

Anda menggunakan prettyfaces juga? Kemudian setel petugas operator ke MAJU:

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>
Reinaldo Gil
sumber
Ini masih menjadi masalah saat digunakan dengan OCP Rewrite. Aku berhutang budi padamu :)
Babl
7

Satu hal yang saya perhatikan dengan Primefaces 3.4 dan Netbeans 7.2:

Hapus parameter yang terisi otomatis Netbeans untuk fungsi handleFileUpload yaitu (event) jika tidak event bisa menjadi null.

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

sumber
2

Sepertinya javax.faces.SEPARATOR_CHAR tidak boleh sama dengan _

HazeHorizon
sumber
2
Bisakah Anda menjelaskan lebih lanjut?
Karl Richter
0

Saya memiliki masalah yang sama dengan primefaces 5.3 dan saya membahas semua poin yang dijelaskan oleh BalusC tanpa hasil. Saya mengikuti sarannya untuk men-debug FileUploadRenderer # decode () dan saya menemukan bahwa web.xml saya tidak disetel dengan benar

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

Nilai param harus 1 dari 3 nilai ini, tetapi tidak semuanya !! Seluruh bagian parameter konteks dapat dihapus dan defaultnya adalah otomatis

eric A
sumber
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

Pengajuan kelas publik @ViewSoped mengimplementasikan 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
sumber
Bisakah Anda menjelaskan mengapa ini adalah jawaban? Ini hanya kode, bukan penjelasan atau apapun
Kukeltje
"# {bean.uploadFile}" vs "# {bean.uploadFasta}", hapus update = "messages" dan itu akan (hanya) yang bekerja untuk saya!
romsky
0

Tak satu pun dari saran di sini yang bermanfaat bagi saya. Jadi saya harus men-debug primefaces dan menemukan alasan masalahnya adalah:

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

Kemudian saya telah menambahkan bagian ke servlet wajah saya di web.xml. Jadi itu telah memperbaiki masalahnya:

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

Saya memiliki masalah yang sama, karena fakta bahwa saya memiliki semua konfigurasi yang dijelaskan dalam posting ini, tetapi dalam kasus saya adalah karena saya memiliki dua impor jquery (salah satunya adalah kueri primefaces) yang menyebabkan konflik saat mengunggah file.

Lihat konflik Primefaces Jquery

Christian Altamirano Ayala
sumber
Bukankah Anda mendapatkan kesalahan khusus di konsol pengembang browser?
Kukeltje
@Kukeltje inilah yang ditunjukkan konsol: Uncaught TypeError: Object [object Object] tidak memiliki metode 'fileupload'
Christian Altamirano Ayala
0

Untuk orang yang menggunakan Tomee atau Tomcat dan tidak dapat membuatnya berfungsi, coba buat context.xml di META-INF dan tambahkan allowCasualMultipartParsing = "true"

<?xml version="1.0" encoding="UTF-8"?>
<Context allowCasualMultipartParsing="true">
  <!-- empty or not depending your project -->
</Context>
Xavier Lambros
sumber
Ini adalah solusi untuk konfigurasi / pemesanan filter yang salah.
BalusC
Hai @BalusC, bisakah Anda memberi kami penjelasan lebih lanjut? Apakah ada cara yang lebih baik daripada ini untuk mengatasi masalah ini?
Xavier Lambros
Lihat jawaban saya di pertanyaan ini.
BalusC
0

Dengan JBoss 7.2 (Undertow) dan PrimeFaces 6.0 org.primefaces.webapp.filter.FileUploadFilter harus dihapus dari web.xml dan pengunggah file parameter konteks harus disetel ke asli:

<context-param>
    <param-name>primefaces.UPLOADER</param-name>
    <param-value>native</param-value>
</context-param>
Alex D
sumber
Sebaiknya? Apakah Anda mendapatkan kesalahan khusus jika tidak?
Kukeltje
Ya, FileUploadEvent saya tidak dipanggil tanpa perubahan ini.
Alex D
Itu bukan kesalahan eksplisit, itu adalah perilaku yang tidak terduga
Kukeltje