web-dev-qa-db-ja.com

PrimeFaces p:fileUploadの使用方法は?リスナーメソッドが呼び出されない、またはUploadedFileがnullである/エラーをスローする/使用できない

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>

そして、Bean:

@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を使用しています。

96

<p:fileUpload>の設定およびトラブルシューティングの方法は、PrimeFacesのバージョンによって異なります。

すべてのPrimeFacesバージョン

以下の要件は、すべてのPrimeFacesバージョンに適用されます。

  1. <h:form>enctype属性をmultipart/form-dataに設定する必要があります。これが存在しない場合、ajaxアップロードは正常に機能する可能性がありますが、一般的なブラウザーの動作は指定されておらず、フォームの構成とWebブラウザーのメーカー/バージョンに依存します。常に安全な側に指定するだけです。

  2. mode="advanced"を使用する場合(つまり、ajaxアップロード、これがデフォルトです)、(マスター)テンプレートに<h:head>があることを確認してください。これにより、必要なJavaScriptファイルが適切に含まれるようになります。これはmode="simple"(非ajaxアップロード)には必要ありませんが、これは他のすべてのPrimeFacesコンポーネントのルックアンドフィールと機能を損なうため、とにかく見逃したくないでしょう。

  3. mode="simple"を使用する場合(つまり、ajax以外のアップロード)、ajax="false"によるPrimeFacesコマンドボタン/リンクでajaxを無効にする必要があります。また、<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!
}

autoallowTypesupdateonstartoncompleteなどのajax関連の属性はであることに注意してください。 mode="simple"のignore。したがって、そのような場合にそれらを指定する必要はありません。

また、後のHTTPリクエストによって呼び出される別のBeanメソッドではなく、上記のメソッド内でファイルの内容をすぐに読み取る必要があることに注意してください。これは、アップロードされたファイルのコンテンツがリクエストスコープであるため、後で/異なるHTTPリクエストで使用できないためです。後のリクエストでそれを読み取ろうとすると、ほとんどの場合、一時ファイルでJava.io.FileNotFoundExceptionになります。


PrimeFaces 5.x

JSF 2.2を使用しており、faces-config.xmlもJSF 2.2バージョンに準拠していると宣言されている場合、追加の設定は必要ありません。 PrimeFacesファイルアップロードフィルターはまったく必要ありません。使用するターゲットサーバーに応じてJSFを適切にインストールおよび構成する方法が不明な場合は、 Mavenを介してJSFライブラリを適切にインストールおよび構成する方法 および 「JSFのインストール」セクションに進んでくださいJSF wikiページの

ただし、JSF 2.2をまだ使用しておらず、アップグレードできない場合(サーブレット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>

facesServlet<servlet-name>値は、同じ<servlet>javax.faces.webapp.FacesServletweb.xmlエントリの値と正確に一致する必要があります。たとえば、それがFaces Servlet、次に一致するように編集する必要があります。


PrimeFaces 4.x

PrimeFaces 5.xと同じ話が4.xにも当てはまります。

UploadedFile#getContents()によるアップロードされたファイルコンテンツの取得には、潜在的な問題のみがあります。これは、Apache Commons FileUploadの代わりにネイティブAPIが使用される場合、nullを返します。代わりにUploadedFile#getInputStream()を使用する必要があります。 MySQLでp:fileUploadからアップロードされたイメージをBLOBとして挿入する方法? も参照してください。

ネイティブAPIの別の潜在的な問題は、アップロードコンポーネントが、アップロードコンポーネントを処理しない別の「通常の」ajaxリクエストが起動されるフォームに存在する場合に現れます。 PrimeFaces 4.0/JSF 2.2.xのAJAXでファイルのアップロードが機能しない-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にファイルアップロードフィルターを明示的に登録する必要があります。

次のライブラリが必要です。

これらはwebappのランタイムクラスパスに存在する必要があります。 Mavenを使用するときは、少なくともランタイムスコープであることを確認してください(コンパイルのデフォルトスコープも適切です)。 JARを手動で持ち歩く場合は、/WEB-INF/libフォルダーに配置するようにしてください。

ファイルアップロードフィルター登録の詳細は、上記のPrimeFaces 5.xセクションにあります。 PrimeFaces 4+を使用していて、JSF 2.2/Servlet 3.0ネイティブファイルアップロードの代わりにApache Commons FileUploadを明示的に使用する場合は、前述のライブラリの横にある、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ファイルアップロードフィルターを使用している場合のみ:before PrimeFacesファイルアップロードフィルターを実行し、リクエストボディを既に消費しているWebアプリケーションに別のFilterがあります。 getParameter()getParameterMap()getReader()などの呼び出し。要求本文は1回しか解析できません。ファイルアップロードフィルターがジョブを実行する前にこれらのメソッドのいずれかを呼び出すと、ファイルアップロードフィルターは空の要求本文を取得します。

    これを修正するには、ファイルアップロードフィルターの<filter-mapping>を追加する必要がありますbefore他のフィルターをweb.xmlに追加します。リクエストがmultipart/form-dataリクエストでない場合、ファイルアップロードフィルターは、何も起こらなかったかのように続行します。アノテーション(PrettyFacesなど)を使用するために自動的に追加されるフィルターを使用する場合、web.xmlを介して明示的な順序を追加する必要があります。 WARの注釈を使用してサーブレットフィルターの実行順序を定義する方法 を参照してください。

  2. PrimeFacesファイルアップロードフィルターを使用している場合のみ:before PrimeFacesファイルアップロードフィルターを実行し、 RequestDispatcher#forward() 呼び出しを実行する別のFilterがWebアプリにあります。通常、 PrettyFaces などのURL書き換えフィルターはこれを行います。これはFORWARDディスパッチャーをトリガーしますが、フィルターはデフォルトでREQUESTディスパッチャーでのみリッスンします。

    これを修正するには、PrimeFacesファイルアップロードフィルターbefore転送フィルターを配置するか、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トラフィックをデバッグしてください。 Webブラウザーの開発者ツールセットを開き(Chrome/Firebug23 +/IE9 +でF12を押します)、Net/Networkセクションを確認します。 HTTP部分が正常に見える場合は、JSFコードをデバッグします。 FileUploadRenderer#decode() にブレークポイントを設定し、そこから先に進みます。


アップロードしたファイルを保存する

最終的に機能するようになったら、次の質問は「アップロードされたファイルをどのように/どこに保存しますか?」のようなものになるでしょう。さて、ここから続けてください: JSFにアップロードされたファイルを保存する方法

211
BalusC

あなたもprettyfacesを使用していますか?次に、ディスパッチャをFORWARDに設定します。

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

Primefaces 3.4とNetbeans 7.2で気付いた1つのポイント:

関数handleFileUploadのNetbeans自動入力パラメータを削除します。つまり、(イベント)そうでない場合、イベントは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>
6
user1791617

Javax.faces.SEPARATOR_CHARは_と等しくてはいけないようです

2
HazeHorizon

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>

param-valueはこれら3つの値のうちの1つである必要がありますが、すべてではありません!! context-paramセクション全体を削除でき、デフォルトはauto

0
eric A

ここでの提案はどちらも役に立たなかった。だから私はprimefacesをデバッグする必要があり、問題の理由は次のとおりであることがわかりました。

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

次に、web.xmlのFacesサーブレットにセクションを追加しました。それで問題は修正されました:

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

この投稿で説明するすべての構成を持っているという事実のため、私は同じ問題を抱えていましたが、私の場合は、ファイルをアップロードする競合を引き起こす2つのjqueryインポート(そのうちの1つはprimefacesのクエリでした)があるためでした.

Primefaces Jquery conflictを参照

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>

TomeeまたはTomcatを使用して動作しない場合は、context.xmlMETA-INFに作成して追加してみてくださいallowCasualMultipartParsing = "true"

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