Як використовувати PrimeFaces p: fileUpload? Метод слухача ніколи не викликається, або UploadedFile недійсний / видає помилку / не використовується


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.

Відповіді:


224

<p:fileUpload>Налаштування та усунення несправностей залежить від версії PrimeFaces.

Усі версії PrimeFaces

Наведені нижче вимоги стосуються всіх версій PrimeFaces:

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

  2. Під час використання mode="advanced"(тобто завантаження ajax, це за замовчуванням), тоді переконайтеся, що ви маєте <h:head>в (головний) шаблон. Це забезпечить належне включення необхідних файлів JavaScript. Це не потрібно для mode="simple"(не-ajax завантаження), але це порушить look'n'feel та функціональність усіх інших компонентів 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, але якщо ваш слухач не викликається, перевірте, чи викликається атрибуту, 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 використовується файловий API. Вам потрібно використовувати UploadedFile#getInputStream()замість цього. Див. Також Як вставити завантажене зображення з p: fileUpload як BLOB в MySQL?

Інша потенційна проблема з нативним API виявиться в тому випадку, коли компонент завантаження присутній у формі, в якій запускається інший "звичайний" запит ajax, який не обробляє компонент завантаження. Дивіться також Завантаження файлів не працює з AJAX у PrimeFaces 4.0 / JSF 2.2.x - javax.servlet.ServletException: Тип вмісту запиту не є багаточастинним / формою-даними .

Обидві проблеми також можна вирішити, перейшовши на 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 .


2
Іншою причиною може бути те, що ви не зареєстрували фільтр завантаження PrimeFaces web.xmlвідповідно до Посібника користувача PrimeFaces. Ви все-таки це прочитали? Однак це не пояснює, чому mode="simple"працює для вас.
BalusC

1
Так, я прочитав його, і я зареєстрував фільтр, але я просто помітив, що він дає мені помилку під час запуску сервера "СЕВЕР: WebModule [/ EventsCalendary] PWC1270: Виняток запускає фільтр PrimeFaces FileUpload Filter" Я відчуваю себе так німим, що не помічаючи це раніше. Якісь поради щодо вирішення цієї помилки?
Родріго Кавалканте

2
Можливо, відображення фільтра неправильне. Він повинен бути відображений на <servlet-name>тому, FacesServletяк ви визначилися в web.xml. Більшість IDE / генераторів коду за замовчуванням Faces Servletпризначає, але це може бути настільки ж добре facesServletабо щось, що більше підтверджує умови іменування.
BalusC

2
Nevermind вирішив це, додавши commons-fileupload до classpath та commons-io, чи є де-небудь сказане, що ці бібліотеки потрібні? У будь-якому випадку, здається, все працює зараз, метод називається так, як і слід було, дякую.
Родріго Кавалканте

1
Отже, все склалося з ситуацією, коли я перетворюю той самий конфігуратор у TomEE та JBoss .. forum.primefaces.org/viewtopic.php?f=3&t=43798
Дмитро Олександров

30

Ви також використовуєте доситьfaceface? Потім встановіть диспетчера вперед:

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

Це все ще проблема, коли використовується з OCP Rewrite. Я завдячую вам пивом :)
Бабл,

7

Один момент я помітив у 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>


0

У мене була така ж проблема з версіями 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 значень, але не всі вони !! Весь розділ контексту-парами можна видалити, а за замовчуванням буде автоматично


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 публічний клас реалізує програму 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>

Чи можете ви пояснити, чому це відповідь? Це лише код, а не пояснення чи що завгодно
Kukeltje

"# {bean.uploadFile}" vs "# {bean.uploadFasta}", видаліть update = "повідомлення", і це (тільки) працює для мене!
ромський

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 (один з них був запитом для прем'єрфейсів), що спричинило конфлікти для завантаження файлів.

Дивіться конфлікт Jquery Primefaces


Тоді ви не отримали певної помилки в консолі розробника браузера?
Кукельтьє

@Kukeltje ось що показала консоль: Uncaught TypeError: У Object [object Object] немає методу 'fileupload'
Christian Altamirano Ayala

0

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

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

Це обхід для неправильної конфігурації / замовлення фільтра.
BalusC

Привіт @BalusC, ти можеш дати нам більше пояснень? Чи є кращий спосіб, ніж ця робота?
Ксав'є Ламброс

Дивіться мою відповідь у цьому питанні.
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>

Повинен? Ви отримуєте конкретні помилки, якщо цього не робите?
Кукельттьє

Так, мій FileUploadEvent не посилається без цих змін.
Олексій Д

Це не явна помилка, тобто несподівана поведінка
Kukeltje
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.