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 by @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"));
    
  • 服务器启动期间的 VM 参数通过 -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和值/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/60548806/

相关文章:

http - 如何获得 HTTP 100 继续在嵌入式 Grizzly 上为 WebDAV 工作?

java - JSP 数据到 Servlet 使用 EL

android - Retrofit 2 文件上传不附加文件

java - eclipse mars 中 apache tomcat 8startup 的问题

java runtime.exec cmd/c 解析引用参数

java - 启动 Apache tomcat 服务器时出错

java - 在同一页面中的何处存储选定的元素值?

java - Singleton的其他成员

c# - 'HttpRequest' 不包含 'Files' 的定义

image - 将用户的个人资料照片上传到 imgur 而无需对 imgur 进行用户身份验证