[英]How can I upload multiple files with JSF 2.2
我正在嘗試使用h:inputFile
添加多個文件上傳。 我快速瀏覽了源代碼,似乎它沒有渲染multiple="multiple"
的選項。 有沒有辦法在不編寫自定義組件的情況下解決這個問題? 如果沒有,是否有建議的自定義 JSF2.2 組件可以處理多個 Ajax 文件上傳?
更新:我已經使用passthrough
標記傳遞了multiple="multiple"
,但是當我調試FileRenderer
時,相關的代碼會用第二個文件覆蓋第一個文件:
for (Part cur : parts) {
if (clientId.equals(cur.getName())) {
component.setTransient(true);
setSubmittedValue(component, cur);
}
}
如您所見,由於有兩個Part
具有相同的clientId
,它總是使用最后一個而不是傳遞一個列表。
如果有,請推薦一個替代方案。
如何使用JSF 2.2上傳多個文件
您確實可以使用另一個JSF 2.2功能實現此功能: 直通屬性 。 將multiple
屬性設置為passthrough屬性( 瀏覽器支持目前相當廣泛 )。
<html ... xmlns:a="http://xmlns.jcp.org/jsf/passthrough">
...
<h:inputFile ... a:multiple="true" />
但是, <h:inputFile>
組件本身不支持從請求中獲取多個Part
並將其設置為數組或Collection
bean屬性。 它只會設置與輸入字段名稱匹配的最后一部分。 基本上,為了支持多個部分,需要創建一個自定義渲染器(您應該立即利用這個機會立即支持multiple
屬性而不依賴於passthrough屬性)。
為了在不創建整個渲染器的情況下使用“變通方法”,您可以通過以下小實用程序方法通過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;
}
請注意,為了安全和清晰 ,getter可以更好地返回null
。 實際上,整個getter方法應該是不必要的,但它就是這樣。
在更現代的瀏覽器上,您甚至可以選擇整個文件夾。 這只需要一個更新的directory
屬性。 從Firefox 46開始支持此功能(自42以來,但需要在about:config中明確啟用)。 基於Webkit的瀏覽器(Chrome 11 +,Safari 4+和Edge)通過專有的webkitdirectory
屬性支持此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
我認為使用passthrough標簽使用標准JSF 2.2可以使用多個文件上傳。
<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" />
...
javax.faces.Input
系列組件的javax.faces.File
類型的JSF渲染器類FileRenderer無法正確處理此情況。
相反,當它遍歷表單的各個部分時,它只是用上傳集合中的每個文件覆蓋前一部分。
我認為,一個更好的策略是總是有分量的值是一個List<Part>
,而不僅僅是Part
的建議在這里和實施在這里 。
使其工作的最后一件事是在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>
即使是很久以前:考慮到你自己的評論,我會推薦像PrimeFaces fileUploadMultiple這樣的組件,提到不要忘記web.xml
所需的更改以及所有需要上傳的庫。 根據您的需求,將其視為變通方法或完整解決方案。 PrimeFaces是一個相當不錯的組件庫
由於這個問題是很久以前提出的,我想在這里提供更新。 如果您正在使用新的Jakarta EE Faces 4.0規范,那么支持多個文件上傳將變得非常簡單:
如前所述, h:from
必須使用 enctype "multipart/form-data"
進行擴展。 而h:inputFile
需要 passthrough 屬性multiple=true
:
<ui:composition template="/WEB-INF/templates/layout.xhtml"
xmlns:faces="jakarta.faces" xmlns:f="jakarta.faces.core"
xmlns:h="jakarta.faces.html" xmlns:ui="jakarta.faces.facelets"
xmlns:pt="jakarta.faces.passthrough">
<f:view>
<h:form id="models_form_id" enctype="multipart/form-data">
.....
<h:inputFile id="file" value="#{myBean.files}" pt:multiple="true"/>
....
<h:commandButton id="submit" value="Submit" action="#{myBean.submit}" />
</h:form>
</f:view>
</ui:composition>
您的 bean 代碼只需要支持 'files' 屬性作為jakarta.servlet.http.Part
元素的列表:
@Named
@RequestScoped
public class MyBean implements Serializable {
private List<Part> files;
public List<Part> getFiles() {
return files;
}
public void setFiles(List<Part> files) {
this.files = files;
}
public void submit() throws IOException {
if (files != null) {
System.out.println(" uploading " + files.size() + " files");
for (Part file : files) {
System.out.println("name: " + file.getSubmittedFileName());
System.out.println("type: " + file.getContentType());
System.out.println("size: " + file.getSize());
InputStream content = file.getInputStream();
// Write content to disk or DB.
}
}
}
}
....
而已。 現在,您可以將上傳的文件作為表單中的任何其他數據進行處理。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.