Как настроить и устранить неисправности <p:fileUpload>
зависит от версии PrimeFaces.
Все версии PrimeFaces
Приведенные ниже требования относятся ко всем версиям PrimeFaces:
Атрибут enctype
<h:form>
должен быть установлен в multipart/form-data
. Когда это отсутствует, загрузка ajax может просто работать, но общее поведение браузера не определено и зависит от состава формы и производителя / версии веб-браузера. Просто всегда указывайте это, чтобы быть на безопасной стороне.
При использовании mode="advanced"
(т. Е. Ajax upload, это значение по умолчанию), затем убедитесь, что у вас есть <h:head>
в (главном) шаблоне. Это обеспечит правильное включение необходимых файлов JavaScript. Это не требуется для mode="simple"
(не-AJAX-загрузка), но это нарушит внешний вид и функциональность всех других компонентов PrimeFaces, так что вы все равно не пропустите это.
При использовании 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:
Только если вы используете фильтр загрузки файлов PrimeFaces: в вашем веб-приложении есть еще один Filter
, который запускает до фильтра загрузки файлов PrimeFaces и уже использует тело запроса, например, звонит getParameter()
, getParameterMap()
, getReader()
и так далее. Тело запроса может быть проанализировано только один раз. Когда вы вызываете один из этих методов до того, как фильтр загрузки файлов выполнит свою работу, фильтр загрузки файлов получит пустое тело запроса.
Чтобы это исправить, вам нужно поставить <filter-mapping>
фильтра загрузки файлов перед другим фильтром в web.xml
. Если запрос не является запросом multipart/form-data
, тогда фильтр загрузки файлов продолжит работу, как будто ничего не произошло. Если вы используете фильтры, которые добавляются автоматически, потому что они используют аннотации (например, PrettyFaces), вам может потребоваться добавить явное упорядочение через web.xml. См. Как определить порядок выполнения фильтра сервлетов с использованием аннотаций в WAR
Только если вы используете фильтр загрузки файлов 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>
Есть вложенное <h:form>
. Это недопустимо в HTML, и поведение браузера не определено. Более часто браузер не будет отправлять ожидаемые данные при отправке. Убедитесь, что вы не вкладываете <h:form>
. Это полностью независимо от формы enctype
. Просто не вкладывайте формы вообще.
Если проблемы не устранены, отладьте HTTP-трафик. Откройте набор инструментов разработчика веб-браузера (нажмите F12 в Chrome / Firebug23 + / IE9 +) и проверьте раздел Сеть / Сеть. Если часть HTTP выглядит нормально, отладьте код JSF. Установите точку останова на FileUploadRenderer#decode()
и продвигайтесь оттуда.
Сохранение загруженного файла
После того, как вы, наконец, заставите его работать, ваш следующий вопрос, вероятно, будет таким: «Как / где мне сохранить загруженный файл?». Ну, продолжайте здесь: Как сохранить загруженный файл в формате JSF .