如何使用 JSF 2.2 <h:inputFile> 上传文件?保存的文件在哪里?

Posted

技术标签:

【中文标题】如何使用 JSF 2.2 <h:inputFile> 上传文件?保存的文件在哪里?【英文标题】:How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File? 【发布时间】:2015-02-24 23:05:33 【问题描述】:

我希望能够在我的 JSF2.2 Web 应用程序中上传文件,因此我开始使用新的 &lt;h:inputFile&gt; 组件。

我唯一的问题是,如何指定位置,将文件保存在服务器中的哪个位置?我想将它们作为java.io.File 实例来获取。这必须在 backing bean 中实现,但我不清楚如何实现。

【问题讨论】:

将 h:inputFile 的值绑定到 bean 中的 Part 属性。然后,您的操作方法可以使用 part.write(fileName) 将数据保存在您喜欢的任何位置。 【参考方案1】:

JSF 不会将文件保存在任何预定义的位置。它基本上只会以javax.servlet.http.Part 实例的形式为您提供上传的文件,该实例在幕后临时存储在服务器内存和/或临时磁盘存储位置中,您不必担心。

重要的是,在调用 bean 操作(侦听器)方法时,您需要尽快阅读Part。当与HTTP请求关联的HTTP响应完成时,临时存储可能会被清除。换句话说,上传的文件不一定在后续请求中可用。

所以,给定一个

<h:form enctype="multipart/form-data">
    <h:inputFile value="#bean.uploadedFile">
        <f:ajax listener="#bean.upload" />
    </h:inputFile>
</h:form>

你基本上有两个选择来保存它:

1。将所有原始文件内容读入byte[]

您可以为此使用InputStream#readAllBytes()

private Part uploadedFile; // +getter+setter
private String fileName;
private byte[] fileContents;

public void upload() 
    fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.

    try (InputStream input = uploadedFile.getInputStream()) 
        fileContents = input.readAllBytes();
    
    catch (IOException e) 
        // Show faces message?
    

注意Path#getFileName()。这是关于获取提交的文件名的 MSIE 修复。此浏览器错误地沿名称发送完整的文件路径,而不仅仅是文件名。

如果您还没有使用 Java 9,因此无法使用 InputStream#readAllBytes(),那么请前往 Convert InputStream to byte array in Java 了解将 InputStream 转换为 byte[] 的所有其他方法。

请记住,上传文件的每个字节都会占用一个字节的服务器内存。请注意,当用户经常这样做或很容易以这种方式滥用您的系统时,您的服务器不会耗尽内存。如果您想避免这种情况,最好使用本地磁盘文件系统上的(临时)文件。

2。或者,将其写入本地磁盘文件系统

为了将其保存到所需的位置,您需要通过Part#getInputStream() 获取内容,然后将copy 获取到代表该位置的Path。您可以按照通常的方式在(ajax)操作(侦听器)方法中执行此操作。这是一个在 html DOM change 事件期间使用 ajax 侦听器执行此操作的示例:

private Part uploadedFile; // +getter+setter
private File savedFile;

public void upload() 
    String fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
    savedFile = new File(uploads, fileName);

    try (InputStream input = file.getInputStream()) 
        Files.copy(input, savedFile.toPath());
    
    catch (IOException e) 
        // Show faces message?
    

注意Path#getFileName()。这是关于获取提交的文件名的 MSIE 修复。此浏览器错误地沿名称发送完整的文件路径,而不仅仅是文件名。

uploads 文件夹和filename 完全由您控制。例如。 "/path/to/uploads"Part#getSubmittedFileName() 分别。请记住,任何现有文件都将被覆盖,您可能需要使用 File#createTempFile() 自动生成文件名。

不要不要使用Part#write(),就像某些人可能建议的那样。它基本上会重命名由@MultipartConfig(location) 标识的临时存储位置中的文件。另外使用ExternalContext#getRealPath() 将上传的文件保存在部署文件夹中。重新部署 WAR 时该文件将丢失,原因很简单,即该文件未包含在原始 WAR 中。始终将其保存在部署文件夹之外的绝对路径上。

如需上传预览功能的现场演示,请查看&lt;o:graphicImage&gt; demo on OmniFaces showcase的最后一项。

另见:

Write file into disk using JSF 2.2 inputFile How to save uploaded file in JSF Recommended way to save uploaded files in a servlet application

【讨论】:

这里的 f:ajax 示例中的事件是什么?点击? 只是默认的。答案是原样。 是的,我的意思是默认值是什么?

以上是关于如何使用 JSF 2.2 <h:inputFile> 上传文件?保存的文件在哪里?的主要内容,如果未能解决你的问题,请参考以下文章

<t:inputFileUpload> 将 JSF 1.2 迁移到 JSF 2.2 后不再工作

JSF 2.2 @ViewScoped 绑定错误?

JSF 2.2 多部分表单未提交[重复]

JSF 2.2 ViewScoped Bean 被多次创建

如何使用指定版本2.3的JSF Facet创建Eclipse动态Web项目?

<protected-views> 是不是应该用于 JSF 2.2 CSRF 保护?