tomcat - 在 servlet 应用程序中保存上传文件的推荐方法

标签 tomcat servlets file-upload servlet-3.0

我读了here那个人无论如何都不应该将文件保存在服务器中,因为它不可移植、事务性强并且需要外部参数。但是,考虑到我需要一个用于 tomcat (7) 的 tmp 解决方案,并且我对我想知道的服务器机器具有(相对)控制权:

  • 保存文件的最佳位置是什么?我应该将它保存在 /WEB-INF/uploads (建议反对 here )或 $CATALINA_BASE 下的某个地方(参见 here )或...? JavaEE 6 教程 gets the path from the user (:wtf:)。注意:该文件不应以任何方式下载。

  • 我是否应该按照详细说明设置配置参数 here ?我会欣赏一些代码(我宁愿给它一个相对路径 - 所以它至少是 Tomcat 可移植的)- Part.write()看起来很有希望——但显然需要一个绝对路径

  • 我对这种方法相对于数据库/JCR 存储库的缺点的阐述很感兴趣

不幸的是FileServlet @BalusC 专注于下载文件,而他的 answer关于上传文件的部分跳过了关于文件保存位置的部分。

最好是可以轻松转换为使用 DB 或 JCR 实现(如 jackrabbit)的解决方案。

最佳答案

将其存储在 IDE 项目文件夹(即服务器的部署文件夹)的可访问位置除外,原因在 Uploaded image only available after refreshing the page 的回答中提到。 :

  1. Changes in the IDE's project folder does not immediately get reflected in the server's work folder. There's kind of a background job in the IDE which takes care that the server's work folder get synced with last updates (this is in IDE terms called "publishing"). This is the main cause of the problem you're seeing.

  2. In real world code there are circumstances where storing uploaded files in the webapp's deploy folder will not work at all. Some servers do (either by default or by configuration) not expand the deployed WAR file into the local disk file system, but instead fully in the memory. You can't create new files in the memory without basically editing the deployed WAR file and redeploying it.

  3. Even when the server expands the deployed WAR file into the local disk file system, all newly created files will get lost on a redeploy or even a simple restart, simply because those new files are not part of the original WAR file.

对我或其他任何人来说,将其保存在本地磁盘文件系统的确切位置并不重要,只要您 do not ever use getRealPath() method .使用该方法在任何情况下都令人担忧。

存储位置的路径又可以用多种方式定义。您必须自己全部完成。也许这就是您的困惑所在,因为您以某种方式期望服务器自动完成所有这些工作。请注意 @MultipartConfig(location) 指定最终上传目的地,但案例文件大小的临时存储位置超过内存存储阈值。

因此,可以通过以下任一方式定义最终存储位置的路径:

  • 硬编码:

      File uploads = new File("/path/to/uploads");
    
  • 环境变量来自 SET UPLOAD_LOCATION=/path/to/uploads :

      File uploads = new File(System.getenv("UPLOAD_LOCATION"));
    
  • 服务器启动期间的虚拟机参数 -Dupload.location="/path/to/uploads" :

      File uploads = new File(System.getProperty("upload.location"));
    
  • *.properties文件条目为 upload.location=/path/to/uploads :

      File uploads = new File(properties.getProperty("upload.location"));
    
  • web.xml <context-param>名字upload.location和值(value)/path/to/uploads :

      File uploads = new File(getServletContext().getInitParameter("upload.location"));
    
  • 如果有的话,使用服务器提供的位置,例如在 JBoss AS/WildFly :

      File uploads = new File(System.getProperty("jboss.server.data.dir"), "uploads");
    

无论哪种方式,您都可以按如下方式轻松引用和保存文件:

File file = new File(uploads, "somefilename.ext");

try (InputStream input = part.getInputStream()) {
    Files.copy(input, file.toPath());
}

或者,当您想要自动生成一个唯一的文件名以防止用户覆盖巧合名称相同的现有文件时:

File file = File.createTempFile("somefilename-", ".ext", uploads);

try (InputStream input = part.getInputStream()) {
    Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}

如何获取part JSP/Servlet 中的答案在 How to upload files to server using JSP/Servlet? 中以及如何获得part在 JSF 中得到回答 How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?

注意:不要使用 Part#write() 因为它解释相对于 @MultipartConfig(location) 中定义的临时存储位置的路径.还要绝对确保您不会通过错误地使用 Reader 在读/写期间将字节转换为字符来破坏二进制文件,例如 PDF 文件或图像文件。/Writer而不是 InputStream/OutputStream .

另见:

关于tomcat - 在 servlet 应用程序中保存上传文件的推荐方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34786363/

相关文章:

java - 对传递给 servlet 的密码使用 sha256 是否会使其容易受到暴力攻击?

android - 在 Android 上通过 HTML FIleUpload 将图片上传到服务器

android - 将文件上传到 asp.net 服务器的进度条

spring - org.springframework.aop.framework.Cglib2AopProxy WARN - 无法代理方法

eclipse - 使用 OpenShift 远程调试 tomcat

java - 即使在 WebServlet 注释中指定 "loadonstartup"元素之后,Tomcat 也不会选择 servlet

java - 在jsp servlet中创建文件

java - ClassLoader 似乎没有正确返回对象

java - EmbeddedServletContainerFactory TomcatEmbeddedServletContainerFactory在spring boot版本2.0.0.M1找不到

c# - 如何构建base64 rest web服务来上传带有其他信息的图像文件