问题描述
我希望能够在我的 JSF2.2 Web 应用程序中上传文件,因此我开始使用新的 组件.
I would like to be able to upload files in my JSF2.2 web application, so I started using the new <h:inputFile>
component.
我唯一的问题是,如何指定文件将在服务器中保存的位置?我想把它们当作 java.io.File
实例.这必须在支持 bean 中实现,但我不清楚如何实现.
My only question is, how can I specify the location, where the files will be saved in the server? I would like to get hold of them as java.io.File
instances. This has to be implemented in the backing bean, but I don't clearly understand how.
推荐答案
JSF 不会将文件保存在任何预定义的位置.它基本上只会为您提供 风格的上传文件javax.servlet.http.Part
幕后实例,临时存储在服务器内存和/或临时磁盘存储位置,您不必担心.
JSF won't save the file in any predefined location. It will basically just offer you the uploaded file in flavor of a javax.servlet.http.Part
instance which is behind the scenes temporarily stored in server's memory and/or temporary disk storage location which you shouldn't worry about.
重要的是,当调用bean action(监听器)方法时,你需要尽快阅读Part
.当与HTTP请求相关联的HTTP响应完成时,可以清除临时存储器.换句话说,上传的文件不一定在后续请求中可用.
Important is that you need to read the Part
as soon as possible when the bean action (listener) method is invoked. The temporary storage may be cleared out when the HTTP response associated with the HTTP request is completed. In other words, the uploaded file won't necessarily be available in a subsequent request.
所以,给定一个
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.uploadedFile}">
<f:ajax listener="#{bean.upload}" />
</h:inputFile>
</h:form>
您基本上有两个选项可以保存它:
You have basically 2 options to save it:
您可以使用InputStream#readAllBytes()
为此.
You can use InputStream#readAllBytes()
for this.
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 修复.此浏览器错误地沿名称发送了完整的文件路径,而不仅仅是文件名.
Note the Path#getFileName()
. This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
如果您尚未使用 Java 9,因此无法使用 InputStream#readAllBytes()
,请前往 将 InputStream 转换为 Java 中的字节数组 用于将 InputStream
转换为 byte[].
In case you're not on Java 9 yet and therefore can't use InputStream#readAllBytes()
, then head to Convert InputStream to byte array in Java for all other ways to convert InputStream
to byte[]
.
请记住,上传文件的每个字节都会占用一个字节的服务器内存.当用户经常这样做或者很容易以这种方式滥用您的系统时,请注意您的服务器不要耗尽内存.如果您想避免这种情况,最好改用本地磁盘文件系统上的(临时)文件.
Keep in mind that each byte of an uploaded file costs one byte of server memory. Be careful that your server don't exhaust of memory when users do this too often or can easily abuse your system in this way. If you want to avoid this, better use (temporary) files on local disk file system instead.
为了将其保存到所需位置,您需要通过Part#getInputStream()
然后 copy 到 Path
代表位置.您可以以通常的方式在(ajax)操作(侦听器)方法中执行此操作.这是在 HTML DOM change
事件期间使用 ajax 侦听器执行此操作的示例:
In order to save it to the desired location, you need to get the content by Part#getInputStream()
and then copy it to the Path
representing the location. You can do this in an (ajax) action (listener) method the usual way. Here's an example which does it with an ajax listener during the HTML DOM change
event:
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 修复.此浏览器错误地沿名称发送了完整的文件路径,而不仅仅是文件名.
Note the Path#getFileName()
. This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
uploads
文件夹和 filename
完全在您的控制之下.例如."/path/to/uploads"
和 Part#getSubmittedFileName()
分别.请记住,任何现有文件都将被覆盖,您可能希望使用 File#createTempFile()
自动生成文件名.
The uploads
folder and the filename
is fully under your control. E.g. "/path/to/uploads"
and Part#getSubmittedFileName()
respectively. Keep in mind that any existing file would be overwritten, you might want to use File#createTempFile()
to autogenerate a filename.
不要不要使用Part#write()
正如某些prople 可能建议的那样.它将基本上重命名由 @MultipartConfig(location)
标识的临时存储位置中的文件.还要不要使用 ExternalContext#getRealPath()
将上传的文件保存在部署文件夹中.重新部署 WAR 时,该文件将丢失,原因很简单,原始 WAR 中不包含该文件.始终将其保存在部署文件夹之外的绝对路径中.
Do not use Part#write()
as some prople may suggest. It will basically rename the file in the temporary storage location as identified by @MultipartConfig(location)
. Also do not use ExternalContext#getRealPath()
in order to save the uploaded file in deploy folder. The file will get lost when the WAR is redeployed for the simple reason that the file is not contained in the original WAR. Always save it on an absolute path outside the deploy folder.
有关上传和预览功能的现场演示,请查看<的最后一项.o:graphicImage>
OmniFaces 展示上的演示.
For a live demo of upload-and-preview feature, check the last item of <o:graphicImage>
demo on OmniFaces showcase.
这篇关于如何使用 JSF 2.2 <h:inputFile> 上传文件?保存的文件在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!