【问题标题】:FileUpload and Form Submit文件上传和表单提交
【发布时间】:2019-02-28 09:29:55
【问题描述】:

考虑一个带有 fileUpload 组件的表单。用户使用 fileUpload 组件选择一些文件,然后提交表单,合理地认为所选文件是与表单一起隐式提交的,但事实并非如此。 Primefaces fileUpload 组件要求用户在提交之前将文件作为显式操作上传,并为此提供方便的“上传”按钮。但是,如果用户忽略了这一点,则提交的表单没有文件,也没有任何迹象表明它们被排除在提交之外。在某些用例中,文件以后可能不会附加到表单提交创建的对象上。相比之下,JSF 和 Omnifaces inputFile 组件以及它们所基于的 HTML5 <input type="file"> 在提交时上传文件,这对我来说似乎更有用。

这是一些示例代码。先介绍一下:

    <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"
        xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:p="http://primefaces.org/ui">
    <h:head></h:head>
    <h:body>
        <f:view>
            <h:form id="form" enctype="multipart/form-data" method="POST">
                <p:panelGrid id="grid" columns="2" cellpadding="15">
                    <p:outputLabel>HTML5 input type="file"</p:outputLabel>
                    <input type="file" id="fileupload1" name="fileupload1" multiple="multiple" />
                    <p:outputLabel>Primefaces fileUpload</p:outputLabel>
                    <p:fileUpload id="fileupload2" fileUploadListener="#{myBean.handleFileUpload}" multiple="true" />
                    <p:outputLabel>JSF Input File</p:outputLabel>
                    <h:inputFile id="fileupload3" value="#{myBean.uploadedFile}" />
                </p:panelGrid>
                <p:commandButton id="submit" value="Submit" actionListener="#{myBean.submit}" process="@form" ajax="false" />
            </h:form>
        </f:view>
    </h:body>
    </html>

还有后台bean:

@ManagedBean
@SessionScoped
public class MyBean {

    private Map<String, Path> uploadedFiles = new HashMap<String, Path>();
    Part uploadedFile;

    public void handleFileUpload(FileUploadEvent event) {
        System.out.println("Uploaded file: " + event.getFile().getFileName());
    }

    public void submit(ActionEvent actionEvent) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
        for (Part part : request.getParts()) {
            if (part != null && part.getSize() > 0 && part.getSubmittedFileName() != null) {
                String fileName = part.getSubmittedFileName();
                String contentType = part.getContentType();
                System.out.println("File in request: " + fileName + "; contentType " + contentType + "; size: " + part.getSize());
            }
        }
        System.out.println("Primefaces uploaded Files (" + (uploadedFiles == null ? "0" : uploadedFiles.size()) + "):");
        if (uploadedFiles != null) {
            for (String name : uploadedFiles.keySet()) {
                System.out.println("     Name: " + name + "; Path " + uploadedFiles.get(name));
            }
        }
        System.out.println("JSF uploaded file: " + (uploadedFile == null ? "null" : uploadedFile.getSubmittedFileName() + ", size " + uploadedFile.getSize()));
    }

    public Part getUploadedFile() {
        System.out.println("get uploaded File Part: " + (uploadedFile == null ? "none" : uploadedFile.getSubmittedFileName()));
        return uploadedFile;
    }

    public void setUploadedFile(Part uploadedFile) {
        System.out.println("set uploaded File Part: " + (uploadedFile == null ? "none" : uploadedFile.getSubmittedFileName()));
        this.uploadedFile = uploadedFile;
    }
}

如果您在所有三个文件上传组件中选择文件后提交此表单,则 Primefaces 是唯一一个不会在提交时上传文件的表单。当然,您可以将“auto”设置为 true 以使其在选择时上传文件,但如果用户决定不上传文件,则无法退出。您可以将其设置为必需,但在一般情况下,用户可能不会选择上传任何文件。因此,Primefaces 组件似乎在这方面落后了一步,尽管它非常易于使用且功能更全面。

是否有一种 Primefaces 方法可以在提交时上传多个文件,但我错过了?

【问题讨论】:

  • 你在哪里读到 "JSF 标签、Primefaces 标签和 Omnifaces 标签都要求用户上传文件作为提交前的显式操作,并为此提供一个方便的“上传”按钮。" ?根据我的理解,这不是真的
  • p:fileUpload, h:inputFileo:inputFile 都渲染一个input type="file" btw,所以它完全是 HTML5,而且它们都没有上传按钮......所以我很好奇如何你得出了你的结论。他们还支持ajax上传顺便说一句,所以选择时会自动上传。
  • 我现在无法创建测试,因为我只有手机。您是否有需要显式上传按钮的minimal reproducible example
  • 我不明白你的核心问题。您是否想问如何使输入字段成为必需?如果是这样,为什么不像往常一样设置required="true" 属性?或者,您是否想问如何在业务操作中区分上传的文件和未上传的文件?如果是这样,你为什么不做一个if(file!=null) 检查?您似乎很适合做任何一个,这就是为什么这个问题如此令人困惑的原因。
  • 感谢您抽出宝贵时间回复,对于我的原始帖子中缺乏清晰性和错误,我深表歉意。我对 Omnifaces 组件的理解是错误的。我用一个丑陋但 MCV 的例子更新了这篇文章。核心问题实际上是围绕 PF 组件所需的附加“上传”操作的可用性。我没有想过将 PF 文件上传小部件标记为必需,这会起作用,除了在我当前的用例中,提交支持请求票证时,用户通常不会提交任何文件。

标签: jsf file-upload primefaces usability omnifaces


【解决方案1】:

感谢@Kukeltje 帮助我找到答案。

HTML5 &lt;input type="file"&gt;、JSF 的 &lt;h:inputFile&gt; 和 Omnifaces &lt;o:inputFile&gt; 等“简单”文件上传小部件允许用户在提交时选择一个或多个要上传的文件。

一些更复杂的 fileUpload 小部件,如 Primefaces 之一(带有mode="advanced",默认模式和multiple="true")允许用户在提交时间之前一键上传多个文件,但如果用户忽略了这样做提交时未上传所选文件。如果设计者想要避免用户假定所选文件在提交时上传而实际上没有上传的可用性问题,PF 小部件可以与mode="simple" 一起使用。以这种方式使用 PF 小部件的好处是美观且能够选择多个文件。

作为脚注,与原始问题无关,特别是 PF 小部件存在问题,可能还有类似框架中的其他类似小部件。在简单模式下,如果用户选择了多个文件,小部件只会显示第一个选择的文件。

我看到另一个问题,即用户在任何允许多个小部件中选择多个文件后,无法取消选择这些文件。在用 JS 尝试列出选择的文件后,我发现由于浏览器安全性,我无法在 JS 中更改列表,请参阅 BalusC 的答案here。我最终得到了一些简单的 JS,它在提交时检查 PF 上传小部件是否有任何选定的文件,如果有,则阻止提交并要求用户在提交之前上传文件。我认为这是最有用的解决方案。

<p:commandButton value="Submit" actionListener="#{bean.submit}" onclick="return checkAttachments();" ajax="false" />

<script>
function checkAttachments() {
    var attachmentRows = $(".ui-fileupload-row");
    console.log("rows " + attachmentRows.length);
    if (attachmentRows.length == 0 ) {
        return true;
    }
    PF('uploadAttachmentsWarningDialog').show();
    return false;
}
</script>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-26
    • 2015-07-24
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 2014-09-24
    • 2013-12-25
    相关资源
    最近更新 更多