【问题标题】:How to get JSF to upload file with Apache Commons FileUpload如何让 JSF 使用 Apache Commons FileUpload 上传文件
【发布时间】:2012-02-28 13:27:41
【问题描述】:

我知道如何使用 Primefaces 或 Tomahawk 进行文件上传,但是,我正在尝试使用 Apache Commons FileUpload 进行文件上传,到目前为止我遇到了一些障碍。即使我的表单使用multipart/form-data,当我提交表单时,内容类型也会变成application/x-www-form-urlencoded。这是我的代码

<h:body>
    <h:form enctype="multipart/form-data">
        Upload File
        <input type="file" name="file"/>
        <p:commandButton value="Submit" action="#{viewBean.submit}"/>
    </h:form>
</h:body>

这是我的ViewBean

@ManagedBean
@ViewScoped
public class ViewBean implements Serializable {
    public void submit() {
        String url = "/FileUploadServlet";
        FacesContext context = FacesContext.getCurrentInstance();
        try {
            String contentType = context.getExternalContext().getRequestContentType();
            context.getExternalContext().dispatch(url);
        } catch (Exception e) {
            logger.log(Level.SEVERE, "Exception when calling Servlet", e);
        } finally {
            context.responseComplete();
        }
    }
}

所以当我尝试打印上面的内容类型时,它显示了application/x-www-form-urlencoded。如果我把ajax="false"放到我的p:commandButton中,那么submit()方法甚至不会被调用,但是如果我取出enctype="multipart/form-data"(仍然保留ajax="false"),那么submit()被调用但它不是多部分的,它是application/x-www-form-urlencoded,因此 apache commons fileupload 抛出异常,因为它不是多部分的。似乎无论我做什么,我似乎都无法获得多部分请求。请帮忙

【问题讨论】:

    标签: jsf file-upload jsf-2 apache-commons-fileupload


    【解决方案1】:

    所以当我尝试打印上面的内容类型时,它显示了 application/x-www-form-urlencoded。

    &lt;p:commandButton&gt; 默认发送级别 1 XMLHttpRequest 的 ajax 请求。这支持multipart/form-data。只有 level 2 XMLHttpRequest 支持它,但它只在最新的浏览器(也支持 HTML5 的浏览器)中支持,并且在 JSF JS API 和 PrimeFaces JS API 中都没有实现。


    如果我将 ajax="false" 放入我的 p:commandButton,那么 submit() 方法甚至不会被调用

    这样,一个完整的multipart/form-data 发送。不调用提交方法只是因为 2.2 版之前的 JSF 不支持开箱即用的multipart/form-data 请求。 JSF 默认使用request.getParameter()getParameterMap() 在底层HTTP servlet 请求上收集提交的数据。但是,当使用application/x-www-form-urlencoded 以外的编码时,这将返回null。由于JSF是根据提交的数据来确定要调用的action方法,所以当数据为null时,将无法定位和调用。

    理论上,如果您创建一个 Filter,它使用 Apache Commons FileUpload 或新的 Servlet 3.0 request.getPart()/getParts() 方法从 multipart/form-data 请求中提取数据,并使用覆盖getParameter() 调用的自定义实现,其中提供了提取数据的映射,然后JSF 将能够根据getParameter() 调用的结果完成所需的工作。您可以在 this article 中找到一个使用 Servlet 3.0 API 的具体示例,以及在 this answer 中稍作修改以使用 Apache Commons FileUpload 的相同示例。

    即将推出的 JSF 2.2 将有一个新的 &lt;h:inputFile&gt; 组件,该组件可绑定到 Servlet 3.0 Part 属性。

    <h:form enctype="multipart/form-data">
        <h:inputFile value="#{bean.file}" />
        <h:commandButton value="submit" action="#{bean.submit}" />
    </h:form>
    

    private Part file;
    

    JSF 2.2 最终版本计划在第一季度末发布,但目前作为快照版本提供。

    【讨论】:

    • 非常感谢。很高兴知道所有这些信息。
    • @BalusC 我按照你说的创建了一个Filter,但是如果h:form 具有enctype="multipart/form-data",则操作方法不会触发。我在 JSF 1.2 中。你能告诉我为什么会这样吗?我已经问了here这个问题
    • @Tapas:我已经发布了答案。请不要忘记未来问题上的[jsf] 标签。我没有看到你的问题,因为我不经常浏览[jsf-1.2]