本文介绍了如何使用JSF 2.2上传多个文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用 h:inputFile 添加多个文件上传。我对源代码进行了快速浏览,看起来它没有提供 multiple =multiple的选项。有没有写一个自定义组件的方法呢?
如果没有,是否有一个可以处理多个Ajax文件上传的建议自定义JSF2.2组件?



更新:
我已经通过 multiple =multiple使用 passthrough 标记,但是当我调试 FileRenderer 相关的一段代码用第二个代码覆盖第一个文件:

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






$ b您可以看到,由于有两个部分具有相同的 clientId ,它总是使用最后一个而不是传递一个列表。



请推荐一个替代品。

解决方案

与另一个JSF 2.2功能:。设置 >)。

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

然而,< h:inputFile> 组件本身不支持从请求中抓取多个 Part c>,并将其设置为数组或 Collection bean属性。它只会设置匹配输入字段名称的最后一部分。基本上,为了支持多个部分,需要创建一个自定义的渲染器(并且您应该马上利用这个机会立即支持多个属性,而不诉诸直通属性)。

为了在不创建整个渲染器的情况下拥有解决方法,您可以通过 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());





$ b

所以,下面的构造应该使用上面的实用方法:

 < h:inputFile value =#{bean.part}a:multiple =true/> 
< h:commandButton ... action =#{bean.submit}/>
 私人部分文件; 
$ b $ public void submit()throws ServletException,IOException {
for(Part part:getAllParts(file)){
String fileName = part.getSubmittedFileName();
InputStream fileContent = part.getInputStream();
// ...
//用它做你的事情。
//例如https://stackoverflow.com/q/14211843/157882
}
}

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

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





$ b请注意,getter可以用于总是比较好,总是返回 null 。实际上,整个getter方法应该是不必要的,但它是这样。



在更现代的浏览器上,您甚至可以选择整个文件夹。这只需要更新的目录属性。自从Firefox 46(自42以来已经支持,但需要在about:config中明确启用)才支持这个功能。基于Webkit的浏览器(Chrome 11+,Safari 4+和Edge)通过专有的 webkit目录属性支持这一功能。所以,如果你指定了这两个属性,你通常是安全的。

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

请注意,这不会发送物理文件夹,而只是包含在这些文件夹中的文件。






更新:如果您碰巧使用JSF实用程序库,从版本2.5开始,这应该使得多重和目录选择更加单调乏味。 code>< o:inputFile value =#{bean.files}multiple =true/>

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

可将值绑定到 List< Part>

 私人列表< Part>文件; // + getter + setter 


I am trying to add a multiple file upload using h:inputFile. I had a quick look through the source code and it appears that it does not have the option to render multiple="multiple". Is there a way around this without writing a custom component?If not, is there a suggested custom JSF2.2 component available that can handle multiple Ajax file uploads?

Update:I have passed the multiple="multiple" using passthrough tag, but when I debugged the FileRenderer the relevant piece of code overwrites the first file with the second:

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

As you can see, since there are two Parts with the same clientId, it always use the last instead of passing a list.

Please recommend an alternative if there is one.

解决方案

You can indeed achieve this with another JSF 2.2 feature: passthrough attributes. Set the multiple attribute as a passthrough attribute (browser support is currently quite broad).

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

However, the <h:inputFile> component itself doesn't support grabbing multiple Parts from the request and setting it as an array or Collection bean property. It would only set the last part matching the input field name. Basically, to support multiple parts, a custom renderer needs to be created (and you should immediately take the opportunity to just support multiple attribute right away without resorting to passthrough attributes).

For the sake of having a "workaround" without creating a whole renderer, you could however manually grab all the parts via HttpServletRequest with help of below little utility method:

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());
}

So, the below construct should work with above utility method:

<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;
}

Do note that the getter can for safety and clarity better always return null. Actually, the entire getter method should have been unnecessary, but it is what it is.

On the more modern browsers you can even select whole folders. This only requires a yet newer directory attribute. This is supported since Firefox 46 (already since 42, but needs to be explicitly enabled in about:config). Webkit based browsers (Chrome 11+, Safari 4+ and Edge) support this via the proprietary webkitdirectory attribute. So if you specify both attributes, you're generally safe.

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

Do note that this does not send physical folders, but only files contained in those folders.


Update: if you happen to use JSF utility library OmniFaces, since version 2.5 the <o:inputFile> is offered which should make multiple and directory selection less tedious.

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

The value can be bound to a List<Part>.

private List<Part> files; // +getter+setter

这篇关于如何使用JSF 2.2上传多个文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 22:20