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

101

Я пытаюсь загрузить файл с помощью 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.

Родриго Кавальканте
источник

Ответы:

226

Способ настройки и устранения неполадок <p:fileUpload>зависит от версии PrimeFaces.

Все версии PrimeFaces

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

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

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

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

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

Или, если вы хотите загрузить файл без использования 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 8.x

Конфигурация идентична информации о версии 5.x ниже, но если ваш слушатель не вызывается, проверьте, вызывается ли attriubute, listenerа не (как в версиях до 8.x)fileUploadListener

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 +) и проверьте раздел Net / Network. Если часть HTTP выглядит нормально, отладьте код JSF. Установите точку останова FileUploadRenderer#decode()и двигайтесь дальше .


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

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

BalusC
источник
2
Другой причиной может быть то, что вы не зарегистрировали фильтр загрузки PrimeFaces в web.xmlсоответствии с Руководством пользователя PrimeFaces. Вы все равно это читали? Однако это не объясняет, почему mode="simple"работает для вас.
BalusC
1
Да, я прочитал его и зарегистрировал фильтр, но только что заметил, что он выдает ошибку при запуске сервера "SEVERE: WebModule [/ EventsCalendary] PWC1270: Exception start filter PrimeFaces FileUpload Filter" Я чувствую себя таким глупым, потому что не заметив это раньше. Какие-нибудь советы по устранению этой ошибки?
Родриго Кавальканте
2
Возможно, отображение фильтра неверно. Она должна быть отображена на <servlet-name>из , FacesServletкак вы определяемые в web.xml. По умолчанию большинство IDE / генераторов кода Faces Servlet, но это может быть так же хорошо facesServletили что-то еще, что больше подтверждает соглашения об именах.
BalusC
2
Nevermind решил это, добавив commons-fileupload в путь к классам и commons-io, есть ли где-нибудь, что эти библиотеки необходимы? Во всяком случае, сейчас вроде все работает, метод вызывается, как и положено, спасибо.
Родриго Кавальканте
1
В итоге получилось, что я использую одну и ту же конфигурацию в TomEE и JBoss .. forum.primefaces.org/viewtopic.php?f=3&t=43798
Дмитрий Александров
30

Ты тоже пользуешься симпатичными лицами? Затем установите диспетчер на ВПЕРЕД:

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>
Рейнальдо Хиль
источник
Это все еще проблема при использовании с OCP Rewrite. Я должен тебе пива :)
Babl
7

Один момент, который я заметил с Primefaces 3.4 и Netbeans 7.2:

Удалите автоматически заполняемые параметры Netbeans для функции handleFileUpload, т.е. (событие), в противном случае событие может иметь значение 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>

источник
2

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

ДымкаГоризонт
источник
2
Не могли бы вы уточнить, пожалуйста ?!
Карл Рихтер
0

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

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

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

Эрик А
источник
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 Открытый класс Submission реализует 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>
Вальдейр Мендес да Силва
источник
Вы можете объяснить, почему это ответ? Это всего лишь код, а не объяснение или что-то в этом
роде
"# {bean.uploadFile}" против "# {bean.uploadFasta}", удалите update = "messages", и это будет (только), что работает для меня!
romsky
0

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

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

Затем я добавил раздел в свой сервлет лиц в файле 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

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

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

Кристиан Альтамирано Аяла
источник
Разве вы тогда не получили конкретную ошибку в консоли разработчика браузера?
Kukeltje 05
@Kukeltje, вот что показала консоль: Uncaught TypeError: Object [object Object] не имеет метода fileupload
Кристиан Альтамирано Айала
0

Если вы используете 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>
Ксавье Ламброс
источник
Это обходной путь из-за неправильной конфигурации / порядка фильтра.
BalusC
Привет @BalusC, не могли бы вы дать нам больше объяснений? Есть ли лучший способ, чем эта работа?
Xavier Lambros
Смотрите мой ответ в этом вопросе.
BalusC
0

С JBoss 7.2 (Undertow) и PrimeFaces 6.0 org.primefaces.webapp.filter.FileUploadFilter должен быть удален из web.xml, а загрузчик файла контекстных параметров должен быть установлен на собственный:

<context-param>
    <param-name>primefaces.UPLOADER</param-name>
    <param-value>native</param-value>
</context-param>
Alex D
источник
Должен? Получаете ли вы конкретные ошибки, если нет?
Kukeltje
Да, мой FileUploadEvent не запускается без этих изменений.
Alex D
Это не явная ошибка, это неожиданное поведение
Kukeltje