Как использовать PrimeFaces p: fileUpload?Метод слушателя никогда не вызывается или UploadedFile имеет значение null / выдает ошибку / не используется - PullRequest
95 голосов
/ 16 января 2012

Я пытаюсь загрузить файл с помощью PrimeFaces, но метод fileUploadListener не вызывается после завершения загрузки.

Вот представление:

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

И боб:

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

}

Я установил точку останова на метод, но он никогда не вызывается.При использовании mode="simple" и ajax="false" он вызывается, но я хочу, чтобы он работал в расширенном режиме.Я использую Netbeans и Glassfish 3.1.

Ответы [ 9 ]

207 голосов
/ 16 января 2012

Как настроить и устранить неисправности <p:fileUpload> зависит от версии PrimeFaces.

Все версии PrimeFaces

Приведенные ниже требования относятся ко всем версиям PrimeFaces:

  1. Атрибут enctype <h:form> должен быть установлен в multipart/form-data. Когда это отсутствует, загрузка ajax может просто работать, но общее поведение браузера не определено и зависит от состава формы и производителя / версии веб-браузера. Просто всегда указывайте это, чтобы быть на безопасной стороне.

  2. При использовании mode="advanced" (т. Е. Ajax upload, это значение по умолчанию), затем убедитесь, что у вас есть <h:head> в (главном) шаблоне. Это обеспечит правильное включение необходимых файлов JavaScript. Это не требуется для mode="simple" (не-AJAX-загрузка), но это нарушит внешний вид и функциональность всех других компонентов PrimeFaces, так что вы все равно не пропустите это.

  3. При использовании mode="simple" (то есть без загрузки AJAX), ajax должен быть отключен на любых кнопках / ссылках команд PrimeFaces с помощью ajax="false", и вы должны использовать <p:fileUpload value> с <p:commandButton action> вместо <p:fileUpload fileUploadListener>.

Итак, если вы хотите (авто) загрузку файлов с поддержкой ajax (обратите внимание на <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!
}

Или, если вы хотите загрузить не-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!
}

Обратите внимание, что атрибуты, связанные с ajax, такие как auto, allowTypes, update, onstart, oncomplete и т. Д. игнорируются в mode="simple". Поэтому нет необходимости указывать их в таком случае.

Также обратите внимание, что вы должны немедленно прочитать содержимое файла внутри вышеупомянутых методов, а не в другом методе bean-компонента, вызванном более поздним HTTP-запросом. Это связано с тем, что содержимое загружаемого файла является областью действия запроса и, следовательно, недоступно для последующего / другого HTTP-запроса. Любая попытка прочитать его в более позднем запросе, скорее всего, закончится java.io.FileNotFoundException во временном файле.


PrimeFaces 5.x

Это не требует каких-либо дополнительных настроек, если вы используете JSF 2.2, а ваш faces-config.xml также объявлен как соответствующий JSF 2.2 версии. Вам вообще не нужен фильтр загрузки файлов PrimeFaces. Если вам непонятно, как правильно установить и настроить JSF в зависимости от используемого целевого сервера, перейдите к Как правильно установить и настроить библиотеки JSF через Maven? и раздел «Установка JSF» нашего Вики-страница JSF .

Если вы еще не используете JSF 2.2 и не можете его обновить (это должно быть легко, если вы уже находитесь в контейнере, совместимом с Servlet 3.0), вам необходимо вручную зарегистрировать указанный ниже фильтр загрузки файлов PrimeFaces в web.xml (он проанализирует запрос нескольких частей и заполнит карту параметров обычного запроса, чтобы FacesServlet мог продолжать работать как обычно):

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

Значение <servlet-name> facesServlet должно точно соответствовать значению в записи <servlet> javax.faces.webapp.FacesServlet в том же web.xml. Так что, если это, например, Faces Servlet, тогда вам нужно отредактировать его соответствующим образом.


PrimeFaces 4.x

Та же история, что и в PrimeFaces 5.x, применима и к 4.x.

Существует только потенциальная проблема с получением загруженного содержимого файла с помощью UploadedFile#getContents(). Это вернет null, если вместо Apache Commons FileUpload используется собственный API. Вам нужно использовать UploadedFile#getInputStream() вместо этого. См. Также Как вставить загруженное изображение из p: fileUpload как BLOB в MySQL?

Другая потенциальная проблема с нативным API проявится в том случае, когда компонент загрузки присутствует в форме, в которой запускается другой «обычный» запрос ajax, который не обрабатывает компонент загрузки. См. Также Загрузка файлов не работает с AJAX в PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: тип содержимого запроса не является multipart / form-data .

Обе проблемы также можно решить, переключившись на Apache Commons FileUpload. Подробности см. В разделе PrimeFaces 3.x.


PrimeFaces 3.x

Эта версия не поддерживает загрузку собственных файлов JSF 2.2 / Servlet 3.0. Вам необходимо вручную установить Apache Commons FileUpload и явно зарегистрировать фильтр загрузки файлов в web.xml.

Вам нужны следующие библиотеки:

Они должны присутствовать в пути к классам веб-приложения. При использовании Maven убедитесь, что они как минимум ограничены областью выполнения (область компиляции по умолчанию также хороша). При переноске JAR вручную убедитесь, что они находятся в папке /WEB-INF/lib.

Подробности регистрации фильтра загрузки файлов можно найти в разделе PrimeFaces 5.x здесь выше. Если вы используете PrimeFaces 4+ и хотите явно использовать Apache Commons FileUpload вместо загрузки собственных файлов JSF 2.2 / Servlet 3.0, то вам нужно рядом с упомянутыми библиотеками и отфильтровать также следующий контекстный параметр в web.xml :

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

Устранение неполадок

Если это все еще не работает, вот еще одна возможная причина, не связанная с конфигурацией PrimeFaces:

  1. Только если вы используете фильтр загрузки файлов PrimeFaces: в вашем веб-приложении есть еще один Filter, который запускает до фильтра загрузки файлов PrimeFaces и уже использует тело запроса, например, звонит getParameter(), getParameterMap(), getReader() и так далее. Тело запроса может быть проанализировано только один раз. Когда вы вызываете один из этих методов до того, как фильтр загрузки файлов выполнит свою работу, фильтр загрузки файлов получит пустое тело запроса.

    Чтобы это исправить, вам нужно поставить <filter-mapping> фильтра загрузки файлов перед другим фильтром в web.xml. Если запрос не является запросом multipart/form-data, тогда фильтр загрузки файлов продолжит работу, как будто ничего не произошло. Если вы используете фильтры, которые добавляются автоматически, потому что они используют аннотации (например, PrettyFaces), вам может потребоваться добавить явное упорядочение через web.xml. См. Как определить порядок выполнения фильтра сервлетов с использованием аннотаций в WAR

  2. Только если вы используете фильтр загрузки файлов PrimeFaces: в вашем веб-приложении есть еще один Filter, который запускает до фильтра загрузки файлов PrimeFaces и выполнил RequestDispatcher#forward() звонок. Обычно это делают фильтры перезаписи URL, например PrettyFaces . Это вызывает диспетчер FORWARD, но фильтры по умолчанию прослушивают только диспетчер REQUEST.

    Чтобы это исправить, вам нужно либо установить фильтр загрузки файлов PrimeFaces перед фильтром пересылки, либо перенастроить фильтр загрузки файлов PrimeFaces для прослушивания диспетчера FORWARD:

    <filter-mapping>
        <filter-name>primeFacesFileUploadFilter</filter-name>
        <servlet-name>facesServlet</servlet-name>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
    </filter-mapping>
    
  3. Есть вложенное <h:form>. Это недопустимо в HTML, и поведение браузера не определено. Более часто браузер не будет отправлять ожидаемые данные при отправке. Убедитесь, что вы не вкладываете <h:form>. Это полностью независимо от формы enctype. Просто не вкладывайте формы вообще.

Если проблемы не устранены, отладьте HTTP-трафик. Откройте набор инструментов разработчика веб-браузера (нажмите F12 в Chrome / Firebug23 + / IE9 +) и проверьте раздел Сеть / Сеть. Если часть HTTP выглядит нормально, отладьте код JSF. Установите точку останова на FileUploadRenderer#decode() и продвигайтесь оттуда.


Сохранение загруженного файла

После того, как вы, наконец, заставите его работать, ваш следующий вопрос, вероятно, будет таким: «Как / где мне сохранить загруженный файл?». Ну, продолжайте здесь: Как сохранить загруженный файл в формате JSF .

30 голосов
/ 01 февраля 2012

Вы тоже используете симпатичные лица?Затем установите диспетчер на FORWARD:

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>
6 голосов
/ 01 ноября 2012

Одна вещь, которую я заметил с Primefaces 3.4 и Netbeans 7.2:

Удалите автоматически заполненные параметры Netbeans для функции handleFileUpload, т. Е. (Событие), иначе событие может быть нулевым.

<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>
2 голосов
/ 28 февраля 2014

Похоже, javax.faces.SEPARATOR_CHAR не должен быть равен _

0 голосов
/ 13 февраля 2019

Для тех, кто использует Tomee или Tomcat и не может заставить их работать, попробуйте создать context.xml в META-INF и добавить allowCasualMultipartParsing = "true"

<?xml version="1.0" encoding="UTF-8"?>
<Context allowCasualMultipartParsing="true">
  <!-- empty or not depending your project -->
</Context>
0 голосов
/ 05 октября 2017

У меня была та же проблема, из-за того, что у меня были все настройки, описанные в этом посте, но в моем случае это было из-за того, что у меня было два импорта jquery (один из них был запросом Primefaces), что вызывало конфликты при загрузке файлов.

См. Конфликт JQuery Primefaces

0 голосов
/ 28 июля 2017

Ни одно из предложений здесь не помогло мне.Поэтому я должен был отладить основные лица и обнаружил, что причина проблемы:

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

Затем я добавил раздел в свой сервлет Faces в файле web.xml.Итак, это решило проблему:

<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 голосов
/ 16 мая 2017

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 реализует Сериализуемый {

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>
0 голосов
/ 05 января 2017

У меня была та же проблема с простыми лицами 5.3, и я прошел все пункты, описанные BalusC, но безрезультатно.Я последовал его совету по отладке FileUploadRenderer # decode () и обнаружил, что мой web.xml был неправильно установлен

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

Параметр-значение должно быть 1 из этих 3 значений, но не все из них!! Весь раздел context-param может быть удален и по умолчанию будет auto

...