14

を使用して複数ファイルのアップロードを追加しようとしていますh:inputFile。ソースコードをざっと見てみたところ、レンダリングするオプションがないようmultiple="multiple"です。カスタム コンポーネントを作成せずにこれを回避する方法はありますか? そうでない場合、複数の Ajax ファイルのアップロードを処理できるカスタム JSF2.2 コンポーネントの提案はありますか?

更新: multiple="multiple"usingpassthroughタグを渡しましたがFileRenderer、関連するコードをデバッグすると、最初のファイルが 2 番目のファイルで上書きされます。

for (Part cur : parts) {
  if (clientId.equals(cur.getName())) {
    component.setTransient(true);
    setSubmittedValue(component, cur);
  }
}

ご覧のとおりPart、同じ を持つが 2 つあるclientIdため、リストを渡す代わりに常に最後のものを使用します。

代替案があればお勧めをお願いします。

4

3 に答える 3

14

JSF 2.2で複数のファイルをアップロードするにはどうすればよいですか

確かに、別の JSF 2.2 機能であるpassthrough attributesを使用してこれを実現できます。multiple属性をパススルー属性として設定します (ブラウザのサポートは現在非常に広範です)。

<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:inputFile ... a:multiple="true" />

ただし、コンポーネント自体は、リクエストから複数の を取得して配列またはBean プロパティとして設定することを<h:inputFile>サポートしていません。入力フィールド名に一致する最後の部分のみを設定します。基本的に、複数のパーツをサポートするには、カスタム レンダラーを作成する必要があります (パススルー属性に頼らずに、すぐに属性をサポートする機会を利用する必要があります)。PartCollectionmultiple

ただし、レンダラー全体を作成せずに「回避策」を講じるHttpServletRequestために、以下の小さなユーティリティ メソッドを使用してすべてのパーツを手動で取得できます。

public static Collection<Part> getAllParts(Part part) throws ServletException, IOException {
    HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
    return request.getParts().stream().filter(p -> part.getName().equals(p.getName())).collect(Collectors.toList());
}

したがって、以下の構成は上記のユーティリティ メソッドで動作するはずです。

<h:inputFile value="#{bean.part}" a:multiple="true" />
<h:commandButton ... action="#{bean.submit}" />

private Part file;

public void submit() throws ServletException, IOException {
    for (Part part : getAllParts(file)) {
        String fileName = part.getSubmittedFileName();
        InputStream fileContent = part.getInputStream();
        // ... 
        // Do your thing with it.
        // E.g. https://stackoverflow.com/q/14211843/157882
    }
}

public Part getFile() {
    return null; // Important!
}

public void setFile(Part file) {
    this.file = file;
}

安全性と明確さのために、ゲッターは常に return を返すことができることに注意してくださいnull。実際には、getter メソッド全体が不要なはずですが、実際にはそうです。

最新のブラウザーでは、フォルダー全体を選択することもできます。これには、さらに新しいdirectory属性のみが必要です。これは Firefox 46 以降でサポートされています (すでに 42 以降ですが、about:config で明示的に有効にする必要があります)。Webkit ベースのブラウザー (Chrome 11 以降、Safari 4 以降、および Edge) は、独自のwebkitdirectory属性を介してこれをサポートします。したがって、両方の属性を指定すると、通常は安全です。

<h:inputFile ... a:multiple="true" a:directory="true" a:webkitdirectory="true" />

これは物理フォルダーではなく、それらのフォルダーに含まれるファイルのみを送信することに注意してください。


更新: JSF ユーティリティ ライブラリOmniFacesを使用している場合は、バージョン 2.5 以降、<o:inputFile>複数のディレクトリの選択が面倒でなくなるはずの が提供されています。

<o:inputFile value="#{bean.files}" multiple="true" />

<o:inputFile value="#{bean.files}" directory="true" />

値は にバインドできますList<Part>

private List<Part> files; // +getter+setter
于 2016-04-08T15:12:42.320 に答える
1

標準のJSF 2.2でパススルータグを使って複数ファイルアップロードができると思います。

ステップ1:

<html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  xmlns:pt="http://xmlns.jcp.org/jsf/passthrough">
...

<h:form id="form" enctype="multipart/form-data">
    <h:inputFile id="file" value="#{fileUploadBean.uploadedFile}" pt:multiple="multiple" />
    ...

ステップ2:

コンポーネント ファミリのタイプの JSF レンダラー クラスFileRendererは、このケースを正しく処理しません。javax.faces.Filejavax.faces.Input

代わりに、フォームのパーツを反復処理するときに、アップロードされたコレクション内の各ファイルで前のパーツを上書きするだけです。

より良い戦略は、ここで提案され、ここで実装されるのではList<Part>なく、コンポーネントの値を常に a にすることだと思いますPart

ステップ 3:

それを機能させる最後のことは、ルート要素faces-config.xmlに以下を追加して、そのような変更された複数ファイル レンダラー クラスを構成することです。<faces-config>

<render-kit>
    <renderer>
        <description>Multiple File Renderer</description>
        <component-family>javax.faces.Input</component-family>
        <renderer-type>javax.faces.File</renderer-type>
        <renderer-class>com.example.MultipleFileRenderer</renderer-class>
    </renderer>
</render-kit>
于 2013-09-18T05:54:27.867 に答える